diff --git a/.gitattributes b/.gitattributes index 8b86ad5d30..0a392e14f6 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1,3 +1,3 @@ # ignore all differences in line endings -package.json -crlf -*/package.json -crlf +package.json eol=crlf -crlf +*/package.json eol=crlf -crlf diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS new file mode 100644 index 0000000000..6eac745173 --- /dev/null +++ b/.github/CODEOWNERS @@ -0,0 +1 @@ +backend/src/api/database-migration.ts @wiz @softsimon diff --git a/.github/ISSUE_TEMPLATE.md b/.github/ISSUE_TEMPLATE.md deleted file mode 100644 index 08c50925ef..0000000000 --- a/.github/ISSUE_TEMPLATE.md +++ /dev/null @@ -1,37 +0,0 @@ - - -### Description - - - -#### Version - - - -### Steps to reproduce - - - -### Expected behaviour - - - -### Actual behaviour - - - -### Screenshots - - - -#### Device or machine - - - -#### Additional info - - diff --git a/.github/ISSUE_TEMPLATE/00-bug-issue.md b/.github/ISSUE_TEMPLATE/00-bug-issue.md new file mode 100644 index 0000000000..aaa5ef5c79 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/00-bug-issue.md @@ -0,0 +1,43 @@ +--- +name: 🐛 Bug Report +about: Report bugs (no support requests, please) +--- + + + +### Description + + + +#### Version + + + +### Steps to reproduce + + + +### Expected behaviour + + + +### Actual behaviour + + + +### Screenshots + + + +#### Device or machine + + + +#### Additional info + + diff --git a/.github/ISSUE_TEMPLATE/30-feature-request.md b/.github/ISSUE_TEMPLATE/30-feature-request.md new file mode 100644 index 0000000000..8dbbf56de1 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/30-feature-request.md @@ -0,0 +1,27 @@ +--- +name: ✨ Feature Request +about: Request a feature or suggest other enhancements +--- + + + +### Description + + + +### Problem to be solved + + + +### Proposed solution + + + +#### Additional info + + diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml new file mode 100644 index 0000000000..1d01fd18d5 --- /dev/null +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -0,0 +1,8 @@ +blank_issues_enabled: false +contact_links: + - name: 🙋 Need help? Chat with us on Matrix + url: https://matrix.to/#/#mempool.support:bitcoin.kyoto + about: For support requests or general questions + - name: 🌐 Want to help with translations? Use Transifex + url: https://www.transifex.com/mempool/mempool + about: All translations work is done on Transifex diff --git a/.github/dependabot.yml b/.github/dependabot.yml new file mode 100644 index 0000000000..8352de555b --- /dev/null +++ b/.github/dependabot.yml @@ -0,0 +1,68 @@ +version: 2 +updates: + - package-ecosystem: npm + versioning-strategy: increase + directory: "/backend" + schedule: + interval: daily + open-pull-requests-limit: 10 + ignore: + - dependency-name: "*" + update-types: + ["version-update:semver-major", "version-update:semver-patch"] + allow: + - dependency-type: "production" + + - package-ecosystem: npm + directory: "/frontend" + versioning-strategy: increase + groups: + frontend-angular-dependencies: + patterns: + - "@angular*" + - "@ng-*" + - "ngx-*" + frontend-jest-dependencies: + patterns: + - "@types/jest" + - "jest" + frontend-eslint-dependencies: + patterns: + - "@typescript-eslint*" + - "eslint" + schedule: + interval: daily + open-pull-requests-limit: 10 + ignore: + - dependency-name: "*" + update-types: + ["version-update:semver-major", "version-update:semver-patch"] + allow: + - dependency-type: "production" + + - package-ecosystem: docker + directory: "/docker/backend" + schedule: + interval: weekly + ignore: + - dependency-name: "*" + update-types: + ["version-update:semver-major", "version-update:semver-patch"] + + - package-ecosystem: docker + directory: "/docker/frontend" + schedule: + interval: weekly + ignore: + - dependency-name: "*" + update-types: + ["version-update:semver-major", "version-update:semver-patch"] + + - package-ecosystem: "github-actions" + directory: "/" + schedule: + interval: weekly + ignore: + - dependency-name: "*" + update-types: + ["version-update:semver-major", "version-update:semver-patch"] diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md new file mode 100644 index 0000000000..0b3668cf1b --- /dev/null +++ b/.github/pull_request_template.md @@ -0,0 +1,6 @@ + diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000000..8a29e91849 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,362 @@ +name: CI Pipeline for the Backend and Frontend + +on: + pull_request: + types: [opened, review_requested, synchronize] + +jobs: + backend: + if: "!contains(github.event.pull_request.labels.*.name, 'ops') && !contains(github.head_ref, 'ops/')" + strategy: + matrix: + node: ["20", "21"] + flavor: ["dev", "prod"] + fail-fast: false + runs-on: "ubuntu-latest" + + name: Backend (${{ matrix.flavor }}) - node ${{ matrix.node }} + steps: + - name: Checkout + uses: actions/checkout@v3 + with: + path: ${{ matrix.node }}/${{ matrix.flavor }} + + - name: Setup Node + uses: actions/setup-node@v3 + with: + node-version: ${{ matrix.node }} + registry-url: "https://registry.npmjs.org" + + - name: Read rust-toolchain file from repository + id: gettoolchain + run: echo "::set-output name=toolchain::$(cat ./rust/gbt/rust-toolchain)" + working-directory: ${{ matrix.node }}/${{ matrix.flavor }} + + - name: Install ${{ steps.gettoolchain.outputs.toolchain }} Rust toolchain + # Latest version available on this commit is 1.71.1 + # Commit date is Aug 3, 2023 + uses: dtolnay/rust-toolchain@d8352f6b1d2e870bc5716e7a6d9b65c4cc244a1a + with: + toolchain: ${{ steps.gettoolchain.outputs.toolchain }} + + - name: Install + if: ${{ matrix.flavor == 'dev'}} + run: npm ci + working-directory: ${{ matrix.node }}/${{ matrix.flavor }}/backend + + - name: Install (Prod dependencies only) + if: ${{ matrix.flavor == 'prod'}} + run: npm ci --omit=dev --omit=optional + working-directory: ${{ matrix.node }}/${{ matrix.flavor }}/backend + + - name: Lint + if: ${{ matrix.flavor == 'dev'}} + run: npm run lint + working-directory: ${{ matrix.node }}/${{ matrix.flavor }}/backend + + - name: Unit Tests + if: ${{ matrix.flavor == 'dev'}} + run: npm run test:ci + working-directory: ${{ matrix.node }}/${{ matrix.flavor }}/backend + + - name: Build + run: npm run build + working-directory: ${{ matrix.node }}/${{ matrix.flavor }}/backend + + + cache: + name: "Cache assets for builds" + runs-on: "ubuntu-latest" + steps: + - name: Checkout + uses: actions/checkout@v3 + with: + path: assets + + - name: Setup Node + uses: actions/setup-node@v3 + with: + node-version: ${{ matrix.node }} + registry-url: "https://registry.npmjs.org" + + - name: Install (Prod dependencies only) + run: npm ci --omit=dev --omit=optional + working-directory: assets/frontend + + - name: Restore cached mining pool assets + continue-on-error: true + id: cache-mining-pool-restore + uses: actions/cache/restore@v4 + with: + path: | + mining-pool-assets.zip + key: mining-pool-assets-cache + + - name: Restore promo video assets + continue-on-error: true + id: cache-promo-video-restore + uses: actions/cache/restore@v4 + with: + path: | + promo-video-assets.zip + key: promo-video-assets-cache + + - name: Unzip assets before building (src/resources) + continue-on-error: true + run: unzip -o mining-pool-assets.zip -d assets/frontend/src/resources/mining-pools + + - name: Unzip assets before building (src/resources) + continue-on-error: true + run: unzip -o promo-video-assets.zip -d assets/frontend/src/resources/promo-video + + # - name: Unzip assets before building (dist) + # continue-on-error: true + # run: unzip assets.zip -d assets/frontend/dist/mempool/browser/resources + + - name: Sync-assets + run: npm run sync-assets-dev + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + MEMPOOL_CDN: 1 + VERBOSE: 1 + working-directory: assets/frontend + + - name: Zip mining-pool assets + run: zip -jrq mining-pool-assets.zip assets/frontend/src/resources/mining-pools/* + + - name: Zip promo-video assets + run: zip -jrq promo-video-assets.zip assets/frontend/src/resources/promo-video/* + + - name: Upload mining pool assets as artifact + uses: actions/upload-artifact@v4 + with: + name: mining-pool-assets + path: mining-pool-assets.zip + + - name: Upload promo video assets as artifact + uses: actions/upload-artifact@v4 + with: + name: promo-video-assets + path: promo-video-assets.zip + + - name: Save mining pool assets cache + id: cache-mining-pool-save + uses: actions/cache/save@v4 + with: + path: | + mining-pool-assets.zip + key: mining-pool-assets-cache + + - name: Save promo video assets cache + id: cache-promo-video-save + uses: actions/cache/save@v4 + with: + path: | + promo-video-assets.zip + key: promo-video-assets-cache + + frontend: + needs: cache + if: "!contains(github.event.pull_request.labels.*.name, 'ops') && !contains(github.head_ref, 'ops/')" + strategy: + matrix: + node: ["20", "21"] + flavor: ["dev", "prod"] + fail-fast: false + runs-on: "ubuntu-latest" + + name: Frontend (${{ matrix.flavor }}) - node ${{ matrix.node }} + steps: + - name: Checkout + uses: actions/checkout@v3 + with: + path: ${{ matrix.node }}/${{ matrix.flavor }} + + - name: Setup Node + uses: actions/setup-node@v3 + with: + node-version: ${{ matrix.node }} + registry-url: "https://registry.npmjs.org" + + - name: Install (Prod dependencies only) + run: npm ci --omit=dev --omit=optional + if: ${{ matrix.flavor == 'prod'}} + working-directory: ${{ matrix.node }}/${{ matrix.flavor }}/frontend + + - name: Install + if: ${{ matrix.flavor == 'dev'}} + run: npm ci + working-directory: ${{ matrix.node }}/${{ matrix.flavor }}/frontend + + - name: Lint + if: ${{ matrix.flavor == 'dev'}} + run: npm run lint + working-directory: ${{ matrix.node }}/${{ matrix.flavor }}/frontend + + # - name: Test + # run: npm run test + + - name: Restore cached mining pool assets + continue-on-error: true + id: cache-mining-pool-restore + uses: actions/cache/restore@v4 + with: + path: | + mining-pool-assets.zip + key: mining-pool-assets-cache + + - name: Restore promo video assets + continue-on-error: true + id: cache-promo-video-restore + uses: actions/cache/restore@v4 + with: + path: | + promo-video-assets.zip + key: promo-video-assets-cache + + - name: Download artifact + uses: actions/download-artifact@v4 + with: + name: mining-pool-assets + + - name: Unzip assets before building (src/resources) + run: unzip -o mining-pool-assets.zip -d ${{ matrix.node }}/${{ matrix.flavor }}/frontend/src/resources/mining-pools + + - name: Download artifact + uses: actions/download-artifact@v4 + with: + name: promo-video-assets + + - name: Unzip assets before building (src/resources) + run: unzip -o promo-video-assets.zip -d ${{ matrix.node }}/${{ matrix.flavor }}/frontend/src/resources/promo-video + + # - name: Unzip assets before building (dist) + # run: unzip assets.zip -d ${{ matrix.node }}/${{ matrix.flavor }}/frontend/dist/mempool/browser/resources + + - name: Display resulting source tree + run: ls -R + + - name: Build + run: npm run build + working-directory: ${{ matrix.node }}/${{ matrix.flavor }}/frontend + env: + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + MEMPOOL_CDN: 1 + VERBOSE: 1 + + e2e: + if: "!contains(github.event.pull_request.labels.*.name, 'ops') && !contains(github.head_ref, 'ops/')" + runs-on: "ubuntu-latest" + needs: frontend + strategy: + fail-fast: false + matrix: + module: ["mempool", "liquid"] + include: + - module: "mempool" + spec: | + cypress/e2e/mainnet/*.spec.ts + cypress/e2e/signet/*.spec.ts + cypress/e2e/testnet4/*.spec.ts + - module: "liquid" + spec: | + cypress/e2e/liquid/liquid.spec.ts + cypress/e2e/liquidtestnet/liquidtestnet.spec.ts + + name: E2E tests for ${{ matrix.module }} + steps: + - name: Checkout + uses: actions/checkout@v3 + with: + path: ${{ matrix.module }} + + - name: Setup node + uses: actions/setup-node@v3 + with: + node-version: 20 + cache: "npm" + cache-dependency-path: ${{ matrix.module }}/frontend/package-lock.json + + - name: Restore cached mining pool assets + continue-on-error: true + id: cache-mining-pool-restore + uses: actions/cache/restore@v4 + with: + path: | + mining-pool-assets.zip + key: mining-pool-assets-cache + + - name: Restore cached promo video assets + continue-on-error: true + id: cache-promo-video-restore + uses: actions/cache/restore@v4 + with: + path: | + promo-video-assets.zip + key: promo-video-assets-cache + + - name: Download artifact + uses: actions/download-artifact@v4 + with: + name: mining-pool-assets + + - name: Unzip assets before building (src/resources) + run: unzip -o mining-pool-assets.zip -d ${{ matrix.module }}/frontend/src/resources/mining-pools + + - name: Download artifact + uses: actions/download-artifact@v4 + with: + name: promo-video-assets + + - name: Unzip assets before building (src/resources) + run: unzip -o promo-video-assets.zip -d ${{ matrix.module }}/frontend/src/resources/promo-video + + - name: Chrome browser tests (${{ matrix.module }}) + uses: cypress-io/github-action@v5 + with: + tag: ${{ github.event_name }} + working-directory: ${{ matrix.module }}/frontend + build: npm run config:defaults:${{ matrix.module }} + start: npm run start:local-staging + wait-on: "http://localhost:4200" + wait-on-timeout: 120 + record: true + parallel: true + spec: ${{ matrix.spec }} + group: Tests on Chrome (${{ matrix.module }}) + browser: "chrome" + ci-build-id: "${{ github.sha }}-${{ github.workflow }}-${{ github.event_name }}" + env: + COMMIT_INFO_MESSAGE: ${{ github.event.pull_request.title }} + CYPRESS_RECORD_KEY: ${{ secrets.CYPRESS_RECORD_KEY }} + GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }} + CYPRESS_PROJECT_ID: ${{ secrets.CYPRESS_PROJECT_ID }} + + validate_docker_json: + if: "!contains(github.event.pull_request.labels.*.name, 'ops') && !contains(github.head_ref, 'ops/')" + runs-on: "ubuntu-latest" + name: Validate generated backend Docker JSON + + steps: + - name: Checkout + uses: actions/checkout@v3 + with: + path: docker + + - name: Install jq + run: sudo apt-get install jq -y + + - name: Create new start script to run on CI + run: | + sed '$d' start.sh > start_ci.sh + working-directory: docker/docker/backend + + - name: Run the script to generate the sample JSON + run: | + sh start_ci.sh + working-directory: docker/docker/backend + + - name: Validate JSON syntax + run: | + cat mempool-config.json | jq + working-directory: docker/docker/backend diff --git a/.github/workflows/get_backend_block_height.yml b/.github/workflows/get_backend_block_height.yml new file mode 100644 index 0000000000..52f3b038cd --- /dev/null +++ b/.github/workflows/get_backend_block_height.yml @@ -0,0 +1,19 @@ +name: 'Check if servers are in sync' + +on: [workflow_dispatch] + +jobs: + print-backend-sha: + runs-on: 'ubuntu-latest' + name: Get block height + steps: + - name: Checkout + uses: actions/checkout@v3 + with: + path: repo + + - name: Run script + working-directory: repo + run: | + chmod +x ./scripts/get_block_tip_height.sh + sh ./scripts/get_block_tip_height.sh diff --git a/.github/workflows/get_backend_hash.yml b/.github/workflows/get_backend_hash.yml new file mode 100644 index 0000000000..57950dee47 --- /dev/null +++ b/.github/workflows/get_backend_hash.yml @@ -0,0 +1,19 @@ +name: 'Print backend hashes' + +on: [workflow_dispatch] + +jobs: + print-backend-sha: + runs-on: 'ubuntu-latest' + name: Print backend hashes + steps: + - name: Checkout + uses: actions/checkout@v3 + with: + path: repo + + - name: Run script + working-directory: repo + run: | + chmod +x ./scripts/get_backend_hash.sh + sh ./scripts/get_backend_hash.sh diff --git a/.github/workflows/get_image_digest.yml b/.github/workflows/get_image_digest.yml new file mode 100644 index 0000000000..7414eeb081 --- /dev/null +++ b/.github/workflows/get_image_digest.yml @@ -0,0 +1,26 @@ +name: 'Print images digest' + +on: + workflow_dispatch: + inputs: + version: + description: 'Image Version' + required: false + default: 'latest' + type: string +jobs: + print-images-sha: + runs-on: 'ubuntu-latest' + name: Print digest for images + steps: + - name: Checkout + uses: actions/checkout@v3 + with: + path: digest + + - name: Run script + working-directory: digest + run: | + sh ./docker/scripts/get_image_digest.sh $VERSION + env: + VERSION: ${{ github.event.inputs.version }} diff --git a/.github/workflows/on-tag.yml b/.github/workflows/on-tag.yml new file mode 100644 index 0000000000..634a27ab94 --- /dev/null +++ b/.github/workflows/on-tag.yml @@ -0,0 +1,107 @@ +name: Docker build on tag +env: + DOCKER_CLI_EXPERIMENTAL: enabled + TAG_FMT: "^refs/tags/(((.?[0-9]+){3,4}))$" + DOCKER_BUILDKIT: 0 + COMPOSE_DOCKER_CLI_BUILD: 0 + +on: + push: + tags: + - v[0-9]+.[0-9]+.[0-9]+ + - v[0-9]+.[0-9]+.[0-9]+-* + +permissions: + contents: read + +jobs: + build: + strategy: + matrix: + service: + - frontend + - backend + runs-on: ubuntu-latest + timeout-minutes: 120 + name: Build and push to DockerHub + steps: + # Workaround based on JonasAlfredsson/docker-on-tmpfs@v1.0.1 + - name: Replace the current swap file + shell: bash + run: | + sudo swapoff /mnt/swapfile + sudo rm -v /mnt/swapfile + sudo fallocate -l 13G /mnt/swapfile + sudo chmod 600 /mnt/swapfile + sudo mkswap /mnt/swapfile + sudo swapon /mnt/swapfile + + - name: Show current memory and swap status + shell: bash + run: | + sudo free -h + echo + sudo swapon --show + + - name: Mount a tmpfs over /var/lib/docker + shell: bash + run: | + if [ ! -d "/var/lib/docker" ]; then + echo "Directory '/var/lib/docker' not found" + exit 1 + fi + sudo mount -t tmpfs -o size=10G tmpfs /var/lib/docker + sudo systemctl restart docker + sudo df -h | grep docker + + - name: Set env variables + run: echo "TAG=${GITHUB_REF/refs\/tags\//}" >> $GITHUB_ENV + + - name: Show set environment variables + run: | + printf " TAG: %s\n" "$TAG" + + - name: Add SHORT_SHA env property with commit short sha + run: echo "SHORT_SHA=`echo ${GITHUB_SHA} | cut -c1-8`" >> $GITHUB_ENV + + - name: Login to Docker for building + run: echo "${{ secrets.DOCKER_PASSWORD }}" | docker login -u "${{ secrets.DOCKER_USERNAME }}" --password-stdin + + - name: Checkout project + uses: actions/checkout@v4 + + - name: Init repo for Dockerization + run: docker/init.sh "$TAG" + + - name: Set up QEMU + uses: docker/setup-qemu-action@v3 + id: qemu + + - name: Setup Docker buildx action + uses: docker/setup-buildx-action@v3 + id: buildx + + - name: Available platforms + run: echo ${{ steps.buildx.outputs.platforms }} + + - name: Cache Docker layers + uses: actions/cache@v3 + id: cache + with: + path: /tmp/.buildx-cache + key: ${{ runner.os }}-buildx-${{ github.sha }} + restore-keys: | + ${{ runner.os }}-buildx- + + - name: Run Docker buildx for ${{ matrix.service }} against tag + run: | + docker buildx build \ + --cache-from "type=local,src=/tmp/.buildx-cache" \ + --cache-to "type=local,dest=/tmp/.buildx-cache" \ + --platform linux/amd64,linux/arm64 \ + --tag ${{ secrets.DOCKER_HUB_USER }}/${{ matrix.service }}:$TAG \ + --tag ${{ secrets.DOCKER_HUB_USER }}/${{ matrix.service }}:latest \ + --build-context rustgbt=./rust \ + --build-context backend=./backend \ + --output "type=registry" ./${{ matrix.service }}/ \ + --build-arg commitHash=$SHORT_SHA diff --git a/.gitignore b/.gitignore index cf813d1f4c..381f2187c2 100644 --- a/.gitignore +++ b/.gitignore @@ -1 +1,9 @@ sitemap +data +docker-compose.yml +backend/mempool-config.json +*.swp +frontend/src/resources/config.template.js +frontend/src/resources/config.js +target +docker/backend/start_ci.sh \ No newline at end of file diff --git a/.nvmrc b/.nvmrc new file mode 100644 index 0000000000..a9b234d515 --- /dev/null +++ b/.nvmrc @@ -0,0 +1 @@ +v20.8.0 diff --git a/.vscode/settings.json b/.vscode/settings.json new file mode 100644 index 0000000000..323fa25e4c --- /dev/null +++ b/.vscode/settings.json @@ -0,0 +1,6 @@ +{ + "editor.tabSize": 2, + "typescript.preferences.importModuleSpecifier": "relative", + "typescript.tsdk": "./backend/node_modules/typescript/lib", + "rust-analyzer.procMacro.ignored": { "napi-derive": ["napi"] } +} \ No newline at end of file diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000000..0e43bda944 --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,51 @@ +# Contributing to The Mempool Open Source Project + +Thank you for contributing to The Mempool Open Source Project managed by Mempool Space K.K. (“Mempool”). + +In order to clarify the intellectual property license granted with Contributions from any person or entity, Mempool must have a statement on file from each Contributor indicating their agreement to the Contributor License Agreement (“Agreement”). This license is for your protection as a Contributor as well as the protection of Mempool and its other contributors and users; it does not change your rights to use your own Contributions for any other purpose. + +When submitting a pull request for the first time, please create a file with a name like `/contributors/{github_username}.txt`, and in the content of that file indicate your agreement to the Contributor License Agreement terms below. An example of what that file should contain can be seen in wiz's agreement file. (This method of CLA "signing" is borrowed from Medium's open source project.) + +Also, please GPG-sign all your commits (`git config commit.gpgsign true`). + +# Contributor License Agreement + +Last Updated: January 25, 2022 + +By accepting this Agreement, You agree to the following terms and conditions for Your present and future Contributions submitted to Mempool. Except for the license granted herein to Mempool and recipients of software distributed by Mempool, You reserve all right, title, and interest in and to Your Contributions. + +### 1. Definitions + +“You” (or “Your”) shall mean the copyright owner or legal entity authorized by the copyright owner that is making this Agreement with Mempool. For legal entities, the entity making a Contribution and all other entities that control, are controlled by, or are under common control with that entity are considered to be a single Contributor. 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. + +“Contribution” shall mean any original work of authorship, including any modifications or additions to an existing work, that is intentionally submitted by You to Mempool for inclusion in, or documentation of, any of the products owned or managed by Mempool (“Work”). For the purposes of this definition, “submitted” means any form of electronic, verbal, or written communication sent to Mempool 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, Mempool for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by You as “Not a Contribution.” + +### 2. Grant of Copyright License + +Subject to the terms and conditions of this Agreement, You hereby grant to Mempool and to recipients of software distributed by Mempool 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 Your Contributions and such derivative works. + +### 3. Grant of Patent License + +Subject to the terms and conditions of this Agreement, You hereby grant to Mempool and to recipients of software distributed by Mempool 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 You that are necessarily infringed by Your Contribution(s) alone or by combination of Your Contribution(s) with the Work to which such Contribution(s) was submitted. If any entity institutes patent litigation against You or any other entity (including a cross-claim or counterclaim in a lawsuit) alleging that your Contribution, or the Work to which you have contributed, constitutes direct or contributory patent infringement, then any patent licenses granted to that entity under this Agreement for that Contribution or Work shall terminate as of the date such litigation is filed. + +### 4. Authority + +You represent that you are legally entitled to grant the above license. If your employer(s) has rights to intellectual property that you create that includes your Contributions, you represent that you have received permission to make Contributions on behalf of that employer, that your employer has waived such rights for your Contributions to Mempool, or that your employer has executed a separate Corporate Contributor License Agreement with Mempool. + +### 5. Originality + +You represent that each of Your Contributions is Your original creation (see section 7 for submissions on behalf of others). You represent that Your Contribution submissions include complete details of any third-party license or other restriction (including, but not limited to, related patents and trademarks) of which you are personally aware, and which are associated with any part of Your Contributions. + +### 6. Support + +You are not expected to provide support for Your Contributions, except to the extent You desire to provide support. You may provide support for free, for a fee, or not at all. Unless required by applicable law or agreed to in writing, You provide Your 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. + +### 7. Third Party Contributions + +Should You wish to submit work that is not Your original creation, You may submit it to Mempool separately from any Contribution, identifying the complete details of its source and of any license or other restriction (including, but not limited to, related patents, trademarks, and license agreements) of which you are personally aware, and conspicuously marking the work as “Submitted on behalf of a third-party: [named here]”. + +### 8. Notifications + +You agree to notify Mempool of any facts or circumstances of which you become aware that would make these representations inaccurate in any respect. + +EOF diff --git a/COPYING.md b/COPYING.md new file mode 100644 index 0000000000..cba6f6a15a --- /dev/null +++ b/COPYING.md @@ -0,0 +1,660 @@ +### GNU AFFERO GENERAL PUBLIC LICENSE + +Version 3, 19 November 2007 + +Copyright (C) 2007 Free Software Foundation, Inc. + + +Everyone is permitted to copy and distribute verbatim copies of this +license document, but changing it is not allowed. + +### Preamble + +The GNU Affero General Public License is a free, copyleft license for +software and other kinds of works, specifically designed to ensure +cooperation with the community in the case of network server software. + +The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +our General Public Licenses are intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains +free software for all its users. + +When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + +Developers that use our General Public Licenses protect your rights +with two steps: (1) assert copyright on the software, and (2) offer +you this License which gives you legal permission to copy, distribute +and/or modify the software. + +A secondary benefit of defending all users' freedom is that +improvements made in alternate versions of the program, if they +receive widespread use, become available for other developers to +incorporate. Many developers of free software are heartened and +encouraged by the resulting cooperation. However, in the case of +software used on network servers, this result may fail to come about. +The GNU General Public License permits making a modified version and +letting the public access it on a server without ever releasing its +source code to the public. + +The GNU Affero General Public License is designed specifically to +ensure that, in such cases, the modified source code becomes available +to the community. It requires the operator of a network server to +provide the source code of the modified version running there to the +users of that server. Therefore, public use of a modified version, on +a publicly accessible server, gives the public access to the source +code of the modified version. + +An older license, called the Affero General Public License and +published by Affero, was designed to accomplish similar goals. This is +a different license, not a version of the Affero GPL, but Affero has +released a new version of the Affero GPL which permits relicensing +under this license. + +The precise terms and conditions for copying, distribution and +modification follow. + +### TERMS AND CONDITIONS + +#### 0. Definitions. + +"This License" refers to version 3 of the GNU Affero General Public +License. + +"Copyright" also means copyright-like laws that apply to other kinds +of works, such as semiconductor masks. + +"The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + +To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of +an exact copy. The resulting work is called a "modified version" of +the earlier work or a work "based on" the earlier work. + +A "covered work" means either the unmodified Program or a work based +on the Program. + +To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + +To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user +through a computer network, with no transfer of a copy, is not +conveying. + +An interactive user interface displays "Appropriate Legal Notices" to +the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + +#### 1. Source Code. + +The "source code" for a work means the preferred form of the work for +making modifications to it. "Object code" means any non-source form of +a work. + +A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + +The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + +The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + +The Corresponding Source need not include anything that users can +regenerate automatically from other parts of the Corresponding Source. + +The Corresponding Source for a work in source code form is that same +work. + +#### 2. Basic Permissions. + +All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + +You may make, run and propagate covered works that you do not convey, +without conditions so long as your license otherwise remains in force. +You may convey covered works to others for the sole purpose of having +them make modifications exclusively for you, or provide you with +facilities for running those works, provided that you comply with the +terms of this License in conveying all material for which you do not +control copyright. Those thus making or running the covered works for +you must do so exclusively on your behalf, under your direction and +control, on terms that prohibit them from making any copies of your +copyrighted material outside their relationship with you. + +Conveying under any other circumstances is permitted solely under the +conditions stated below. Sublicensing is not allowed; section 10 makes +it unnecessary. + +#### 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + +No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + +When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such +circumvention is effected by exercising rights under this License with +respect to the covered work, and you disclaim any intention to limit +operation or modification of the work as a means of enforcing, against +the work's users, your or third parties' legal rights to forbid +circumvention of technological measures. + +#### 4. Conveying Verbatim Copies. + +You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + +You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + +#### 5. Conveying Modified Source Versions. + +You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these +conditions: + +- a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. +- b) The work must carry prominent notices stating that it is + released under this License and any conditions added under + section 7. This requirement modifies the requirement in section 4 + to "keep intact all notices". +- c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. +- d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + +A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + +#### 6. Conveying Non-Source Forms. + +You may convey a covered work in object code form under the terms of +sections 4 and 5, provided that you also convey the machine-readable +Corresponding Source under the terms of this License, in one of these +ways: + +- a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. +- b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the Corresponding + Source from a network server at no charge. +- c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. +- d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. +- e) Convey the object code using peer-to-peer transmission, + provided you inform other peers where the object code and + Corresponding Source of the work are being offered to the general + public at no charge under subsection 6d. + +A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + +A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, +family, or household purposes, or (2) anything designed or sold for +incorporation into a dwelling. In determining whether a product is a +consumer product, doubtful cases shall be resolved in favor of +coverage. For a particular product received by a particular user, +"normally used" refers to a typical or common use of that class of +product, regardless of the status of the particular user or of the way +in which the particular user actually uses, or expects or is expected +to use, the product. A product is a consumer product regardless of +whether the product has substantial commercial, industrial or +non-consumer uses, unless such uses represent the only significant +mode of use of the product. + +"Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to +install and execute modified versions of a covered work in that User +Product from a modified version of its Corresponding Source. The +information must suffice to ensure that the continued functioning of +the modified object code is in no case prevented or interfered with +solely because modification has been made. + +If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + +The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or +updates for a work that has been modified or installed by the +recipient, or for the User Product in which it has been modified or +installed. Access to a network may be denied when the modification +itself materially and adversely affects the operation of the network +or violates the rules and protocols for communication across the +network. + +Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + +#### 7. Additional Terms. + +"Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + +When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + +Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders +of that material) supplement the terms of this License with terms: + +- a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or +- b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or +- c) Prohibiting misrepresentation of the origin of that material, + or requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or +- d) Limiting the use for publicity purposes of names of licensors + or authors of the material; or +- e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or +- f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions + of it) with contractual assumptions of liability to the recipient, + for any liability that these contractual assumptions directly + impose on those licensors and authors. + +All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + +If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + +Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; the +above requirements apply either way. + +#### 8. Termination. + +You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + +However, if you cease all violation of this License, then your license +from a particular copyright holder is reinstated (a) provisionally, +unless and until the copyright holder explicitly and finally +terminates your license, and (b) permanently, if the copyright holder +fails to notify you of the violation by some reasonable means prior to +60 days after the cessation. + +Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + +Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + +#### 9. Acceptance Not Required for Having Copies. + +You are not required to accept this License in order to receive or run +a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + +#### 10. Automatic Licensing of Downstream Recipients. + +Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + +An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + +You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + +#### 11. Patents. + +A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + +A contributor's "essential patent claims" are all patent claims owned +or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + +Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + +In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + +If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + +If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + +A patent license is "discriminatory" if it does not include within the +scope of its coverage, prohibits the exercise of, or is conditioned on +the non-exercise of one or more of the rights that are specifically +granted under this License. You may not convey a covered work if you +are a party to an arrangement with a third party that is in the +business of distributing software, under which you make payment to the +third party based on the extent of your activity of conveying the +work, and under which the third party grants, to any of the parties +who would receive the covered work from you, a discriminatory patent +license (a) in connection with copies of the covered work conveyed by +you (or copies made from those copies), or (b) primarily for and in +connection with specific products or compilations that contain the +covered work, unless you entered into that arrangement, or that patent +license was granted, prior to 28 March 2007. + +Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + +#### 12. No Surrender of Others' Freedom. + +If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under +this License and any other pertinent obligations, then as a +consequence you may not convey it at all. For example, if you agree to +terms that obligate you to collect a royalty for further conveying +from those to whom you convey the Program, the only way you could +satisfy both those terms and this License would be to refrain entirely +from conveying the Program. + +#### 13. Remote Network Interaction; Use with the GNU General Public License. + +Notwithstanding any other provision of this License, if you modify the +Program, your modified version must prominently offer all users +interacting with it remotely through a computer network (if your +version supports such interaction) an opportunity to receive the +Corresponding Source of your version by providing access to the +Corresponding Source from a network server at no charge, through some +standard or customary means of facilitating copying of software. This +Corresponding Source shall include the Corresponding Source for any +work covered by version 3 of the GNU General Public License that is +incorporated pursuant to the following paragraph. + +Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the work with which it is combined will remain governed by version +3 of the GNU General Public License. + +#### 14. Revised Versions of this License. + +The Free Software Foundation may publish revised and/or new versions +of the GNU Affero General Public License from time to time. Such new +versions will be similar in spirit to the present version, but may +differ in detail to address new problems or concerns. + +Each version is given a distinguishing version number. If the Program +specifies that a certain numbered version of the GNU Affero General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU Affero General Public License, you may choose any version ever +published by the Free Software Foundation. + +If the Program specifies that a proxy can decide which future versions +of the GNU Affero General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + +Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + +#### 15. Disclaimer of Warranty. + +THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT +WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT +LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR +A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND +PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE +DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR +CORRECTION. + +#### 16. Limitation of Liability. + +IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR +CONVEYS THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, +INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES +ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT +NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR +LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM +TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER +PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. + +#### 17. Interpretation of Sections 15 and 16. + +If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + +END OF TERMS AND CONDITIONS + +### How to Apply These Terms to Your New Programs + +If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these +terms. + +To do so, attach the following notices to the program. It is safest to +attach them to the start of each source file to most effectively state +the exclusion of warranty; and each file should have at least the +"copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU Affero General Public License as + published by the Free Software Foundation, either version 3 of the + License, or (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU Affero General Public License for more details. + + You should have received a copy of the GNU Affero General Public License + along with this program. If not, see . + +Also add information on how to contact you by electronic and paper +mail. + +If your software can interact with users remotely through a computer +network, you should also make sure that it provides a way for users to +get its source. For example, if your program is a web application, its +interface could display a "Source" link that leads users to an archive +of the code. There are many ways you could offer source, and different +solutions will be better for different programs; see section 13 for +the specific requirements. + +You should also get your employer (if you work as a programmer) or +school, if any, to sign a "copyright disclaimer" for the program, if +necessary. For more information on this, and how to apply and follow +the GNU AGPL, see . diff --git a/Dockerfile b/Dockerfile deleted file mode 100644 index d8e5d0f95e..0000000000 --- a/Dockerfile +++ /dev/null @@ -1,62 +0,0 @@ -FROM alpine:latest - -RUN mkdir /mempool.space/ -COPY ./backend /mempool.space/backend/ -COPY ./frontend /mempool.space/frontend/ -COPY ./mariadb-structure.sql /mempool.space/mariadb-structure.sql -#COPY ./nginx.conf /mempool.space/nginx.conf - -RUN apk add mariadb mariadb-client jq git nginx npm rsync - -RUN mysql_install_db --user=mysql --datadir=/var/lib/mysql/ -RUN /usr/bin/mysqld_safe --datadir='/var/lib/mysql/'& \ - sleep 60 && \ - mysql -e "create database mempool" && \ - mysql -e "grant all privileges on mempool.* to 'mempool'@'localhost' identified by 'mempool'" && \ - mysql mempool < /mempool.space/mariadb-structure.sql -RUN sed -i "/^skip-networking/ c#skip-networking" /etc/my.cnf.d/mariadb-server.cnf - -RUN export NG_CLI_ANALYTICS=ci && \ - npm install -g typescript && \ - cd /mempool.space/frontend && \ - npm install && \ - cd /mempool.space/backend && \ - npm install && \ - tsc - -COPY ./nginx-nossl-docker.conf /etc/nginx/nginx.conf - -ENV ENV dev -ENV DB_HOST localhost -ENV DB_PORT 3306 -ENV DB_USER mempool -ENV DB_PASSWORD mempool -ENV DB_DATABASE mempool -ENV HTTP_PORT 80 -ENV API_ENDPOINT /api/v1/ -ENV CHAT_SSL_ENABLED false -#ENV CHAT_SSL_PRIVKEY -#ENV CHAT_SSL_CERT -#ENV CHAT_SSL_CHAIN -ENV MEMPOOL_REFRESH_RATE_MS 500 -ENV INITIAL_BLOCK_AMOUNT 8 -ENV DEFAULT_PROJECTED_BLOCKS_AMOUNT 8 -ENV KEEP_BLOCK_AMOUNT 24 -ENV BITCOIN_NODE_HOST bitcoinhost -ENV BITCOIN_NODE_PORT 8332 -ENV BITCOIN_NODE_USER bitcoinuser -ENV BITCOIN_NODE_PASS bitcoinpass -ENV TX_PER_SECOND_SPAN_SECONDS 150 - -#RUN echo "mysqld_safe& sleep 20 && cd /mempool.space/backend && rm -f mempool-config.json && rm -f cache.json && touch cache.json && jq -n env > mempool-config.json && node dist/index.js" > /entrypoint.sh - -RUN cd /mempool.space/frontend/ && \ - npm run build && \ - rsync -av --delete dist/mempool/ /var/www/html/ - -EXPOSE 80 - -COPY ./entrypoint.sh /mempool.space/entrypoint.sh -RUN chmod +x /mempool.space/entrypoint.sh -WORKDIR /mempool.space -CMD ["/mempool.space/entrypoint.sh"] diff --git a/LICENSE b/LICENSE index 45d73ad1d8..b6a09390af 100644 --- a/LICENSE +++ b/LICENSE @@ -1,21 +1,28 @@ -MIT License +The Mempool Open Source Project® +Copyright (c) 2019-2023 Mempool Space K.K. and other shadowy super-coders -Copyright (c) 2019 Simon Lindh +This program is free software; you can redistribute it and/or modify it under +the terms of the GNU Affero General Public License as published by the Free +Software Foundation, either version 3 of the License or any later version +approved by a proxy statement published on . -Permission is hereby granted, free of charge, to any person obtaining a copy -of this software and associated documentation files (the "Software"), to deal -in the Software without restriction, including without limitation the rights -to use, copy, modify, merge, publish, distribute, sublicense, and/or sell -copies of the Software, and to permit persons to whom the Software is -furnished to do so, subject to the following conditions: +However, this copyright license does not include an implied right or license +to use any trademarks, service marks, logos, or trade names of Mempool Space K.K. +or any other contributor to The Mempool Open Source Project. -The above copyright notice and this permission notice shall be included in all -copies or substantial portions of the Software. +The Mempool Open Source Project®, Mempool Accelerator™, Mempool Enterprise®, +Mempool Liquidity™, mempool.space®, Be your own explorer™, Explore the full +Bitcoin ecosystem™, Mempool Goggles™, the mempool Logo, the mempool Square logo, +the mempool Blocks logo, the mempool Blocks 3 | 2 logo, the mempool.space Vertical +Logo, and the mempool.space Horizontal logo are registered trademarks or trademarks +of Mempool Space K.K in Japan, the United States, and/or other countries. -THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE -AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, -OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE -SOFTWARE. +See our full Trademark Policy and Guidelines for more details, published on +. + +This program is distributed in the hope that it will be useful, but WITHOUT ANY +WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A +PARTICULAR PURPOSE. See the full license terms for more details. + +You should have received a copy of both the GNU Affero General Public License +along with this program. If not, see . diff --git a/README.md b/README.md index 5af4a8d56d..7e426f1550 100644 --- a/README.md +++ b/README.md @@ -1,215 +1,38 @@ -# mempool -## a mempool visualizer and explorer for Bitcoin +# The Mempool Open Source Project® [![mempool](https://img.shields.io/endpoint?url=https://dashboard.cypress.io/badge/simple/ry4br7/master&style=flat-square)](https://dashboard.cypress.io/projects/ry4br7/runs) -![mempool](https://pbs.twimg.com/media/EAETXWCU4AAv2v-?format=jpg&name=4096x4096) -![blockchain](https://pbs.twimg.com/media/EAETXWAU8AAj4IP?format=jpg&name=4096x4096) +https://user-images.githubusercontent.com/93150691/226236121-375ea64f-b4a1-4cc0-8fad-a6fb33226840.mp4 -## Pick the right version for your use case +
-Mempool V1 has basic explorer functionality and can run from a Bitcoin Core full node on a Raspberry Pi (no pruning, txindex=1). +Mempool is the fully-featured mempool visualizer, explorer, and API service running at [mempool.space](https://mempool.space/). -Mempool V2 is what runs on https://mempool.space and has advanced explorer functionality, but requires a fully synced electrs backend running on powerful server hardware. +It is an open-source project developed and operated for the benefit of the Bitcoin community, with a focus on the emerging transaction fee market that is evolving Bitcoin into a multi-layer ecosystem. -# Mempool V1 using Docker (easy) +# Installation Methods -Install from Docker Hub, passing your Bitcoin Core RPC credentials as environment variables: +Mempool can be self-hosted on a wide variety of your own hardware, ranging from a simple one-click installation on a Raspberry Pi full-node distro all the way to a robust production instance on a powerful FreeBSD server. -```bash -docker pull mempool/mempool:v1.0 -docker create -p 80:80 -e BITCOIN_NODE_HOST=192.168.1.102 -e BITCOIN_NODE_USER=foo -e BITCOIN_NODE_PASS=bar --name mempool mempool/mempool:v1.0 -docker start mempool -docker logs mempool -``` +Most people should use a one-click install method. -You should see mempool starting up, which takes over an hour (needs 8 blocks). When it's ready, visit http://127.0.0.1/ to see your mempool. +Other install methods are meant for developers and others with experience managing servers. If you want support for your own production instance of Mempool, or if you'd like to have your own instance of Mempool run by the mempool.space team on their own global ISP infrastructure—check out Mempool Enterprise®. -# Mempool V1 not using Docker (advanced) + +## One-Click Installation -## Dependencies +Mempool can be conveniently installed on the following full-node distros: +- [Umbrel](https://github.com/getumbrel/umbrel) +- [RaspiBlitz](https://github.com/rootzoll/raspiblitz) +- [RoninDojo](https://code.samourai.io/ronindojo/RoninDojo) +- [myNode](https://github.com/mynodebtc/mynode) +- [StartOS](https://github.com/Start9Labs/start-os) +- [nix-bitcoin](https://github.com/fort-nix/nix-bitcoin/blob/a1eacce6768ca4894f365af8f79be5bbd594e1c3/examples/configuration.nix#L129) -* Bitcoin (full node required, no pruning, txindex=1) -* NodeJS (official stable LTS) -* MySQL or MariaDB (default config) -* Nginx (use supplied nginx.conf) +**We highly recommend you deploy your own Mempool instance this way.** No matter which option you pick, you'll be able to get your own fully-sovereign instance of Mempool up quickly without needing to fiddle with any settings. -## Checking out release tag -```bash - git clone https://github.com/mempool-space/mempool.space - cd mempool.space - git checkout v1.0.0 # put latest release tag here -``` +## Advanced Installation Methods -## Bitcoin Core (bitcoind) +Mempool can be installed in other ways too, but we only recommend doing so if you're a developer, have experience managing servers, or otherwise know what you're doing. -Enable RPC and txindex in bitcoin.conf - -```bash - rpcuser=mempool - rpcpassword=71b61986da5b03a5694d7c7d5165ece5 - txindex=1 -``` - -## NodeJS - -Install dependencies and build code: - -```bash - # Install TypeScript Globally - npm install -g typescript - - # Frontend - cd frontend - npm install - npm run build - - # Backend - cd ../backend/ - npm install - npm run build -``` - -## Mempool Configuration -In the `backend` folder, make a copy of the sample config and modify it to fit your settings. - -```bash - cp mempool-config.sample.json mempool-config.json -``` - -Edit `mempool-config.json` to add your Bitcoin Core node RPC credentials: -```bash - "BITCOIN_NODE_HOST": "192.168.1.5", - "BITCOIN_NODE_PORT": 8332, - "BITCOIN_NODE_USER": "mempool", - "BITCOIN_NODE_PASS": "71b61986da5b03a5694d7c7d5165ece5", -``` - -## MySQL - -Install MariaDB: - -```bash - # Linux - apt-get install mariadb-server mariadb-client - - # macOS - brew install mariadb - brew services start mariadb -``` - -Create database and grant privileges: -```bash - MariaDB [(none)]> drop database mempool; - Query OK, 0 rows affected (0.00 sec) - - MariaDB [(none)]> create database mempool; - Query OK, 1 row affected (0.00 sec) - - MariaDB [(none)]> grant all privileges on mempool.* to 'mempool' identified by 'mempool'; - Query OK, 0 rows affected (0.00 sec) -``` - -From the root folder, initialize database structure: - -```bash - mysql -u mempool -p mempool < mariadb-structure.sql -``` - -## Running (Backend) - -Create an initial empty cache and start the app: - -```bash - touch cache.json - npm run start # node dist/index.js -``` - -After starting you should see: - -```bash - Server started on port 8999 :) - New block found (#586498)! 0 of 1986 found in mempool. 1985 not found. - New block found (#586499)! 0 of 1094 found in mempool. 1093 not found. - New block found (#586500)! 0 of 2735 found in mempool. 2734 not found. - New block found (#586501)! 0 of 2675 found in mempool. 2674 not found. - New block found (#586502)! 0 of 975 found in mempool. 974 not found. - New block found (#586503)! 0 of 2130 found in mempool. 2129 not found. - New block found (#586504)! 0 of 2770 found in mempool. 2769 not found. - New block found (#586505)! 0 of 2759 found in mempool. 2758 not found. - Updating mempool - Calculated fee for transaction 1 / 3257 - Calculated fee for transaction 2 / 3257 - Calculated fee for transaction 3 / 3257 - Calculated fee for transaction 4 / 3257 - Calculated fee for transaction 5 / 3257 - Calculated fee for transaction 6 / 3257 - Calculated fee for transaction 7 / 3257 - Calculated fee for transaction 8 / 3257 - Calculated fee for transaction 9 / 3257 -``` -You need to wait for at least *8 blocks to be mined*, so please wait ~80 minutes. -The backend also needs to index transactions, calculate fees, etc. -When it's ready you will see output like this: - -```bash - Mempool updated in 0.189 seconds - Updating mempool - Mempool updated in 0.096 seconds - Updating mempool - Mempool updated in 0.099 seconds - Updating mempool - Calculated fee for transaction 1 / 10 - Calculated fee for transaction 2 / 10 - Calculated fee for transaction 3 / 10 - Calculated fee for transaction 4 / 10 - Calculated fee for transaction 5 / 10 - Calculated fee for transaction 6 / 10 - Calculated fee for transaction 7 / 10 - Calculated fee for transaction 8 / 10 - Calculated fee for transaction 9 / 10 - Calculated fee for transaction 10 / 10 - Mempool updated in 0.243 seconds - Updating mempool -``` - -## nginx + CertBot (LetsEncrypt) -Setup nginx using the supplied nginx.conf - -```bash - # install nginx and certbot - apt-get install -y nginx python-certbot-nginx - - # replace example.com with your domain name - certbot --nginx -d example.com - - # install the mempool configuration for nginx - cp nginx.conf /etc/nginx/nginx.conf - - # edit the installed nginx.conf, and replace all - # instances of example.com with your domain name -``` -Make sure you can access https:/// in browser before proceeding - - -## Running (Frontend) - -Build the frontend static HTML/CSS/JS, rsync the output into nginx folder: - -```bash - cd frontend/ - npm run build - sudo rsync -av --delete dist/mempool/ /var/www/html/ -``` - -### Optional frontend configuration -In the `frontend` folder, make a copy of the sample config and modify it to fit your settings. - -```bash - cp mempool-frontend-config.sample.json mempool-frontend-config.json -``` - -## Try It Out - -If everything went okay you should see the beautiful mempool :grin: - -If you get stuck on "loading blocks", this means the websocket can't connect. -Check your nginx proxy setup, firewalls, etc. and open an issue if you need help. +- See the [`docker/`](./docker/) directory for instructions on deploying Mempool with Docker. +- See the [`backend/`](./backend/) and [`frontend/`](./frontend/) directories for manual install instructions oriented for developers. +- See the [`production/`](./production/) directory for guidance on setting up a more serious Mempool instance designed for high performance at scale. diff --git a/backend/.dockerignore b/backend/.dockerignore new file mode 100644 index 0000000000..94143827ed --- /dev/null +++ b/backend/.dockerignore @@ -0,0 +1 @@ +Dockerfile diff --git a/backend/.editorconfig b/backend/.editorconfig new file mode 100644 index 0000000000..9787413cd7 --- /dev/null +++ b/backend/.editorconfig @@ -0,0 +1,17 @@ +# Editor configuration, see https://editorconfig.org +root = true + +[*] +charset = utf-8 +indent_style = space +indent_size = 2 +insert_final_newline = true +trim_trailing_whitespace = true + +[*.ts] +quote_type = single + +[*.md] +max_line_length = off +trim_trailing_whitespace = false + diff --git a/backend/.eslintignore b/backend/.eslintignore new file mode 100644 index 0000000000..76add878f8 --- /dev/null +++ b/backend/.eslintignore @@ -0,0 +1,2 @@ +node_modules +dist \ No newline at end of file diff --git a/backend/.eslintrc b/backend/.eslintrc new file mode 100644 index 0000000000..a9b16ef9d1 --- /dev/null +++ b/backend/.eslintrc @@ -0,0 +1,40 @@ +{ + "root": true, + "parser": "@typescript-eslint/parser", + "plugins": [ + "@typescript-eslint" + ], + "extends": [ + "eslint:recommended", + "plugin:@typescript-eslint/eslint-recommended", + "plugin:@typescript-eslint/recommended", + "prettier" + ], + "rules": { + "@typescript-eslint/ban-ts-comment": 1, + "@typescript-eslint/ban-types": 1, + "@typescript-eslint/no-empty-function": 1, + "@typescript-eslint/no-explicit-any": 1, + "@typescript-eslint/no-inferrable-types": 0, + "@typescript-eslint/no-namespace": 1, + "@typescript-eslint/no-this-alias": 1, + "@typescript-eslint/no-var-requires": 1, + "@typescript-eslint/explicit-function-return-type": 1, + "@typescript-eslint/no-unused-vars": 1, + "no-console": 1, + "no-constant-condition": 1, + "no-dupe-else-if": 1, + "no-empty": 1, + "no-prototype-builtins": 1, + "no-self-assign": 1, + "no-useless-catch": 1, + "no-var": 1, + "prefer-const": 1, + "prefer-rest-params": 1, + "quotes": [1, "single", { "allowTemplateLiterals": true }], + "semi": 1, + "curly": [1, "all"], + "eqeqeq": 1, + "no-trailing-spaces": 1 + } +} diff --git a/backend/.gitignore b/backend/.gitignore index ba8416a23b..23380b731e 100644 --- a/backend/.gitignore +++ b/backend/.gitignore @@ -1,7 +1,17 @@ # See http://help.github.com/ignore-files/ for more about ignoring files. -# production config +# production config and external assets +!mempool-config.template.json +!mempool-config.sample.json mempool-config.json +pools.json +icons.json + +# docker +Dockerfile +GeoIP +start.sh +wait-for-it.sh # compiled output /dist @@ -42,4 +52,8 @@ testem.log .DS_Store Thumbs.db -cache.json +# package folder (npm run package output) +/package + +# Rust GBT folder (We build externally first) +/rust-gbt diff --git a/backend/.prettierignore b/backend/.prettierignore new file mode 100644 index 0000000000..d5f19d89b3 --- /dev/null +++ b/backend/.prettierignore @@ -0,0 +1,2 @@ +node_modules +package-lock.json diff --git a/backend/.prettierrc b/backend/.prettierrc new file mode 100644 index 0000000000..b8039f8430 --- /dev/null +++ b/backend/.prettierrc @@ -0,0 +1,6 @@ +{ + "endOfLine": "lf", + "printWidth": 80, + "tabWidth": 2, + "trailingComma": "es5" +} diff --git a/backend/.vscode/settings.json b/backend/.vscode/settings.json new file mode 100644 index 0000000000..41e35fc77c --- /dev/null +++ b/backend/.vscode/settings.json @@ -0,0 +1,4 @@ +{ + "editor.tabSize": 2, + "typescript.tsdk": "../backend/node_modules/typescript/lib" +} \ No newline at end of file diff --git a/backend/README.md b/backend/README.md new file mode 100644 index 0000000000..6ae4ae3e2b --- /dev/null +++ b/backend/README.md @@ -0,0 +1,256 @@ +# Mempool Backend + +These instructions are mostly intended for developers. + +If you choose to use these instructions for a production setup, be aware that you will still probably need to do additional configuration for your specific OS, environment, use-case, etc. We do our best here to provide a good starting point, but only proceed if you know what you're doing. Mempool only provides support for custom setups to project sponsors through [Mempool Enterprise®](https://mempool.space/enterprise). + +See other ways to set up Mempool on [the main README](/../../#installation-methods). + +Jump to a section in this doc: +- [Set Up the Backend](#setup) +- [Development Tips](#development-tips) + +## Setup + +### 1. Clone Mempool Repository + +Get the latest Mempool code: + +``` +git clone https://github.com/mempool/mempool +cd mempool +``` + +Check out the latest release: + +``` +latestrelease=$(curl -s https://api.github.com/repos/mempool/mempool/releases/latest|grep tag_name|head -1|cut -d '"' -f4) +git checkout $latestrelease +``` + +### 2. Configure Bitcoin Core + +Turn on `txindex`, enable RPC, and set RPC credentials in `bitcoin.conf`: + +``` +txindex=1 +server=1 +rpcuser=mempool +rpcpassword=mempool +``` + +### 3. Configure Electrum Server + +[Pick an Electrum Server implementation](https://mempool.space/docs/faq#address-lookup-issues), configure it, and make sure it's synced. + +**This step is optional.** You can run Mempool without configuring an Electrum Server for it, but address lookups will be disabled. + +### 4. Configure MariaDB + +_Mempool needs MariaDB v10.5 or later. If you already have MySQL installed, make sure to migrate any existing databases **before** installing MariaDB._ + +Get MariaDB from your operating system's package manager: + +``` +# Debian, Ubuntu, etc. +apt-get install mariadb-server mariadb-client + +# macOS +brew install mariadb +mysql.server start +``` + +Create a database and grant privileges: + +``` +MariaDB [(none)]> drop database mempool; +Query OK, 0 rows affected (0.00 sec) + +MariaDB [(none)]> create database mempool; +Query OK, 1 row affected (0.00 sec) + +MariaDB [(none)]> grant all privileges on mempool.* to 'mempool'@'%' identified by 'mempool'; +Query OK, 0 rows affected (0.00 sec) +``` + +### 5. Prepare Mempool Backend + +#### Build + +_Make sure to use Node.js 16.10 and npm 7._ + +_The build process requires [Rust](https://www.rust-lang.org/tools/install) to be installed._ + +Install dependencies with `npm` and build the backend: + +``` +cd backend +npm install --no-install-links # npm@9.4.2 and later can omit the --no-install-links +npm run build +``` + +#### Configure + +In the backend folder, make a copy of the sample config file: + +``` +cp mempool-config.sample.json mempool-config.json +``` + +Edit `mempool-config.json` as needed. + +In particular, make sure: +- the correct Bitcoin Core RPC credentials are specified in `CORE_RPC` +- the correct `BACKEND` is specified in `MEMPOOL`: + - "electrum" if you're using [romanz/electrs](https://github.com/romanz/electrs) or [cculianu/Fulcrum](https://github.com/cculianu/Fulcrum) + - "esplora" if you're using [mempool/electrs](https://github.com/mempool/electrs) + - "none" if you're not using any Electrum Server + +### 6. Run Mempool Backend + +Run the Mempool backend: + +``` +npm run start + +``` +You can also set env var `MEMPOOL_CONFIG_FILE` to specify a custom config file location: +``` +MEMPOOL_CONFIG_FILE=/path/to/mempool-config.json npm run start +``` + +When it's running, you should see output like this: + +``` +Mempool updated in 0.189 seconds +Updating mempool +Mempool updated in 0.096 seconds +Updating mempool +Mempool updated in 0.099 seconds +Updating mempool +Calculated fee for transaction 1 / 10 +Calculated fee for transaction 2 / 10 +Calculated fee for transaction 3 / 10 +Calculated fee for transaction 4 / 10 +Calculated fee for transaction 5 / 10 +Calculated fee for transaction 6 / 10 +Calculated fee for transaction 7 / 10 +Calculated fee for transaction 8 / 10 +Calculated fee for transaction 9 / 10 +Calculated fee for transaction 10 / 10 +Mempool updated in 0.243 seconds +Updating mempool +``` + +### 7. Set Up Mempool Frontend +With the backend configured and running, proceed to set up the [Mempool frontend](../frontend#manual-setup). + +## Development Tips + +### Set Up Backend Watchers + +The Mempool backend is static. TypeScript scripts are compiled into the `dist` folder and served through a Node.js web server. + +As a result, for development purposes, you may find it helpful to set up backend watchers to avoid the manual shutdown/recompile/restart command-line cycle. + +First, install `nodemon` and `ts-node`: + +``` +npm install -g ts-node nodemon +``` + +Then, run the watcher: + +``` +nodemon src/index.ts --ignore cache/ +``` + +`nodemon` should be in npm's global binary folder. If needed, you can determine where that is with `npm -g bin`. + +### Useful Regtest Commands + +Helpful link: https://gist.github.com/System-Glitch/cb4e87bf1ae3fec9925725bb3ebe223a + +Run bitcoind on regtest: + ``` + bitcoind -regtest + ``` + +Create a new wallet, if needed: + ``` + bitcoin-cli -regtest createwallet test + ``` + +Load wallet (this command may take a while if you have a lot of UTXOs): + ``` + bitcoin-cli -regtest loadwallet test + ``` + +Get a new address: + ``` + address=$(bitcoin-cli -regtest getnewaddress) + ``` + +Mine blocks to the previously generated address. You need at least 101 blocks before you can spend. This will take some time to execute (~1 min): + ``` + bitcoin-cli -regtest generatetoaddress 101 $address + ``` + +Send 0.1 BTC at 5 sat/vB to another address: + ``` + bitcoin-cli -named -regtest sendtoaddress address=$(bitcoin-cli -regtest getnewaddress) amount=0.1 fee_rate=5 + ``` + +See more example of `sendtoaddress`: + ``` + bitcoin-cli sendtoaddress # will print the help + ``` + +Mini script to generate random network activity (random TX count with random tx fee-rate). It's slow so don't expect to use this to test mempool spam, except if you let it run for a long time, or maybe with multiple regtest nodes connected to each other. + ``` + #!/bin/bash + address=$(bitcoin-cli -regtest getnewaddress) + bitcoin-cli -regtest generatetoaddress 101 $address + for i in {1..1000000} + do + for y in $(seq 1 "$(jot -r 1 1 1000)") + do + bitcoin-cli -regtest -named sendtoaddress address=$address amount=0.01 fee_rate=$(jot -r 1 1 100) + done + bitcoin-cli -regtest generatetoaddress 1 $address + sleep 5 + done + ``` + +Generate block at regular interval (every 10 seconds in this example): + ``` + watch -n 10 "bitcoin-cli -regtest generatetoaddress 1 $address" + ``` + +### Mining pools update + +By default, mining pools will be not automatically updated regularly (`config.MEMPOOL.AUTOMATIC_POOLS_UPDATE` is set to `false`). + +To manually update your mining pools, you can use the `--update-pools` command line flag when you run the nodejs backend. For example `npm run start --update-pools`. This will trigger the mining pools update and automatically re-index appropriate blocks. + +You can enable the automatic mining pools update by settings `config.MEMPOOL.AUTOMATIC_POOLS_UPDATE` to `true` in your `mempool-config.json`. + +When a `coinbase tag` or `coinbase address` change is detected, pool assignments for all relevant blocks (tagged to that pool or the `unknown` mining pool, starting from height 130635) are updated using the new criteria. + +### Re-index tables + +You can manually force the nodejs backend to drop all data from a specified set of tables for future re-index. This is mostly useful for the mining dashboard and the lightning explorer. + +Use the `--reindex` command to specify a list of comma separated table which will be truncated at start. Note that a 5 seconds delay will be observed before truncating tables in order to give you a chance to cancel (CTRL+C) in case of misuse of the command. + +Usage: +``` +npm run start --reindex=blocks,hashrates +``` +Example output: +``` +Feb 13 14:55:27 [63246] WARN: Indexed data for "hashrates" tables will be erased in 5 seconds (using '--reindex') +Feb 13 14:55:32 [63246] NOTICE: Table hashrates has been truncated +``` + +Reference: https://github.com/mempool/mempool/pull/1269 diff --git a/backend/cache/.gitignore b/backend/cache/.gitignore new file mode 100644 index 0000000000..a6c57f5fb2 --- /dev/null +++ b/backend/cache/.gitignore @@ -0,0 +1 @@ +*.json diff --git a/backend/jest.config.ts b/backend/jest.config.ts new file mode 100644 index 0000000000..14f932f986 --- /dev/null +++ b/backend/jest.config.ts @@ -0,0 +1,20 @@ +import type { Config } from "@jest/types" + +const config: Config.InitialOptions = { + preset: "ts-jest", + testEnvironment: "node", + verbose: true, + automock: false, + collectCoverage: true, + collectCoverageFrom: ["./src/**/**.ts"], + coverageProvider: "babel", + coverageThreshold: { + global: { + lines: 1 + } + }, + setupFiles: [ + "./testSetup.ts", + ], +} +export default config; diff --git a/backend/mempool-config.sample.json b/backend/mempool-config.sample.json index 6372dede50..4650c1e645 100644 --- a/backend/mempool-config.sample.json +++ b/backend/mempool-config.sample.json @@ -1,21 +1,161 @@ { - "HTTP_PORT": 8999, - "DB_HOST": "localhost", - "DB_PORT": 3306, - "DB_USER": "mempool", - "DB_PASSWORD": "mempool", - "DB_DATABASE": "mempool", - "API_ENDPOINT": "/api/v1/", - "ELECTRS_POLL_RATE_MS": 2000, - "MEMPOOL_REFRESH_RATE_MS": 2000, - "DEFAULT_PROJECTED_BLOCKS_AMOUNT": 8, - "KEEP_BLOCK_AMOUNT": 24, - "INITIAL_BLOCK_AMOUNT": 8, - "TX_PER_SECOND_SPAN_SECONDS": 150, - "ELECTRS_API_URL": "https://www.blockstream.info/testnet/api", - "BISQ_ENABLED": false, - "BSQ_BLOCKS_DATA_PATH": "/bisq/data", - "SSL": false, - "SSL_CERT_FILE_PATH": "/etc/letsencrypt/live/mysite/fullchain.pem", - "SSL_KEY_FILE_PATH": "/etc/letsencrypt/live/mysite/privkey.pem" + "MEMPOOL": { + "OFFICIAL": false, + "NETWORK": "mainnet", + "BACKEND": "electrum", + "ENABLED": true, + "HTTP_PORT": 8999, + "SPAWN_CLUSTER_PROCS": 0, + "API_URL_PREFIX": "/api/v1/", + "POLL_RATE_MS": 2000, + "CACHE_DIR": "./cache", + "CACHE_ENABLED": true, + "CLEAR_PROTECTION_MINUTES": 20, + "RECOMMENDED_FEE_PERCENTILE": 50, + "BLOCK_WEIGHT_UNITS": 4000000, + "INITIAL_BLOCKS_AMOUNT": 8, + "MEMPOOL_BLOCKS_AMOUNT": 8, + "INDEXING_BLOCKS_AMOUNT": 11000, + "BLOCKS_SUMMARIES_INDEXING": false, + "GOGGLES_INDEXING": false, + "USE_SECOND_NODE_FOR_MINFEE": false, + "EXTERNAL_ASSETS": [], + "EXTERNAL_MAX_RETRY": 1, + "EXTERNAL_RETRY_INTERVAL": 0, + "USER_AGENT": "mempool", + "STDOUT_LOG_MIN_PRIORITY": "debug", + "AUTOMATIC_POOLS_UPDATE": false, + "POOLS_JSON_URL": "https://raw.githubusercontent.com/mempool/mining-pools/master/pools-v2.json", + "POOLS_JSON_TREE_URL": "https://api.github.com/repos/mempool/mining-pools/git/trees/master", + "AUDIT": false, + "RUST_GBT": false, + "LIMIT_GBT": false, + "CPFP_INDEXING": false, + "DISK_CACHE_BLOCK_INTERVAL": 6, + "MAX_PUSH_TX_SIZE_WEIGHT": 4000000, + "ALLOW_UNREACHABLE": true, + "PRICE_UPDATES_PER_HOUR": 1, + "MAX_TRACKED_ADDRESSES": 100, + "UNIX_SOCKET_PATH": "" + }, + "CORE_RPC": { + "HOST": "127.0.0.1", + "PORT": 8332, + "USERNAME": "mempool", + "PASSWORD": "mempool", + "TIMEOUT": 60000, + "COOKIE": false, + "COOKIE_PATH": "/path/to/bitcoin/.cookie" + }, + "ELECTRUM": { + "HOST": "127.0.0.1", + "PORT": 50002, + "TLS_ENABLED": true + }, + "ESPLORA": { + "REST_API_URL": "http://127.0.0.1:3000", + "UNIX_SOCKET_PATH": "/tmp/esplora-bitcoin-mainnet", + "BATCH_QUERY_BASE_SIZE": 1000, + "RETRY_UNIX_SOCKET_AFTER": 30000, + "REQUEST_TIMEOUT": 10000, + "FALLBACK_TIMEOUT": 5000, + "FALLBACK": [], + "MAX_BEHIND_TIP": 2 + }, + "SECOND_CORE_RPC": { + "HOST": "127.0.0.1", + "PORT": 8332, + "USERNAME": "mempool", + "PASSWORD": "mempool", + "TIMEOUT": 60000, + "COOKIE": false, + "COOKIE_PATH": "/path/to/bitcoin/.cookie" + }, + "DATABASE": { + "ENABLED": true, + "HOST": "127.0.0.1", + "PORT": 3306, + "SOCKET": "/var/run/mysql/mysql.sock", + "DATABASE": "mempool", + "USERNAME": "mempool", + "PASSWORD": "mempool", + "TIMEOUT": 180000, + "PID_DIR": "" + }, + "SYSLOG": { + "ENABLED": true, + "HOST": "127.0.0.1", + "PORT": 514, + "MIN_PRIORITY": "info", + "FACILITY": "local7" + }, + "STATISTICS": { + "ENABLED": true, + "TX_PER_SECOND_SAMPLE_PERIOD": 150 + }, + "MAXMIND": { + "ENABLED": false, + "GEOLITE2_CITY": "/usr/local/share/GeoIP/GeoLite2-City.mmdb", + "GEOLITE2_ASN": "/usr/local/share/GeoIP/GeoLite2-ASN.mmdb", + "GEOIP2_ISP": "/usr/local/share/GeoIP/GeoIP2-ISP.mmdb" + }, + "LIGHTNING": { + "ENABLED": false, + "BACKEND": "lnd", + "STATS_REFRESH_INTERVAL": 600, + "GRAPH_REFRESH_INTERVAL": 600, + "LOGGER_UPDATE_INTERVAL": 30, + "FORENSICS_INTERVAL": 43200, + "FORENSICS_RATE_LIMIT": 20 + }, + "LND": { + "TLS_CERT_PATH": "tls.cert", + "MACAROON_PATH": "readonly.macaroon", + "REST_API_URL": "https://localhost:8080", + "TIMEOUT": 10000 + }, + "CLIGHTNING": { + "SOCKET": "lightning-rpc" + }, + "SOCKS5PROXY": { + "ENABLED": false, + "USE_ONION": true, + "HOST": "127.0.0.1", + "PORT": 9050, + "USERNAME": "", + "PASSWORD": "" + }, + "EXTERNAL_DATA_SERVER": { + "MEMPOOL_API": "https://mempool.space/api/v1", + "MEMPOOL_ONION": "http://mempoolhqx4isw62xs7abwphsq7ldayuidyx2v2oethdhhj6mlo2r6ad.onion/api/v1", + "LIQUID_API": "https://liquid.network/api/v1", + "LIQUID_ONION": "http://liquidmom47f6s3m53ebfxn47p76a6tlnxib3wp6deux7wuzotdr6cyd.onion/api/v1" + }, + "REDIS": { + "ENABLED": false, + "UNIX_SOCKET_PATH": "/tmp/redis.sock", + "BATCH_QUERY_BASE_SIZE": 5000 + }, + "REPLICATION": { + "ENABLED": false, + "AUDIT": false, + "AUDIT_START_HEIGHT": 774000, + "STATISTICS": false, + "STATISTICS_START_TIME": 1481932800, + "SERVERS": [ + "list", + "of", + "trusted", + "servers" + ] + }, + "MEMPOOL_SERVICES": { + "API": "https://mempool.space/api/v1/services", + "ACCELERATIONS": false + }, + "FIAT_PRICE": { + "ENABLED": true, + "PAID": false, + "API_KEY": "your-api-key-from-freecurrencyapi.com" + } } diff --git a/backend/npm_package.sh b/backend/npm_package.sh new file mode 100755 index 0000000000..db305f3813 --- /dev/null +++ b/backend/npm_package.sh @@ -0,0 +1,17 @@ +#/bin/sh +set -e + +# Remove previous dist folder +rm -rf dist +# Build new dist folder +npm run build +# Remove previous package folder +rm -rf package +# Move JS and deps +mv dist package +cp -R node_modules package +# Remove symlink for rust-gbt and insert real folder +rm package/node_modules/rust-gbt +cp -R rust-gbt package/node_modules +# Clean up deps +npm run package-rm-build-deps diff --git a/backend/npm_package_rm_build_deps.sh b/backend/npm_package_rm_build_deps.sh new file mode 100755 index 0000000000..5d7af24573 --- /dev/null +++ b/backend/npm_package_rm_build_deps.sh @@ -0,0 +1,9 @@ +#/bin/sh +set -e + +# Cleaning up inside the node_modules folder +cd package/node_modules +rm -rf \ + typescript \ + @typescript-eslint \ + @napi-rs diff --git a/backend/package-lock.json b/backend/package-lock.json new file mode 100644 index 0000000000..04e15afa2b --- /dev/null +++ b/backend/package-lock.json @@ -0,0 +1,13478 @@ +{ + "name": "mempool-backend", + "version": "3.0.0-dev", + "lockfileVersion": 2, + "requires": true, + "packages": { + "": { + "name": "mempool-backend", + "version": "3.0.0-dev", + "hasInstallScript": true, + "license": "GNU Affero General Public License v3.0", + "dependencies": { + "@babel/core": "^7.24.0", + "@mempool/electrum-client": "1.1.9", + "@types/node": "^18.15.3", + "axios": "~1.7.2", + "bitcoinjs-lib": "~6.1.3", + "crypto-js": "~4.2.0", + "express": "~4.19.2", + "maxmind": "~4.3.11", + "mysql2": "~3.10.0", + "redis": "^4.6.6", + "rust-gbt": "file:./rust-gbt", + "socks-proxy-agent": "~7.0.0", + "typescript": "~4.9.3", + "ws": "~8.18.0" + }, + "devDependencies": { + "@babel/code-frame": "^7.18.6", + "@babel/core": "^7.24.0", + "@types/compression": "^1.7.2", + "@types/crypto-js": "^4.1.1", + "@types/express": "^4.17.17", + "@types/jest": "^29.5.0", + "@types/ws": "~8.5.10", + "@typescript-eslint/eslint-plugin": "^5.55.0", + "@typescript-eslint/parser": "^5.55.0", + "eslint": "^8.36.0", + "eslint-config-prettier": "^8.8.0", + "jest": "^29.5.0", + "prettier": "^3.0.0", + "ts-jest": "^29.1.1", + "ts-node": "^10.9.1" + } + }, + "../rust/gbt": { + "version": "3.0.1", + "extraneous": true, + "engines": { + "node": ">= 12" + } + }, + "node_modules/@aashutoshrathi/word-wrap": { + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/@aashutoshrathi/word-wrap/-/word-wrap-1.2.6.tgz", + "integrity": "sha512-1Yjs2SvM8TflER/OD3cOjhWWOZb58A2t7wpE2S9XfBYTiIl+XFhQG2bjy4Pu1I+EAlCNUzRDYDdFwFYUKvXcIA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/@ampproject/remapping": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.2.0.tgz", + "integrity": "sha512-qRmjj8nj9qmLTQXXmaR1cck3UXSRMPrbsLJAasZpF+t3riI71BXed5ebIOYwQntykeZuhjsdweEc9BxH5Jc26w==", + "dev": true, + "dependencies": { + "@jridgewell/gen-mapping": "^0.1.0", + "@jridgewell/trace-mapping": "^0.3.9" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/code-frame": { + "version": "7.23.5", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.23.5.tgz", + "integrity": "sha512-CgH3s1a96LipHCmSUmYFPwY7MNx8C3avkq7i4Wl3cfa662ldtUe4VM1TPXX70pfmrlWTb6jLqTYrZyT2ZTJBgA==", + "dev": true, + "dependencies": { + "@babel/highlight": "^7.23.4", + "chalk": "^2.4.2" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/compat-data": { + "version": "7.23.5", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.23.5.tgz", + "integrity": "sha512-uU27kfDRlhfKl+w1U6vp16IuvSLtjAxdArVXPa9BvLkrr7CYIsxH5adpHObeAGY/41+syctUWOZ140a2Rvkgjw==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/core": { + "version": "7.24.0", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.24.0.tgz", + "integrity": "sha512-fQfkg0Gjkza3nf0c7/w6Xf34BW4YvzNfACRLmmb7XRLa6XHdR+K9AlJlxneFfWYf6uhOzuzZVTjF/8KfndZANw==", + "dev": true, + "dependencies": { + "@ampproject/remapping": "^2.2.0", + "@babel/code-frame": "^7.23.5", + "@babel/generator": "^7.23.6", + "@babel/helper-compilation-targets": "^7.23.6", + "@babel/helper-module-transforms": "^7.23.3", + "@babel/helpers": "^7.24.0", + "@babel/parser": "^7.24.0", + "@babel/template": "^7.24.0", + "@babel/traverse": "^7.24.0", + "@babel/types": "^7.24.0", + "convert-source-map": "^2.0.0", + "debug": "^4.1.0", + "gensync": "^1.0.0-beta.2", + "json5": "^2.2.3", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/babel" + } + }, + "node_modules/@babel/core/node_modules/convert-source-map": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", + "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", + "dev": true + }, + "node_modules/@babel/generator": { + "version": "7.23.6", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.23.6.tgz", + "integrity": "sha512-qrSfCYxYQB5owCmGLbl8XRpX1ytXlpueOb0N0UmQwA073KZxejgQTzAmJezxvpwQD9uGtK2shHdi55QT+MbjIw==", + "dev": true, + "dependencies": { + "@babel/types": "^7.23.6", + "@jridgewell/gen-mapping": "^0.3.2", + "@jridgewell/trace-mapping": "^0.3.17", + "jsesc": "^2.5.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/generator/node_modules/@jridgewell/gen-mapping": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.2.tgz", + "integrity": "sha512-mh65xKQAzI6iBcFzwv28KVWSmCkdRBWoOh+bYQGW3+6OZvbbN3TqMGo5hqYxQniRcH9F2VZIoJCm4pa3BPDK/A==", + "dev": true, + "dependencies": { + "@jridgewell/set-array": "^1.0.1", + "@jridgewell/sourcemap-codec": "^1.4.10", + "@jridgewell/trace-mapping": "^0.3.9" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/helper-compilation-targets": { + "version": "7.23.6", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.23.6.tgz", + "integrity": "sha512-9JB548GZoQVmzrFgp8o7KxdgkTGm6xs9DW0o/Pim72UDjzr5ObUQ6ZzYPqA+g9OTS2bBQoctLJrky0RDCAWRgQ==", + "dev": true, + "dependencies": { + "@babel/compat-data": "^7.23.5", + "@babel/helper-validator-option": "^7.23.5", + "browserslist": "^4.22.2", + "lru-cache": "^5.1.1", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-environment-visitor": { + "version": "7.22.20", + "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.22.20.tgz", + "integrity": "sha512-zfedSIzFhat/gFhWfHtgWvlec0nqB9YEIVrpuwjruLlXfUSnA8cJB0miHKwqDnQ7d32aKo2xt88/xZptwxbfhA==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-function-name": { + "version": "7.23.0", + "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.23.0.tgz", + "integrity": "sha512-OErEqsrxjZTJciZ4Oo+eoZqeW9UIiOcuYKRJA4ZAgV9myA+pOXhhmpfNCKjEH/auVfEYVFJ6y1Tc4r0eIApqiw==", + "dev": true, + "dependencies": { + "@babel/template": "^7.22.15", + "@babel/types": "^7.23.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-hoist-variables": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.22.5.tgz", + "integrity": "sha512-wGjk9QZVzvknA6yKIUURb8zY3grXCcOZt+/7Wcy8O2uctxhplmUPkOdlgoNhmdVee2c92JXbf1xpMtVNbfoxRw==", + "dev": true, + "dependencies": { + "@babel/types": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-imports": { + "version": "7.22.15", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.22.15.tgz", + "integrity": "sha512-0pYVBnDKZO2fnSPCrgM/6WMc7eS20Fbok+0r88fp+YtWVLZrp4CkafFGIp+W0VKw4a22sgebPT99y+FDNMdP4w==", + "dev": true, + "dependencies": { + "@babel/types": "^7.22.15" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-transforms": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.23.3.tgz", + "integrity": "sha512-7bBs4ED9OmswdfDzpz4MpWgSrV7FXlc3zIagvLFjS5H+Mk7Snr21vQ6QwrsoCGMfNC4e4LQPdoULEt4ykz0SRQ==", + "dev": true, + "dependencies": { + "@babel/helper-environment-visitor": "^7.22.20", + "@babel/helper-module-imports": "^7.22.15", + "@babel/helper-simple-access": "^7.22.5", + "@babel/helper-split-export-declaration": "^7.22.6", + "@babel/helper-validator-identifier": "^7.22.20" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-plugin-utils": { + "version": "7.20.2", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.20.2.tgz", + "integrity": "sha512-8RvlJG2mj4huQ4pZ+rU9lqKi9ZKiRmuvGuM2HlWmkmgOhbs6zEAw6IEiJ5cQqGbDzGZOhwuOQNtZMi/ENLjZoQ==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-simple-access": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.22.5.tgz", + "integrity": "sha512-n0H99E/K+Bika3++WNL17POvo4rKWZ7lZEp1Q+fStVbUi8nxPQEBOlTmCOxW/0JsS56SKKQ+ojAe2pHKJHN35w==", + "dev": true, + "dependencies": { + "@babel/types": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-split-export-declaration": { + "version": "7.22.6", + "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.22.6.tgz", + "integrity": "sha512-AsUnxuLhRYsisFiaJwvp1QF+I3KjD5FOxut14q/GzovUe6orHLesW2C7d754kRm53h5gqrz6sFl6sxc4BVtE/g==", + "dev": true, + "dependencies": { + "@babel/types": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-string-parser": { + "version": "7.23.4", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.23.4.tgz", + "integrity": "sha512-803gmbQdqwdf4olxrX4AJyFBV/RTr3rSmOj0rKwesmzlfhYNDEs+/iOcznzpNWlJlIlTJC2QfPFcHB6DlzdVLQ==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.22.20", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.20.tgz", + "integrity": "sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-option": { + "version": "7.23.5", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.23.5.tgz", + "integrity": "sha512-85ttAOMLsr53VgXkTbkx8oA6YTfT4q7/HzXSLEYmjcSTJPMPQtvq1BD79Byep5xMUYbGRzEpDsjUf3dyp54IKw==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helpers": { + "version": "7.24.0", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.24.0.tgz", + "integrity": "sha512-ulDZdc0Aj5uLc5nETsa7EPx2L7rM0YJM8r7ck7U73AXi7qOV44IHHRAYZHY6iU1rr3C5N4NtTmMRUJP6kwCWeA==", + "dev": true, + "dependencies": { + "@babel/template": "^7.24.0", + "@babel/traverse": "^7.24.0", + "@babel/types": "^7.24.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/highlight": { + "version": "7.23.4", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.23.4.tgz", + "integrity": "sha512-acGdbYSfp2WheJoJm/EBBBLh/ID8KDc64ISZ9DYtBmC8/Q204PZJLHyzeB5qMzJ5trcOkybd78M4x2KWsUq++A==", + "dev": true, + "dependencies": { + "@babel/helper-validator-identifier": "^7.22.20", + "chalk": "^2.4.2", + "js-tokens": "^4.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/parser": { + "version": "7.24.0", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.24.0.tgz", + "integrity": "sha512-QuP/FxEAzMSjXygs8v4N9dvdXzEHN4W1oF3PxuWAtPo08UdM17u89RDMgjLn/mlc56iM0HlLmVkO/wgR+rDgHg==", + "dev": true, + "bin": { + "parser": "bin/babel-parser.js" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/plugin-syntax-async-generators": { + "version": "7.8.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz", + "integrity": "sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-bigint": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-bigint/-/plugin-syntax-bigint-7.8.3.tgz", + "integrity": "sha512-wnTnFlG+YxQm3vDxpGE57Pj0srRU4sHE/mDkt1qv2YJJSeUAec2ma4WLUnUPeKjyrfntVwe/N6dCXpU+zL3Npg==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-class-properties": { + "version": "7.12.13", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.13.tgz", + "integrity": "sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.12.13" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-import-meta": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-meta/-/plugin-syntax-import-meta-7.10.4.tgz", + "integrity": "sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.10.4" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-json-strings": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz", + "integrity": "sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-jsx": { + "version": "7.21.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.21.4.tgz", + "integrity": "sha512-5hewiLct5OKyh6PLKEYaFclcqtIgCb6bmELouxjF6up5q3Sov7rOayW4RwhbaBL0dit8rA80GNfY+UuDp2mBbQ==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.20.2" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-logical-assignment-operators": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz", + "integrity": "sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.10.4" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-nullish-coalescing-operator": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz", + "integrity": "sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-numeric-separator": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.10.4.tgz", + "integrity": "sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.10.4" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-object-rest-spread": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz", + "integrity": "sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-optional-catch-binding": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz", + "integrity": "sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-optional-chaining": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz", + "integrity": "sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-top-level-await": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.14.5.tgz", + "integrity": "sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.14.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-typescript": { + "version": "7.21.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.21.4.tgz", + "integrity": "sha512-xz0D39NvhQn4t4RNsHmDnnsaQizIlUkdtYvLs8La1BlfjQ6JEwxkJGeqJMW2tAXx+q6H+WFuUTXNdYVpEya0YA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.20.2" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/template": { + "version": "7.24.0", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.24.0.tgz", + "integrity": "sha512-Bkf2q8lMB0AFpX0NFEqSbx1OkTHf0f+0j82mkw+ZpzBnkk7e9Ql0891vlfgi+kHwOk8tQjiQHpqh4LaSa0fKEA==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.23.5", + "@babel/parser": "^7.24.0", + "@babel/types": "^7.24.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/traverse": { + "version": "7.24.0", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.24.0.tgz", + "integrity": "sha512-HfuJlI8qq3dEDmNU5ChzzpZRWq+oxCZQyMzIMEqLho+AQnhMnKQUzH6ydo3RBl/YjPCuk68Y6s0Gx0AeyULiWw==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.23.5", + "@babel/generator": "^7.23.6", + "@babel/helper-environment-visitor": "^7.22.20", + "@babel/helper-function-name": "^7.23.0", + "@babel/helper-hoist-variables": "^7.22.5", + "@babel/helper-split-export-declaration": "^7.22.6", + "@babel/parser": "^7.24.0", + "@babel/types": "^7.24.0", + "debug": "^4.3.1", + "globals": "^11.1.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/types": { + "version": "7.24.0", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.24.0.tgz", + "integrity": "sha512-+j7a5c253RfKh8iABBhywc8NSfP5LURe7Uh4qpsh6jc+aLJguvmIUBdjSdEMQv2bENrCR5MfRdjGo7vzS/ob7w==", + "dev": true, + "dependencies": { + "@babel/helper-string-parser": "^7.23.4", + "@babel/helper-validator-identifier": "^7.22.20", + "to-fast-properties": "^2.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@bcoe/v8-coverage": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz", + "integrity": "sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==", + "dev": true + }, + "node_modules/@cspotcode/source-map-support": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz", + "integrity": "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==", + "dev": true, + "dependencies": { + "@jridgewell/trace-mapping": "0.3.9" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@cspotcode/source-map-support/node_modules/@jridgewell/trace-mapping": { + "version": "0.3.9", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz", + "integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==", + "dev": true, + "dependencies": { + "@jridgewell/resolve-uri": "^3.0.3", + "@jridgewell/sourcemap-codec": "^1.4.10" + } + }, + "node_modules/@eslint-community/eslint-utils": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz", + "integrity": "sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==", + "dev": true, + "dependencies": { + "eslint-visitor-keys": "^3.3.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" + } + }, + "node_modules/@eslint-community/regexpp": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.5.0.tgz", + "integrity": "sha512-vITaYzIcNmjn5tF5uxcZ/ft7/RXGrMUIS9HalWckEOF6ESiwXKoMzAQf2UW0aVd6rnOeExTJVd5hmWXucBKGXQ==", + "dev": true, + "engines": { + "node": "^12.0.0 || ^14.0.0 || >=16.0.0" + } + }, + "node_modules/@eslint/eslintrc": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.0.2.tgz", + "integrity": "sha512-3W4f5tDUra+pA+FzgugqL2pRimUTDJWKr7BINqOpkZrC0uYI0NIc0/JFgBROCU07HR6GieA5m3/rsPIhDmCXTQ==", + "dev": true, + "dependencies": { + "ajv": "^6.12.4", + "debug": "^4.3.2", + "espree": "^9.5.1", + "globals": "^13.19.0", + "ignore": "^5.2.0", + "import-fresh": "^3.2.1", + "js-yaml": "^4.1.0", + "minimatch": "^3.1.2", + "strip-json-comments": "^3.1.1" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@eslint/eslintrc/node_modules/globals": { + "version": "13.20.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.20.0.tgz", + "integrity": "sha512-Qg5QtVkCy/kv3FUSlu4ukeZDVf9ee0iXLAUYX13gbR17bnejFTzr4iS9bY7kwCf1NztRNm1t91fjOiyx4CSwPQ==", + "dev": true, + "dependencies": { + "type-fest": "^0.20.2" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@eslint/eslintrc/node_modules/type-fest": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", + "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@eslint/js": { + "version": "8.37.0", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.37.0.tgz", + "integrity": "sha512-x5vzdtOOGgFVDCUs81QRB2+liax8rFg3+7hqM+QhBG0/G3F1ZsoYl97UrqgHgQ9KKT7G6c4V+aTUCgu/n22v1A==", + "dev": true, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + } + }, + "node_modules/@humanwhocodes/config-array": { + "version": "0.11.8", + "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.8.tgz", + "integrity": "sha512-UybHIJzJnR5Qc/MsD9Kr+RpO2h+/P1GhOwdiLPXK5TWk5sgTdu88bTD9UP+CKbPPh5Rni1u0GjAdYQLemG8g+g==", + "dev": true, + "dependencies": { + "@humanwhocodes/object-schema": "^1.2.1", + "debug": "^4.1.1", + "minimatch": "^3.0.5" + }, + "engines": { + "node": ">=10.10.0" + } + }, + "node_modules/@humanwhocodes/module-importer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", + "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", + "dev": true, + "engines": { + "node": ">=12.22" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "node_modules/@humanwhocodes/object-schema": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz", + "integrity": "sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==", + "dev": true + }, + "node_modules/@istanbuljs/load-nyc-config": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz", + "integrity": "sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ==", + "dev": true, + "dependencies": { + "camelcase": "^5.3.1", + "find-up": "^4.1.0", + "get-package-type": "^0.1.0", + "js-yaml": "^3.13.1", + "resolve-from": "^5.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@istanbuljs/load-nyc-config/node_modules/argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "dev": true, + "dependencies": { + "sprintf-js": "~1.0.2" + } + }, + "node_modules/@istanbuljs/load-nyc-config/node_modules/find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "dev": true, + "dependencies": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@istanbuljs/load-nyc-config/node_modules/js-yaml": { + "version": "3.14.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", + "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", + "dev": true, + "dependencies": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/@istanbuljs/load-nyc-config/node_modules/locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "dev": true, + "dependencies": { + "p-locate": "^4.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@istanbuljs/load-nyc-config/node_modules/p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "dev": true, + "dependencies": { + "p-try": "^2.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@istanbuljs/load-nyc-config/node_modules/p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "dev": true, + "dependencies": { + "p-limit": "^2.2.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@istanbuljs/load-nyc-config/node_modules/resolve-from": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", + "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/@istanbuljs/schema": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.3.tgz", + "integrity": "sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/@jest/console": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/@jest/console/-/console-29.5.0.tgz", + "integrity": "sha512-NEpkObxPwyw/XxZVLPmAGKE89IQRp4puc6IQRPru6JKd1M3fW9v1xM1AnzIJE65hbCkzQAdnL8P47e9hzhiYLQ==", + "dev": true, + "dependencies": { + "@jest/types": "^29.5.0", + "@types/node": "*", + "chalk": "^4.0.0", + "jest-message-util": "^29.5.0", + "jest-util": "^29.5.0", + "slash": "^3.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/console/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/@jest/console/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/@jest/console/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/@jest/console/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/@jest/console/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/@jest/console/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@jest/core": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/@jest/core/-/core-29.5.0.tgz", + "integrity": "sha512-28UzQc7ulUrOQw1IsN/kv1QES3q2kkbl/wGslyhAclqZ/8cMdB5M68BffkIdSJgKBUt50d3hbwJ92XESlE7LiQ==", + "dev": true, + "dependencies": { + "@jest/console": "^29.5.0", + "@jest/reporters": "^29.5.0", + "@jest/test-result": "^29.5.0", + "@jest/transform": "^29.5.0", + "@jest/types": "^29.5.0", + "@types/node": "*", + "ansi-escapes": "^4.2.1", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "exit": "^0.1.2", + "graceful-fs": "^4.2.9", + "jest-changed-files": "^29.5.0", + "jest-config": "^29.5.0", + "jest-haste-map": "^29.5.0", + "jest-message-util": "^29.5.0", + "jest-regex-util": "^29.4.3", + "jest-resolve": "^29.5.0", + "jest-resolve-dependencies": "^29.5.0", + "jest-runner": "^29.5.0", + "jest-runtime": "^29.5.0", + "jest-snapshot": "^29.5.0", + "jest-util": "^29.5.0", + "jest-validate": "^29.5.0", + "jest-watcher": "^29.5.0", + "micromatch": "^4.0.4", + "pretty-format": "^29.5.0", + "slash": "^3.0.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "peerDependencies": { + "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" + }, + "peerDependenciesMeta": { + "node-notifier": { + "optional": true + } + } + }, + "node_modules/@jest/core/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/@jest/core/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/@jest/core/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/@jest/core/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/@jest/core/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/@jest/core/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@jest/environment": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-29.5.0.tgz", + "integrity": "sha512-5FXw2+wD29YU1d4I2htpRX7jYnAyTRjP2CsXQdo9SAM8g3ifxWPSV0HnClSn71xwctr0U3oZIIH+dtbfmnbXVQ==", + "dev": true, + "dependencies": { + "@jest/fake-timers": "^29.5.0", + "@jest/types": "^29.5.0", + "@types/node": "*", + "jest-mock": "^29.5.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/expect": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/@jest/expect/-/expect-29.5.0.tgz", + "integrity": "sha512-PueDR2HGihN3ciUNGr4uelropW7rqUfTiOn+8u0leg/42UhblPxHkfoh0Ruu3I9Y1962P3u2DY4+h7GVTSVU6g==", + "dev": true, + "dependencies": { + "expect": "^29.5.0", + "jest-snapshot": "^29.5.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/expect-utils": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/@jest/expect-utils/-/expect-utils-29.5.0.tgz", + "integrity": "sha512-fmKzsidoXQT2KwnrwE0SQq3uj8Z763vzR8LnLBwC2qYWEFpjX8daRsk6rHUM1QvNlEW/UJXNXm59ztmJJWs2Mg==", + "dev": true, + "dependencies": { + "jest-get-type": "^29.4.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/fake-timers": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-29.5.0.tgz", + "integrity": "sha512-9ARvuAAQcBwDAqOnglWq2zwNIRUDtk/SCkp/ToGEhFv5r86K21l+VEs0qNTaXtyiY0lEePl3kylijSYJQqdbDg==", + "dev": true, + "dependencies": { + "@jest/types": "^29.5.0", + "@sinonjs/fake-timers": "^10.0.2", + "@types/node": "*", + "jest-message-util": "^29.5.0", + "jest-mock": "^29.5.0", + "jest-util": "^29.5.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/globals": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/@jest/globals/-/globals-29.5.0.tgz", + "integrity": "sha512-S02y0qMWGihdzNbUiqSAiKSpSozSuHX5UYc7QbnHP+D9Lyw8DgGGCinrN9uSuHPeKgSSzvPom2q1nAtBvUsvPQ==", + "dev": true, + "dependencies": { + "@jest/environment": "^29.5.0", + "@jest/expect": "^29.5.0", + "@jest/types": "^29.5.0", + "jest-mock": "^29.5.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/reporters": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/@jest/reporters/-/reporters-29.5.0.tgz", + "integrity": "sha512-D05STXqj/M8bP9hQNSICtPqz97u7ffGzZu+9XLucXhkOFBqKcXe04JLZOgIekOxdb73MAoBUFnqvf7MCpKk5OA==", + "dev": true, + "dependencies": { + "@bcoe/v8-coverage": "^0.2.3", + "@jest/console": "^29.5.0", + "@jest/test-result": "^29.5.0", + "@jest/transform": "^29.5.0", + "@jest/types": "^29.5.0", + "@jridgewell/trace-mapping": "^0.3.15", + "@types/node": "*", + "chalk": "^4.0.0", + "collect-v8-coverage": "^1.0.0", + "exit": "^0.1.2", + "glob": "^7.1.3", + "graceful-fs": "^4.2.9", + "istanbul-lib-coverage": "^3.0.0", + "istanbul-lib-instrument": "^5.1.0", + "istanbul-lib-report": "^3.0.0", + "istanbul-lib-source-maps": "^4.0.0", + "istanbul-reports": "^3.1.3", + "jest-message-util": "^29.5.0", + "jest-util": "^29.5.0", + "jest-worker": "^29.5.0", + "slash": "^3.0.0", + "string-length": "^4.0.1", + "strip-ansi": "^6.0.0", + "v8-to-istanbul": "^9.0.1" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "peerDependencies": { + "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" + }, + "peerDependenciesMeta": { + "node-notifier": { + "optional": true + } + } + }, + "node_modules/@jest/reporters/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/@jest/reporters/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/@jest/reporters/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/@jest/reporters/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/@jest/reporters/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/@jest/reporters/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@jest/schemas": { + "version": "29.4.3", + "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-29.4.3.tgz", + "integrity": "sha512-VLYKXQmtmuEz6IxJsrZwzG9NvtkQsWNnWMsKxqWNu3+CnfzJQhp0WDDKWLVV9hLKr0l3SLLFRqcYHjhtyuDVxg==", + "dev": true, + "dependencies": { + "@sinclair/typebox": "^0.25.16" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/source-map": { + "version": "29.4.3", + "resolved": "https://registry.npmjs.org/@jest/source-map/-/source-map-29.4.3.tgz", + "integrity": "sha512-qyt/mb6rLyd9j1jUts4EQncvS6Yy3PM9HghnNv86QBlV+zdL2inCdK1tuVlL+J+lpiw2BI67qXOrX3UurBqQ1w==", + "dev": true, + "dependencies": { + "@jridgewell/trace-mapping": "^0.3.15", + "callsites": "^3.0.0", + "graceful-fs": "^4.2.9" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/test-result": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/@jest/test-result/-/test-result-29.5.0.tgz", + "integrity": "sha512-fGl4rfitnbfLsrfx1uUpDEESS7zM8JdgZgOCQuxQvL1Sn/I6ijeAVQWGfXI9zb1i9Mzo495cIpVZhA0yr60PkQ==", + "dev": true, + "dependencies": { + "@jest/console": "^29.5.0", + "@jest/types": "^29.5.0", + "@types/istanbul-lib-coverage": "^2.0.0", + "collect-v8-coverage": "^1.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/test-sequencer": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/@jest/test-sequencer/-/test-sequencer-29.5.0.tgz", + "integrity": "sha512-yPafQEcKjkSfDXyvtgiV4pevSeyuA6MQr6ZIdVkWJly9vkqjnFfcfhRQqpD5whjoU8EORki752xQmjaqoFjzMQ==", + "dev": true, + "dependencies": { + "@jest/test-result": "^29.5.0", + "graceful-fs": "^4.2.9", + "jest-haste-map": "^29.5.0", + "slash": "^3.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/transform": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-29.5.0.tgz", + "integrity": "sha512-8vbeZWqLJOvHaDfeMuoHITGKSz5qWc9u04lnWrQE3VyuSw604PzQM824ZeX9XSjUCeDiE3GuxZe5UKa8J61NQw==", + "dev": true, + "dependencies": { + "@babel/core": "^7.11.6", + "@jest/types": "^29.5.0", + "@jridgewell/trace-mapping": "^0.3.15", + "babel-plugin-istanbul": "^6.1.1", + "chalk": "^4.0.0", + "convert-source-map": "^2.0.0", + "fast-json-stable-stringify": "^2.1.0", + "graceful-fs": "^4.2.9", + "jest-haste-map": "^29.5.0", + "jest-regex-util": "^29.4.3", + "jest-util": "^29.5.0", + "micromatch": "^4.0.4", + "pirates": "^4.0.4", + "slash": "^3.0.0", + "write-file-atomic": "^4.0.2" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/transform/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/@jest/transform/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/@jest/transform/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/@jest/transform/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/@jest/transform/node_modules/convert-source-map": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", + "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", + "dev": true + }, + "node_modules/@jest/transform/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/@jest/transform/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@jest/types": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.5.0.tgz", + "integrity": "sha512-qbu7kN6czmVRc3xWFQcAN03RAUamgppVUdXrvl1Wr3jlNF93o9mJbGcDWrwGB6ht44u7efB1qCFgVQmca24Uog==", + "dev": true, + "dependencies": { + "@jest/schemas": "^29.4.3", + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", + "@types/node": "*", + "@types/yargs": "^17.0.8", + "chalk": "^4.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/@jest/types/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/@jest/types/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/@jest/types/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/@jest/types/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/@jest/types/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/@jest/types/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@jridgewell/gen-mapping": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.1.1.tgz", + "integrity": "sha512-sQXCasFk+U8lWYEe66WxRDOE9PjVz4vSM51fTu3Hw+ClTpUSQb718772vH3pyS5pShp6lvQM7SxgIDXXXmOX7w==", + "dev": true, + "dependencies": { + "@jridgewell/set-array": "^1.0.0", + "@jridgewell/sourcemap-codec": "^1.4.10" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz", + "integrity": "sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==", + "dev": true, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/set-array": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.2.tgz", + "integrity": "sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==", + "dev": true, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.4.14", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz", + "integrity": "sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==", + "dev": true + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.17", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.17.tgz", + "integrity": "sha512-MCNzAp77qzKca9+W/+I0+sEpaUnZoeasnghNeVc41VZCEKaCH73Vq3BZZ/SzWIgrqE4H4ceI+p+b6C0mHf9T4g==", + "dev": true, + "dependencies": { + "@jridgewell/resolve-uri": "3.1.0", + "@jridgewell/sourcemap-codec": "1.4.14" + } + }, + "node_modules/@mempool/electrum-client": { + "version": "1.1.9", + "resolved": "https://registry.npmjs.org/@mempool/electrum-client/-/electrum-client-1.1.9.tgz", + "integrity": "sha512-mlvPiCzUlaETpYW3i6V87A24jjMYgsebaXtUo3WQyyLnYUuxs0KiXQ2mnKh3h15j8Xg/hfxeGIi+5OC9u0nftQ==", + "engines": { + "node": ">=6" + } + }, + "node_modules/@noble/hashes": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.3.0.tgz", + "integrity": "sha512-ilHEACi9DwqJB0pw7kv+Apvh50jiiSyR/cQ3y4W7lOR5mhvn/50FLUfsnfJz0BDZtl/RR16kXvptiv6q1msYZg==", + "funding": [ + { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + ] + }, + "node_modules/@nodelib/fs.scandir": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", + "dev": true, + "dependencies": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.stat": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", + "dev": true, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.walk": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", + "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", + "dev": true, + "dependencies": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@redis/bloom": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@redis/bloom/-/bloom-1.2.0.tgz", + "integrity": "sha512-HG2DFjYKbpNmVXsa0keLHp/3leGJz1mjh09f2RLGGLQZzSHpkmZWuwJbAvo3QcRY8p80m5+ZdXZdYOSBLlp7Cg==", + "peerDependencies": { + "@redis/client": "^1.0.0" + } + }, + "node_modules/@redis/client": { + "version": "1.5.7", + "resolved": "https://registry.npmjs.org/@redis/client/-/client-1.5.7.tgz", + "integrity": "sha512-gaOBOuJPjK5fGtxSseaKgSvjiZXQCdLlGg9WYQst+/GRUjmXaiB5kVkeQMRtPc7Q2t93XZcJfBMSwzs/XS9UZw==", + "dependencies": { + "cluster-key-slot": "1.1.2", + "generic-pool": "3.9.0", + "yallist": "4.0.0" + }, + "engines": { + "node": ">=14" + } + }, + "node_modules/@redis/client/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" + }, + "node_modules/@redis/graph": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@redis/graph/-/graph-1.1.0.tgz", + "integrity": "sha512-16yZWngxyXPd+MJxeSr0dqh2AIOi8j9yXKcKCwVaKDbH3HTuETpDVPcLujhFYVPtYrngSco31BUcSa9TH31Gqg==", + "peerDependencies": { + "@redis/client": "^1.0.0" + } + }, + "node_modules/@redis/json": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@redis/json/-/json-1.0.4.tgz", + "integrity": "sha512-LUZE2Gdrhg0Rx7AN+cZkb1e6HjoSKaeeW8rYnt89Tly13GBI5eP4CwDVr+MY8BAYfCg4/N15OUrtLoona9uSgw==", + "peerDependencies": { + "@redis/client": "^1.0.0" + } + }, + "node_modules/@redis/search": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@redis/search/-/search-1.1.2.tgz", + "integrity": "sha512-/cMfstG/fOh/SsE+4/BQGeuH/JJloeWuH+qJzM8dbxuWvdWibWAOAHHCZTMPhV3xIlH4/cUEIA8OV5QnYpaVoA==", + "peerDependencies": { + "@redis/client": "^1.0.0" + } + }, + "node_modules/@redis/time-series": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@redis/time-series/-/time-series-1.0.4.tgz", + "integrity": "sha512-ThUIgo2U/g7cCuZavucQTQzA9g9JbDDY2f64u3AbAoz/8vE2lt2U37LamDUVChhaDA3IRT9R6VvJwqnUfTJzng==", + "peerDependencies": { + "@redis/client": "^1.0.0" + } + }, + "node_modules/@sinclair/typebox": { + "version": "0.25.24", + "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.25.24.tgz", + "integrity": "sha512-XJfwUVUKDHF5ugKwIcxEgc9k8b7HbznCp6eUfWgu710hMPNIO4aw4/zB5RogDQz8nd6gyCDpU9O/m6qYEWY6yQ==", + "dev": true + }, + "node_modules/@sinonjs/commons": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-2.0.0.tgz", + "integrity": "sha512-uLa0j859mMrg2slwQYdO/AkrOfmH+X6LTVmNTS9CqexuE2IvVORIkSpJLqePAbEnKJ77aMmCwr1NUZ57120Xcg==", + "dev": true, + "dependencies": { + "type-detect": "4.0.8" + } + }, + "node_modules/@sinonjs/fake-timers": { + "version": "10.0.2", + "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-10.0.2.tgz", + "integrity": "sha512-SwUDyjWnah1AaNl7kxsa7cfLhlTYoiyhDAIgyh+El30YvXs/o7OLXpYH88Zdhyx9JExKrmHDJ+10bwIcY80Jmw==", + "dev": true, + "dependencies": { + "@sinonjs/commons": "^2.0.0" + } + }, + "node_modules/@tsconfig/node10": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.9.tgz", + "integrity": "sha512-jNsYVVxU8v5g43Erja32laIDHXeoNvFEpX33OK4d6hljo3jDhCBDhx5dhCCTMWUojscpAagGiRkBKxpdl9fxqA==", + "dev": true + }, + "node_modules/@tsconfig/node12": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.11.tgz", + "integrity": "sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==", + "dev": true + }, + "node_modules/@tsconfig/node14": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.3.tgz", + "integrity": "sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==", + "dev": true + }, + "node_modules/@tsconfig/node16": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.3.tgz", + "integrity": "sha512-yOlFc+7UtL/89t2ZhjPvvB/DeAr3r+Dq58IgzsFkOAvVC6NMJXmCGjbptdXdR9qsX7pKcTL+s87FtYREi2dEEQ==", + "dev": true + }, + "node_modules/@types/babel__core": { + "version": "7.20.0", + "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.0.tgz", + "integrity": "sha512-+n8dL/9GWblDO0iU6eZAwEIJVr5DWigtle+Q6HLOrh/pdbXOhOtqzq8VPPE2zvNJzSKY4vH/z3iT3tn0A3ypiQ==", + "dev": true, + "dependencies": { + "@babel/parser": "^7.20.7", + "@babel/types": "^7.20.7", + "@types/babel__generator": "*", + "@types/babel__template": "*", + "@types/babel__traverse": "*" + } + }, + "node_modules/@types/babel__generator": { + "version": "7.6.4", + "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.6.4.tgz", + "integrity": "sha512-tFkciB9j2K755yrTALxD44McOrk+gfpIpvC3sxHjRawj6PfnQxrse4Clq5y/Rq+G3mrBurMax/lG8Qn2t9mSsg==", + "dev": true, + "dependencies": { + "@babel/types": "^7.0.0" + } + }, + "node_modules/@types/babel__template": { + "version": "7.4.1", + "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.1.tgz", + "integrity": "sha512-azBFKemX6kMg5Io+/rdGT0dkGreboUVR0Cdm3fz9QJWpaQGJRQXl7C+6hOTCZcMll7KFyEQpgbYI2lHdsS4U7g==", + "dev": true, + "dependencies": { + "@babel/parser": "^7.1.0", + "@babel/types": "^7.0.0" + } + }, + "node_modules/@types/babel__traverse": { + "version": "7.18.3", + "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.18.3.tgz", + "integrity": "sha512-1kbcJ40lLB7MHsj39U4Sh1uTd2E7rLEa79kmDpI6cy+XiXsteB3POdQomoq4FxszMrO3ZYchkhYJw7A2862b3w==", + "dev": true, + "dependencies": { + "@babel/types": "^7.3.0" + } + }, + "node_modules/@types/body-parser": { + "version": "1.19.2", + "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.2.tgz", + "integrity": "sha512-ALYone6pm6QmwZoAgeyNksccT9Q4AWZQ6PvfwR37GT6r6FWUPguq6sUmNGSMV2Wr761oQoBxwGGa6DR5o1DC9g==", + "dev": true, + "dependencies": { + "@types/connect": "*", + "@types/node": "*" + } + }, + "node_modules/@types/compression": { + "version": "1.7.2", + "resolved": "https://registry.npmjs.org/@types/compression/-/compression-1.7.2.tgz", + "integrity": "sha512-lwEL4M/uAGWngWFLSG87ZDr2kLrbuR8p7X+QZB1OQlT+qkHsCPDVFnHPyXf4Vyl4yDDorNY+mAhosxkCvppatg==", + "dev": true, + "dependencies": { + "@types/express": "*" + } + }, + "node_modules/@types/connect": { + "version": "3.4.35", + "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.35.tgz", + "integrity": "sha512-cdeYyv4KWoEgpBISTxWvqYsVy444DOqehiF3fM3ne10AmJ62RSyNkUnxMJXHQWRQQX2eR94m5y1IZyDwBjV9FQ==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/crypto-js": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/@types/crypto-js/-/crypto-js-4.1.1.tgz", + "integrity": "sha512-BG7fQKZ689HIoc5h+6D2Dgq1fABRa0RbBWKBd9SP/MVRVXROflpm5fhwyATX5duFmbStzyzyycPB8qUYKDH3NA==", + "dev": true + }, + "node_modules/@types/express": { + "version": "4.17.17", + "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.17.tgz", + "integrity": "sha512-Q4FmmuLGBG58btUnfS1c1r/NQdlp3DMfGDGig8WhfpA2YRUtEkxAjkZb0yvplJGYdF1fsQ81iMDcH24sSCNC/Q==", + "dev": true, + "dependencies": { + "@types/body-parser": "*", + "@types/express-serve-static-core": "^4.17.33", + "@types/qs": "*", + "@types/serve-static": "*" + } + }, + "node_modules/@types/express-serve-static-core": { + "version": "4.17.33", + "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.17.33.tgz", + "integrity": "sha512-TPBqmR/HRYI3eC2E5hmiivIzv+bidAfXofM+sbonAGvyDhySGw9/PQZFt2BLOrjUUR++4eJVpx6KnLQK1Fk9tA==", + "dev": true, + "dependencies": { + "@types/node": "*", + "@types/qs": "*", + "@types/range-parser": "*" + } + }, + "node_modules/@types/graceful-fs": { + "version": "4.1.6", + "resolved": "https://registry.npmjs.org/@types/graceful-fs/-/graceful-fs-4.1.6.tgz", + "integrity": "sha512-Sig0SNORX9fdW+bQuTEovKj3uHcUL6LQKbCrrqb1X7J6/ReAbhCXRAhc+SMejhLELFj2QcyuxmUooZ4bt5ReSw==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/istanbul-lib-coverage": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.4.tgz", + "integrity": "sha512-z/QT1XN4K4KYuslS23k62yDIDLwLFkzxOuMplDtObz0+y7VqJCaO2o+SPwHCvLFZh7xazvvoor2tA/hPz9ee7g==", + "dev": true + }, + "node_modules/@types/istanbul-lib-report": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@types/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz", + "integrity": "sha512-plGgXAPfVKFoYfa9NpYDAkseG+g6Jr294RqeqcqDixSbU34MZVJRi/P+7Y8GDpzkEwLaGZZOpKIEmeVZNtKsrg==", + "dev": true, + "dependencies": { + "@types/istanbul-lib-coverage": "*" + } + }, + "node_modules/@types/istanbul-reports": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.1.tgz", + "integrity": "sha512-c3mAZEuK0lvBp8tmuL74XRKn1+y2dcwOUpH7x4WrF6gk1GIgiluDRgMYQtw2OFcBvAJWlt6ASU3tSqxp0Uu0Aw==", + "dev": true, + "dependencies": { + "@types/istanbul-lib-report": "*" + } + }, + "node_modules/@types/jest": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/@types/jest/-/jest-29.5.0.tgz", + "integrity": "sha512-3Emr5VOl/aoBwnWcH/EFQvlSAmjV+XtV9GGu5mwdYew5vhQh0IUZx/60x0TzHDu09Bi7HMx10t/namdJw5QIcg==", + "dev": true, + "dependencies": { + "expect": "^29.0.0", + "pretty-format": "^29.0.0" + } + }, + "node_modules/@types/json-schema": { + "version": "7.0.11", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.11.tgz", + "integrity": "sha512-wOuvG1SN4Us4rez+tylwwwCV1psiNVOkJeM3AUWUNWg/jDQY2+HE/444y5gc+jBmRqASOm2Oeh5c1axHobwRKQ==", + "dev": true + }, + "node_modules/@types/mime": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@types/mime/-/mime-3.0.1.tgz", + "integrity": "sha512-Y4XFY5VJAuw0FgAqPNd6NNoV44jbq9Bz2L7Rh/J6jLTiHBSBJa9fxqQIvkIld4GsoDOcCbvzOUAbLPsSKKg+uA==", + "dev": true + }, + "node_modules/@types/node": { + "version": "18.15.11", + "resolved": "https://registry.npmjs.org/@types/node/-/node-18.15.11.tgz", + "integrity": "sha512-E5Kwq2n4SbMzQOn6wnmBjuK9ouqlURrcZDVfbo9ftDDTFt3nk7ZKK4GMOzoYgnpQJKcxwQw+lGaBvvlMo0qN/Q==" + }, + "node_modules/@types/prettier": { + "version": "2.7.2", + "resolved": "https://registry.npmjs.org/@types/prettier/-/prettier-2.7.2.tgz", + "integrity": "sha512-KufADq8uQqo1pYKVIYzfKbJfBAc0sOeXqGbFaSpv8MRmC/zXgowNZmFcbngndGk922QDmOASEXUZCaY48gs4cg==", + "dev": true + }, + "node_modules/@types/qs": { + "version": "6.9.7", + "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.7.tgz", + "integrity": "sha512-FGa1F62FT09qcrueBA6qYTrJPVDzah9a+493+o2PCXsesWHIn27G98TsSMs3WPNbZIEj4+VJf6saSFpvD+3Zsw==", + "dev": true + }, + "node_modules/@types/range-parser": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.4.tgz", + "integrity": "sha512-EEhsLsD6UsDM1yFhAvy0Cjr6VwmpMWqFBCb9w07wVugF7w9nfajxLuVmngTIpgS6svCnm6Vaw+MZhoDCKnOfsw==", + "dev": true + }, + "node_modules/@types/semver": { + "version": "7.3.13", + "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.3.13.tgz", + "integrity": "sha512-21cFJr9z3g5dW8B0CVI9g2O9beqaThGQ6ZFBqHfwhzLDKUxaqTIy3vnfah/UPkfOiF2pLq+tGz+W8RyCskuslw==", + "dev": true + }, + "node_modules/@types/serve-static": { + "version": "1.15.1", + "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.15.1.tgz", + "integrity": "sha512-NUo5XNiAdULrJENtJXZZ3fHtfMolzZwczzBbnAeBbqBwG+LaG6YaJtuwzwGSQZ2wsCrxjEhNNjAkKigy3n8teQ==", + "dev": true, + "dependencies": { + "@types/mime": "*", + "@types/node": "*" + } + }, + "node_modules/@types/stack-utils": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-2.0.1.tgz", + "integrity": "sha512-Hl219/BT5fLAaz6NDkSuhzasy49dwQS/DSdu4MdggFB8zcXv7vflBI3xp7FEmkmdDkBUI2bPUNeMttp2knYdxw==", + "dev": true + }, + "node_modules/@types/ws": { + "version": "8.5.10", + "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.5.10.tgz", + "integrity": "sha512-vmQSUcfalpIq0R9q7uTo2lXs6eGIpt9wtnLdMv9LVpIjCA/+ufZRozlVoVelIYixx1ugCBKDhn89vnsEGOCx9A==", + "dev": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/yargs": { + "version": "17.0.24", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.24.tgz", + "integrity": "sha512-6i0aC7jV6QzQB8ne1joVZ0eSFIstHsCrobmOtghM11yGlH0j43FKL2UhWdELkyps0zuf7qVTUVCCR+tgSlyLLw==", + "dev": true, + "dependencies": { + "@types/yargs-parser": "*" + } + }, + "node_modules/@types/yargs-parser": { + "version": "21.0.0", + "resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-21.0.0.tgz", + "integrity": "sha512-iO9ZQHkZxHn4mSakYV0vFHAVDyEOIJQrV2uZ06HxEPcx+mt8swXoZHIbaaJ2crJYFfErySgktuTZ3BeLz+XmFA==", + "dev": true + }, + "node_modules/@typescript-eslint/eslint-plugin": { + "version": "5.57.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.57.0.tgz", + "integrity": "sha512-itag0qpN6q2UMM6Xgk6xoHa0D0/P+M17THnr4SVgqn9Rgam5k/He33MA7/D7QoJcdMxHFyX7U9imaBonAX/6qA==", + "dev": true, + "dependencies": { + "@eslint-community/regexpp": "^4.4.0", + "@typescript-eslint/scope-manager": "5.57.0", + "@typescript-eslint/type-utils": "5.57.0", + "@typescript-eslint/utils": "5.57.0", + "debug": "^4.3.4", + "grapheme-splitter": "^1.0.4", + "ignore": "^5.2.0", + "natural-compare-lite": "^1.4.0", + "semver": "^7.3.7", + "tsutils": "^3.21.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "@typescript-eslint/parser": "^5.0.0", + "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/eslint-plugin/node_modules/lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dev": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@typescript-eslint/eslint-plugin/node_modules/semver": { + "version": "7.5.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", + "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", + "dev": true, + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@typescript-eslint/eslint-plugin/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true + }, + "node_modules/@typescript-eslint/parser": { + "version": "5.57.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.57.0.tgz", + "integrity": "sha512-orrduvpWYkgLCyAdNtR1QIWovcNZlEm6yL8nwH/eTxWLd8gsP+25pdLHYzL2QdkqrieaDwLpytHqycncv0woUQ==", + "dev": true, + "dependencies": { + "@typescript-eslint/scope-manager": "5.57.0", + "@typescript-eslint/types": "5.57.0", + "@typescript-eslint/typescript-estree": "5.57.0", + "debug": "^4.3.4" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/scope-manager": { + "version": "5.57.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.57.0.tgz", + "integrity": "sha512-NANBNOQvllPlizl9LatX8+MHi7bx7WGIWYjPHDmQe5Si/0YEYfxSljJpoTyTWFTgRy3X8gLYSE4xQ2U+aCozSw==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "5.57.0", + "@typescript-eslint/visitor-keys": "5.57.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/type-utils": { + "version": "5.57.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.57.0.tgz", + "integrity": "sha512-kxXoq9zOTbvqzLbdNKy1yFrxLC6GDJFE2Yuo3KqSwTmDOFjUGeWSakgoXT864WcK5/NAJkkONCiKb1ddsqhLXQ==", + "dev": true, + "dependencies": { + "@typescript-eslint/typescript-estree": "5.57.0", + "@typescript-eslint/utils": "5.57.0", + "debug": "^4.3.4", + "tsutils": "^3.21.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "*" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/types": { + "version": "5.57.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.57.0.tgz", + "integrity": "sha512-mxsod+aZRSyLT+jiqHw1KK6xrANm19/+VFALVFP5qa/aiJnlP38qpyaTd0fEKhWvQk6YeNZ5LGwI1pDpBRBhtQ==", + "dev": true, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/typescript-estree": { + "version": "5.57.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.57.0.tgz", + "integrity": "sha512-LTzQ23TV82KpO8HPnWuxM2V7ieXW8O142I7hQTxWIHDcCEIjtkat6H96PFkYBQqGFLW/G/eVVOB9Z8rcvdY/Vw==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "5.57.0", + "@typescript-eslint/visitor-keys": "5.57.0", + "debug": "^4.3.4", + "globby": "^11.1.0", + "is-glob": "^4.0.3", + "semver": "^7.3.7", + "tsutils": "^3.21.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dev": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/semver": { + "version": "7.5.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", + "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", + "dev": true, + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true + }, + "node_modules/@typescript-eslint/utils": { + "version": "5.57.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.57.0.tgz", + "integrity": "sha512-ps/4WohXV7C+LTSgAL5CApxvxbMkl9B9AUZRtnEFonpIxZDIT7wC1xfvuJONMidrkB9scs4zhtRyIwHh4+18kw==", + "dev": true, + "dependencies": { + "@eslint-community/eslint-utils": "^4.2.0", + "@types/json-schema": "^7.0.9", + "@types/semver": "^7.3.12", + "@typescript-eslint/scope-manager": "5.57.0", + "@typescript-eslint/types": "5.57.0", + "@typescript-eslint/typescript-estree": "5.57.0", + "eslint-scope": "^5.1.1", + "semver": "^7.3.7" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, + "node_modules/@typescript-eslint/utils/node_modules/lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dev": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@typescript-eslint/utils/node_modules/semver": { + "version": "7.5.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", + "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", + "dev": true, + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@typescript-eslint/utils/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true + }, + "node_modules/@typescript-eslint/visitor-keys": { + "version": "5.57.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.57.0.tgz", + "integrity": "sha512-ery2g3k0hv5BLiKpPuwYt9KBkAp2ugT6VvyShXdLOkax895EC55sP0Tx5L0fZaQueiK3fBLvHVvEl3jFS5ia+g==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "5.57.0", + "eslint-visitor-keys": "^3.3.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/accepts": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", + "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==", + "dependencies": { + "mime-types": "~2.1.34", + "negotiator": "0.6.3" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/acorn": { + "version": "8.8.2", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.2.tgz", + "integrity": "sha512-xjIYgE8HBrkpd/sJqOGNspf8uHG+NOHGOw6a/Urj8taM2EXfdNAH2oFcPeIFfsv3+kz/mJrS5VuMqbNLjCa2vw==", + "dev": true, + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-jsx": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", + "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", + "dev": true, + "peerDependencies": { + "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, + "node_modules/acorn-walk": { + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.2.0.tgz", + "integrity": "sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA==", + "dev": true, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/agent-base": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", + "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", + "dependencies": { + "debug": "4" + }, + "engines": { + "node": ">= 6.0.0" + } + }, + "node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/ansi-escapes": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", + "integrity": "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==", + "dev": true, + "dependencies": { + "type-fest": "^0.21.3" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "dependencies": { + "color-convert": "^1.9.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/anymatch": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", + "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", + "dev": true, + "dependencies": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/arg": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", + "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==", + "dev": true + }, + "node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true + }, + "node_modules/array-flatten": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", + "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==" + }, + "node_modules/array-union": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", + "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==" + }, + "node_modules/axios": { + "version": "1.7.2", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.7.2.tgz", + "integrity": "sha512-2A8QhOMrbomlDuiLeK9XibIBzuHeRcqqNOHp0Cyp5EoJ1IFDh+XZH3A6BkXtv0K4gFGCI0Y4BM7B1wOEi0Rmgw==", + "dependencies": { + "follow-redirects": "^1.15.6", + "form-data": "^4.0.0", + "proxy-from-env": "^1.1.0" + } + }, + "node_modules/babel-jest": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-29.5.0.tgz", + "integrity": "sha512-mA4eCDh5mSo2EcA9xQjVTpmbbNk32Zb3Q3QFQsNhaK56Q+yoXowzFodLux30HRgyOho5rsQ6B0P9QpMkvvnJ0Q==", + "dev": true, + "dependencies": { + "@jest/transform": "^29.5.0", + "@types/babel__core": "^7.1.14", + "babel-plugin-istanbul": "^6.1.1", + "babel-preset-jest": "^29.5.0", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.9", + "slash": "^3.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "peerDependencies": { + "@babel/core": "^7.8.0" + } + }, + "node_modules/babel-jest/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/babel-jest/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/babel-jest/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/babel-jest/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/babel-jest/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/babel-jest/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/babel-plugin-istanbul": { + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-6.1.1.tgz", + "integrity": "sha512-Y1IQok9821cC9onCx5otgFfRm7Lm+I+wwxOx738M/WLPZ9Q42m4IG5W0FNX8WLL2gYMZo3JkuXIH2DOpWM+qwA==", + "dev": true, + "dependencies": { + "@babel/helper-plugin-utils": "^7.0.0", + "@istanbuljs/load-nyc-config": "^1.0.0", + "@istanbuljs/schema": "^0.1.2", + "istanbul-lib-instrument": "^5.0.4", + "test-exclude": "^6.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/babel-plugin-jest-hoist": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-29.5.0.tgz", + "integrity": "sha512-zSuuuAlTMT4mzLj2nPnUm6fsE6270vdOfnpbJ+RmruU75UhLFvL0N2NgI7xpeS7NaB6hGqmd5pVpGTDYvi4Q3w==", + "dev": true, + "dependencies": { + "@babel/template": "^7.3.3", + "@babel/types": "^7.3.3", + "@types/babel__core": "^7.1.14", + "@types/babel__traverse": "^7.0.6" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/babel-preset-current-node-syntax": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/babel-preset-current-node-syntax/-/babel-preset-current-node-syntax-1.0.1.tgz", + "integrity": "sha512-M7LQ0bxarkxQoN+vz5aJPsLBn77n8QgTFmo8WK0/44auK2xlCXrYcUxHFxgU7qW5Yzw/CjmLRK2uJzaCd7LvqQ==", + "dev": true, + "dependencies": { + "@babel/plugin-syntax-async-generators": "^7.8.4", + "@babel/plugin-syntax-bigint": "^7.8.3", + "@babel/plugin-syntax-class-properties": "^7.8.3", + "@babel/plugin-syntax-import-meta": "^7.8.3", + "@babel/plugin-syntax-json-strings": "^7.8.3", + "@babel/plugin-syntax-logical-assignment-operators": "^7.8.3", + "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3", + "@babel/plugin-syntax-numeric-separator": "^7.8.3", + "@babel/plugin-syntax-object-rest-spread": "^7.8.3", + "@babel/plugin-syntax-optional-catch-binding": "^7.8.3", + "@babel/plugin-syntax-optional-chaining": "^7.8.3", + "@babel/plugin-syntax-top-level-await": "^7.8.3" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/babel-preset-jest": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-29.5.0.tgz", + "integrity": "sha512-JOMloxOqdiBSxMAzjRaH023/vvcaSaec49zvg+2LmNsktC7ei39LTJGw02J+9uUtTZUq6xbLyJ4dxe9sSmIuAg==", + "dev": true, + "dependencies": { + "babel-plugin-jest-hoist": "^29.5.0", + "babel-preset-current-node-syntax": "^1.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true + }, + "node_modules/base-x": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/base-x/-/base-x-4.0.0.tgz", + "integrity": "sha512-FuwxlW4H5kh37X/oW59pwTzzTKRzfrrQwhmyspRM7swOEZcHtDZSCt45U6oKgtuFE+WYPblePMVIPR4RZrh/hw==" + }, + "node_modules/bech32": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/bech32/-/bech32-2.0.0.tgz", + "integrity": "sha512-LcknSilhIGatDAsY1ak2I8VtGaHNhgMSYVxFrGLXv+xLHytaKZKcaUJJUE7qmBr7h33o5YQwP55pMI0xmkpJwg==" + }, + "node_modules/bip174": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/bip174/-/bip174-2.1.0.tgz", + "integrity": "sha512-lkc0XyiX9E9KiVAS1ZiOqK1xfiwvf4FXDDdkDq5crcDzOq+xGytY+14qCsqz7kCiy8rpN1CRNfacRhf9G3JNSA==", + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/bitcoinjs-lib": { + "version": "6.1.3", + "resolved": "https://registry.npmjs.org/bitcoinjs-lib/-/bitcoinjs-lib-6.1.3.tgz", + "integrity": "sha512-TYXs/Qf+GNk2nnsB9HrXWqzFuEgCg0Gx+v3UW3B8VuceFHXVvhT+7hRnTSvwkX0i8rz2rtujeU6gFaDcFqYFDw==", + "dependencies": { + "@noble/hashes": "^1.2.0", + "bech32": "^2.0.0", + "bip174": "^2.1.0", + "bs58check": "^3.0.1", + "typeforce": "^1.11.3", + "varuint-bitcoin": "^1.1.2" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/body-parser": { + "version": "1.20.2", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.2.tgz", + "integrity": "sha512-ml9pReCu3M61kGlqoTm2umSXTlRTuGTx0bfYj+uIUKKYycG5NtSbeetV3faSU6R7ajOPw0g/J1PvK4qNy7s5bA==", + "dependencies": { + "bytes": "3.1.2", + "content-type": "~1.0.5", + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "1.2.0", + "http-errors": "2.0.0", + "iconv-lite": "0.4.24", + "on-finished": "2.4.1", + "qs": "6.11.0", + "raw-body": "2.5.2", + "type-is": "~1.6.18", + "unpipe": "1.0.0" + }, + "engines": { + "node": ">= 0.8", + "npm": "1.2.8000 || >= 1.4.16" + } + }, + "node_modules/body-parser/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/body-parser/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" + }, + "node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/braces": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", + "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "dev": true, + "dependencies": { + "fill-range": "^7.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/browserslist": { + "version": "4.23.0", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.23.0.tgz", + "integrity": "sha512-QW8HiM1shhT2GuzkvklfjcKDiWFXHOeFCIA/huJPwHsslwcydgk7X+z2zXpEijP98UCY7HbubZt5J2Zgvf0CaQ==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "dependencies": { + "caniuse-lite": "^1.0.30001587", + "electron-to-chromium": "^1.4.668", + "node-releases": "^2.0.14", + "update-browserslist-db": "^1.0.13" + }, + "bin": { + "browserslist": "cli.js" + }, + "engines": { + "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" + } + }, + "node_modules/bs-logger": { + "version": "0.2.6", + "resolved": "https://registry.npmjs.org/bs-logger/-/bs-logger-0.2.6.tgz", + "integrity": "sha512-pd8DCoxmbgc7hyPKOvxtqNcjYoOsABPQdcCUjGp3d42VR2CX1ORhk2A87oqqu5R1kk+76nsxZupkmyd+MVtCog==", + "dev": true, + "dependencies": { + "fast-json-stable-stringify": "2.x" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/bs58": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/bs58/-/bs58-5.0.0.tgz", + "integrity": "sha512-r+ihvQJvahgYT50JD05dyJNKlmmSlMoOGwn1lCcEzanPglg7TxYjioQUYehQ9mAR/+hOSd2jRc/Z2y5UxBymvQ==", + "dependencies": { + "base-x": "^4.0.0" + } + }, + "node_modules/bs58check": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/bs58check/-/bs58check-3.0.1.tgz", + "integrity": "sha512-hjuuJvoWEybo7Hn/0xOrczQKKEKD63WguEjlhLExYs2wUBcebDC1jDNK17eEAD2lYfw82d5ASC1d7K3SWszjaQ==", + "dependencies": { + "@noble/hashes": "^1.2.0", + "bs58": "^5.0.0" + } + }, + "node_modules/bser": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/bser/-/bser-2.1.1.tgz", + "integrity": "sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ==", + "dev": true, + "dependencies": { + "node-int64": "^0.4.0" + } + }, + "node_modules/buffer-from": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", + "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", + "dev": true + }, + "node_modules/bytes": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", + "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/call-bind": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.7.tgz", + "integrity": "sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w==", + "dependencies": { + "es-define-property": "^1.0.0", + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.4", + "set-function-length": "^1.2.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/camelcase": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", + "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/caniuse-lite": { + "version": "1.0.30001591", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001591.tgz", + "integrity": "sha512-PCzRMei/vXjJyL5mJtzNiUCKP59dm8Apqc3PH8gJkMnMXZGox93RbE76jHsmLwmIo6/3nsYIpJtx0O7u5PqFuQ==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/caniuse-lite" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ] + }, + "node_modules/chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "dependencies": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/char-regex": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/char-regex/-/char-regex-1.0.2.tgz", + "integrity": "sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/ci-info": { + "version": "3.8.0", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.8.0.tgz", + "integrity": "sha512-eXTggHWSooYhq49F2opQhuHWgzucfF2YgODK4e1566GQs5BIfP30B0oenwBJHfWxAs2fyPB1s7Mg949zLf61Yw==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/sibiraj-s" + } + ], + "engines": { + "node": ">=8" + } + }, + "node_modules/cjs-module-lexer": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/cjs-module-lexer/-/cjs-module-lexer-1.2.2.tgz", + "integrity": "sha512-cOU9usZw8/dXIXKtwa8pM0OTJQuJkxMN6w30csNRUerHfeQ5R6U3kkU/FtJeIf3M202OHfY2U8ccInBG7/xogA==", + "dev": true + }, + "node_modules/cliui": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", + "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", + "dev": true, + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.1", + "wrap-ansi": "^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/cluster-key-slot": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/cluster-key-slot/-/cluster-key-slot-1.1.2.tgz", + "integrity": "sha512-RMr0FhtfXemyinomL4hrWcYJxmX6deFdCxpJzhDttxgO1+bcCnkk+9drydLVDmAMG7NE6aN/fl4F7ucU/90gAA==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/co": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", + "integrity": "sha512-QVb0dM5HvG+uaxitm8wONl7jltx8dqhfU33DcqtOZcLSVIKSDDLDi7+0LbAKiyI8hD9u42m2YxXSkMGWThaecQ==", + "dev": true, + "engines": { + "iojs": ">= 1.0.0", + "node": ">= 0.12.0" + } + }, + "node_modules/collect-v8-coverage": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/collect-v8-coverage/-/collect-v8-coverage-1.0.1.tgz", + "integrity": "sha512-iBPtljfCNcTKNAto0KEtDfZ3qzjJvqE3aTGZsbhjSBlorqpXJlaWWtPO35D+ZImoC3KWejX64o+yPGxhWSTzfg==", + "dev": true + }, + "node_modules/color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dev": true, + "dependencies": { + "color-name": "1.1.3" + } + }, + "node_modules/color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", + "dev": true + }, + "node_modules/combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "dependencies": { + "delayed-stream": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", + "dev": true + }, + "node_modules/content-disposition": { + "version": "0.5.4", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", + "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==", + "dependencies": { + "safe-buffer": "5.2.1" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/content-type": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz", + "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/convert-source-map": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.9.0.tgz", + "integrity": "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==", + "dev": true + }, + "node_modules/cookie": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.6.0.tgz", + "integrity": "sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/cookie-signature": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", + "integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==" + }, + "node_modules/create-require": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz", + "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==", + "dev": true + }, + "node_modules/cross-spawn": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", + "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "dev": true, + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/crypto-js": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/crypto-js/-/crypto-js-4.2.0.tgz", + "integrity": "sha512-KALDyEYgpY+Rlob/iriUtjV6d5Eq+Y191A5g4UqLAi8CyGP9N1+FdVbkc1SxKc2r4YAYqG8JzO2KGL+AizD70Q==" + }, + "node_modules/debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/dedent": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/dedent/-/dedent-0.7.0.tgz", + "integrity": "sha512-Q6fKUPqnAHAyhiUgFU7BUzLiv0kd8saH9al7tnu5Q/okj6dnupxyTgFIBjVzJATdfIAm9NAsvXNzjaKa+bxVyA==", + "dev": true + }, + "node_modules/deep-is": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", + "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", + "dev": true + }, + "node_modules/deepmerge": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz", + "integrity": "sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/define-data-property": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz", + "integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==", + "dependencies": { + "es-define-property": "^1.0.0", + "es-errors": "^1.3.0", + "gopd": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/denque": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/denque/-/denque-2.1.0.tgz", + "integrity": "sha512-HVQE3AAb/pxF8fQAoiqpvg9i3evqug3hoiwakOyZAwJm+6vZehbkYXZ0l4JxS+I3QxM97v5aaRNhj8v5oBhekw==", + "engines": { + "node": ">=0.10" + } + }, + "node_modules/depd": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", + "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/destroy": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz", + "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==", + "engines": { + "node": ">= 0.8", + "npm": "1.2.8000 || >= 1.4.16" + } + }, + "node_modules/detect-newline": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/detect-newline/-/detect-newline-3.1.0.tgz", + "integrity": "sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/diff": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", + "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", + "dev": true, + "engines": { + "node": ">=0.3.1" + } + }, + "node_modules/diff-sequences": { + "version": "29.4.3", + "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-29.4.3.tgz", + "integrity": "sha512-ofrBgwpPhCD85kMKtE9RYFFq6OC1A89oW2vvgWZNCwxrUpRUILopY7lsYyMDSjc8g6U6aiO0Qubg6r4Wgt5ZnA==", + "dev": true, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/dir-glob": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", + "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", + "dev": true, + "dependencies": { + "path-type": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/doctrine": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", + "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", + "dev": true, + "dependencies": { + "esutils": "^2.0.2" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/ee-first": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", + "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==" + }, + "node_modules/electron-to-chromium": { + "version": "1.4.686", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.686.tgz", + "integrity": "sha512-3avY1B+vUzNxEgkBDpKOP8WarvUAEwpRaiCL0He5OKWEFxzaOFiq4WoZEZe7qh0ReS7DiWoHMnYoQCKxNZNzSg==", + "dev": true + }, + "node_modules/emittery": { + "version": "0.13.1", + "resolved": "https://registry.npmjs.org/emittery/-/emittery-0.13.1.tgz", + "integrity": "sha512-DeWwawk6r5yR9jFgnDKYt4sLS0LmHJJi3ZOnb5/JdbYwj3nW+FxQnHIjhBKz8YLC7oRNPVM9NQ47I3CVx34eqQ==", + "dev": true, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sindresorhus/emittery?sponsor=1" + } + }, + "node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true + }, + "node_modules/encodeurl": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", + "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/error-ex": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", + "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", + "dev": true, + "dependencies": { + "is-arrayish": "^0.2.1" + } + }, + "node_modules/es-define-property": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.0.tgz", + "integrity": "sha512-jxayLKShrEqqzJ0eumQbVhTYQM27CfT1T35+gCgDFoL82JLsXqTJ76zv6A0YLOgEnLUMvLzsDsGIrl8NFpT2gQ==", + "dependencies": { + "get-intrinsic": "^1.2.4" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-errors": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", + "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/escalade": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", + "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/escape-html": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", + "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==" + }, + "node_modules/escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "dev": true, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/eslint": { + "version": "8.37.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.37.0.tgz", + "integrity": "sha512-NU3Ps9nI05GUoVMxcZx1J8CNR6xOvUT4jAUMH5+z8lpp3aEdPVCImKw6PWG4PY+Vfkpr+jvMpxs/qoE7wq0sPw==", + "dev": true, + "dependencies": { + "@eslint-community/eslint-utils": "^4.2.0", + "@eslint-community/regexpp": "^4.4.0", + "@eslint/eslintrc": "^2.0.2", + "@eslint/js": "8.37.0", + "@humanwhocodes/config-array": "^0.11.8", + "@humanwhocodes/module-importer": "^1.0.1", + "@nodelib/fs.walk": "^1.2.8", + "ajv": "^6.10.0", + "chalk": "^4.0.0", + "cross-spawn": "^7.0.2", + "debug": "^4.3.2", + "doctrine": "^3.0.0", + "escape-string-regexp": "^4.0.0", + "eslint-scope": "^7.1.1", + "eslint-visitor-keys": "^3.4.0", + "espree": "^9.5.1", + "esquery": "^1.4.2", + "esutils": "^2.0.2", + "fast-deep-equal": "^3.1.3", + "file-entry-cache": "^6.0.1", + "find-up": "^5.0.0", + "glob-parent": "^6.0.2", + "globals": "^13.19.0", + "grapheme-splitter": "^1.0.4", + "ignore": "^5.2.0", + "import-fresh": "^3.0.0", + "imurmurhash": "^0.1.4", + "is-glob": "^4.0.0", + "is-path-inside": "^3.0.3", + "js-sdsl": "^4.1.4", + "js-yaml": "^4.1.0", + "json-stable-stringify-without-jsonify": "^1.0.1", + "levn": "^0.4.1", + "lodash.merge": "^4.6.2", + "minimatch": "^3.1.2", + "natural-compare": "^1.4.0", + "optionator": "^0.9.1", + "strip-ansi": "^6.0.1", + "strip-json-comments": "^3.1.0", + "text-table": "^0.2.0" + }, + "bin": { + "eslint": "bin/eslint.js" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint-config-prettier": { + "version": "8.8.0", + "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-8.8.0.tgz", + "integrity": "sha512-wLbQiFre3tdGgpDv67NQKnJuTlcUVYHas3k+DZCc2U2BadthoEY4B7hLPvAxaqdyOGCzuLfii2fqGph10va7oA==", + "dev": true, + "bin": { + "eslint-config-prettier": "bin/cli.js" + }, + "peerDependencies": { + "eslint": ">=7.0.0" + } + }, + "node_modules/eslint-scope": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", + "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", + "dev": true, + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^4.1.1" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/eslint-visitor-keys": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.0.tgz", + "integrity": "sha512-HPpKPUBQcAsZOsHAFwTtIKcYlCje62XB7SEAcxjtmW6TD1WVpkS6i6/hOVtTZIl4zGj/mBqpFVGvaDneik+VoQ==", + "dev": true, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/eslint/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/eslint/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/eslint/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/eslint/node_modules/escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint/node_modules/eslint-scope": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.1.1.tgz", + "integrity": "sha512-QKQM/UXpIiHcLqJ5AOyIW7XZmzjkzQXYE54n1++wb0u9V/abW3l9uQnxX8Z5Xd18xyKIMTUAyQ0k1e8pz6LUrw==", + "dev": true, + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + } + }, + "node_modules/eslint/node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/eslint/node_modules/globals": { + "version": "13.20.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.20.0.tgz", + "integrity": "sha512-Qg5QtVkCy/kv3FUSlu4ukeZDVf9ee0iXLAUYX13gbR17bnejFTzr4iS9bY7kwCf1NztRNm1t91fjOiyx4CSwPQ==", + "dev": true, + "dependencies": { + "type-fest": "^0.20.2" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/eslint/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/eslint/node_modules/type-fest": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", + "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/espree": { + "version": "9.5.1", + "resolved": "https://registry.npmjs.org/espree/-/espree-9.5.1.tgz", + "integrity": "sha512-5yxtHSZXRSW5pvv3hAlXM5+/Oswi1AUFqBmbibKb5s6bp3rGIDkyXU6xCoyuuLhijr4SFwPrXRoZjz0AZDN9tg==", + "dev": true, + "dependencies": { + "acorn": "^8.8.0", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^3.4.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/esprima": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", + "dev": true, + "bin": { + "esparse": "bin/esparse.js", + "esvalidate": "bin/esvalidate.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/esquery": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.5.0.tgz", + "integrity": "sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg==", + "dev": true, + "dependencies": { + "estraverse": "^5.1.0" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/esquery/node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/esrecurse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "dev": true, + "dependencies": { + "estraverse": "^5.2.0" + }, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/esrecurse/node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/estraverse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", + "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", + "dev": true, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/etag": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", + "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/execa": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", + "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==", + "dev": true, + "dependencies": { + "cross-spawn": "^7.0.3", + "get-stream": "^6.0.0", + "human-signals": "^2.1.0", + "is-stream": "^2.0.0", + "merge-stream": "^2.0.0", + "npm-run-path": "^4.0.1", + "onetime": "^5.1.2", + "signal-exit": "^3.0.3", + "strip-final-newline": "^2.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sindresorhus/execa?sponsor=1" + } + }, + "node_modules/exit": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz", + "integrity": "sha512-Zk/eNKV2zbjpKzrsQ+n1G6poVbErQxJ0LBOJXaKZ1EViLzH+hrLu9cdXI4zw9dBQJslwBEpbQ2P1oS7nDxs6jQ==", + "dev": true, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/expect": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/expect/-/expect-29.5.0.tgz", + "integrity": "sha512-yM7xqUrCO2JdpFo4XpM82t+PJBFybdqoQuJLDGeDX2ij8NZzqRHyu3Hp188/JX7SWqud+7t4MUdvcgGBICMHZg==", + "dev": true, + "dependencies": { + "@jest/expect-utils": "^29.5.0", + "jest-get-type": "^29.4.3", + "jest-matcher-utils": "^29.5.0", + "jest-message-util": "^29.5.0", + "jest-util": "^29.5.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/express": { + "version": "4.19.2", + "resolved": "https://registry.npmjs.org/express/-/express-4.19.2.tgz", + "integrity": "sha512-5T6nhjsT+EOMzuck8JjBHARTHfMht0POzlA60WV2pMD3gyXw2LZnZ+ueGdNxG+0calOJcWKbpFcuzLZ91YWq9Q==", + "dependencies": { + "accepts": "~1.3.8", + "array-flatten": "1.1.1", + "body-parser": "1.20.2", + "content-disposition": "0.5.4", + "content-type": "~1.0.4", + "cookie": "0.6.0", + "cookie-signature": "1.0.6", + "debug": "2.6.9", + "depd": "2.0.0", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "finalhandler": "1.2.0", + "fresh": "0.5.2", + "http-errors": "2.0.0", + "merge-descriptors": "1.0.1", + "methods": "~1.1.2", + "on-finished": "2.4.1", + "parseurl": "~1.3.3", + "path-to-regexp": "0.1.7", + "proxy-addr": "~2.0.7", + "qs": "6.11.0", + "range-parser": "~1.2.1", + "safe-buffer": "5.2.1", + "send": "0.18.0", + "serve-static": "1.15.0", + "setprototypeof": "1.2.0", + "statuses": "2.0.1", + "type-is": "~1.6.18", + "utils-merge": "1.0.1", + "vary": "~1.1.2" + }, + "engines": { + "node": ">= 0.10.0" + } + }, + "node_modules/express/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/express/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" + }, + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "dev": true + }, + "node_modules/fast-glob": { + "version": "3.2.12", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.12.tgz", + "integrity": "sha512-DVj4CQIYYow0BlaelwK1pHl5n5cRSJfM60UA0zK891sVInoPri2Ekj7+e1CT3/3qxXenpI+nBBmQAcJPJgaj4w==", + "dev": true, + "dependencies": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.2", + "merge2": "^1.3.0", + "micromatch": "^4.0.4" + }, + "engines": { + "node": ">=8.6.0" + } + }, + "node_modules/fast-glob/node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", + "dev": true + }, + "node_modules/fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", + "dev": true + }, + "node_modules/fastq": { + "version": "1.15.0", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.15.0.tgz", + "integrity": "sha512-wBrocU2LCXXa+lWBt8RoIRD89Fi8OdABODa/kEnyeyjS5aZO5/GNvI5sEINADqP/h8M29UHTHUb53sUu5Ihqdw==", + "dev": true, + "dependencies": { + "reusify": "^1.0.4" + } + }, + "node_modules/fb-watchman": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/fb-watchman/-/fb-watchman-2.0.2.tgz", + "integrity": "sha512-p5161BqbuCaSnB8jIbzQHOlpgsPmK5rJVDfDKO91Axs5NC1uu3HRQm6wt9cd9/+GtQQIO53JdGXXoyDpTAsgYA==", + "dev": true, + "dependencies": { + "bser": "2.1.1" + } + }, + "node_modules/file-entry-cache": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", + "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", + "dev": true, + "dependencies": { + "flat-cache": "^3.0.4" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + } + }, + "node_modules/fill-range": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", + "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "dev": true, + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/finalhandler": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.2.0.tgz", + "integrity": "sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg==", + "dependencies": { + "debug": "2.6.9", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "on-finished": "2.4.1", + "parseurl": "~1.3.3", + "statuses": "2.0.1", + "unpipe": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/finalhandler/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/finalhandler/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" + }, + "node_modules/find-up": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "dev": true, + "dependencies": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/flat-cache": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.0.4.tgz", + "integrity": "sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg==", + "dev": true, + "dependencies": { + "flatted": "^3.1.0", + "rimraf": "^3.0.2" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + } + }, + "node_modules/flatted": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.7.tgz", + "integrity": "sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ==", + "dev": true + }, + "node_modules/follow-redirects": { + "version": "1.15.6", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.6.tgz", + "integrity": "sha512-wWN62YITEaOpSK584EZXJafH1AGpO8RVgElfkuXbTOrPX4fIfOyEpW/CsiNd8JdYrAoOvafRTOEnvsO++qCqFA==", + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/RubenVerborgh" + } + ], + "engines": { + "node": ">=4.0" + }, + "peerDependenciesMeta": { + "debug": { + "optional": true + } + } + }, + "node_modules/form-data": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz", + "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==", + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/forwarded": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", + "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/fresh": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", + "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", + "dev": true + }, + "node_modules/fsevents": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", + "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", + "dev": true, + "hasInstallScript": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/generate-function": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/generate-function/-/generate-function-2.3.1.tgz", + "integrity": "sha512-eeB5GfMNeevm/GRYq20ShmsaGcmI81kIX2K9XQx5miC8KdHaC6Jm0qQ8ZNeGOi7wYB8OsdxKs+Y2oVuTFuVwKQ==", + "dependencies": { + "is-property": "^1.0.2" + } + }, + "node_modules/generic-pool": { + "version": "3.9.0", + "resolved": "https://registry.npmjs.org/generic-pool/-/generic-pool-3.9.0.tgz", + "integrity": "sha512-hymDOu5B53XvN4QT9dBmZxPX4CWhBPPLguTZ9MMFeFa/Kg0xWVfylOVNlJji/E7yTZWFd/q9GO5TxDLq156D7g==", + "engines": { + "node": ">= 4" + } + }, + "node_modules/gensync": { + "version": "1.0.0-beta.2", + "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", + "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", + "dev": true, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "dev": true, + "engines": { + "node": "6.* || 8.* || >= 10.*" + } + }, + "node_modules/get-intrinsic": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.4.tgz", + "integrity": "sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ==", + "dependencies": { + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "has-proto": "^1.0.1", + "has-symbols": "^1.0.3", + "hasown": "^2.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-package-type": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/get-package-type/-/get-package-type-0.1.0.tgz", + "integrity": "sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==", + "dev": true, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/get-stream": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", + "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "dev": true, + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/glob-parent": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "dev": true, + "dependencies": { + "is-glob": "^4.0.3" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/globals": { + "version": "11.12.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", + "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/globby": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", + "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", + "dev": true, + "dependencies": { + "array-union": "^2.1.0", + "dir-glob": "^3.0.1", + "fast-glob": "^3.2.9", + "ignore": "^5.2.0", + "merge2": "^1.4.1", + "slash": "^3.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/gopd": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz", + "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==", + "dependencies": { + "get-intrinsic": "^1.1.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/graceful-fs": { + "version": "4.2.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", + "dev": true + }, + "node_modules/grapheme-splitter": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/grapheme-splitter/-/grapheme-splitter-1.0.4.tgz", + "integrity": "sha512-bzh50DW9kTPM00T8y4o8vQg89Di9oLJVLW/KaOGIXJWP/iqCN6WKYkbNOF04vFLJhwcpYUh9ydh/+5vpOqV4YQ==", + "dev": true + }, + "node_modules/has": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", + "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", + "dev": true, + "dependencies": { + "function-bind": "^1.1.1" + }, + "engines": { + "node": ">= 0.4.0" + } + }, + "node_modules/has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/has-property-descriptors": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz", + "integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==", + "dependencies": { + "es-define-property": "^1.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-proto": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.3.tgz", + "integrity": "sha512-SJ1amZAJUiZS+PhsVLf5tGydlaVB8EdFpaSO4gmiUKUOxk8qzn5AIy4ZeJUmh22znIdk/uMAUT2pl3FxzVUH+Q==", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-symbols": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", + "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/hasown": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", + "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/html-escaper": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz", + "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==", + "dev": true + }, + "node_modules/http-errors": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", + "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==", + "dependencies": { + "depd": "2.0.0", + "inherits": "2.0.4", + "setprototypeof": "1.2.0", + "statuses": "2.0.1", + "toidentifier": "1.0.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/human-signals": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz", + "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==", + "dev": true, + "engines": { + "node": ">=10.17.0" + } + }, + "node_modules/iconv-lite": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/ignore": { + "version": "5.2.4", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.4.tgz", + "integrity": "sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ==", + "dev": true, + "engines": { + "node": ">= 4" + } + }, + "node_modules/import-fresh": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", + "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", + "dev": true, + "dependencies": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/import-local": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/import-local/-/import-local-3.1.0.tgz", + "integrity": "sha512-ASB07uLtnDs1o6EHjKpX34BKYDSqnFerfTOJL2HvMqF70LnxpjkzDB8J44oT9pu4AMPkQwf8jl6szgvNd2tRIg==", + "dev": true, + "dependencies": { + "pkg-dir": "^4.2.0", + "resolve-cwd": "^3.0.0" + }, + "bin": { + "import-local-fixture": "fixtures/cli.js" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", + "dev": true, + "engines": { + "node": ">=0.8.19" + } + }, + "node_modules/inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", + "dev": true, + "dependencies": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" + }, + "node_modules/ip": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/ip/-/ip-2.0.1.tgz", + "integrity": "sha512-lJUL9imLTNi1ZfXT+DU6rBBdbiKGBuay9B6xGSPVjUeQwaH1RIGqef8RZkUtHioLmSNpPR5M4HVKJGm1j8FWVQ==" + }, + "node_modules/ipaddr.js": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", + "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==", + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/is-arrayish": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", + "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==", + "dev": true + }, + "node_modules/is-core-module": { + "version": "2.11.0", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.11.0.tgz", + "integrity": "sha512-RRjxlvLDkD1YJwDbroBHMb+cukurkDWNyHx7D3oNB5x9rb5ogcksMC5wHCadcXoo67gVr/+3GFySh3134zi6rw==", + "dev": true, + "dependencies": { + "has": "^1.0.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-generator-fn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-generator-fn/-/is-generator-fn-2.1.0.tgz", + "integrity": "sha512-cTIB4yPYL/Grw0EaSzASzg6bBy9gqCofvWN8okThAYIxKJZC+udlRAmGbM0XLeniEJSs8uEgHPGuHSe1XsOLSQ==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dev": true, + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true, + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/is-path-inside": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", + "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-property": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-property/-/is-property-1.0.2.tgz", + "integrity": "sha512-Ks/IoX00TtClbGQr4TWXemAnktAQvYB7HzcCxDGqEZU6oCmb2INHuOoKxbtR+HFkmYWBKv/dOZtGRiAjDhj92g==" + }, + "node_modules/is-stream": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", + "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", + "dev": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "dev": true + }, + "node_modules/istanbul-lib-coverage": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.0.tgz", + "integrity": "sha512-eOeJ5BHCmHYvQK7xt9GkdHuzuCGS1Y6g9Gvnx3Ym33fz/HpLRYxiS0wHNr+m/MBC8B647Xt608vCDEvhl9c6Mw==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/istanbul-lib-instrument": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-5.2.1.tgz", + "integrity": "sha512-pzqtp31nLv/XFOzXGuvhCb8qhjmTVo5vjVk19XE4CRlSWz0KoeJ3bw9XsA7nOp9YBf4qHjwBxkDzKcME/J29Yg==", + "dev": true, + "dependencies": { + "@babel/core": "^7.12.3", + "@babel/parser": "^7.14.7", + "@istanbuljs/schema": "^0.1.2", + "istanbul-lib-coverage": "^3.2.0", + "semver": "^6.3.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/istanbul-lib-report": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz", + "integrity": "sha512-wcdi+uAKzfiGT2abPpKZ0hSU1rGQjUQnLvtY5MpQ7QCTahD3VODhcu4wcfY1YtkGaDD5yuydOLINXsfbus9ROw==", + "dev": true, + "dependencies": { + "istanbul-lib-coverage": "^3.0.0", + "make-dir": "^3.0.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/istanbul-lib-report/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/istanbul-lib-report/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/istanbul-lib-source-maps": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-4.0.1.tgz", + "integrity": "sha512-n3s8EwkdFIJCG3BPKBYvskgXGoy88ARzvegkitk60NxRdwltLOTaH7CUiMRXvwYorl0Q712iEjcWB+fK/MrWVw==", + "dev": true, + "dependencies": { + "debug": "^4.1.1", + "istanbul-lib-coverage": "^3.0.0", + "source-map": "^0.6.1" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/istanbul-reports": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.1.5.tgz", + "integrity": "sha512-nUsEMa9pBt/NOHqbcbeJEgqIlY/K7rVWUX6Lql2orY5e9roQOthbR3vtY4zzf2orPELg80fnxxk9zUyPlgwD1w==", + "dev": true, + "dependencies": { + "html-escaper": "^2.0.0", + "istanbul-lib-report": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/jest/-/jest-29.5.0.tgz", + "integrity": "sha512-juMg3he2uru1QoXX078zTa7pO85QyB9xajZc6bU+d9yEGwrKX6+vGmJQ3UdVZsvTEUARIdObzH68QItim6OSSQ==", + "dev": true, + "dependencies": { + "@jest/core": "^29.5.0", + "@jest/types": "^29.5.0", + "import-local": "^3.0.2", + "jest-cli": "^29.5.0" + }, + "bin": { + "jest": "bin/jest.js" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "peerDependencies": { + "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" + }, + "peerDependenciesMeta": { + "node-notifier": { + "optional": true + } + } + }, + "node_modules/jest-changed-files": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/jest-changed-files/-/jest-changed-files-29.5.0.tgz", + "integrity": "sha512-IFG34IUMUaNBIxjQXF/iu7g6EcdMrGRRxaUSw92I/2g2YC6vCdTltl4nHvt7Ci5nSJwXIkCu8Ka1DKF+X7Z1Ag==", + "dev": true, + "dependencies": { + "execa": "^5.0.0", + "p-limit": "^3.1.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-circus": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/jest-circus/-/jest-circus-29.5.0.tgz", + "integrity": "sha512-gq/ongqeQKAplVxqJmbeUOJJKkW3dDNPY8PjhJ5G0lBRvu0e3EWGxGy5cI4LAGA7gV2UHCtWBI4EMXK8c9nQKA==", + "dev": true, + "dependencies": { + "@jest/environment": "^29.5.0", + "@jest/expect": "^29.5.0", + "@jest/test-result": "^29.5.0", + "@jest/types": "^29.5.0", + "@types/node": "*", + "chalk": "^4.0.0", + "co": "^4.6.0", + "dedent": "^0.7.0", + "is-generator-fn": "^2.0.0", + "jest-each": "^29.5.0", + "jest-matcher-utils": "^29.5.0", + "jest-message-util": "^29.5.0", + "jest-runtime": "^29.5.0", + "jest-snapshot": "^29.5.0", + "jest-util": "^29.5.0", + "p-limit": "^3.1.0", + "pretty-format": "^29.5.0", + "pure-rand": "^6.0.0", + "slash": "^3.0.0", + "stack-utils": "^2.0.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-circus/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/jest-circus/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/jest-circus/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/jest-circus/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/jest-circus/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-circus/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-cli": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/jest-cli/-/jest-cli-29.5.0.tgz", + "integrity": "sha512-L1KcP1l4HtfwdxXNFCL5bmUbLQiKrakMUriBEcc1Vfz6gx31ORKdreuWvmQVBit+1ss9NNR3yxjwfwzZNdQXJw==", + "dev": true, + "dependencies": { + "@jest/core": "^29.5.0", + "@jest/test-result": "^29.5.0", + "@jest/types": "^29.5.0", + "chalk": "^4.0.0", + "exit": "^0.1.2", + "graceful-fs": "^4.2.9", + "import-local": "^3.0.2", + "jest-config": "^29.5.0", + "jest-util": "^29.5.0", + "jest-validate": "^29.5.0", + "prompts": "^2.0.1", + "yargs": "^17.3.1" + }, + "bin": { + "jest": "bin/jest.js" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "peerDependencies": { + "node-notifier": "^8.0.1 || ^9.0.0 || ^10.0.0" + }, + "peerDependenciesMeta": { + "node-notifier": { + "optional": true + } + } + }, + "node_modules/jest-cli/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/jest-cli/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/jest-cli/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/jest-cli/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/jest-cli/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-cli/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-config": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/jest-config/-/jest-config-29.5.0.tgz", + "integrity": "sha512-kvDUKBnNJPNBmFFOhDbm59iu1Fii1Q6SxyhXfvylq3UTHbg6o7j/g8k2dZyXWLvfdKB1vAPxNZnMgtKJcmu3kA==", + "dev": true, + "dependencies": { + "@babel/core": "^7.11.6", + "@jest/test-sequencer": "^29.5.0", + "@jest/types": "^29.5.0", + "babel-jest": "^29.5.0", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "deepmerge": "^4.2.2", + "glob": "^7.1.3", + "graceful-fs": "^4.2.9", + "jest-circus": "^29.5.0", + "jest-environment-node": "^29.5.0", + "jest-get-type": "^29.4.3", + "jest-regex-util": "^29.4.3", + "jest-resolve": "^29.5.0", + "jest-runner": "^29.5.0", + "jest-util": "^29.5.0", + "jest-validate": "^29.5.0", + "micromatch": "^4.0.4", + "parse-json": "^5.2.0", + "pretty-format": "^29.5.0", + "slash": "^3.0.0", + "strip-json-comments": "^3.1.1" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "peerDependencies": { + "@types/node": "*", + "ts-node": ">=9.0.0" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + }, + "ts-node": { + "optional": true + } + } + }, + "node_modules/jest-config/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/jest-config/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/jest-config/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/jest-config/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/jest-config/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-config/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-diff": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-29.5.0.tgz", + "integrity": "sha512-LtxijLLZBduXnHSniy0WMdaHjmQnt3g5sa16W4p0HqukYTTsyTW3GD1q41TyGl5YFXj/5B2U6dlh5FM1LIMgxw==", + "dev": true, + "dependencies": { + "chalk": "^4.0.0", + "diff-sequences": "^29.4.3", + "jest-get-type": "^29.4.3", + "pretty-format": "^29.5.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-diff/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/jest-diff/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/jest-diff/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/jest-diff/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/jest-diff/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-diff/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-docblock": { + "version": "29.4.3", + "resolved": "https://registry.npmjs.org/jest-docblock/-/jest-docblock-29.4.3.tgz", + "integrity": "sha512-fzdTftThczeSD9nZ3fzA/4KkHtnmllawWrXO69vtI+L9WjEIuXWs4AmyME7lN5hU7dB0sHhuPfcKofRsUb/2Fg==", + "dev": true, + "dependencies": { + "detect-newline": "^3.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-each": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/jest-each/-/jest-each-29.5.0.tgz", + "integrity": "sha512-HM5kIJ1BTnVt+DQZ2ALp3rzXEl+g726csObrW/jpEGl+CDSSQpOJJX2KE/vEg8cxcMXdyEPu6U4QX5eruQv5hA==", + "dev": true, + "dependencies": { + "@jest/types": "^29.5.0", + "chalk": "^4.0.0", + "jest-get-type": "^29.4.3", + "jest-util": "^29.5.0", + "pretty-format": "^29.5.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-each/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/jest-each/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/jest-each/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/jest-each/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/jest-each/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-each/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-environment-node": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-29.5.0.tgz", + "integrity": "sha512-ExxuIK/+yQ+6PRGaHkKewYtg6hto2uGCgvKdb2nfJfKXgZ17DfXjvbZ+jA1Qt9A8EQSfPnt5FKIfnOO3u1h9qw==", + "dev": true, + "dependencies": { + "@jest/environment": "^29.5.0", + "@jest/fake-timers": "^29.5.0", + "@jest/types": "^29.5.0", + "@types/node": "*", + "jest-mock": "^29.5.0", + "jest-util": "^29.5.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-get-type": { + "version": "29.4.3", + "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-29.4.3.tgz", + "integrity": "sha512-J5Xez4nRRMjk8emnTpWrlkyb9pfRQQanDrvWHhsR1+VUfbwxi30eVcZFlcdGInRibU4G5LwHXpI7IRHU0CY+gg==", + "dev": true, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-haste-map": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-29.5.0.tgz", + "integrity": "sha512-IspOPnnBro8YfVYSw6yDRKh/TiCdRngjxeacCps1cQ9cgVN6+10JUcuJ1EabrgYLOATsIAigxA0rLR9x/YlrSA==", + "dev": true, + "dependencies": { + "@jest/types": "^29.5.0", + "@types/graceful-fs": "^4.1.3", + "@types/node": "*", + "anymatch": "^3.0.3", + "fb-watchman": "^2.0.0", + "graceful-fs": "^4.2.9", + "jest-regex-util": "^29.4.3", + "jest-util": "^29.5.0", + "jest-worker": "^29.5.0", + "micromatch": "^4.0.4", + "walker": "^1.0.8" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "optionalDependencies": { + "fsevents": "^2.3.2" + } + }, + "node_modules/jest-leak-detector": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/jest-leak-detector/-/jest-leak-detector-29.5.0.tgz", + "integrity": "sha512-u9YdeeVnghBUtpN5mVxjID7KbkKE1QU4f6uUwuxiY0vYRi9BUCLKlPEZfDGR67ofdFmDz9oPAy2G92Ujrntmow==", + "dev": true, + "dependencies": { + "jest-get-type": "^29.4.3", + "pretty-format": "^29.5.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-matcher-utils": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-29.5.0.tgz", + "integrity": "sha512-lecRtgm/rjIK0CQ7LPQwzCs2VwW6WAahA55YBuI+xqmhm7LAaxokSB8C97yJeYyT+HvQkH741StzpU41wohhWw==", + "dev": true, + "dependencies": { + "chalk": "^4.0.0", + "jest-diff": "^29.5.0", + "jest-get-type": "^29.4.3", + "pretty-format": "^29.5.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-matcher-utils/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/jest-matcher-utils/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/jest-matcher-utils/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/jest-matcher-utils/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/jest-matcher-utils/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-matcher-utils/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-message-util": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-29.5.0.tgz", + "integrity": "sha512-Kijeg9Dag6CKtIDA7O21zNTACqD5MD/8HfIV8pdD94vFyFuer52SigdC3IQMhab3vACxXMiFk+yMHNdbqtyTGA==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.12.13", + "@jest/types": "^29.5.0", + "@types/stack-utils": "^2.0.0", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.9", + "micromatch": "^4.0.4", + "pretty-format": "^29.5.0", + "slash": "^3.0.0", + "stack-utils": "^2.0.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-message-util/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/jest-message-util/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/jest-message-util/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/jest-message-util/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/jest-message-util/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-message-util/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-mock": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-29.5.0.tgz", + "integrity": "sha512-GqOzvdWDE4fAV2bWQLQCkujxYWL7RxjCnj71b5VhDAGOevB3qj3Ovg26A5NI84ZpODxyzaozXLOh2NCgkbvyaw==", + "dev": true, + "dependencies": { + "@jest/types": "^29.5.0", + "@types/node": "*", + "jest-util": "^29.5.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-pnp-resolver": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/jest-pnp-resolver/-/jest-pnp-resolver-1.2.3.tgz", + "integrity": "sha512-+3NpwQEnRoIBtx4fyhblQDPgJI0H1IEIkX7ShLUjPGA7TtUTvI1oiKi3SR4oBR0hQhQR80l4WAe5RrXBwWMA8w==", + "dev": true, + "engines": { + "node": ">=6" + }, + "peerDependencies": { + "jest-resolve": "*" + }, + "peerDependenciesMeta": { + "jest-resolve": { + "optional": true + } + } + }, + "node_modules/jest-regex-util": { + "version": "29.4.3", + "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-29.4.3.tgz", + "integrity": "sha512-O4FglZaMmWXbGHSQInfXewIsd1LMn9p3ZXB/6r4FOkyhX2/iP/soMG98jGvk/A3HAN78+5VWcBGO0BJAPRh4kg==", + "dev": true, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-resolve": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-29.5.0.tgz", + "integrity": "sha512-1TzxJ37FQq7J10jPtQjcc+MkCkE3GBpBecsSUWJ0qZNJpmg6m0D9/7II03yJulm3H/fvVjgqLh/k2eYg+ui52w==", + "dev": true, + "dependencies": { + "chalk": "^4.0.0", + "graceful-fs": "^4.2.9", + "jest-haste-map": "^29.5.0", + "jest-pnp-resolver": "^1.2.2", + "jest-util": "^29.5.0", + "jest-validate": "^29.5.0", + "resolve": "^1.20.0", + "resolve.exports": "^2.0.0", + "slash": "^3.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-resolve-dependencies": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/jest-resolve-dependencies/-/jest-resolve-dependencies-29.5.0.tgz", + "integrity": "sha512-sjV3GFr0hDJMBpYeUuGduP+YeCRbd7S/ck6IvL3kQ9cpySYKqcqhdLLC2rFwrcL7tz5vYibomBrsFYWkIGGjOg==", + "dev": true, + "dependencies": { + "jest-regex-util": "^29.4.3", + "jest-snapshot": "^29.5.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-resolve/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/jest-resolve/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/jest-resolve/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/jest-resolve/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/jest-resolve/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-resolve/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-runner": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/jest-runner/-/jest-runner-29.5.0.tgz", + "integrity": "sha512-m7b6ypERhFghJsslMLhydaXBiLf7+jXy8FwGRHO3BGV1mcQpPbwiqiKUR2zU2NJuNeMenJmlFZCsIqzJCTeGLQ==", + "dev": true, + "dependencies": { + "@jest/console": "^29.5.0", + "@jest/environment": "^29.5.0", + "@jest/test-result": "^29.5.0", + "@jest/transform": "^29.5.0", + "@jest/types": "^29.5.0", + "@types/node": "*", + "chalk": "^4.0.0", + "emittery": "^0.13.1", + "graceful-fs": "^4.2.9", + "jest-docblock": "^29.4.3", + "jest-environment-node": "^29.5.0", + "jest-haste-map": "^29.5.0", + "jest-leak-detector": "^29.5.0", + "jest-message-util": "^29.5.0", + "jest-resolve": "^29.5.0", + "jest-runtime": "^29.5.0", + "jest-util": "^29.5.0", + "jest-watcher": "^29.5.0", + "jest-worker": "^29.5.0", + "p-limit": "^3.1.0", + "source-map-support": "0.5.13" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-runner/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/jest-runner/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/jest-runner/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/jest-runner/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/jest-runner/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-runner/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-runtime": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/jest-runtime/-/jest-runtime-29.5.0.tgz", + "integrity": "sha512-1Hr6Hh7bAgXQP+pln3homOiEZtCDZFqwmle7Ew2j8OlbkIu6uE3Y/etJQG8MLQs3Zy90xrp2C0BRrtPHG4zryw==", + "dev": true, + "dependencies": { + "@jest/environment": "^29.5.0", + "@jest/fake-timers": "^29.5.0", + "@jest/globals": "^29.5.0", + "@jest/source-map": "^29.4.3", + "@jest/test-result": "^29.5.0", + "@jest/transform": "^29.5.0", + "@jest/types": "^29.5.0", + "@types/node": "*", + "chalk": "^4.0.0", + "cjs-module-lexer": "^1.0.0", + "collect-v8-coverage": "^1.0.0", + "glob": "^7.1.3", + "graceful-fs": "^4.2.9", + "jest-haste-map": "^29.5.0", + "jest-message-util": "^29.5.0", + "jest-mock": "^29.5.0", + "jest-regex-util": "^29.4.3", + "jest-resolve": "^29.5.0", + "jest-snapshot": "^29.5.0", + "jest-util": "^29.5.0", + "slash": "^3.0.0", + "strip-bom": "^4.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-runtime/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/jest-runtime/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/jest-runtime/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/jest-runtime/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/jest-runtime/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-runtime/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-snapshot": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-29.5.0.tgz", + "integrity": "sha512-x7Wolra5V0tt3wRs3/ts3S6ciSQVypgGQlJpz2rsdQYoUKxMxPNaoHMGJN6qAuPJqS+2iQ1ZUn5kl7HCyls84g==", + "dev": true, + "dependencies": { + "@babel/core": "^7.11.6", + "@babel/generator": "^7.7.2", + "@babel/plugin-syntax-jsx": "^7.7.2", + "@babel/plugin-syntax-typescript": "^7.7.2", + "@babel/traverse": "^7.7.2", + "@babel/types": "^7.3.3", + "@jest/expect-utils": "^29.5.0", + "@jest/transform": "^29.5.0", + "@jest/types": "^29.5.0", + "@types/babel__traverse": "^7.0.6", + "@types/prettier": "^2.1.5", + "babel-preset-current-node-syntax": "^1.0.0", + "chalk": "^4.0.0", + "expect": "^29.5.0", + "graceful-fs": "^4.2.9", + "jest-diff": "^29.5.0", + "jest-get-type": "^29.4.3", + "jest-matcher-utils": "^29.5.0", + "jest-message-util": "^29.5.0", + "jest-util": "^29.5.0", + "natural-compare": "^1.4.0", + "pretty-format": "^29.5.0", + "semver": "^7.3.5" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-snapshot/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/jest-snapshot/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/jest-snapshot/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/jest-snapshot/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/jest-snapshot/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-snapshot/node_modules/lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dev": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/jest-snapshot/node_modules/semver": { + "version": "7.5.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", + "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", + "dev": true, + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/jest-snapshot/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-snapshot/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true + }, + "node_modules/jest-util": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-29.5.0.tgz", + "integrity": "sha512-RYMgG/MTadOr5t8KdhejfvUU82MxsCu5MF6KuDUHl+NuwzUt+Sm6jJWxTJVrDR1j5M/gJVCPKQEpWXY+yIQ6lQ==", + "dev": true, + "dependencies": { + "@jest/types": "^29.5.0", + "@types/node": "*", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "graceful-fs": "^4.2.9", + "picomatch": "^2.2.3" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-util/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/jest-util/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/jest-util/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/jest-util/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/jest-util/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-util/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-validate": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-29.5.0.tgz", + "integrity": "sha512-pC26etNIi+y3HV8A+tUGr/lph9B18GnzSRAkPaaZJIE1eFdiYm6/CewuiJQ8/RlfHd1u/8Ioi8/sJ+CmbA+zAQ==", + "dev": true, + "dependencies": { + "@jest/types": "^29.5.0", + "camelcase": "^6.2.0", + "chalk": "^4.0.0", + "jest-get-type": "^29.4.3", + "leven": "^3.1.0", + "pretty-format": "^29.5.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-validate/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/jest-validate/node_modules/camelcase": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", + "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/jest-validate/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/jest-validate/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/jest-validate/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/jest-validate/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-validate/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-watcher": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/jest-watcher/-/jest-watcher-29.5.0.tgz", + "integrity": "sha512-KmTojKcapuqYrKDpRwfqcQ3zjMlwu27SYext9pt4GlF5FUgB+7XE1mcCnSm6a4uUpFyQIkb6ZhzZvHl+jiBCiA==", + "dev": true, + "dependencies": { + "@jest/test-result": "^29.5.0", + "@jest/types": "^29.5.0", + "@types/node": "*", + "ansi-escapes": "^4.2.1", + "chalk": "^4.0.0", + "emittery": "^0.13.1", + "jest-util": "^29.5.0", + "string-length": "^4.0.1" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-watcher/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/jest-watcher/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/jest-watcher/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/jest-watcher/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/jest-watcher/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-watcher/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-worker": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-29.5.0.tgz", + "integrity": "sha512-NcrQnevGoSp4b5kg+akIpthoAFHxPBcb5P6mYPY0fUNT+sSvmtu6jlkEle3anczUKIKEbMxFimk9oTP/tpIPgA==", + "dev": true, + "dependencies": { + "@types/node": "*", + "jest-util": "^29.5.0", + "merge-stream": "^2.0.0", + "supports-color": "^8.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/jest-worker/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-worker/node_modules/supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" + } + }, + "node_modules/js-sdsl": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/js-sdsl/-/js-sdsl-4.4.0.tgz", + "integrity": "sha512-FfVSdx6pJ41Oa+CF7RDaFmTnCaFhua+SNYQX74riGOpl96x+2jQCqEfQ2bnXu/5DPCqlRuiqyvTJM0Qjz26IVg==", + "dev": true, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/js-sdsl" + } + }, + "node_modules/js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "dev": true + }, + "node_modules/js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "dev": true, + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/jsesc": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", + "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", + "dev": true, + "bin": { + "jsesc": "bin/jsesc" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/json-parse-even-better-errors": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", + "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", + "dev": true + }, + "node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true + }, + "node_modules/json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", + "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", + "dev": true + }, + "node_modules/json5": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", + "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", + "dev": true, + "bin": { + "json5": "lib/cli.js" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/kleur": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/kleur/-/kleur-3.0.3.tgz", + "integrity": "sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/leven": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz", + "integrity": "sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/levn": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", + "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", + "dev": true, + "dependencies": { + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/lines-and-columns": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", + "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", + "dev": true + }, + "node_modules/locate-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "dev": true, + "dependencies": { + "p-locate": "^5.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/lodash.memoize": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-4.1.2.tgz", + "integrity": "sha512-t7j+NzmgnQzTAYXcsHYLgimltOV1MXHtlOWf6GjL9Kj8GK5FInw5JotxvbOs+IvV1/Dzo04/fCGfLVs7aXb4Ag==", + "dev": true + }, + "node_modules/lodash.merge": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", + "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", + "dev": true + }, + "node_modules/long": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/long/-/long-5.2.1.tgz", + "integrity": "sha512-GKSNGeNAtw8IryjjkhZxuKB3JzlcLTwjtiQCHKvqQet81I93kXslhDQruGI/QsddO83mcDToBVy7GqGS/zYf/A==" + }, + "node_modules/lru-cache": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", + "dev": true, + "dependencies": { + "yallist": "^3.0.2" + } + }, + "node_modules/make-dir": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", + "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", + "dev": true, + "dependencies": { + "semver": "^6.0.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/make-error": { + "version": "1.3.6", + "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", + "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", + "dev": true + }, + "node_modules/makeerror": { + "version": "1.0.12", + "resolved": "https://registry.npmjs.org/makeerror/-/makeerror-1.0.12.tgz", + "integrity": "sha512-JmqCvUhmt43madlpFzG4BQzG2Z3m6tvQDNKdClZnO3VbIudJYmxsT0FNJMeiB2+JTSlTQTSbU8QdesVmwJcmLg==", + "dev": true, + "dependencies": { + "tmpl": "1.0.5" + } + }, + "node_modules/maxmind": { + "version": "4.3.11", + "resolved": "https://registry.npmjs.org/maxmind/-/maxmind-4.3.11.tgz", + "integrity": "sha512-tJDrKbUzN6PSA88tWgg0L2R4Ln00XwecYQJPFI+RvlF2k1sx6VQYtuQ1SVxm8+bw5tF7GWV4xyb+3/KyzEpPUw==", + "dependencies": { + "mmdb-lib": "2.0.2", + "tiny-lru": "11.0.1" + }, + "engines": { + "node": ">=12", + "npm": ">=6" + } + }, + "node_modules/media-typer": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", + "integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/merge-descriptors": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", + "integrity": "sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w==" + }, + "node_modules/merge-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", + "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", + "dev": true + }, + "node_modules/merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "dev": true, + "engines": { + "node": ">= 8" + } + }, + "node_modules/methods": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", + "integrity": "sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/micromatch": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", + "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", + "dev": true, + "dependencies": { + "braces": "^3.0.2", + "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/mime": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", + "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", + "bin": { + "mime": "cli.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mimic-fn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", + "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/mmdb-lib": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/mmdb-lib/-/mmdb-lib-2.0.2.tgz", + "integrity": "sha512-shi1I+fCPQonhTi7qyb6hr7hi87R7YS69FlfJiMFuJ12+grx0JyL56gLNzGTYXPU7EhAPkMLliGeyHer0K+AVA==", + "engines": { + "node": ">=10", + "npm": ">=6" + } + }, + "node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + }, + "node_modules/mysql2": { + "version": "3.10.0", + "resolved": "https://registry.npmjs.org/mysql2/-/mysql2-3.10.0.tgz", + "integrity": "sha512-qx0mfWYt1DpTPkw8mAcHW/OwqqyNqBLBHvY5IjN8+icIYTjt6znrgYJ+gxqNNRpVknb5Wc/gcCM4XjbCR0j5tw==", + "dependencies": { + "denque": "^2.1.0", + "generate-function": "^2.3.1", + "iconv-lite": "^0.6.3", + "long": "^5.2.1", + "lru-cache": "^8.0.0", + "named-placeholders": "^1.1.3", + "seq-queue": "^0.0.5", + "sqlstring": "^2.3.2" + }, + "engines": { + "node": ">= 8.0" + } + }, + "node_modules/mysql2/node_modules/iconv-lite": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", + "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/mysql2/node_modules/lru-cache": { + "version": "8.0.5", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-8.0.5.tgz", + "integrity": "sha512-MhWWlVnuab1RG5/zMRRcVGXZLCXrZTgfwMikgzCegsPnG62yDQo5JnqKkrK4jO5iKqDAZGItAqN5CtKBCBWRUA==", + "engines": { + "node": ">=16.14" + } + }, + "node_modules/named-placeholders": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/named-placeholders/-/named-placeholders-1.1.3.tgz", + "integrity": "sha512-eLoBxg6wE/rZkJPhU/xRX1WTpkFEwDJEN96oxFrTsqBdbT5ec295Q+CoHrL9IT0DipqKhmGcaZmwOt8OON5x1w==", + "dependencies": { + "lru-cache": "^7.14.1" + }, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/named-placeholders/node_modules/lru-cache": { + "version": "7.18.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.18.3.tgz", + "integrity": "sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==", + "engines": { + "node": ">=12" + } + }, + "node_modules/natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", + "dev": true + }, + "node_modules/natural-compare-lite": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare-lite/-/natural-compare-lite-1.4.0.tgz", + "integrity": "sha512-Tj+HTDSJJKaZnfiuw+iaF9skdPpTo2GtEly5JHnWV/hfv2Qj/9RKsGISQtLh2ox3l5EAGw487hnBee0sIJ6v2g==", + "dev": true + }, + "node_modules/negotiator": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", + "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/node-int64": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz", + "integrity": "sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw==", + "dev": true + }, + "node_modules/node-releases": { + "version": "2.0.14", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.14.tgz", + "integrity": "sha512-y10wOWt8yZpqXmOgRo77WaHEmhYQYGNA6y421PKsKYWEK8aW+cqAphborZDhqfyKrbZEN92CN1X2KbafY2s7Yw==", + "dev": true + }, + "node_modules/normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/npm-run-path": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", + "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", + "dev": true, + "dependencies": { + "path-key": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/object-inspect": { + "version": "1.13.1", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.1.tgz", + "integrity": "sha512-5qoj1RUiKOMsCCNLV1CBiPYE10sziTsnmNxkAI/rZhiD63CF7IqdFGC/XzjWjpSgLf0LxXX3bDFIh0E18f6UhQ==", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/on-finished": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", + "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", + "dependencies": { + "ee-first": "1.1.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "dev": true, + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/onetime": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", + "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", + "dev": true, + "dependencies": { + "mimic-fn": "^2.1.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/optionator": { + "version": "0.9.3", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.3.tgz", + "integrity": "sha512-JjCoypp+jKn1ttEFExxhetCKeJt9zhAgAve5FXHixTvFDW/5aEktX9bufBKLRRMdU7bNtpLfcGu94B3cdEJgjg==", + "dev": true, + "dependencies": { + "@aashutoshrathi/word-wrap": "^1.2.3", + "deep-is": "^0.1.3", + "fast-levenshtein": "^2.0.6", + "levn": "^0.4.1", + "prelude-ls": "^1.2.1", + "type-check": "^0.4.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "dev": true, + "dependencies": { + "yocto-queue": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-locate": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "dev": true, + "dependencies": { + "p-limit": "^3.0.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-try": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", + "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/parent-module": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "dev": true, + "dependencies": { + "callsites": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/parse-json": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", + "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", + "dev": true, + "dependencies": { + "@babel/code-frame": "^7.0.0", + "error-ex": "^1.3.1", + "json-parse-even-better-errors": "^2.3.0", + "lines-and-columns": "^1.1.6" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/parseurl": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", + "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/path-parse": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", + "dev": true + }, + "node_modules/path-to-regexp": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", + "integrity": "sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ==" + }, + "node_modules/path-type": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", + "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/picocolors": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", + "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==", + "dev": true + }, + "node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true, + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/pirates": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.5.tgz", + "integrity": "sha512-8V9+HQPupnaXMA23c5hvl69zXvTwTzyAYasnkb0Tts4XvO4CliqONMOnvlq26rkhLC3nWDFBJf73LU1e1VZLaQ==", + "dev": true, + "engines": { + "node": ">= 6" + } + }, + "node_modules/pkg-dir": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", + "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", + "dev": true, + "dependencies": { + "find-up": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/pkg-dir/node_modules/find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "dev": true, + "dependencies": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/pkg-dir/node_modules/locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "dev": true, + "dependencies": { + "p-locate": "^4.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/pkg-dir/node_modules/p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "dev": true, + "dependencies": { + "p-try": "^2.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/pkg-dir/node_modules/p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "dev": true, + "dependencies": { + "p-limit": "^2.2.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/prelude-ls": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", + "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", + "dev": true, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/prettier": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.0.0.tgz", + "integrity": "sha512-zBf5eHpwHOGPC47h0zrPyNn+eAEIdEzfywMoYn2XPi0P44Zp0tSq64rq0xAREh4auw2cJZHo9QUob+NqCQky4g==", + "dev": true, + "bin": { + "prettier": "bin/prettier.cjs" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/prettier/prettier?sponsor=1" + } + }, + "node_modules/pretty-format": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.5.0.tgz", + "integrity": "sha512-V2mGkI31qdttvTFX7Mt4efOqHXqJWMu4/r66Xh3Z3BwZaPfPJgp6/gbwoujRpPUtfEF6AUUWx3Jim3GCw5g/Qw==", + "dev": true, + "dependencies": { + "@jest/schemas": "^29.4.3", + "ansi-styles": "^5.0.0", + "react-is": "^18.0.0" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + } + }, + "node_modules/pretty-format/node_modules/ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/prompts": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/prompts/-/prompts-2.4.2.tgz", + "integrity": "sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==", + "dev": true, + "dependencies": { + "kleur": "^3.0.3", + "sisteransi": "^1.0.5" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/proxy-addr": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", + "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==", + "dependencies": { + "forwarded": "0.2.0", + "ipaddr.js": "1.9.1" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/proxy-from-env": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", + "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==" + }, + "node_modules/punycode": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.0.tgz", + "integrity": "sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/pure-rand": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/pure-rand/-/pure-rand-6.0.1.tgz", + "integrity": "sha512-t+x1zEHDjBwkDGY5v5ApnZ/utcd4XYDiJsaQQoptTXgUXX95sDg1elCdJghzicm7n2mbCBJ3uYWr6M22SO19rg==", + "dev": true, + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/dubzzz" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/fast-check" + } + ] + }, + "node_modules/qs": { + "version": "6.11.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz", + "integrity": "sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==", + "dependencies": { + "side-channel": "^1.0.4" + }, + "engines": { + "node": ">=0.6" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/queue-microtask": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/range-parser": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", + "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/raw-body": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.2.tgz", + "integrity": "sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA==", + "dependencies": { + "bytes": "3.1.2", + "http-errors": "2.0.0", + "iconv-lite": "0.4.24", + "unpipe": "1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/react-is": { + "version": "18.2.0", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz", + "integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==", + "dev": true + }, + "node_modules/redis": { + "version": "4.6.6", + "resolved": "https://registry.npmjs.org/redis/-/redis-4.6.6.tgz", + "integrity": "sha512-aLs2fuBFV/VJ28oLBqYykfnhGGkFxvx0HdCEBYdJ99FFbSEMZ7c1nVKwR6ZRv+7bb7JnC0mmCzaqu8frgOYhpA==", + "dependencies": { + "@redis/bloom": "1.2.0", + "@redis/client": "1.5.7", + "@redis/graph": "1.1.0", + "@redis/json": "1.0.4", + "@redis/search": "1.1.2", + "@redis/time-series": "1.0.4" + } + }, + "node_modules/require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/resolve": { + "version": "1.22.1", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.1.tgz", + "integrity": "sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw==", + "dev": true, + "dependencies": { + "is-core-module": "^2.9.0", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + }, + "bin": { + "resolve": "bin/resolve" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/resolve-cwd": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-3.0.0.tgz", + "integrity": "sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg==", + "dev": true, + "dependencies": { + "resolve-from": "^5.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/resolve-cwd/node_modules/resolve-from": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", + "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/resolve.exports": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/resolve.exports/-/resolve.exports-2.0.2.tgz", + "integrity": "sha512-X2UW6Nw3n/aMgDVy+0rSqgHlv39WZAlZrXCdnbyEiKm17DSqHX4MmQMaST3FbeWR5FTuRcUwYAziZajji0Y7mg==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/reusify": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", + "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", + "dev": true, + "engines": { + "iojs": ">=1.0.0", + "node": ">=0.10.0" + } + }, + "node_modules/rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "dev": true, + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/run-parallel": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "dependencies": { + "queue-microtask": "^1.2.2" + } + }, + "node_modules/rust-gbt": { + "resolved": "rust-gbt", + "link": true + }, + "node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" + }, + "node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true, + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/send": { + "version": "0.18.0", + "resolved": "https://registry.npmjs.org/send/-/send-0.18.0.tgz", + "integrity": "sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==", + "dependencies": { + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "1.2.0", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "fresh": "0.5.2", + "http-errors": "2.0.0", + "mime": "1.6.0", + "ms": "2.1.3", + "on-finished": "2.4.1", + "range-parser": "~1.2.1", + "statuses": "2.0.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/send/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/send/node_modules/debug/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" + }, + "node_modules/send/node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" + }, + "node_modules/seq-queue": { + "version": "0.0.5", + "resolved": "https://registry.npmjs.org/seq-queue/-/seq-queue-0.0.5.tgz", + "integrity": "sha512-hr3Wtp/GZIc/6DAGPDcV4/9WoZhjrkXsi5B/07QgX8tsdc6ilr7BFM6PM6rbdAX1kFSDYeZGLipIZZKyQP0O5Q==" + }, + "node_modules/serve-static": { + "version": "1.15.0", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.15.0.tgz", + "integrity": "sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g==", + "dependencies": { + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "parseurl": "~1.3.3", + "send": "0.18.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/set-function-length": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz", + "integrity": "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==", + "dependencies": { + "define-data-property": "^1.1.4", + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.4", + "gopd": "^1.0.1", + "has-property-descriptors": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/setprototypeof": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", + "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==" + }, + "node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/side-channel": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.6.tgz", + "integrity": "sha512-fDW/EZ6Q9RiO8eFG8Hj+7u/oW+XrPTIChwCOM2+th2A6OblDtYYIpve9m+KvI9Z4C9qSEXlaGR6bTEYHReuglA==", + "dependencies": { + "call-bind": "^1.0.7", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.4", + "object-inspect": "^1.13.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/signal-exit": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", + "dev": true + }, + "node_modules/sisteransi": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz", + "integrity": "sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==", + "dev": true + }, + "node_modules/slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/smart-buffer": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/smart-buffer/-/smart-buffer-4.2.0.tgz", + "integrity": "sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==", + "engines": { + "node": ">= 6.0.0", + "npm": ">= 3.0.0" + } + }, + "node_modules/socks": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/socks/-/socks-2.7.1.tgz", + "integrity": "sha512-7maUZy1N7uo6+WVEX6psASxtNlKaNVMlGQKkG/63nEDdLOWNbiUMoLK7X4uYoLhQstau72mLgfEWcXcwsaHbYQ==", + "dependencies": { + "ip": "^2.0.0", + "smart-buffer": "^4.2.0" + }, + "engines": { + "node": ">= 10.13.0", + "npm": ">= 3.0.0" + } + }, + "node_modules/socks-proxy-agent": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/socks-proxy-agent/-/socks-proxy-agent-7.0.0.tgz", + "integrity": "sha512-Fgl0YPZ902wEsAyiQ+idGd1A7rSFx/ayC1CQVMw5P+EQx2V0SgpGtf6OKFhVjPflPUl9YMmEOnmfjCdMUsygww==", + "dependencies": { + "agent-base": "^6.0.2", + "debug": "^4.3.3", + "socks": "^2.6.2" + }, + "engines": { + "node": ">= 10" + } + }, + "node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/source-map-support": { + "version": "0.5.13", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.13.tgz", + "integrity": "sha512-SHSKFHadjVA5oR4PPqhtAVdcBWwRYVd6g6cAXnIbRiIwc2EhPrTuKUBdSLvlEKyIP3GCf89fltvcZiP9MMFA1w==", + "dev": true, + "dependencies": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + } + }, + "node_modules/sprintf-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==", + "dev": true + }, + "node_modules/sqlstring": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/sqlstring/-/sqlstring-2.3.3.tgz", + "integrity": "sha512-qC9iz2FlN7DQl3+wjwn3802RTyjCx7sDvfQEXchwa6CWOx07/WVfh91gBmQ9fahw8snwGEWU3xGzOt4tFyHLxg==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/stack-utils": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/stack-utils/-/stack-utils-2.0.6.tgz", + "integrity": "sha512-XlkWvfIm6RmsWtNJx+uqtKLS8eqFbxUg0ZzLXqY0caEy9l7hruX8IpiDnjsLavoBgqCCR71TqWO8MaXYheJ3RQ==", + "dev": true, + "dependencies": { + "escape-string-regexp": "^2.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/stack-utils/node_modules/escape-string-regexp": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz", + "integrity": "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/statuses": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", + "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/string-length": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/string-length/-/string-length-4.0.2.tgz", + "integrity": "sha512-+l6rNN5fYHNhZZy41RXsYptCjA2Igmq4EG7kZAYFQI1E1VTXarr6ZPXBg6eq7Y6eK4FEhY6AJlyuFIb/v/S0VQ==", + "dev": true, + "dependencies": { + "char-regex": "^1.0.2", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-bom": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-4.0.0.tgz", + "integrity": "sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-final-newline": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz", + "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "dev": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/supports-preserve-symlinks-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", + "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", + "dev": true, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/test-exclude": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-6.0.0.tgz", + "integrity": "sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==", + "dev": true, + "dependencies": { + "@istanbuljs/schema": "^0.1.2", + "glob": "^7.1.4", + "minimatch": "^3.0.4" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/text-table": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", + "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", + "dev": true + }, + "node_modules/tiny-lru": { + "version": "11.0.1", + "resolved": "https://registry.npmjs.org/tiny-lru/-/tiny-lru-11.0.1.tgz", + "integrity": "sha512-iNgFugVuQgBKrqeO/mpiTTgmBsTP0WL6yeuLfLs/Ctf0pI/ixGqIRm8sDCwMcXGe9WWvt2sGXI5mNqZbValmJg==", + "engines": { + "node": ">=12" + } + }, + "node_modules/tmpl": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/tmpl/-/tmpl-1.0.5.tgz", + "integrity": "sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw==", + "dev": true + }, + "node_modules/to-fast-properties": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", + "integrity": "sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/toidentifier": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", + "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==", + "engines": { + "node": ">=0.6" + } + }, + "node_modules/ts-jest": { + "version": "29.1.1", + "resolved": "https://registry.npmjs.org/ts-jest/-/ts-jest-29.1.1.tgz", + "integrity": "sha512-D6xjnnbP17cC85nliwGiL+tpoKN0StpgE0TeOjXQTU6MVCfsB4v7aW05CgQ/1OywGb0x/oy9hHFnN+sczTiRaA==", + "dev": true, + "dependencies": { + "bs-logger": "0.x", + "fast-json-stable-stringify": "2.x", + "jest-util": "^29.0.0", + "json5": "^2.2.3", + "lodash.memoize": "4.x", + "make-error": "1.x", + "semver": "^7.5.3", + "yargs-parser": "^21.0.1" + }, + "bin": { + "ts-jest": "cli.js" + }, + "engines": { + "node": "^14.15.0 || ^16.10.0 || >=18.0.0" + }, + "peerDependencies": { + "@babel/core": ">=7.0.0-beta.0 <8", + "@jest/types": "^29.0.0", + "babel-jest": "^29.0.0", + "jest": "^29.0.0", + "typescript": ">=4.3 <6" + }, + "peerDependenciesMeta": { + "@babel/core": { + "optional": true + }, + "@jest/types": { + "optional": true + }, + "babel-jest": { + "optional": true + }, + "esbuild": { + "optional": true + } + } + }, + "node_modules/ts-jest/node_modules/lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dev": true, + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/ts-jest/node_modules/semver": { + "version": "7.5.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", + "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", + "dev": true, + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/ts-jest/node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true + }, + "node_modules/ts-node": { + "version": "10.9.1", + "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.1.tgz", + "integrity": "sha512-NtVysVPkxxrwFGUUxGYhfux8k78pQB3JqYBXlLRZgdGUqTO5wU/UyHop5p70iEbGhB7q5KmiZiU0Y3KlJrScEw==", + "dev": true, + "dependencies": { + "@cspotcode/source-map-support": "^0.8.0", + "@tsconfig/node10": "^1.0.7", + "@tsconfig/node12": "^1.0.7", + "@tsconfig/node14": "^1.0.0", + "@tsconfig/node16": "^1.0.2", + "acorn": "^8.4.1", + "acorn-walk": "^8.1.1", + "arg": "^4.1.0", + "create-require": "^1.1.0", + "diff": "^4.0.1", + "make-error": "^1.1.1", + "v8-compile-cache-lib": "^3.0.1", + "yn": "3.1.1" + }, + "bin": { + "ts-node": "dist/bin.js", + "ts-node-cwd": "dist/bin-cwd.js", + "ts-node-esm": "dist/bin-esm.js", + "ts-node-script": "dist/bin-script.js", + "ts-node-transpile-only": "dist/bin-transpile.js", + "ts-script": "dist/bin-script-deprecated.js" + }, + "peerDependencies": { + "@swc/core": ">=1.2.50", + "@swc/wasm": ">=1.2.50", + "@types/node": "*", + "typescript": ">=2.7" + }, + "peerDependenciesMeta": { + "@swc/core": { + "optional": true + }, + "@swc/wasm": { + "optional": true + } + } + }, + "node_modules/tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "dev": true + }, + "node_modules/tsutils": { + "version": "3.21.0", + "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-3.21.0.tgz", + "integrity": "sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==", + "dev": true, + "dependencies": { + "tslib": "^1.8.1" + }, + "engines": { + "node": ">= 6" + }, + "peerDependencies": { + "typescript": ">=2.8.0 || >= 3.2.0-dev || >= 3.3.0-dev || >= 3.4.0-dev || >= 3.5.0-dev || >= 3.6.0-dev || >= 3.6.0-beta || >= 3.7.0-dev || >= 3.7.0-beta" + } + }, + "node_modules/type-check": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", + "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", + "dev": true, + "dependencies": { + "prelude-ls": "^1.2.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/type-detect": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", + "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==", + "dev": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/type-fest": { + "version": "0.21.3", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz", + "integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/type-is": { + "version": "1.6.18", + "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", + "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", + "dependencies": { + "media-typer": "0.3.0", + "mime-types": "~2.1.24" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/typeforce": { + "version": "1.18.0", + "resolved": "https://registry.npmjs.org/typeforce/-/typeforce-1.18.0.tgz", + "integrity": "sha512-7uc1O8h1M1g0rArakJdf0uLRSSgFcYexrVoKo+bzJd32gd4gDy2L/Z+8/FjPnU9ydY3pEnVPtr9FyscYY60K1g==" + }, + "node_modules/typescript": { + "version": "4.9.5", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.5.tgz", + "integrity": "sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g==", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=4.2.0" + } + }, + "node_modules/unpipe": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", + "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/update-browserslist-db": { + "version": "1.0.13", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.13.tgz", + "integrity": "sha512-xebP81SNcPuNpPP3uzeW1NYXxI3rxyJzF3pD6sH4jE7o/IX+WtSpwnVU+qIsDPyk0d3hmFQ7mjqc6AtV604hbg==", + "dev": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "dependencies": { + "escalade": "^3.1.1", + "picocolors": "^1.0.0" + }, + "bin": { + "update-browserslist-db": "cli.js" + }, + "peerDependencies": { + "browserslist": ">= 4.21.0" + } + }, + "node_modules/uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "dev": true, + "dependencies": { + "punycode": "^2.1.0" + } + }, + "node_modules/utils-merge": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", + "integrity": "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==", + "engines": { + "node": ">= 0.4.0" + } + }, + "node_modules/v8-compile-cache-lib": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz", + "integrity": "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==", + "dev": true + }, + "node_modules/v8-to-istanbul": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-9.1.0.tgz", + "integrity": "sha512-6z3GW9x8G1gd+JIIgQQQxXuiJtCXeAjp6RaPEPLv62mH3iPHPxV6W3robxtCzNErRo6ZwTmzWhsbNvjyEBKzKA==", + "dev": true, + "dependencies": { + "@jridgewell/trace-mapping": "^0.3.12", + "@types/istanbul-lib-coverage": "^2.0.1", + "convert-source-map": "^1.6.0" + }, + "engines": { + "node": ">=10.12.0" + } + }, + "node_modules/varuint-bitcoin": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/varuint-bitcoin/-/varuint-bitcoin-1.1.2.tgz", + "integrity": "sha512-4EVb+w4rx+YfVM32HQX42AbbT7/1f5zwAYhIujKXKk8NQK+JfRVl3pqT3hjNn/L+RstigmGGKVwHA/P0wgITZw==", + "dependencies": { + "safe-buffer": "^5.1.1" + } + }, + "node_modules/vary": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", + "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/walker": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/walker/-/walker-1.0.8.tgz", + "integrity": "sha512-ts/8E8l5b7kY0vlWLewOkDXMmPdLcVV4GmOQLyxuSswIJsweeFZtAsMF7k1Nszz+TYBQrlYRmzOnr398y1JemQ==", + "dev": true, + "dependencies": { + "makeerror": "1.0.12" + } + }, + "node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrap-ansi/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/wrap-ansi/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/wrap-ansi/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", + "dev": true + }, + "node_modules/write-file-atomic": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-4.0.2.tgz", + "integrity": "sha512-7KxauUdBmSdWnmpaGFg+ppNjKF8uNLry8LyzjauQDOVONfFLNKrKvQOxZ/VuTIcS/gge/YNahf5RIIQWTSarlg==", + "dev": true, + "dependencies": { + "imurmurhash": "^0.1.4", + "signal-exit": "^3.0.7" + }, + "engines": { + "node": "^12.13.0 || ^14.15.0 || >=16.0.0" + } + }, + "node_modules/ws": { + "version": "8.18.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.0.tgz", + "integrity": "sha512-8VbfWfHLbbwu3+N6OKsOMpBdT4kXPDDB9cJk2bJ6mh9ucxdlnNvH1e+roYkKmN9Nxw2yjz7VzeO9oOz2zJ04Pw==", + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": ">=5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, + "node_modules/y18n": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", + "dev": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/yallist": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", + "dev": true + }, + "node_modules/yargs": { + "version": "17.7.1", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.1.tgz", + "integrity": "sha512-cwiTb08Xuv5fqF4AovYacTFNxk62th7LKJ6BL9IGUpTJrWoU7/7WdQGTP2SjKf1dUNBGzDd28p/Yfs/GI6JrLw==", + "dev": true, + "dependencies": { + "cliui": "^8.0.1", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.3", + "y18n": "^5.0.5", + "yargs-parser": "^21.1.1" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/yargs-parser": { + "version": "21.1.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", + "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", + "dev": true, + "engines": { + "node": ">=12" + } + }, + "node_modules/yn": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", + "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/yocto-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "rust-gbt": { + "version": "0.0.1" + } + }, + "dependencies": { + "@aashutoshrathi/word-wrap": { + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/@aashutoshrathi/word-wrap/-/word-wrap-1.2.6.tgz", + "integrity": "sha512-1Yjs2SvM8TflER/OD3cOjhWWOZb58A2t7wpE2S9XfBYTiIl+XFhQG2bjy4Pu1I+EAlCNUzRDYDdFwFYUKvXcIA==", + "dev": true + }, + "@ampproject/remapping": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.2.0.tgz", + "integrity": "sha512-qRmjj8nj9qmLTQXXmaR1cck3UXSRMPrbsLJAasZpF+t3riI71BXed5ebIOYwQntykeZuhjsdweEc9BxH5Jc26w==", + "dev": true, + "requires": { + "@jridgewell/gen-mapping": "^0.1.0", + "@jridgewell/trace-mapping": "^0.3.9" + } + }, + "@babel/code-frame": { + "version": "7.23.5", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.23.5.tgz", + "integrity": "sha512-CgH3s1a96LipHCmSUmYFPwY7MNx8C3avkq7i4Wl3cfa662ldtUe4VM1TPXX70pfmrlWTb6jLqTYrZyT2ZTJBgA==", + "dev": true, + "requires": { + "@babel/highlight": "^7.23.4", + "chalk": "^2.4.2" + } + }, + "@babel/compat-data": { + "version": "7.23.5", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.23.5.tgz", + "integrity": "sha512-uU27kfDRlhfKl+w1U6vp16IuvSLtjAxdArVXPa9BvLkrr7CYIsxH5adpHObeAGY/41+syctUWOZ140a2Rvkgjw==", + "dev": true + }, + "@babel/core": { + "version": "7.24.0", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.24.0.tgz", + "integrity": "sha512-fQfkg0Gjkza3nf0c7/w6Xf34BW4YvzNfACRLmmb7XRLa6XHdR+K9AlJlxneFfWYf6uhOzuzZVTjF/8KfndZANw==", + "dev": true, + "requires": { + "@ampproject/remapping": "^2.2.0", + "@babel/code-frame": "^7.23.5", + "@babel/generator": "^7.23.6", + "@babel/helper-compilation-targets": "^7.23.6", + "@babel/helper-module-transforms": "^7.23.3", + "@babel/helpers": "^7.24.0", + "@babel/parser": "^7.24.0", + "@babel/template": "^7.24.0", + "@babel/traverse": "^7.24.0", + "@babel/types": "^7.24.0", + "convert-source-map": "^2.0.0", + "debug": "^4.1.0", + "gensync": "^1.0.0-beta.2", + "json5": "^2.2.3", + "semver": "^6.3.1" + }, + "dependencies": { + "convert-source-map": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", + "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", + "dev": true + } + } + }, + "@babel/generator": { + "version": "7.23.6", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.23.6.tgz", + "integrity": "sha512-qrSfCYxYQB5owCmGLbl8XRpX1ytXlpueOb0N0UmQwA073KZxejgQTzAmJezxvpwQD9uGtK2shHdi55QT+MbjIw==", + "dev": true, + "requires": { + "@babel/types": "^7.23.6", + "@jridgewell/gen-mapping": "^0.3.2", + "@jridgewell/trace-mapping": "^0.3.17", + "jsesc": "^2.5.1" + }, + "dependencies": { + "@jridgewell/gen-mapping": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.2.tgz", + "integrity": "sha512-mh65xKQAzI6iBcFzwv28KVWSmCkdRBWoOh+bYQGW3+6OZvbbN3TqMGo5hqYxQniRcH9F2VZIoJCm4pa3BPDK/A==", + "dev": true, + "requires": { + "@jridgewell/set-array": "^1.0.1", + "@jridgewell/sourcemap-codec": "^1.4.10", + "@jridgewell/trace-mapping": "^0.3.9" + } + } + } + }, + "@babel/helper-compilation-targets": { + "version": "7.23.6", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.23.6.tgz", + "integrity": "sha512-9JB548GZoQVmzrFgp8o7KxdgkTGm6xs9DW0o/Pim72UDjzr5ObUQ6ZzYPqA+g9OTS2bBQoctLJrky0RDCAWRgQ==", + "dev": true, + "requires": { + "@babel/compat-data": "^7.23.5", + "@babel/helper-validator-option": "^7.23.5", + "browserslist": "^4.22.2", + "lru-cache": "^5.1.1", + "semver": "^6.3.1" + } + }, + "@babel/helper-environment-visitor": { + "version": "7.22.20", + "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.22.20.tgz", + "integrity": "sha512-zfedSIzFhat/gFhWfHtgWvlec0nqB9YEIVrpuwjruLlXfUSnA8cJB0miHKwqDnQ7d32aKo2xt88/xZptwxbfhA==", + "dev": true + }, + "@babel/helper-function-name": { + "version": "7.23.0", + "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.23.0.tgz", + "integrity": "sha512-OErEqsrxjZTJciZ4Oo+eoZqeW9UIiOcuYKRJA4ZAgV9myA+pOXhhmpfNCKjEH/auVfEYVFJ6y1Tc4r0eIApqiw==", + "dev": true, + "requires": { + "@babel/template": "^7.22.15", + "@babel/types": "^7.23.0" + } + }, + "@babel/helper-hoist-variables": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.22.5.tgz", + "integrity": "sha512-wGjk9QZVzvknA6yKIUURb8zY3grXCcOZt+/7Wcy8O2uctxhplmUPkOdlgoNhmdVee2c92JXbf1xpMtVNbfoxRw==", + "dev": true, + "requires": { + "@babel/types": "^7.22.5" + } + }, + "@babel/helper-module-imports": { + "version": "7.22.15", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.22.15.tgz", + "integrity": "sha512-0pYVBnDKZO2fnSPCrgM/6WMc7eS20Fbok+0r88fp+YtWVLZrp4CkafFGIp+W0VKw4a22sgebPT99y+FDNMdP4w==", + "dev": true, + "requires": { + "@babel/types": "^7.22.15" + } + }, + "@babel/helper-module-transforms": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.23.3.tgz", + "integrity": "sha512-7bBs4ED9OmswdfDzpz4MpWgSrV7FXlc3zIagvLFjS5H+Mk7Snr21vQ6QwrsoCGMfNC4e4LQPdoULEt4ykz0SRQ==", + "dev": true, + "requires": { + "@babel/helper-environment-visitor": "^7.22.20", + "@babel/helper-module-imports": "^7.22.15", + "@babel/helper-simple-access": "^7.22.5", + "@babel/helper-split-export-declaration": "^7.22.6", + "@babel/helper-validator-identifier": "^7.22.20" + } + }, + "@babel/helper-plugin-utils": { + "version": "7.20.2", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.20.2.tgz", + "integrity": "sha512-8RvlJG2mj4huQ4pZ+rU9lqKi9ZKiRmuvGuM2HlWmkmgOhbs6zEAw6IEiJ5cQqGbDzGZOhwuOQNtZMi/ENLjZoQ==", + "dev": true + }, + "@babel/helper-simple-access": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.22.5.tgz", + "integrity": "sha512-n0H99E/K+Bika3++WNL17POvo4rKWZ7lZEp1Q+fStVbUi8nxPQEBOlTmCOxW/0JsS56SKKQ+ojAe2pHKJHN35w==", + "dev": true, + "requires": { + "@babel/types": "^7.22.5" + } + }, + "@babel/helper-split-export-declaration": { + "version": "7.22.6", + "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.22.6.tgz", + "integrity": "sha512-AsUnxuLhRYsisFiaJwvp1QF+I3KjD5FOxut14q/GzovUe6orHLesW2C7d754kRm53h5gqrz6sFl6sxc4BVtE/g==", + "dev": true, + "requires": { + "@babel/types": "^7.22.5" + } + }, + "@babel/helper-string-parser": { + "version": "7.23.4", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.23.4.tgz", + "integrity": "sha512-803gmbQdqwdf4olxrX4AJyFBV/RTr3rSmOj0rKwesmzlfhYNDEs+/iOcznzpNWlJlIlTJC2QfPFcHB6DlzdVLQ==", + "dev": true + }, + "@babel/helper-validator-identifier": { + "version": "7.22.20", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.20.tgz", + "integrity": "sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A==", + "dev": true + }, + "@babel/helper-validator-option": { + "version": "7.23.5", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.23.5.tgz", + "integrity": "sha512-85ttAOMLsr53VgXkTbkx8oA6YTfT4q7/HzXSLEYmjcSTJPMPQtvq1BD79Byep5xMUYbGRzEpDsjUf3dyp54IKw==", + "dev": true + }, + "@babel/helpers": { + "version": "7.24.0", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.24.0.tgz", + "integrity": "sha512-ulDZdc0Aj5uLc5nETsa7EPx2L7rM0YJM8r7ck7U73AXi7qOV44IHHRAYZHY6iU1rr3C5N4NtTmMRUJP6kwCWeA==", + "dev": true, + "requires": { + "@babel/template": "^7.24.0", + "@babel/traverse": "^7.24.0", + "@babel/types": "^7.24.0" + } + }, + "@babel/highlight": { + "version": "7.23.4", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.23.4.tgz", + "integrity": "sha512-acGdbYSfp2WheJoJm/EBBBLh/ID8KDc64ISZ9DYtBmC8/Q204PZJLHyzeB5qMzJ5trcOkybd78M4x2KWsUq++A==", + "dev": true, + "requires": { + "@babel/helper-validator-identifier": "^7.22.20", + "chalk": "^2.4.2", + "js-tokens": "^4.0.0" + } + }, + "@babel/parser": { + "version": "7.24.0", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.24.0.tgz", + "integrity": "sha512-QuP/FxEAzMSjXygs8v4N9dvdXzEHN4W1oF3PxuWAtPo08UdM17u89RDMgjLn/mlc56iM0HlLmVkO/wgR+rDgHg==", + "dev": true + }, + "@babel/plugin-syntax-async-generators": { + "version": "7.8.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz", + "integrity": "sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.8.0" + } + }, + "@babel/plugin-syntax-bigint": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-bigint/-/plugin-syntax-bigint-7.8.3.tgz", + "integrity": "sha512-wnTnFlG+YxQm3vDxpGE57Pj0srRU4sHE/mDkt1qv2YJJSeUAec2ma4WLUnUPeKjyrfntVwe/N6dCXpU+zL3Npg==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.8.0" + } + }, + "@babel/plugin-syntax-class-properties": { + "version": "7.12.13", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.13.tgz", + "integrity": "sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.12.13" + } + }, + "@babel/plugin-syntax-import-meta": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-meta/-/plugin-syntax-import-meta-7.10.4.tgz", + "integrity": "sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.10.4" + } + }, + "@babel/plugin-syntax-json-strings": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz", + "integrity": "sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.8.0" + } + }, + "@babel/plugin-syntax-jsx": { + "version": "7.21.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-jsx/-/plugin-syntax-jsx-7.21.4.tgz", + "integrity": "sha512-5hewiLct5OKyh6PLKEYaFclcqtIgCb6bmELouxjF6up5q3Sov7rOayW4RwhbaBL0dit8rA80GNfY+UuDp2mBbQ==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.20.2" + } + }, + "@babel/plugin-syntax-logical-assignment-operators": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz", + "integrity": "sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.10.4" + } + }, + "@babel/plugin-syntax-nullish-coalescing-operator": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz", + "integrity": "sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.8.0" + } + }, + "@babel/plugin-syntax-numeric-separator": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.10.4.tgz", + "integrity": "sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.10.4" + } + }, + "@babel/plugin-syntax-object-rest-spread": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz", + "integrity": "sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.8.0" + } + }, + "@babel/plugin-syntax-optional-catch-binding": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz", + "integrity": "sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.8.0" + } + }, + "@babel/plugin-syntax-optional-chaining": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz", + "integrity": "sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.8.0" + } + }, + "@babel/plugin-syntax-top-level-await": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.14.5.tgz", + "integrity": "sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.14.5" + } + }, + "@babel/plugin-syntax-typescript": { + "version": "7.21.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-typescript/-/plugin-syntax-typescript-7.21.4.tgz", + "integrity": "sha512-xz0D39NvhQn4t4RNsHmDnnsaQizIlUkdtYvLs8La1BlfjQ6JEwxkJGeqJMW2tAXx+q6H+WFuUTXNdYVpEya0YA==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.20.2" + } + }, + "@babel/template": { + "version": "7.24.0", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.24.0.tgz", + "integrity": "sha512-Bkf2q8lMB0AFpX0NFEqSbx1OkTHf0f+0j82mkw+ZpzBnkk7e9Ql0891vlfgi+kHwOk8tQjiQHpqh4LaSa0fKEA==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.23.5", + "@babel/parser": "^7.24.0", + "@babel/types": "^7.24.0" + } + }, + "@babel/traverse": { + "version": "7.24.0", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.24.0.tgz", + "integrity": "sha512-HfuJlI8qq3dEDmNU5ChzzpZRWq+oxCZQyMzIMEqLho+AQnhMnKQUzH6ydo3RBl/YjPCuk68Y6s0Gx0AeyULiWw==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.23.5", + "@babel/generator": "^7.23.6", + "@babel/helper-environment-visitor": "^7.22.20", + "@babel/helper-function-name": "^7.23.0", + "@babel/helper-hoist-variables": "^7.22.5", + "@babel/helper-split-export-declaration": "^7.22.6", + "@babel/parser": "^7.24.0", + "@babel/types": "^7.24.0", + "debug": "^4.3.1", + "globals": "^11.1.0" + } + }, + "@babel/types": { + "version": "7.24.0", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.24.0.tgz", + "integrity": "sha512-+j7a5c253RfKh8iABBhywc8NSfP5LURe7Uh4qpsh6jc+aLJguvmIUBdjSdEMQv2bENrCR5MfRdjGo7vzS/ob7w==", + "dev": true, + "requires": { + "@babel/helper-string-parser": "^7.23.4", + "@babel/helper-validator-identifier": "^7.22.20", + "to-fast-properties": "^2.0.0" + } + }, + "@bcoe/v8-coverage": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/@bcoe/v8-coverage/-/v8-coverage-0.2.3.tgz", + "integrity": "sha512-0hYQ8SB4Db5zvZB4axdMHGwEaQjkZzFjQiN9LVYvIFB2nSUHW9tYpxWriPrWDASIxiaXax83REcLxuSdnGPZtw==", + "dev": true + }, + "@cspotcode/source-map-support": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz", + "integrity": "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==", + "dev": true, + "requires": { + "@jridgewell/trace-mapping": "0.3.9" + }, + "dependencies": { + "@jridgewell/trace-mapping": { + "version": "0.3.9", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz", + "integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==", + "dev": true, + "requires": { + "@jridgewell/resolve-uri": "^3.0.3", + "@jridgewell/sourcemap-codec": "^1.4.10" + } + } + } + }, + "@eslint-community/eslint-utils": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz", + "integrity": "sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==", + "dev": true, + "requires": { + "eslint-visitor-keys": "^3.3.0" + } + }, + "@eslint-community/regexpp": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.5.0.tgz", + "integrity": "sha512-vITaYzIcNmjn5tF5uxcZ/ft7/RXGrMUIS9HalWckEOF6ESiwXKoMzAQf2UW0aVd6rnOeExTJVd5hmWXucBKGXQ==", + "dev": true + }, + "@eslint/eslintrc": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.0.2.tgz", + "integrity": "sha512-3W4f5tDUra+pA+FzgugqL2pRimUTDJWKr7BINqOpkZrC0uYI0NIc0/JFgBROCU07HR6GieA5m3/rsPIhDmCXTQ==", + "dev": true, + "requires": { + "ajv": "^6.12.4", + "debug": "^4.3.2", + "espree": "^9.5.1", + "globals": "^13.19.0", + "ignore": "^5.2.0", + "import-fresh": "^3.2.1", + "js-yaml": "^4.1.0", + "minimatch": "^3.1.2", + "strip-json-comments": "^3.1.1" + }, + "dependencies": { + "globals": { + "version": "13.20.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.20.0.tgz", + "integrity": "sha512-Qg5QtVkCy/kv3FUSlu4ukeZDVf9ee0iXLAUYX13gbR17bnejFTzr4iS9bY7kwCf1NztRNm1t91fjOiyx4CSwPQ==", + "dev": true, + "requires": { + "type-fest": "^0.20.2" + } + }, + "type-fest": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", + "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", + "dev": true + } + } + }, + "@eslint/js": { + "version": "8.37.0", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.37.0.tgz", + "integrity": "sha512-x5vzdtOOGgFVDCUs81QRB2+liax8rFg3+7hqM+QhBG0/G3F1ZsoYl97UrqgHgQ9KKT7G6c4V+aTUCgu/n22v1A==", + "dev": true + }, + "@humanwhocodes/config-array": { + "version": "0.11.8", + "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.8.tgz", + "integrity": "sha512-UybHIJzJnR5Qc/MsD9Kr+RpO2h+/P1GhOwdiLPXK5TWk5sgTdu88bTD9UP+CKbPPh5Rni1u0GjAdYQLemG8g+g==", + "dev": true, + "requires": { + "@humanwhocodes/object-schema": "^1.2.1", + "debug": "^4.1.1", + "minimatch": "^3.0.5" + } + }, + "@humanwhocodes/module-importer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", + "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", + "dev": true + }, + "@humanwhocodes/object-schema": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-1.2.1.tgz", + "integrity": "sha512-ZnQMnLV4e7hDlUvw8H+U8ASL02SS2Gn6+9Ac3wGGLIe7+je2AeAOxPY+izIPJDfFDb7eDjev0Us8MO1iFRN8hA==", + "dev": true + }, + "@istanbuljs/load-nyc-config": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz", + "integrity": "sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ==", + "dev": true, + "requires": { + "camelcase": "^5.3.1", + "find-up": "^4.1.0", + "get-package-type": "^0.1.0", + "js-yaml": "^3.13.1", + "resolve-from": "^5.0.0" + }, + "dependencies": { + "argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "dev": true, + "requires": { + "sprintf-js": "~1.0.2" + } + }, + "find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "dev": true, + "requires": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + } + }, + "js-yaml": { + "version": "3.14.1", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.1.tgz", + "integrity": "sha512-okMH7OXXJ7YrN9Ok3/SXrnu4iX9yOk+25nqX4imS2npuvTYDmo/QEZoqwZkYaIDk3jVvBOTOIEgEhaLOynBS9g==", + "dev": true, + "requires": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + } + }, + "locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "dev": true, + "requires": { + "p-locate": "^4.1.0" + } + }, + "p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "dev": true, + "requires": { + "p-try": "^2.0.0" + } + }, + "p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "dev": true, + "requires": { + "p-limit": "^2.2.0" + } + }, + "resolve-from": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", + "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", + "dev": true + } + } + }, + "@istanbuljs/schema": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.3.tgz", + "integrity": "sha512-ZXRY4jNvVgSVQ8DL3LTcakaAtXwTVUxE81hslsyD2AtoXW/wVob10HkOJ1X/pAlcI7D+2YoZKg5do8G/w6RYgA==", + "dev": true + }, + "@jest/console": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/@jest/console/-/console-29.5.0.tgz", + "integrity": "sha512-NEpkObxPwyw/XxZVLPmAGKE89IQRp4puc6IQRPru6JKd1M3fW9v1xM1AnzIJE65hbCkzQAdnL8P47e9hzhiYLQ==", + "dev": true, + "requires": { + "@jest/types": "^29.5.0", + "@types/node": "*", + "chalk": "^4.0.0", + "jest-message-util": "^29.5.0", + "jest-util": "^29.5.0", + "slash": "^3.0.0" + }, + "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, + "@jest/core": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/@jest/core/-/core-29.5.0.tgz", + "integrity": "sha512-28UzQc7ulUrOQw1IsN/kv1QES3q2kkbl/wGslyhAclqZ/8cMdB5M68BffkIdSJgKBUt50d3hbwJ92XESlE7LiQ==", + "dev": true, + "requires": { + "@jest/console": "^29.5.0", + "@jest/reporters": "^29.5.0", + "@jest/test-result": "^29.5.0", + "@jest/transform": "^29.5.0", + "@jest/types": "^29.5.0", + "@types/node": "*", + "ansi-escapes": "^4.2.1", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "exit": "^0.1.2", + "graceful-fs": "^4.2.9", + "jest-changed-files": "^29.5.0", + "jest-config": "^29.5.0", + "jest-haste-map": "^29.5.0", + "jest-message-util": "^29.5.0", + "jest-regex-util": "^29.4.3", + "jest-resolve": "^29.5.0", + "jest-resolve-dependencies": "^29.5.0", + "jest-runner": "^29.5.0", + "jest-runtime": "^29.5.0", + "jest-snapshot": "^29.5.0", + "jest-util": "^29.5.0", + "jest-validate": "^29.5.0", + "jest-watcher": "^29.5.0", + "micromatch": "^4.0.4", + "pretty-format": "^29.5.0", + "slash": "^3.0.0", + "strip-ansi": "^6.0.0" + }, + "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, + "@jest/environment": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/@jest/environment/-/environment-29.5.0.tgz", + "integrity": "sha512-5FXw2+wD29YU1d4I2htpRX7jYnAyTRjP2CsXQdo9SAM8g3ifxWPSV0HnClSn71xwctr0U3oZIIH+dtbfmnbXVQ==", + "dev": true, + "requires": { + "@jest/fake-timers": "^29.5.0", + "@jest/types": "^29.5.0", + "@types/node": "*", + "jest-mock": "^29.5.0" + } + }, + "@jest/expect": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/@jest/expect/-/expect-29.5.0.tgz", + "integrity": "sha512-PueDR2HGihN3ciUNGr4uelropW7rqUfTiOn+8u0leg/42UhblPxHkfoh0Ruu3I9Y1962P3u2DY4+h7GVTSVU6g==", + "dev": true, + "requires": { + "expect": "^29.5.0", + "jest-snapshot": "^29.5.0" + } + }, + "@jest/expect-utils": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/@jest/expect-utils/-/expect-utils-29.5.0.tgz", + "integrity": "sha512-fmKzsidoXQT2KwnrwE0SQq3uj8Z763vzR8LnLBwC2qYWEFpjX8daRsk6rHUM1QvNlEW/UJXNXm59ztmJJWs2Mg==", + "dev": true, + "requires": { + "jest-get-type": "^29.4.3" + } + }, + "@jest/fake-timers": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/@jest/fake-timers/-/fake-timers-29.5.0.tgz", + "integrity": "sha512-9ARvuAAQcBwDAqOnglWq2zwNIRUDtk/SCkp/ToGEhFv5r86K21l+VEs0qNTaXtyiY0lEePl3kylijSYJQqdbDg==", + "dev": true, + "requires": { + "@jest/types": "^29.5.0", + "@sinonjs/fake-timers": "^10.0.2", + "@types/node": "*", + "jest-message-util": "^29.5.0", + "jest-mock": "^29.5.0", + "jest-util": "^29.5.0" + } + }, + "@jest/globals": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/@jest/globals/-/globals-29.5.0.tgz", + "integrity": "sha512-S02y0qMWGihdzNbUiqSAiKSpSozSuHX5UYc7QbnHP+D9Lyw8DgGGCinrN9uSuHPeKgSSzvPom2q1nAtBvUsvPQ==", + "dev": true, + "requires": { + "@jest/environment": "^29.5.0", + "@jest/expect": "^29.5.0", + "@jest/types": "^29.5.0", + "jest-mock": "^29.5.0" + } + }, + "@jest/reporters": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/@jest/reporters/-/reporters-29.5.0.tgz", + "integrity": "sha512-D05STXqj/M8bP9hQNSICtPqz97u7ffGzZu+9XLucXhkOFBqKcXe04JLZOgIekOxdb73MAoBUFnqvf7MCpKk5OA==", + "dev": true, + "requires": { + "@bcoe/v8-coverage": "^0.2.3", + "@jest/console": "^29.5.0", + "@jest/test-result": "^29.5.0", + "@jest/transform": "^29.5.0", + "@jest/types": "^29.5.0", + "@jridgewell/trace-mapping": "^0.3.15", + "@types/node": "*", + "chalk": "^4.0.0", + "collect-v8-coverage": "^1.0.0", + "exit": "^0.1.2", + "glob": "^7.1.3", + "graceful-fs": "^4.2.9", + "istanbul-lib-coverage": "^3.0.0", + "istanbul-lib-instrument": "^5.1.0", + "istanbul-lib-report": "^3.0.0", + "istanbul-lib-source-maps": "^4.0.0", + "istanbul-reports": "^3.1.3", + "jest-message-util": "^29.5.0", + "jest-util": "^29.5.0", + "jest-worker": "^29.5.0", + "slash": "^3.0.0", + "string-length": "^4.0.1", + "strip-ansi": "^6.0.0", + "v8-to-istanbul": "^9.0.1" + }, + "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, + "@jest/schemas": { + "version": "29.4.3", + "resolved": "https://registry.npmjs.org/@jest/schemas/-/schemas-29.4.3.tgz", + "integrity": "sha512-VLYKXQmtmuEz6IxJsrZwzG9NvtkQsWNnWMsKxqWNu3+CnfzJQhp0WDDKWLVV9hLKr0l3SLLFRqcYHjhtyuDVxg==", + "dev": true, + "requires": { + "@sinclair/typebox": "^0.25.16" + } + }, + "@jest/source-map": { + "version": "29.4.3", + "resolved": "https://registry.npmjs.org/@jest/source-map/-/source-map-29.4.3.tgz", + "integrity": "sha512-qyt/mb6rLyd9j1jUts4EQncvS6Yy3PM9HghnNv86QBlV+zdL2inCdK1tuVlL+J+lpiw2BI67qXOrX3UurBqQ1w==", + "dev": true, + "requires": { + "@jridgewell/trace-mapping": "^0.3.15", + "callsites": "^3.0.0", + "graceful-fs": "^4.2.9" + } + }, + "@jest/test-result": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/@jest/test-result/-/test-result-29.5.0.tgz", + "integrity": "sha512-fGl4rfitnbfLsrfx1uUpDEESS7zM8JdgZgOCQuxQvL1Sn/I6ijeAVQWGfXI9zb1i9Mzo495cIpVZhA0yr60PkQ==", + "dev": true, + "requires": { + "@jest/console": "^29.5.0", + "@jest/types": "^29.5.0", + "@types/istanbul-lib-coverage": "^2.0.0", + "collect-v8-coverage": "^1.0.0" + } + }, + "@jest/test-sequencer": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/@jest/test-sequencer/-/test-sequencer-29.5.0.tgz", + "integrity": "sha512-yPafQEcKjkSfDXyvtgiV4pevSeyuA6MQr6ZIdVkWJly9vkqjnFfcfhRQqpD5whjoU8EORki752xQmjaqoFjzMQ==", + "dev": true, + "requires": { + "@jest/test-result": "^29.5.0", + "graceful-fs": "^4.2.9", + "jest-haste-map": "^29.5.0", + "slash": "^3.0.0" + } + }, + "@jest/transform": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/@jest/transform/-/transform-29.5.0.tgz", + "integrity": "sha512-8vbeZWqLJOvHaDfeMuoHITGKSz5qWc9u04lnWrQE3VyuSw604PzQM824ZeX9XSjUCeDiE3GuxZe5UKa8J61NQw==", + "dev": true, + "requires": { + "@babel/core": "^7.11.6", + "@jest/types": "^29.5.0", + "@jridgewell/trace-mapping": "^0.3.15", + "babel-plugin-istanbul": "^6.1.1", + "chalk": "^4.0.0", + "convert-source-map": "^2.0.0", + "fast-json-stable-stringify": "^2.1.0", + "graceful-fs": "^4.2.9", + "jest-haste-map": "^29.5.0", + "jest-regex-util": "^29.4.3", + "jest-util": "^29.5.0", + "micromatch": "^4.0.4", + "pirates": "^4.0.4", + "slash": "^3.0.0", + "write-file-atomic": "^4.0.2" + }, + "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "convert-source-map": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", + "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==", + "dev": true + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, + "@jest/types": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/@jest/types/-/types-29.5.0.tgz", + "integrity": "sha512-qbu7kN6czmVRc3xWFQcAN03RAUamgppVUdXrvl1Wr3jlNF93o9mJbGcDWrwGB6ht44u7efB1qCFgVQmca24Uog==", + "dev": true, + "requires": { + "@jest/schemas": "^29.4.3", + "@types/istanbul-lib-coverage": "^2.0.0", + "@types/istanbul-reports": "^3.0.0", + "@types/node": "*", + "@types/yargs": "^17.0.8", + "chalk": "^4.0.0" + }, + "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, + "@jridgewell/gen-mapping": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.1.1.tgz", + "integrity": "sha512-sQXCasFk+U8lWYEe66WxRDOE9PjVz4vSM51fTu3Hw+ClTpUSQb718772vH3pyS5pShp6lvQM7SxgIDXXXmOX7w==", + "dev": true, + "requires": { + "@jridgewell/set-array": "^1.0.0", + "@jridgewell/sourcemap-codec": "^1.4.10" + } + }, + "@jridgewell/resolve-uri": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz", + "integrity": "sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==", + "dev": true + }, + "@jridgewell/set-array": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.1.2.tgz", + "integrity": "sha512-xnkseuNADM0gt2bs+BvhO0p78Mk762YnZdsuzFV018NoG1Sj1SCQvpSqa7XUaTam5vAGasABV9qXASMKnFMwMw==", + "dev": true + }, + "@jridgewell/sourcemap-codec": { + "version": "1.4.14", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz", + "integrity": "sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==", + "dev": true + }, + "@jridgewell/trace-mapping": { + "version": "0.3.17", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.17.tgz", + "integrity": "sha512-MCNzAp77qzKca9+W/+I0+sEpaUnZoeasnghNeVc41VZCEKaCH73Vq3BZZ/SzWIgrqE4H4ceI+p+b6C0mHf9T4g==", + "dev": true, + "requires": { + "@jridgewell/resolve-uri": "3.1.0", + "@jridgewell/sourcemap-codec": "1.4.14" + } + }, + "@mempool/electrum-client": { + "version": "1.1.9", + "resolved": "https://registry.npmjs.org/@mempool/electrum-client/-/electrum-client-1.1.9.tgz", + "integrity": "sha512-mlvPiCzUlaETpYW3i6V87A24jjMYgsebaXtUo3WQyyLnYUuxs0KiXQ2mnKh3h15j8Xg/hfxeGIi+5OC9u0nftQ==" + }, + "@noble/hashes": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/@noble/hashes/-/hashes-1.3.0.tgz", + "integrity": "sha512-ilHEACi9DwqJB0pw7kv+Apvh50jiiSyR/cQ3y4W7lOR5mhvn/50FLUfsnfJz0BDZtl/RR16kXvptiv6q1msYZg==" + }, + "@nodelib/fs.scandir": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", + "dev": true, + "requires": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" + } + }, + "@nodelib/fs.stat": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", + "dev": true + }, + "@nodelib/fs.walk": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", + "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", + "dev": true, + "requires": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + } + }, + "@redis/bloom": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@redis/bloom/-/bloom-1.2.0.tgz", + "integrity": "sha512-HG2DFjYKbpNmVXsa0keLHp/3leGJz1mjh09f2RLGGLQZzSHpkmZWuwJbAvo3QcRY8p80m5+ZdXZdYOSBLlp7Cg==", + "requires": {} + }, + "@redis/client": { + "version": "1.5.7", + "resolved": "https://registry.npmjs.org/@redis/client/-/client-1.5.7.tgz", + "integrity": "sha512-gaOBOuJPjK5fGtxSseaKgSvjiZXQCdLlGg9WYQst+/GRUjmXaiB5kVkeQMRtPc7Q2t93XZcJfBMSwzs/XS9UZw==", + "requires": { + "cluster-key-slot": "1.1.2", + "generic-pool": "3.9.0", + "yallist": "4.0.0" + }, + "dependencies": { + "yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" + } + } + }, + "@redis/graph": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@redis/graph/-/graph-1.1.0.tgz", + "integrity": "sha512-16yZWngxyXPd+MJxeSr0dqh2AIOi8j9yXKcKCwVaKDbH3HTuETpDVPcLujhFYVPtYrngSco31BUcSa9TH31Gqg==", + "requires": {} + }, + "@redis/json": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@redis/json/-/json-1.0.4.tgz", + "integrity": "sha512-LUZE2Gdrhg0Rx7AN+cZkb1e6HjoSKaeeW8rYnt89Tly13GBI5eP4CwDVr+MY8BAYfCg4/N15OUrtLoona9uSgw==", + "requires": {} + }, + "@redis/search": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/@redis/search/-/search-1.1.2.tgz", + "integrity": "sha512-/cMfstG/fOh/SsE+4/BQGeuH/JJloeWuH+qJzM8dbxuWvdWibWAOAHHCZTMPhV3xIlH4/cUEIA8OV5QnYpaVoA==", + "requires": {} + }, + "@redis/time-series": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/@redis/time-series/-/time-series-1.0.4.tgz", + "integrity": "sha512-ThUIgo2U/g7cCuZavucQTQzA9g9JbDDY2f64u3AbAoz/8vE2lt2U37LamDUVChhaDA3IRT9R6VvJwqnUfTJzng==", + "requires": {} + }, + "@sinclair/typebox": { + "version": "0.25.24", + "resolved": "https://registry.npmjs.org/@sinclair/typebox/-/typebox-0.25.24.tgz", + "integrity": "sha512-XJfwUVUKDHF5ugKwIcxEgc9k8b7HbznCp6eUfWgu710hMPNIO4aw4/zB5RogDQz8nd6gyCDpU9O/m6qYEWY6yQ==", + "dev": true + }, + "@sinonjs/commons": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-2.0.0.tgz", + "integrity": "sha512-uLa0j859mMrg2slwQYdO/AkrOfmH+X6LTVmNTS9CqexuE2IvVORIkSpJLqePAbEnKJ77aMmCwr1NUZ57120Xcg==", + "dev": true, + "requires": { + "type-detect": "4.0.8" + } + }, + "@sinonjs/fake-timers": { + "version": "10.0.2", + "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-10.0.2.tgz", + "integrity": "sha512-SwUDyjWnah1AaNl7kxsa7cfLhlTYoiyhDAIgyh+El30YvXs/o7OLXpYH88Zdhyx9JExKrmHDJ+10bwIcY80Jmw==", + "dev": true, + "requires": { + "@sinonjs/commons": "^2.0.0" + } + }, + "@tsconfig/node10": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.9.tgz", + "integrity": "sha512-jNsYVVxU8v5g43Erja32laIDHXeoNvFEpX33OK4d6hljo3jDhCBDhx5dhCCTMWUojscpAagGiRkBKxpdl9fxqA==", + "dev": true + }, + "@tsconfig/node12": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.11.tgz", + "integrity": "sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==", + "dev": true + }, + "@tsconfig/node14": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.3.tgz", + "integrity": "sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==", + "dev": true + }, + "@tsconfig/node16": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.3.tgz", + "integrity": "sha512-yOlFc+7UtL/89t2ZhjPvvB/DeAr3r+Dq58IgzsFkOAvVC6NMJXmCGjbptdXdR9qsX7pKcTL+s87FtYREi2dEEQ==", + "dev": true + }, + "@types/babel__core": { + "version": "7.20.0", + "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.0.tgz", + "integrity": "sha512-+n8dL/9GWblDO0iU6eZAwEIJVr5DWigtle+Q6HLOrh/pdbXOhOtqzq8VPPE2zvNJzSKY4vH/z3iT3tn0A3ypiQ==", + "dev": true, + "requires": { + "@babel/parser": "^7.20.7", + "@babel/types": "^7.20.7", + "@types/babel__generator": "*", + "@types/babel__template": "*", + "@types/babel__traverse": "*" + } + }, + "@types/babel__generator": { + "version": "7.6.4", + "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.6.4.tgz", + "integrity": "sha512-tFkciB9j2K755yrTALxD44McOrk+gfpIpvC3sxHjRawj6PfnQxrse4Clq5y/Rq+G3mrBurMax/lG8Qn2t9mSsg==", + "dev": true, + "requires": { + "@babel/types": "^7.0.0" + } + }, + "@types/babel__template": { + "version": "7.4.1", + "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.1.tgz", + "integrity": "sha512-azBFKemX6kMg5Io+/rdGT0dkGreboUVR0Cdm3fz9QJWpaQGJRQXl7C+6hOTCZcMll7KFyEQpgbYI2lHdsS4U7g==", + "dev": true, + "requires": { + "@babel/parser": "^7.1.0", + "@babel/types": "^7.0.0" + } + }, + "@types/babel__traverse": { + "version": "7.18.3", + "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.18.3.tgz", + "integrity": "sha512-1kbcJ40lLB7MHsj39U4Sh1uTd2E7rLEa79kmDpI6cy+XiXsteB3POdQomoq4FxszMrO3ZYchkhYJw7A2862b3w==", + "dev": true, + "requires": { + "@babel/types": "^7.3.0" + } + }, + "@types/body-parser": { + "version": "1.19.2", + "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.2.tgz", + "integrity": "sha512-ALYone6pm6QmwZoAgeyNksccT9Q4AWZQ6PvfwR37GT6r6FWUPguq6sUmNGSMV2Wr761oQoBxwGGa6DR5o1DC9g==", + "dev": true, + "requires": { + "@types/connect": "*", + "@types/node": "*" + } + }, + "@types/compression": { + "version": "1.7.2", + "resolved": "https://registry.npmjs.org/@types/compression/-/compression-1.7.2.tgz", + "integrity": "sha512-lwEL4M/uAGWngWFLSG87ZDr2kLrbuR8p7X+QZB1OQlT+qkHsCPDVFnHPyXf4Vyl4yDDorNY+mAhosxkCvppatg==", + "dev": true, + "requires": { + "@types/express": "*" + } + }, + "@types/connect": { + "version": "3.4.35", + "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.35.tgz", + "integrity": "sha512-cdeYyv4KWoEgpBISTxWvqYsVy444DOqehiF3fM3ne10AmJ62RSyNkUnxMJXHQWRQQX2eR94m5y1IZyDwBjV9FQ==", + "dev": true, + "requires": { + "@types/node": "*" + } + }, + "@types/crypto-js": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/@types/crypto-js/-/crypto-js-4.1.1.tgz", + "integrity": "sha512-BG7fQKZ689HIoc5h+6D2Dgq1fABRa0RbBWKBd9SP/MVRVXROflpm5fhwyATX5duFmbStzyzyycPB8qUYKDH3NA==", + "dev": true + }, + "@types/express": { + "version": "4.17.17", + "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.17.tgz", + "integrity": "sha512-Q4FmmuLGBG58btUnfS1c1r/NQdlp3DMfGDGig8WhfpA2YRUtEkxAjkZb0yvplJGYdF1fsQ81iMDcH24sSCNC/Q==", + "dev": true, + "requires": { + "@types/body-parser": "*", + "@types/express-serve-static-core": "^4.17.33", + "@types/qs": "*", + "@types/serve-static": "*" + } + }, + "@types/express-serve-static-core": { + "version": "4.17.33", + "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.17.33.tgz", + "integrity": "sha512-TPBqmR/HRYI3eC2E5hmiivIzv+bidAfXofM+sbonAGvyDhySGw9/PQZFt2BLOrjUUR++4eJVpx6KnLQK1Fk9tA==", + "dev": true, + "requires": { + "@types/node": "*", + "@types/qs": "*", + "@types/range-parser": "*" + } + }, + "@types/graceful-fs": { + "version": "4.1.6", + "resolved": "https://registry.npmjs.org/@types/graceful-fs/-/graceful-fs-4.1.6.tgz", + "integrity": "sha512-Sig0SNORX9fdW+bQuTEovKj3uHcUL6LQKbCrrqb1X7J6/ReAbhCXRAhc+SMejhLELFj2QcyuxmUooZ4bt5ReSw==", + "dev": true, + "requires": { + "@types/node": "*" + } + }, + "@types/istanbul-lib-coverage": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/@types/istanbul-lib-coverage/-/istanbul-lib-coverage-2.0.4.tgz", + "integrity": "sha512-z/QT1XN4K4KYuslS23k62yDIDLwLFkzxOuMplDtObz0+y7VqJCaO2o+SPwHCvLFZh7xazvvoor2tA/hPz9ee7g==", + "dev": true + }, + "@types/istanbul-lib-report": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@types/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz", + "integrity": "sha512-plGgXAPfVKFoYfa9NpYDAkseG+g6Jr294RqeqcqDixSbU34MZVJRi/P+7Y8GDpzkEwLaGZZOpKIEmeVZNtKsrg==", + "dev": true, + "requires": { + "@types/istanbul-lib-coverage": "*" + } + }, + "@types/istanbul-reports": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@types/istanbul-reports/-/istanbul-reports-3.0.1.tgz", + "integrity": "sha512-c3mAZEuK0lvBp8tmuL74XRKn1+y2dcwOUpH7x4WrF6gk1GIgiluDRgMYQtw2OFcBvAJWlt6ASU3tSqxp0Uu0Aw==", + "dev": true, + "requires": { + "@types/istanbul-lib-report": "*" + } + }, + "@types/jest": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/@types/jest/-/jest-29.5.0.tgz", + "integrity": "sha512-3Emr5VOl/aoBwnWcH/EFQvlSAmjV+XtV9GGu5mwdYew5vhQh0IUZx/60x0TzHDu09Bi7HMx10t/namdJw5QIcg==", + "dev": true, + "requires": { + "expect": "^29.0.0", + "pretty-format": "^29.0.0" + } + }, + "@types/json-schema": { + "version": "7.0.11", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.11.tgz", + "integrity": "sha512-wOuvG1SN4Us4rez+tylwwwCV1psiNVOkJeM3AUWUNWg/jDQY2+HE/444y5gc+jBmRqASOm2Oeh5c1axHobwRKQ==", + "dev": true + }, + "@types/mime": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@types/mime/-/mime-3.0.1.tgz", + "integrity": "sha512-Y4XFY5VJAuw0FgAqPNd6NNoV44jbq9Bz2L7Rh/J6jLTiHBSBJa9fxqQIvkIld4GsoDOcCbvzOUAbLPsSKKg+uA==", + "dev": true + }, + "@types/node": { + "version": "18.15.11", + "resolved": "https://registry.npmjs.org/@types/node/-/node-18.15.11.tgz", + "integrity": "sha512-E5Kwq2n4SbMzQOn6wnmBjuK9ouqlURrcZDVfbo9ftDDTFt3nk7ZKK4GMOzoYgnpQJKcxwQw+lGaBvvlMo0qN/Q==" + }, + "@types/prettier": { + "version": "2.7.2", + "resolved": "https://registry.npmjs.org/@types/prettier/-/prettier-2.7.2.tgz", + "integrity": "sha512-KufADq8uQqo1pYKVIYzfKbJfBAc0sOeXqGbFaSpv8MRmC/zXgowNZmFcbngndGk922QDmOASEXUZCaY48gs4cg==", + "dev": true + }, + "@types/qs": { + "version": "6.9.7", + "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.7.tgz", + "integrity": "sha512-FGa1F62FT09qcrueBA6qYTrJPVDzah9a+493+o2PCXsesWHIn27G98TsSMs3WPNbZIEj4+VJf6saSFpvD+3Zsw==", + "dev": true + }, + "@types/range-parser": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.4.tgz", + "integrity": "sha512-EEhsLsD6UsDM1yFhAvy0Cjr6VwmpMWqFBCb9w07wVugF7w9nfajxLuVmngTIpgS6svCnm6Vaw+MZhoDCKnOfsw==", + "dev": true + }, + "@types/semver": { + "version": "7.3.13", + "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.3.13.tgz", + "integrity": "sha512-21cFJr9z3g5dW8B0CVI9g2O9beqaThGQ6ZFBqHfwhzLDKUxaqTIy3vnfah/UPkfOiF2pLq+tGz+W8RyCskuslw==", + "dev": true + }, + "@types/serve-static": { + "version": "1.15.1", + "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.15.1.tgz", + "integrity": "sha512-NUo5XNiAdULrJENtJXZZ3fHtfMolzZwczzBbnAeBbqBwG+LaG6YaJtuwzwGSQZ2wsCrxjEhNNjAkKigy3n8teQ==", + "dev": true, + "requires": { + "@types/mime": "*", + "@types/node": "*" + } + }, + "@types/stack-utils": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-2.0.1.tgz", + "integrity": "sha512-Hl219/BT5fLAaz6NDkSuhzasy49dwQS/DSdu4MdggFB8zcXv7vflBI3xp7FEmkmdDkBUI2bPUNeMttp2knYdxw==", + "dev": true + }, + "@types/ws": { + "version": "8.5.10", + "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.5.10.tgz", + "integrity": "sha512-vmQSUcfalpIq0R9q7uTo2lXs6eGIpt9wtnLdMv9LVpIjCA/+ufZRozlVoVelIYixx1ugCBKDhn89vnsEGOCx9A==", + "dev": true, + "requires": { + "@types/node": "*" + } + }, + "@types/yargs": { + "version": "17.0.24", + "resolved": "https://registry.npmjs.org/@types/yargs/-/yargs-17.0.24.tgz", + "integrity": "sha512-6i0aC7jV6QzQB8ne1joVZ0eSFIstHsCrobmOtghM11yGlH0j43FKL2UhWdELkyps0zuf7qVTUVCCR+tgSlyLLw==", + "dev": true, + "requires": { + "@types/yargs-parser": "*" + } + }, + "@types/yargs-parser": { + "version": "21.0.0", + "resolved": "https://registry.npmjs.org/@types/yargs-parser/-/yargs-parser-21.0.0.tgz", + "integrity": "sha512-iO9ZQHkZxHn4mSakYV0vFHAVDyEOIJQrV2uZ06HxEPcx+mt8swXoZHIbaaJ2crJYFfErySgktuTZ3BeLz+XmFA==", + "dev": true + }, + "@typescript-eslint/eslint-plugin": { + "version": "5.57.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-5.57.0.tgz", + "integrity": "sha512-itag0qpN6q2UMM6Xgk6xoHa0D0/P+M17THnr4SVgqn9Rgam5k/He33MA7/D7QoJcdMxHFyX7U9imaBonAX/6qA==", + "dev": true, + "requires": { + "@eslint-community/regexpp": "^4.4.0", + "@typescript-eslint/scope-manager": "5.57.0", + "@typescript-eslint/type-utils": "5.57.0", + "@typescript-eslint/utils": "5.57.0", + "debug": "^4.3.4", + "grapheme-splitter": "^1.0.4", + "ignore": "^5.2.0", + "natural-compare-lite": "^1.4.0", + "semver": "^7.3.7", + "tsutils": "^3.21.0" + }, + "dependencies": { + "lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dev": true, + "requires": { + "yallist": "^4.0.0" + } + }, + "semver": { + "version": "7.5.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", + "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", + "dev": true, + "requires": { + "lru-cache": "^6.0.0" + } + }, + "yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true + } + } + }, + "@typescript-eslint/parser": { + "version": "5.57.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-5.57.0.tgz", + "integrity": "sha512-orrduvpWYkgLCyAdNtR1QIWovcNZlEm6yL8nwH/eTxWLd8gsP+25pdLHYzL2QdkqrieaDwLpytHqycncv0woUQ==", + "dev": true, + "requires": { + "@typescript-eslint/scope-manager": "5.57.0", + "@typescript-eslint/types": "5.57.0", + "@typescript-eslint/typescript-estree": "5.57.0", + "debug": "^4.3.4" + } + }, + "@typescript-eslint/scope-manager": { + "version": "5.57.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-5.57.0.tgz", + "integrity": "sha512-NANBNOQvllPlizl9LatX8+MHi7bx7WGIWYjPHDmQe5Si/0YEYfxSljJpoTyTWFTgRy3X8gLYSE4xQ2U+aCozSw==", + "dev": true, + "requires": { + "@typescript-eslint/types": "5.57.0", + "@typescript-eslint/visitor-keys": "5.57.0" + } + }, + "@typescript-eslint/type-utils": { + "version": "5.57.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-5.57.0.tgz", + "integrity": "sha512-kxXoq9zOTbvqzLbdNKy1yFrxLC6GDJFE2Yuo3KqSwTmDOFjUGeWSakgoXT864WcK5/NAJkkONCiKb1ddsqhLXQ==", + "dev": true, + "requires": { + "@typescript-eslint/typescript-estree": "5.57.0", + "@typescript-eslint/utils": "5.57.0", + "debug": "^4.3.4", + "tsutils": "^3.21.0" + } + }, + "@typescript-eslint/types": { + "version": "5.57.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-5.57.0.tgz", + "integrity": "sha512-mxsod+aZRSyLT+jiqHw1KK6xrANm19/+VFALVFP5qa/aiJnlP38qpyaTd0fEKhWvQk6YeNZ5LGwI1pDpBRBhtQ==", + "dev": true + }, + "@typescript-eslint/typescript-estree": { + "version": "5.57.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-5.57.0.tgz", + "integrity": "sha512-LTzQ23TV82KpO8HPnWuxM2V7ieXW8O142I7hQTxWIHDcCEIjtkat6H96PFkYBQqGFLW/G/eVVOB9Z8rcvdY/Vw==", + "dev": true, + "requires": { + "@typescript-eslint/types": "5.57.0", + "@typescript-eslint/visitor-keys": "5.57.0", + "debug": "^4.3.4", + "globby": "^11.1.0", + "is-glob": "^4.0.3", + "semver": "^7.3.7", + "tsutils": "^3.21.0" + }, + "dependencies": { + "lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dev": true, + "requires": { + "yallist": "^4.0.0" + } + }, + "semver": { + "version": "7.5.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", + "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", + "dev": true, + "requires": { + "lru-cache": "^6.0.0" + } + }, + "yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true + } + } + }, + "@typescript-eslint/utils": { + "version": "5.57.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-5.57.0.tgz", + "integrity": "sha512-ps/4WohXV7C+LTSgAL5CApxvxbMkl9B9AUZRtnEFonpIxZDIT7wC1xfvuJONMidrkB9scs4zhtRyIwHh4+18kw==", + "dev": true, + "requires": { + "@eslint-community/eslint-utils": "^4.2.0", + "@types/json-schema": "^7.0.9", + "@types/semver": "^7.3.12", + "@typescript-eslint/scope-manager": "5.57.0", + "@typescript-eslint/types": "5.57.0", + "@typescript-eslint/typescript-estree": "5.57.0", + "eslint-scope": "^5.1.1", + "semver": "^7.3.7" + }, + "dependencies": { + "lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dev": true, + "requires": { + "yallist": "^4.0.0" + } + }, + "semver": { + "version": "7.5.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", + "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", + "dev": true, + "requires": { + "lru-cache": "^6.0.0" + } + }, + "yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true + } + } + }, + "@typescript-eslint/visitor-keys": { + "version": "5.57.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-5.57.0.tgz", + "integrity": "sha512-ery2g3k0hv5BLiKpPuwYt9KBkAp2ugT6VvyShXdLOkax895EC55sP0Tx5L0fZaQueiK3fBLvHVvEl3jFS5ia+g==", + "dev": true, + "requires": { + "@typescript-eslint/types": "5.57.0", + "eslint-visitor-keys": "^3.3.0" + } + }, + "accepts": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", + "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==", + "requires": { + "mime-types": "~2.1.34", + "negotiator": "0.6.3" + } + }, + "acorn": { + "version": "8.8.2", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.8.2.tgz", + "integrity": "sha512-xjIYgE8HBrkpd/sJqOGNspf8uHG+NOHGOw6a/Urj8taM2EXfdNAH2oFcPeIFfsv3+kz/mJrS5VuMqbNLjCa2vw==", + "dev": true + }, + "acorn-jsx": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", + "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", + "dev": true, + "requires": {} + }, + "acorn-walk": { + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.2.0.tgz", + "integrity": "sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA==", + "dev": true + }, + "agent-base": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-6.0.2.tgz", + "integrity": "sha512-RZNwNclF7+MS/8bDg70amg32dyeZGZxiDuQmZxKLAlQjr3jGyLx+4Kkk58UO7D2QdgFIQCovuSuZESne6RG6XQ==", + "requires": { + "debug": "4" + } + }, + "ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dev": true, + "requires": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + } + }, + "ansi-escapes": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", + "integrity": "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==", + "dev": true, + "requires": { + "type-fest": "^0.21.3" + } + }, + "ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "dev": true + }, + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "requires": { + "color-convert": "^1.9.0" + } + }, + "anymatch": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz", + "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==", + "dev": true, + "requires": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + } + }, + "arg": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", + "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==", + "dev": true + }, + "argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true + }, + "array-flatten": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", + "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==" + }, + "array-union": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", + "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", + "dev": true + }, + "asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==" + }, + "axios": { + "version": "1.7.2", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.7.2.tgz", + "integrity": "sha512-2A8QhOMrbomlDuiLeK9XibIBzuHeRcqqNOHp0Cyp5EoJ1IFDh+XZH3A6BkXtv0K4gFGCI0Y4BM7B1wOEi0Rmgw==", + "requires": { + "follow-redirects": "^1.15.6", + "form-data": "^4.0.0", + "proxy-from-env": "^1.1.0" + } + }, + "babel-jest": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/babel-jest/-/babel-jest-29.5.0.tgz", + "integrity": "sha512-mA4eCDh5mSo2EcA9xQjVTpmbbNk32Zb3Q3QFQsNhaK56Q+yoXowzFodLux30HRgyOho5rsQ6B0P9QpMkvvnJ0Q==", + "dev": true, + "requires": { + "@jest/transform": "^29.5.0", + "@types/babel__core": "^7.1.14", + "babel-plugin-istanbul": "^6.1.1", + "babel-preset-jest": "^29.5.0", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.9", + "slash": "^3.0.0" + }, + "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, + "babel-plugin-istanbul": { + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-6.1.1.tgz", + "integrity": "sha512-Y1IQok9821cC9onCx5otgFfRm7Lm+I+wwxOx738M/WLPZ9Q42m4IG5W0FNX8WLL2gYMZo3JkuXIH2DOpWM+qwA==", + "dev": true, + "requires": { + "@babel/helper-plugin-utils": "^7.0.0", + "@istanbuljs/load-nyc-config": "^1.0.0", + "@istanbuljs/schema": "^0.1.2", + "istanbul-lib-instrument": "^5.0.4", + "test-exclude": "^6.0.0" + } + }, + "babel-plugin-jest-hoist": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/babel-plugin-jest-hoist/-/babel-plugin-jest-hoist-29.5.0.tgz", + "integrity": "sha512-zSuuuAlTMT4mzLj2nPnUm6fsE6270vdOfnpbJ+RmruU75UhLFvL0N2NgI7xpeS7NaB6hGqmd5pVpGTDYvi4Q3w==", + "dev": true, + "requires": { + "@babel/template": "^7.3.3", + "@babel/types": "^7.3.3", + "@types/babel__core": "^7.1.14", + "@types/babel__traverse": "^7.0.6" + } + }, + "babel-preset-current-node-syntax": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/babel-preset-current-node-syntax/-/babel-preset-current-node-syntax-1.0.1.tgz", + "integrity": "sha512-M7LQ0bxarkxQoN+vz5aJPsLBn77n8QgTFmo8WK0/44auK2xlCXrYcUxHFxgU7qW5Yzw/CjmLRK2uJzaCd7LvqQ==", + "dev": true, + "requires": { + "@babel/plugin-syntax-async-generators": "^7.8.4", + "@babel/plugin-syntax-bigint": "^7.8.3", + "@babel/plugin-syntax-class-properties": "^7.8.3", + "@babel/plugin-syntax-import-meta": "^7.8.3", + "@babel/plugin-syntax-json-strings": "^7.8.3", + "@babel/plugin-syntax-logical-assignment-operators": "^7.8.3", + "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3", + "@babel/plugin-syntax-numeric-separator": "^7.8.3", + "@babel/plugin-syntax-object-rest-spread": "^7.8.3", + "@babel/plugin-syntax-optional-catch-binding": "^7.8.3", + "@babel/plugin-syntax-optional-chaining": "^7.8.3", + "@babel/plugin-syntax-top-level-await": "^7.8.3" + } + }, + "babel-preset-jest": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/babel-preset-jest/-/babel-preset-jest-29.5.0.tgz", + "integrity": "sha512-JOMloxOqdiBSxMAzjRaH023/vvcaSaec49zvg+2LmNsktC7ei39LTJGw02J+9uUtTZUq6xbLyJ4dxe9sSmIuAg==", + "dev": true, + "requires": { + "babel-plugin-jest-hoist": "^29.5.0", + "babel-preset-current-node-syntax": "^1.0.0" + } + }, + "balanced-match": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz", + "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==", + "dev": true + }, + "base-x": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/base-x/-/base-x-4.0.0.tgz", + "integrity": "sha512-FuwxlW4H5kh37X/oW59pwTzzTKRzfrrQwhmyspRM7swOEZcHtDZSCt45U6oKgtuFE+WYPblePMVIPR4RZrh/hw==" + }, + "bech32": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/bech32/-/bech32-2.0.0.tgz", + "integrity": "sha512-LcknSilhIGatDAsY1ak2I8VtGaHNhgMSYVxFrGLXv+xLHytaKZKcaUJJUE7qmBr7h33o5YQwP55pMI0xmkpJwg==" + }, + "bip174": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/bip174/-/bip174-2.1.0.tgz", + "integrity": "sha512-lkc0XyiX9E9KiVAS1ZiOqK1xfiwvf4FXDDdkDq5crcDzOq+xGytY+14qCsqz7kCiy8rpN1CRNfacRhf9G3JNSA==" + }, + "bitcoinjs-lib": { + "version": "6.1.3", + "resolved": "https://registry.npmjs.org/bitcoinjs-lib/-/bitcoinjs-lib-6.1.3.tgz", + "integrity": "sha512-TYXs/Qf+GNk2nnsB9HrXWqzFuEgCg0Gx+v3UW3B8VuceFHXVvhT+7hRnTSvwkX0i8rz2rtujeU6gFaDcFqYFDw==", + "requires": { + "@noble/hashes": "^1.2.0", + "bech32": "^2.0.0", + "bip174": "^2.1.0", + "bs58check": "^3.0.1", + "typeforce": "^1.11.3", + "varuint-bitcoin": "^1.1.2" + } + }, + "body-parser": { + "version": "1.20.2", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.2.tgz", + "integrity": "sha512-ml9pReCu3M61kGlqoTm2umSXTlRTuGTx0bfYj+uIUKKYycG5NtSbeetV3faSU6R7ajOPw0g/J1PvK4qNy7s5bA==", + "requires": { + "bytes": "3.1.2", + "content-type": "~1.0.5", + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "1.2.0", + "http-errors": "2.0.0", + "iconv-lite": "0.4.24", + "on-finished": "2.4.1", + "qs": "6.11.0", + "raw-body": "2.5.2", + "type-is": "~1.6.18", + "unpipe": "1.0.0" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "requires": { + "ms": "2.0.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" + } + } + }, + "brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "braces": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.2.tgz", + "integrity": "sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A==", + "dev": true, + "requires": { + "fill-range": "^7.0.1" + } + }, + "browserslist": { + "version": "4.23.0", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.23.0.tgz", + "integrity": "sha512-QW8HiM1shhT2GuzkvklfjcKDiWFXHOeFCIA/huJPwHsslwcydgk7X+z2zXpEijP98UCY7HbubZt5J2Zgvf0CaQ==", + "dev": true, + "requires": { + "caniuse-lite": "^1.0.30001587", + "electron-to-chromium": "^1.4.668", + "node-releases": "^2.0.14", + "update-browserslist-db": "^1.0.13" + } + }, + "bs-logger": { + "version": "0.2.6", + "resolved": "https://registry.npmjs.org/bs-logger/-/bs-logger-0.2.6.tgz", + "integrity": "sha512-pd8DCoxmbgc7hyPKOvxtqNcjYoOsABPQdcCUjGp3d42VR2CX1ORhk2A87oqqu5R1kk+76nsxZupkmyd+MVtCog==", + "dev": true, + "requires": { + "fast-json-stable-stringify": "2.x" + } + }, + "bs58": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/bs58/-/bs58-5.0.0.tgz", + "integrity": "sha512-r+ihvQJvahgYT50JD05dyJNKlmmSlMoOGwn1lCcEzanPglg7TxYjioQUYehQ9mAR/+hOSd2jRc/Z2y5UxBymvQ==", + "requires": { + "base-x": "^4.0.0" + } + }, + "bs58check": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/bs58check/-/bs58check-3.0.1.tgz", + "integrity": "sha512-hjuuJvoWEybo7Hn/0xOrczQKKEKD63WguEjlhLExYs2wUBcebDC1jDNK17eEAD2lYfw82d5ASC1d7K3SWszjaQ==", + "requires": { + "@noble/hashes": "^1.2.0", + "bs58": "^5.0.0" + } + }, + "bser": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/bser/-/bser-2.1.1.tgz", + "integrity": "sha512-gQxTNE/GAfIIrmHLUE3oJyp5FO6HRBfhjnw4/wMmA63ZGDJnWBmgY/lyQBpnDUkGmAhbSe39tx2d/iTOAfglwQ==", + "dev": true, + "requires": { + "node-int64": "^0.4.0" + } + }, + "buffer-from": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz", + "integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==", + "dev": true + }, + "bytes": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", + "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==" + }, + "call-bind": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.7.tgz", + "integrity": "sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w==", + "requires": { + "es-define-property": "^1.0.0", + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.4", + "set-function-length": "^1.2.1" + } + }, + "callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "dev": true + }, + "camelcase": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", + "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", + "dev": true + }, + "caniuse-lite": { + "version": "1.0.30001591", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001591.tgz", + "integrity": "sha512-PCzRMei/vXjJyL5mJtzNiUCKP59dm8Apqc3PH8gJkMnMXZGox93RbE76jHsmLwmIo6/3nsYIpJtx0O7u5PqFuQ==", + "dev": true + }, + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + }, + "char-regex": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/char-regex/-/char-regex-1.0.2.tgz", + "integrity": "sha512-kWWXztvZ5SBQV+eRgKFeh8q5sLuZY2+8WUIzlxWVTg+oGwY14qylx1KbKzHd8P6ZYkAg0xyIDU9JMHhyJMZ1jw==", + "dev": true + }, + "ci-info": { + "version": "3.8.0", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.8.0.tgz", + "integrity": "sha512-eXTggHWSooYhq49F2opQhuHWgzucfF2YgODK4e1566GQs5BIfP30B0oenwBJHfWxAs2fyPB1s7Mg949zLf61Yw==", + "dev": true + }, + "cjs-module-lexer": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/cjs-module-lexer/-/cjs-module-lexer-1.2.2.tgz", + "integrity": "sha512-cOU9usZw8/dXIXKtwa8pM0OTJQuJkxMN6w30csNRUerHfeQ5R6U3kkU/FtJeIf3M202OHfY2U8ccInBG7/xogA==", + "dev": true + }, + "cliui": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", + "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", + "dev": true, + "requires": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.1", + "wrap-ansi": "^7.0.0" + } + }, + "cluster-key-slot": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/cluster-key-slot/-/cluster-key-slot-1.1.2.tgz", + "integrity": "sha512-RMr0FhtfXemyinomL4hrWcYJxmX6deFdCxpJzhDttxgO1+bcCnkk+9drydLVDmAMG7NE6aN/fl4F7ucU/90gAA==" + }, + "co": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/co/-/co-4.6.0.tgz", + "integrity": "sha512-QVb0dM5HvG+uaxitm8wONl7jltx8dqhfU33DcqtOZcLSVIKSDDLDi7+0LbAKiyI8hD9u42m2YxXSkMGWThaecQ==", + "dev": true + }, + "collect-v8-coverage": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/collect-v8-coverage/-/collect-v8-coverage-1.0.1.tgz", + "integrity": "sha512-iBPtljfCNcTKNAto0KEtDfZ3qzjJvqE3aTGZsbhjSBlorqpXJlaWWtPO35D+ZImoC3KWejX64o+yPGxhWSTzfg==", + "dev": true + }, + "color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dev": true, + "requires": { + "color-name": "1.1.3" + } + }, + "color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==", + "dev": true + }, + "combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "requires": { + "delayed-stream": "~1.0.0" + } + }, + "concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==", + "dev": true + }, + "content-disposition": { + "version": "0.5.4", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", + "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==", + "requires": { + "safe-buffer": "5.2.1" + } + }, + "content-type": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz", + "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==" + }, + "convert-source-map": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.9.0.tgz", + "integrity": "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==", + "dev": true + }, + "cookie": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.6.0.tgz", + "integrity": "sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw==" + }, + "cookie-signature": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", + "integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==" + }, + "create-require": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz", + "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==", + "dev": true + }, + "cross-spawn": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", + "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "dev": true, + "requires": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + } + }, + "crypto-js": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/crypto-js/-/crypto-js-4.2.0.tgz", + "integrity": "sha512-KALDyEYgpY+Rlob/iriUtjV6d5Eq+Y191A5g4UqLAi8CyGP9N1+FdVbkc1SxKc2r4YAYqG8JzO2KGL+AizD70Q==" + }, + "debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "requires": { + "ms": "2.1.2" + } + }, + "dedent": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/dedent/-/dedent-0.7.0.tgz", + "integrity": "sha512-Q6fKUPqnAHAyhiUgFU7BUzLiv0kd8saH9al7tnu5Q/okj6dnupxyTgFIBjVzJATdfIAm9NAsvXNzjaKa+bxVyA==", + "dev": true + }, + "deep-is": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", + "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", + "dev": true + }, + "deepmerge": { + "version": "4.3.1", + "resolved": "https://registry.npmjs.org/deepmerge/-/deepmerge-4.3.1.tgz", + "integrity": "sha512-3sUqbMEc77XqpdNO7FRyRog+eW3ph+GYCbj+rK+uYyRMuwsVy0rMiVtPn+QJlKFvWP/1PYpapqYn0Me2knFn+A==", + "dev": true + }, + "define-data-property": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz", + "integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==", + "requires": { + "es-define-property": "^1.0.0", + "es-errors": "^1.3.0", + "gopd": "^1.0.1" + } + }, + "delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==" + }, + "denque": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/denque/-/denque-2.1.0.tgz", + "integrity": "sha512-HVQE3AAb/pxF8fQAoiqpvg9i3evqug3hoiwakOyZAwJm+6vZehbkYXZ0l4JxS+I3QxM97v5aaRNhj8v5oBhekw==" + }, + "depd": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", + "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==" + }, + "destroy": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz", + "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==" + }, + "detect-newline": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/detect-newline/-/detect-newline-3.1.0.tgz", + "integrity": "sha512-TLz+x/vEXm/Y7P7wn1EJFNLxYpUD4TgMosxY6fAVJUnJMbupHBOncxyWUG9OpTaH9EBD7uFI5LfEgmMOc54DsA==", + "dev": true + }, + "diff": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", + "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", + "dev": true + }, + "diff-sequences": { + "version": "29.4.3", + "resolved": "https://registry.npmjs.org/diff-sequences/-/diff-sequences-29.4.3.tgz", + "integrity": "sha512-ofrBgwpPhCD85kMKtE9RYFFq6OC1A89oW2vvgWZNCwxrUpRUILopY7lsYyMDSjc8g6U6aiO0Qubg6r4Wgt5ZnA==", + "dev": true + }, + "dir-glob": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", + "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", + "dev": true, + "requires": { + "path-type": "^4.0.0" + } + }, + "doctrine": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", + "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", + "dev": true, + "requires": { + "esutils": "^2.0.2" + } + }, + "ee-first": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", + "integrity": "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow==" + }, + "electron-to-chromium": { + "version": "1.4.686", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.686.tgz", + "integrity": "sha512-3avY1B+vUzNxEgkBDpKOP8WarvUAEwpRaiCL0He5OKWEFxzaOFiq4WoZEZe7qh0ReS7DiWoHMnYoQCKxNZNzSg==", + "dev": true + }, + "emittery": { + "version": "0.13.1", + "resolved": "https://registry.npmjs.org/emittery/-/emittery-0.13.1.tgz", + "integrity": "sha512-DeWwawk6r5yR9jFgnDKYt4sLS0LmHJJi3ZOnb5/JdbYwj3nW+FxQnHIjhBKz8YLC7oRNPVM9NQ47I3CVx34eqQ==", + "dev": true + }, + "emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==", + "dev": true + }, + "encodeurl": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", + "integrity": "sha512-TPJXq8JqFaVYm2CWmPvnP2Iyo4ZSM7/QKcSmuMLDObfpH5fi7RUGmd/rTDf+rut/saiDiQEeVTNgAmJEdAOx0w==" + }, + "error-ex": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", + "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", + "dev": true, + "requires": { + "is-arrayish": "^0.2.1" + } + }, + "es-define-property": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.0.tgz", + "integrity": "sha512-jxayLKShrEqqzJ0eumQbVhTYQM27CfT1T35+gCgDFoL82JLsXqTJ76zv6A0YLOgEnLUMvLzsDsGIrl8NFpT2gQ==", + "requires": { + "get-intrinsic": "^1.2.4" + } + }, + "es-errors": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", + "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==" + }, + "escalade": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", + "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", + "dev": true + }, + "escape-html": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", + "integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow==" + }, + "escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "dev": true + }, + "eslint": { + "version": "8.37.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.37.0.tgz", + "integrity": "sha512-NU3Ps9nI05GUoVMxcZx1J8CNR6xOvUT4jAUMH5+z8lpp3aEdPVCImKw6PWG4PY+Vfkpr+jvMpxs/qoE7wq0sPw==", + "dev": true, + "requires": { + "@eslint-community/eslint-utils": "^4.2.0", + "@eslint-community/regexpp": "^4.4.0", + "@eslint/eslintrc": "^2.0.2", + "@eslint/js": "8.37.0", + "@humanwhocodes/config-array": "^0.11.8", + "@humanwhocodes/module-importer": "^1.0.1", + "@nodelib/fs.walk": "^1.2.8", + "ajv": "^6.10.0", + "chalk": "^4.0.0", + "cross-spawn": "^7.0.2", + "debug": "^4.3.2", + "doctrine": "^3.0.0", + "escape-string-regexp": "^4.0.0", + "eslint-scope": "^7.1.1", + "eslint-visitor-keys": "^3.4.0", + "espree": "^9.5.1", + "esquery": "^1.4.2", + "esutils": "^2.0.2", + "fast-deep-equal": "^3.1.3", + "file-entry-cache": "^6.0.1", + "find-up": "^5.0.0", + "glob-parent": "^6.0.2", + "globals": "^13.19.0", + "grapheme-splitter": "^1.0.4", + "ignore": "^5.2.0", + "import-fresh": "^3.0.0", + "imurmurhash": "^0.1.4", + "is-glob": "^4.0.0", + "is-path-inside": "^3.0.3", + "js-sdsl": "^4.1.4", + "js-yaml": "^4.1.0", + "json-stable-stringify-without-jsonify": "^1.0.1", + "levn": "^0.4.1", + "lodash.merge": "^4.6.2", + "minimatch": "^3.1.2", + "natural-compare": "^1.4.0", + "optionator": "^0.9.1", + "strip-ansi": "^6.0.1", + "strip-json-comments": "^3.1.0", + "text-table": "^0.2.0" + }, + "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "dev": true + }, + "eslint-scope": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.1.1.tgz", + "integrity": "sha512-QKQM/UXpIiHcLqJ5AOyIW7XZmzjkzQXYE54n1++wb0u9V/abW3l9uQnxX8Z5Xd18xyKIMTUAyQ0k1e8pz6LUrw==", + "dev": true, + "requires": { + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" + } + }, + "estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true + }, + "globals": { + "version": "13.20.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.20.0.tgz", + "integrity": "sha512-Qg5QtVkCy/kv3FUSlu4ukeZDVf9ee0iXLAUYX13gbR17bnejFTzr4iS9bY7kwCf1NztRNm1t91fjOiyx4CSwPQ==", + "dev": true, + "requires": { + "type-fest": "^0.20.2" + } + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + }, + "type-fest": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", + "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", + "dev": true + } + } + }, + "eslint-config-prettier": { + "version": "8.8.0", + "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-8.8.0.tgz", + "integrity": "sha512-wLbQiFre3tdGgpDv67NQKnJuTlcUVYHas3k+DZCc2U2BadthoEY4B7hLPvAxaqdyOGCzuLfii2fqGph10va7oA==", + "dev": true, + "requires": {} + }, + "eslint-scope": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", + "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", + "dev": true, + "requires": { + "esrecurse": "^4.3.0", + "estraverse": "^4.1.1" + } + }, + "eslint-visitor-keys": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.0.tgz", + "integrity": "sha512-HPpKPUBQcAsZOsHAFwTtIKcYlCje62XB7SEAcxjtmW6TD1WVpkS6i6/hOVtTZIl4zGj/mBqpFVGvaDneik+VoQ==", + "dev": true + }, + "espree": { + "version": "9.5.1", + "resolved": "https://registry.npmjs.org/espree/-/espree-9.5.1.tgz", + "integrity": "sha512-5yxtHSZXRSW5pvv3hAlXM5+/Oswi1AUFqBmbibKb5s6bp3rGIDkyXU6xCoyuuLhijr4SFwPrXRoZjz0AZDN9tg==", + "dev": true, + "requires": { + "acorn": "^8.8.0", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^3.4.0" + } + }, + "esprima": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", + "dev": true + }, + "esquery": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.5.0.tgz", + "integrity": "sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg==", + "dev": true, + "requires": { + "estraverse": "^5.1.0" + }, + "dependencies": { + "estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true + } + } + }, + "esrecurse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "dev": true, + "requires": { + "estraverse": "^5.2.0" + }, + "dependencies": { + "estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true + } + } + }, + "estraverse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", + "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", + "dev": true + }, + "esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "dev": true + }, + "etag": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", + "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==" + }, + "execa": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", + "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==", + "dev": true, + "requires": { + "cross-spawn": "^7.0.3", + "get-stream": "^6.0.0", + "human-signals": "^2.1.0", + "is-stream": "^2.0.0", + "merge-stream": "^2.0.0", + "npm-run-path": "^4.0.1", + "onetime": "^5.1.2", + "signal-exit": "^3.0.3", + "strip-final-newline": "^2.0.0" + } + }, + "exit": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/exit/-/exit-0.1.2.tgz", + "integrity": "sha512-Zk/eNKV2zbjpKzrsQ+n1G6poVbErQxJ0LBOJXaKZ1EViLzH+hrLu9cdXI4zw9dBQJslwBEpbQ2P1oS7nDxs6jQ==", + "dev": true + }, + "expect": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/expect/-/expect-29.5.0.tgz", + "integrity": "sha512-yM7xqUrCO2JdpFo4XpM82t+PJBFybdqoQuJLDGeDX2ij8NZzqRHyu3Hp188/JX7SWqud+7t4MUdvcgGBICMHZg==", + "dev": true, + "requires": { + "@jest/expect-utils": "^29.5.0", + "jest-get-type": "^29.4.3", + "jest-matcher-utils": "^29.5.0", + "jest-message-util": "^29.5.0", + "jest-util": "^29.5.0" + } + }, + "express": { + "version": "4.19.2", + "resolved": "https://registry.npmjs.org/express/-/express-4.19.2.tgz", + "integrity": "sha512-5T6nhjsT+EOMzuck8JjBHARTHfMht0POzlA60WV2pMD3gyXw2LZnZ+ueGdNxG+0calOJcWKbpFcuzLZ91YWq9Q==", + "requires": { + "accepts": "~1.3.8", + "array-flatten": "1.1.1", + "body-parser": "1.20.2", + "content-disposition": "0.5.4", + "content-type": "~1.0.4", + "cookie": "0.6.0", + "cookie-signature": "1.0.6", + "debug": "2.6.9", + "depd": "2.0.0", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "finalhandler": "1.2.0", + "fresh": "0.5.2", + "http-errors": "2.0.0", + "merge-descriptors": "1.0.1", + "methods": "~1.1.2", + "on-finished": "2.4.1", + "parseurl": "~1.3.3", + "path-to-regexp": "0.1.7", + "proxy-addr": "~2.0.7", + "qs": "6.11.0", + "range-parser": "~1.2.1", + "safe-buffer": "5.2.1", + "send": "0.18.0", + "serve-static": "1.15.0", + "setprototypeof": "1.2.0", + "statuses": "2.0.1", + "type-is": "~1.6.18", + "utils-merge": "1.0.1", + "vary": "~1.1.2" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "requires": { + "ms": "2.0.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" + } + } + }, + "fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", + "dev": true + }, + "fast-glob": { + "version": "3.2.12", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.2.12.tgz", + "integrity": "sha512-DVj4CQIYYow0BlaelwK1pHl5n5cRSJfM60UA0zK891sVInoPri2Ekj7+e1CT3/3qxXenpI+nBBmQAcJPJgaj4w==", + "dev": true, + "requires": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.2", + "merge2": "^1.3.0", + "micromatch": "^4.0.4" + }, + "dependencies": { + "glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "requires": { + "is-glob": "^4.0.1" + } + } + } + }, + "fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==", + "dev": true + }, + "fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", + "dev": true + }, + "fastq": { + "version": "1.15.0", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.15.0.tgz", + "integrity": "sha512-wBrocU2LCXXa+lWBt8RoIRD89Fi8OdABODa/kEnyeyjS5aZO5/GNvI5sEINADqP/h8M29UHTHUb53sUu5Ihqdw==", + "dev": true, + "requires": { + "reusify": "^1.0.4" + } + }, + "fb-watchman": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/fb-watchman/-/fb-watchman-2.0.2.tgz", + "integrity": "sha512-p5161BqbuCaSnB8jIbzQHOlpgsPmK5rJVDfDKO91Axs5NC1uu3HRQm6wt9cd9/+GtQQIO53JdGXXoyDpTAsgYA==", + "dev": true, + "requires": { + "bser": "2.1.1" + } + }, + "file-entry-cache": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", + "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", + "dev": true, + "requires": { + "flat-cache": "^3.0.4" + } + }, + "fill-range": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.0.1.tgz", + "integrity": "sha512-qOo9F+dMUmC2Lcb4BbVvnKJxTPjCm+RRpe4gDuGrzkL7mEVl/djYSu2OdQ2Pa302N4oqkSg9ir6jaLWJ2USVpQ==", + "dev": true, + "requires": { + "to-regex-range": "^5.0.1" + } + }, + "finalhandler": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.2.0.tgz", + "integrity": "sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg==", + "requires": { + "debug": "2.6.9", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "on-finished": "2.4.1", + "parseurl": "~1.3.3", + "statuses": "2.0.1", + "unpipe": "~1.0.0" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "requires": { + "ms": "2.0.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" + } + } + }, + "find-up": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "dev": true, + "requires": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + } + }, + "flat-cache": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.0.4.tgz", + "integrity": "sha512-dm9s5Pw7Jc0GvMYbshN6zchCA9RgQlzzEZX3vylR9IqFfS8XciblUXOKfW6SiuJ0e13eDYZoZV5wdrev7P3Nwg==", + "dev": true, + "requires": { + "flatted": "^3.1.0", + "rimraf": "^3.0.2" + } + }, + "flatted": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.2.7.tgz", + "integrity": "sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ==", + "dev": true + }, + "follow-redirects": { + "version": "1.15.6", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.6.tgz", + "integrity": "sha512-wWN62YITEaOpSK584EZXJafH1AGpO8RVgElfkuXbTOrPX4fIfOyEpW/CsiNd8JdYrAoOvafRTOEnvsO++qCqFA==" + }, + "form-data": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz", + "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==", + "requires": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "mime-types": "^2.1.12" + } + }, + "forwarded": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", + "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==" + }, + "fresh": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", + "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==" + }, + "fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==", + "dev": true + }, + "fsevents": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.2.tgz", + "integrity": "sha512-xiqMQR4xAeHTuB9uWm+fFRcIOgKBMiOBP+eXiyT7jsgVCq1bkVygt00oASowB7EdtpOHaaPgKt812P9ab+DDKA==", + "dev": true, + "optional": true + }, + "function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==" + }, + "generate-function": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/generate-function/-/generate-function-2.3.1.tgz", + "integrity": "sha512-eeB5GfMNeevm/GRYq20ShmsaGcmI81kIX2K9XQx5miC8KdHaC6Jm0qQ8ZNeGOi7wYB8OsdxKs+Y2oVuTFuVwKQ==", + "requires": { + "is-property": "^1.0.2" + } + }, + "generic-pool": { + "version": "3.9.0", + "resolved": "https://registry.npmjs.org/generic-pool/-/generic-pool-3.9.0.tgz", + "integrity": "sha512-hymDOu5B53XvN4QT9dBmZxPX4CWhBPPLguTZ9MMFeFa/Kg0xWVfylOVNlJji/E7yTZWFd/q9GO5TxDLq156D7g==" + }, + "gensync": { + "version": "1.0.0-beta.2", + "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", + "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", + "dev": true + }, + "get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "dev": true + }, + "get-intrinsic": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.4.tgz", + "integrity": "sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ==", + "requires": { + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "has-proto": "^1.0.1", + "has-symbols": "^1.0.3", + "hasown": "^2.0.0" + } + }, + "get-package-type": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/get-package-type/-/get-package-type-0.1.0.tgz", + "integrity": "sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==", + "dev": true + }, + "get-stream": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", + "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", + "dev": true + }, + "glob": { + "version": "7.2.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz", + "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==", + "dev": true, + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.1.1", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + }, + "glob-parent": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "dev": true, + "requires": { + "is-glob": "^4.0.3" + } + }, + "globals": { + "version": "11.12.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", + "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", + "dev": true + }, + "globby": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", + "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", + "dev": true, + "requires": { + "array-union": "^2.1.0", + "dir-glob": "^3.0.1", + "fast-glob": "^3.2.9", + "ignore": "^5.2.0", + "merge2": "^1.4.1", + "slash": "^3.0.0" + } + }, + "gopd": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz", + "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==", + "requires": { + "get-intrinsic": "^1.1.3" + } + }, + "graceful-fs": { + "version": "4.2.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", + "dev": true + }, + "grapheme-splitter": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/grapheme-splitter/-/grapheme-splitter-1.0.4.tgz", + "integrity": "sha512-bzh50DW9kTPM00T8y4o8vQg89Di9oLJVLW/KaOGIXJWP/iqCN6WKYkbNOF04vFLJhwcpYUh9ydh/+5vpOqV4YQ==", + "dev": true + }, + "has": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", + "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", + "dev": true, + "requires": { + "function-bind": "^1.1.1" + } + }, + "has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "dev": true + }, + "has-property-descriptors": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz", + "integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==", + "requires": { + "es-define-property": "^1.0.0" + } + }, + "has-proto": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.3.tgz", + "integrity": "sha512-SJ1amZAJUiZS+PhsVLf5tGydlaVB8EdFpaSO4gmiUKUOxk8qzn5AIy4ZeJUmh22znIdk/uMAUT2pl3FxzVUH+Q==" + }, + "has-symbols": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", + "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==" + }, + "hasown": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz", + "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==", + "requires": { + "function-bind": "^1.1.2" + } + }, + "html-escaper": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/html-escaper/-/html-escaper-2.0.2.tgz", + "integrity": "sha512-H2iMtd0I4Mt5eYiapRdIDjp+XzelXQ0tFE4JS7YFwFevXXMmOp9myNrUvCg0D6ws8iqkRPBfKHgbwig1SmlLfg==", + "dev": true + }, + "http-errors": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", + "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==", + "requires": { + "depd": "2.0.0", + "inherits": "2.0.4", + "setprototypeof": "1.2.0", + "statuses": "2.0.1", + "toidentifier": "1.0.1" + } + }, + "human-signals": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz", + "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==", + "dev": true + }, + "iconv-lite": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "requires": { + "safer-buffer": ">= 2.1.2 < 3" + } + }, + "ignore": { + "version": "5.2.4", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.4.tgz", + "integrity": "sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ==", + "dev": true + }, + "import-fresh": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", + "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", + "dev": true, + "requires": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + } + }, + "import-local": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/import-local/-/import-local-3.1.0.tgz", + "integrity": "sha512-ASB07uLtnDs1o6EHjKpX34BKYDSqnFerfTOJL2HvMqF70LnxpjkzDB8J44oT9pu4AMPkQwf8jl6szgvNd2tRIg==", + "dev": true, + "requires": { + "pkg-dir": "^4.2.0", + "resolve-cwd": "^3.0.0" + } + }, + "imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha512-JmXMZ6wuvDmLiHEml9ykzqO6lwFbof0GG4IkcGaENdCRDDmMVnny7s5HsIgHCbaq0w2MyPhDqkhTUgS2LU2PHA==", + "dev": true + }, + "inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==", + "dev": true, + "requires": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" + }, + "ip": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/ip/-/ip-2.0.1.tgz", + "integrity": "sha512-lJUL9imLTNi1ZfXT+DU6rBBdbiKGBuay9B6xGSPVjUeQwaH1RIGqef8RZkUtHioLmSNpPR5M4HVKJGm1j8FWVQ==" + }, + "ipaddr.js": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", + "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==" + }, + "is-arrayish": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", + "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==", + "dev": true + }, + "is-core-module": { + "version": "2.11.0", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.11.0.tgz", + "integrity": "sha512-RRjxlvLDkD1YJwDbroBHMb+cukurkDWNyHx7D3oNB5x9rb5ogcksMC5wHCadcXoo67gVr/+3GFySh3134zi6rw==", + "dev": true, + "requires": { + "has": "^1.0.3" + } + }, + "is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==", + "dev": true + }, + "is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "dev": true + }, + "is-generator-fn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-generator-fn/-/is-generator-fn-2.1.0.tgz", + "integrity": "sha512-cTIB4yPYL/Grw0EaSzASzg6bBy9gqCofvWN8okThAYIxKJZC+udlRAmGbM0XLeniEJSs8uEgHPGuHSe1XsOLSQ==", + "dev": true + }, + "is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dev": true, + "requires": { + "is-extglob": "^2.1.1" + } + }, + "is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true + }, + "is-path-inside": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", + "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", + "dev": true + }, + "is-property": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-property/-/is-property-1.0.2.tgz", + "integrity": "sha512-Ks/IoX00TtClbGQr4TWXemAnktAQvYB7HzcCxDGqEZU6oCmb2INHuOoKxbtR+HFkmYWBKv/dOZtGRiAjDhj92g==" + }, + "is-stream": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", + "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", + "dev": true + }, + "isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==", + "dev": true + }, + "istanbul-lib-coverage": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.0.tgz", + "integrity": "sha512-eOeJ5BHCmHYvQK7xt9GkdHuzuCGS1Y6g9Gvnx3Ym33fz/HpLRYxiS0wHNr+m/MBC8B647Xt608vCDEvhl9c6Mw==", + "dev": true + }, + "istanbul-lib-instrument": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-5.2.1.tgz", + "integrity": "sha512-pzqtp31nLv/XFOzXGuvhCb8qhjmTVo5vjVk19XE4CRlSWz0KoeJ3bw9XsA7nOp9YBf4qHjwBxkDzKcME/J29Yg==", + "dev": true, + "requires": { + "@babel/core": "^7.12.3", + "@babel/parser": "^7.14.7", + "@istanbuljs/schema": "^0.1.2", + "istanbul-lib-coverage": "^3.2.0", + "semver": "^6.3.0" + } + }, + "istanbul-lib-report": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/istanbul-lib-report/-/istanbul-lib-report-3.0.0.tgz", + "integrity": "sha512-wcdi+uAKzfiGT2abPpKZ0hSU1rGQjUQnLvtY5MpQ7QCTahD3VODhcu4wcfY1YtkGaDD5yuydOLINXsfbus9ROw==", + "dev": true, + "requires": { + "istanbul-lib-coverage": "^3.0.0", + "make-dir": "^3.0.0", + "supports-color": "^7.1.0" + }, + "dependencies": { + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, + "istanbul-lib-source-maps": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/istanbul-lib-source-maps/-/istanbul-lib-source-maps-4.0.1.tgz", + "integrity": "sha512-n3s8EwkdFIJCG3BPKBYvskgXGoy88ARzvegkitk60NxRdwltLOTaH7CUiMRXvwYorl0Q712iEjcWB+fK/MrWVw==", + "dev": true, + "requires": { + "debug": "^4.1.1", + "istanbul-lib-coverage": "^3.0.0", + "source-map": "^0.6.1" + } + }, + "istanbul-reports": { + "version": "3.1.5", + "resolved": "https://registry.npmjs.org/istanbul-reports/-/istanbul-reports-3.1.5.tgz", + "integrity": "sha512-nUsEMa9pBt/NOHqbcbeJEgqIlY/K7rVWUX6Lql2orY5e9roQOthbR3vtY4zzf2orPELg80fnxxk9zUyPlgwD1w==", + "dev": true, + "requires": { + "html-escaper": "^2.0.0", + "istanbul-lib-report": "^3.0.0" + } + }, + "jest": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/jest/-/jest-29.5.0.tgz", + "integrity": "sha512-juMg3he2uru1QoXX078zTa7pO85QyB9xajZc6bU+d9yEGwrKX6+vGmJQ3UdVZsvTEUARIdObzH68QItim6OSSQ==", + "dev": true, + "requires": { + "@jest/core": "^29.5.0", + "@jest/types": "^29.5.0", + "import-local": "^3.0.2", + "jest-cli": "^29.5.0" + } + }, + "jest-changed-files": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/jest-changed-files/-/jest-changed-files-29.5.0.tgz", + "integrity": "sha512-IFG34IUMUaNBIxjQXF/iu7g6EcdMrGRRxaUSw92I/2g2YC6vCdTltl4nHvt7Ci5nSJwXIkCu8Ka1DKF+X7Z1Ag==", + "dev": true, + "requires": { + "execa": "^5.0.0", + "p-limit": "^3.1.0" + } + }, + "jest-circus": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/jest-circus/-/jest-circus-29.5.0.tgz", + "integrity": "sha512-gq/ongqeQKAplVxqJmbeUOJJKkW3dDNPY8PjhJ5G0lBRvu0e3EWGxGy5cI4LAGA7gV2UHCtWBI4EMXK8c9nQKA==", + "dev": true, + "requires": { + "@jest/environment": "^29.5.0", + "@jest/expect": "^29.5.0", + "@jest/test-result": "^29.5.0", + "@jest/types": "^29.5.0", + "@types/node": "*", + "chalk": "^4.0.0", + "co": "^4.6.0", + "dedent": "^0.7.0", + "is-generator-fn": "^2.0.0", + "jest-each": "^29.5.0", + "jest-matcher-utils": "^29.5.0", + "jest-message-util": "^29.5.0", + "jest-runtime": "^29.5.0", + "jest-snapshot": "^29.5.0", + "jest-util": "^29.5.0", + "p-limit": "^3.1.0", + "pretty-format": "^29.5.0", + "pure-rand": "^6.0.0", + "slash": "^3.0.0", + "stack-utils": "^2.0.3" + }, + "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, + "jest-cli": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/jest-cli/-/jest-cli-29.5.0.tgz", + "integrity": "sha512-L1KcP1l4HtfwdxXNFCL5bmUbLQiKrakMUriBEcc1Vfz6gx31ORKdreuWvmQVBit+1ss9NNR3yxjwfwzZNdQXJw==", + "dev": true, + "requires": { + "@jest/core": "^29.5.0", + "@jest/test-result": "^29.5.0", + "@jest/types": "^29.5.0", + "chalk": "^4.0.0", + "exit": "^0.1.2", + "graceful-fs": "^4.2.9", + "import-local": "^3.0.2", + "jest-config": "^29.5.0", + "jest-util": "^29.5.0", + "jest-validate": "^29.5.0", + "prompts": "^2.0.1", + "yargs": "^17.3.1" + }, + "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, + "jest-config": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/jest-config/-/jest-config-29.5.0.tgz", + "integrity": "sha512-kvDUKBnNJPNBmFFOhDbm59iu1Fii1Q6SxyhXfvylq3UTHbg6o7j/g8k2dZyXWLvfdKB1vAPxNZnMgtKJcmu3kA==", + "dev": true, + "requires": { + "@babel/core": "^7.11.6", + "@jest/test-sequencer": "^29.5.0", + "@jest/types": "^29.5.0", + "babel-jest": "^29.5.0", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "deepmerge": "^4.2.2", + "glob": "^7.1.3", + "graceful-fs": "^4.2.9", + "jest-circus": "^29.5.0", + "jest-environment-node": "^29.5.0", + "jest-get-type": "^29.4.3", + "jest-regex-util": "^29.4.3", + "jest-resolve": "^29.5.0", + "jest-runner": "^29.5.0", + "jest-util": "^29.5.0", + "jest-validate": "^29.5.0", + "micromatch": "^4.0.4", + "parse-json": "^5.2.0", + "pretty-format": "^29.5.0", + "slash": "^3.0.0", + "strip-json-comments": "^3.1.1" + }, + "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, + "jest-diff": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/jest-diff/-/jest-diff-29.5.0.tgz", + "integrity": "sha512-LtxijLLZBduXnHSniy0WMdaHjmQnt3g5sa16W4p0HqukYTTsyTW3GD1q41TyGl5YFXj/5B2U6dlh5FM1LIMgxw==", + "dev": true, + "requires": { + "chalk": "^4.0.0", + "diff-sequences": "^29.4.3", + "jest-get-type": "^29.4.3", + "pretty-format": "^29.5.0" + }, + "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, + "jest-docblock": { + "version": "29.4.3", + "resolved": "https://registry.npmjs.org/jest-docblock/-/jest-docblock-29.4.3.tgz", + "integrity": "sha512-fzdTftThczeSD9nZ3fzA/4KkHtnmllawWrXO69vtI+L9WjEIuXWs4AmyME7lN5hU7dB0sHhuPfcKofRsUb/2Fg==", + "dev": true, + "requires": { + "detect-newline": "^3.0.0" + } + }, + "jest-each": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/jest-each/-/jest-each-29.5.0.tgz", + "integrity": "sha512-HM5kIJ1BTnVt+DQZ2ALp3rzXEl+g726csObrW/jpEGl+CDSSQpOJJX2KE/vEg8cxcMXdyEPu6U4QX5eruQv5hA==", + "dev": true, + "requires": { + "@jest/types": "^29.5.0", + "chalk": "^4.0.0", + "jest-get-type": "^29.4.3", + "jest-util": "^29.5.0", + "pretty-format": "^29.5.0" + }, + "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, + "jest-environment-node": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/jest-environment-node/-/jest-environment-node-29.5.0.tgz", + "integrity": "sha512-ExxuIK/+yQ+6PRGaHkKewYtg6hto2uGCgvKdb2nfJfKXgZ17DfXjvbZ+jA1Qt9A8EQSfPnt5FKIfnOO3u1h9qw==", + "dev": true, + "requires": { + "@jest/environment": "^29.5.0", + "@jest/fake-timers": "^29.5.0", + "@jest/types": "^29.5.0", + "@types/node": "*", + "jest-mock": "^29.5.0", + "jest-util": "^29.5.0" + } + }, + "jest-get-type": { + "version": "29.4.3", + "resolved": "https://registry.npmjs.org/jest-get-type/-/jest-get-type-29.4.3.tgz", + "integrity": "sha512-J5Xez4nRRMjk8emnTpWrlkyb9pfRQQanDrvWHhsR1+VUfbwxi30eVcZFlcdGInRibU4G5LwHXpI7IRHU0CY+gg==", + "dev": true + }, + "jest-haste-map": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/jest-haste-map/-/jest-haste-map-29.5.0.tgz", + "integrity": "sha512-IspOPnnBro8YfVYSw6yDRKh/TiCdRngjxeacCps1cQ9cgVN6+10JUcuJ1EabrgYLOATsIAigxA0rLR9x/YlrSA==", + "dev": true, + "requires": { + "@jest/types": "^29.5.0", + "@types/graceful-fs": "^4.1.3", + "@types/node": "*", + "anymatch": "^3.0.3", + "fb-watchman": "^2.0.0", + "fsevents": "^2.3.2", + "graceful-fs": "^4.2.9", + "jest-regex-util": "^29.4.3", + "jest-util": "^29.5.0", + "jest-worker": "^29.5.0", + "micromatch": "^4.0.4", + "walker": "^1.0.8" + } + }, + "jest-leak-detector": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/jest-leak-detector/-/jest-leak-detector-29.5.0.tgz", + "integrity": "sha512-u9YdeeVnghBUtpN5mVxjID7KbkKE1QU4f6uUwuxiY0vYRi9BUCLKlPEZfDGR67ofdFmDz9oPAy2G92Ujrntmow==", + "dev": true, + "requires": { + "jest-get-type": "^29.4.3", + "pretty-format": "^29.5.0" + } + }, + "jest-matcher-utils": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/jest-matcher-utils/-/jest-matcher-utils-29.5.0.tgz", + "integrity": "sha512-lecRtgm/rjIK0CQ7LPQwzCs2VwW6WAahA55YBuI+xqmhm7LAaxokSB8C97yJeYyT+HvQkH741StzpU41wohhWw==", + "dev": true, + "requires": { + "chalk": "^4.0.0", + "jest-diff": "^29.5.0", + "jest-get-type": "^29.4.3", + "pretty-format": "^29.5.0" + }, + "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, + "jest-message-util": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/jest-message-util/-/jest-message-util-29.5.0.tgz", + "integrity": "sha512-Kijeg9Dag6CKtIDA7O21zNTACqD5MD/8HfIV8pdD94vFyFuer52SigdC3IQMhab3vACxXMiFk+yMHNdbqtyTGA==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.12.13", + "@jest/types": "^29.5.0", + "@types/stack-utils": "^2.0.0", + "chalk": "^4.0.0", + "graceful-fs": "^4.2.9", + "micromatch": "^4.0.4", + "pretty-format": "^29.5.0", + "slash": "^3.0.0", + "stack-utils": "^2.0.3" + }, + "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, + "jest-mock": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/jest-mock/-/jest-mock-29.5.0.tgz", + "integrity": "sha512-GqOzvdWDE4fAV2bWQLQCkujxYWL7RxjCnj71b5VhDAGOevB3qj3Ovg26A5NI84ZpODxyzaozXLOh2NCgkbvyaw==", + "dev": true, + "requires": { + "@jest/types": "^29.5.0", + "@types/node": "*", + "jest-util": "^29.5.0" + } + }, + "jest-pnp-resolver": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/jest-pnp-resolver/-/jest-pnp-resolver-1.2.3.tgz", + "integrity": "sha512-+3NpwQEnRoIBtx4fyhblQDPgJI0H1IEIkX7ShLUjPGA7TtUTvI1oiKi3SR4oBR0hQhQR80l4WAe5RrXBwWMA8w==", + "dev": true, + "requires": {} + }, + "jest-regex-util": { + "version": "29.4.3", + "resolved": "https://registry.npmjs.org/jest-regex-util/-/jest-regex-util-29.4.3.tgz", + "integrity": "sha512-O4FglZaMmWXbGHSQInfXewIsd1LMn9p3ZXB/6r4FOkyhX2/iP/soMG98jGvk/A3HAN78+5VWcBGO0BJAPRh4kg==", + "dev": true + }, + "jest-resolve": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/jest-resolve/-/jest-resolve-29.5.0.tgz", + "integrity": "sha512-1TzxJ37FQq7J10jPtQjcc+MkCkE3GBpBecsSUWJ0qZNJpmg6m0D9/7II03yJulm3H/fvVjgqLh/k2eYg+ui52w==", + "dev": true, + "requires": { + "chalk": "^4.0.0", + "graceful-fs": "^4.2.9", + "jest-haste-map": "^29.5.0", + "jest-pnp-resolver": "^1.2.2", + "jest-util": "^29.5.0", + "jest-validate": "^29.5.0", + "resolve": "^1.20.0", + "resolve.exports": "^2.0.0", + "slash": "^3.0.0" + }, + "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, + "jest-resolve-dependencies": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/jest-resolve-dependencies/-/jest-resolve-dependencies-29.5.0.tgz", + "integrity": "sha512-sjV3GFr0hDJMBpYeUuGduP+YeCRbd7S/ck6IvL3kQ9cpySYKqcqhdLLC2rFwrcL7tz5vYibomBrsFYWkIGGjOg==", + "dev": true, + "requires": { + "jest-regex-util": "^29.4.3", + "jest-snapshot": "^29.5.0" + } + }, + "jest-runner": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/jest-runner/-/jest-runner-29.5.0.tgz", + "integrity": "sha512-m7b6ypERhFghJsslMLhydaXBiLf7+jXy8FwGRHO3BGV1mcQpPbwiqiKUR2zU2NJuNeMenJmlFZCsIqzJCTeGLQ==", + "dev": true, + "requires": { + "@jest/console": "^29.5.0", + "@jest/environment": "^29.5.0", + "@jest/test-result": "^29.5.0", + "@jest/transform": "^29.5.0", + "@jest/types": "^29.5.0", + "@types/node": "*", + "chalk": "^4.0.0", + "emittery": "^0.13.1", + "graceful-fs": "^4.2.9", + "jest-docblock": "^29.4.3", + "jest-environment-node": "^29.5.0", + "jest-haste-map": "^29.5.0", + "jest-leak-detector": "^29.5.0", + "jest-message-util": "^29.5.0", + "jest-resolve": "^29.5.0", + "jest-runtime": "^29.5.0", + "jest-util": "^29.5.0", + "jest-watcher": "^29.5.0", + "jest-worker": "^29.5.0", + "p-limit": "^3.1.0", + "source-map-support": "0.5.13" + }, + "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, + "jest-runtime": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/jest-runtime/-/jest-runtime-29.5.0.tgz", + "integrity": "sha512-1Hr6Hh7bAgXQP+pln3homOiEZtCDZFqwmle7Ew2j8OlbkIu6uE3Y/etJQG8MLQs3Zy90xrp2C0BRrtPHG4zryw==", + "dev": true, + "requires": { + "@jest/environment": "^29.5.0", + "@jest/fake-timers": "^29.5.0", + "@jest/globals": "^29.5.0", + "@jest/source-map": "^29.4.3", + "@jest/test-result": "^29.5.0", + "@jest/transform": "^29.5.0", + "@jest/types": "^29.5.0", + "@types/node": "*", + "chalk": "^4.0.0", + "cjs-module-lexer": "^1.0.0", + "collect-v8-coverage": "^1.0.0", + "glob": "^7.1.3", + "graceful-fs": "^4.2.9", + "jest-haste-map": "^29.5.0", + "jest-message-util": "^29.5.0", + "jest-mock": "^29.5.0", + "jest-regex-util": "^29.4.3", + "jest-resolve": "^29.5.0", + "jest-snapshot": "^29.5.0", + "jest-util": "^29.5.0", + "slash": "^3.0.0", + "strip-bom": "^4.0.0" + }, + "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, + "jest-snapshot": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/jest-snapshot/-/jest-snapshot-29.5.0.tgz", + "integrity": "sha512-x7Wolra5V0tt3wRs3/ts3S6ciSQVypgGQlJpz2rsdQYoUKxMxPNaoHMGJN6qAuPJqS+2iQ1ZUn5kl7HCyls84g==", + "dev": true, + "requires": { + "@babel/core": "^7.11.6", + "@babel/generator": "^7.7.2", + "@babel/plugin-syntax-jsx": "^7.7.2", + "@babel/plugin-syntax-typescript": "^7.7.2", + "@babel/traverse": "^7.7.2", + "@babel/types": "^7.3.3", + "@jest/expect-utils": "^29.5.0", + "@jest/transform": "^29.5.0", + "@jest/types": "^29.5.0", + "@types/babel__traverse": "^7.0.6", + "@types/prettier": "^2.1.5", + "babel-preset-current-node-syntax": "^1.0.0", + "chalk": "^4.0.0", + "expect": "^29.5.0", + "graceful-fs": "^4.2.9", + "jest-diff": "^29.5.0", + "jest-get-type": "^29.4.3", + "jest-matcher-utils": "^29.5.0", + "jest-message-util": "^29.5.0", + "jest-util": "^29.5.0", + "natural-compare": "^1.4.0", + "pretty-format": "^29.5.0", + "semver": "^7.3.5" + }, + "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true + }, + "lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dev": true, + "requires": { + "yallist": "^4.0.0" + } + }, + "semver": { + "version": "7.5.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", + "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", + "dev": true, + "requires": { + "lru-cache": "^6.0.0" + } + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + }, + "yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true + } + } + }, + "jest-util": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/jest-util/-/jest-util-29.5.0.tgz", + "integrity": "sha512-RYMgG/MTadOr5t8KdhejfvUU82MxsCu5MF6KuDUHl+NuwzUt+Sm6jJWxTJVrDR1j5M/gJVCPKQEpWXY+yIQ6lQ==", + "dev": true, + "requires": { + "@jest/types": "^29.5.0", + "@types/node": "*", + "chalk": "^4.0.0", + "ci-info": "^3.2.0", + "graceful-fs": "^4.2.9", + "picomatch": "^2.2.3" + }, + "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, + "jest-validate": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/jest-validate/-/jest-validate-29.5.0.tgz", + "integrity": "sha512-pC26etNIi+y3HV8A+tUGr/lph9B18GnzSRAkPaaZJIE1eFdiYm6/CewuiJQ8/RlfHd1u/8Ioi8/sJ+CmbA+zAQ==", + "dev": true, + "requires": { + "@jest/types": "^29.5.0", + "camelcase": "^6.2.0", + "chalk": "^4.0.0", + "jest-get-type": "^29.4.3", + "leven": "^3.1.0", + "pretty-format": "^29.5.0" + }, + "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "camelcase": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-6.3.0.tgz", + "integrity": "sha512-Gmy6FhYlCY7uOElZUSbxo2UCDH8owEk996gkbrpsgGtrJLM3J7jGxl9Ic7Qwwj4ivOE5AWZWRMecDdF7hqGjFA==", + "dev": true + }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, + "jest-watcher": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/jest-watcher/-/jest-watcher-29.5.0.tgz", + "integrity": "sha512-KmTojKcapuqYrKDpRwfqcQ3zjMlwu27SYext9pt4GlF5FUgB+7XE1mcCnSm6a4uUpFyQIkb6ZhzZvHl+jiBCiA==", + "dev": true, + "requires": { + "@jest/test-result": "^29.5.0", + "@jest/types": "^29.5.0", + "@types/node": "*", + "ansi-escapes": "^4.2.1", + "chalk": "^4.0.0", + "emittery": "^0.13.1", + "jest-util": "^29.5.0", + "string-length": "^4.0.1" + }, + "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, + "jest-worker": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-29.5.0.tgz", + "integrity": "sha512-NcrQnevGoSp4b5kg+akIpthoAFHxPBcb5P6mYPY0fUNT+sSvmtu6jlkEle3anczUKIKEbMxFimk9oTP/tpIPgA==", + "dev": true, + "requires": { + "@types/node": "*", + "jest-util": "^29.5.0", + "merge-stream": "^2.0.0", + "supports-color": "^8.0.0" + }, + "dependencies": { + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true + }, + "supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, + "js-sdsl": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/js-sdsl/-/js-sdsl-4.4.0.tgz", + "integrity": "sha512-FfVSdx6pJ41Oa+CF7RDaFmTnCaFhua+SNYQX74riGOpl96x+2jQCqEfQ2bnXu/5DPCqlRuiqyvTJM0Qjz26IVg==", + "dev": true + }, + "js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==", + "dev": true + }, + "js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "dev": true, + "requires": { + "argparse": "^2.0.1" + } + }, + "jsesc": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", + "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", + "dev": true + }, + "json-parse-even-better-errors": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", + "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==", + "dev": true + }, + "json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true + }, + "json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", + "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", + "dev": true + }, + "json5": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", + "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", + "dev": true + }, + "kleur": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/kleur/-/kleur-3.0.3.tgz", + "integrity": "sha512-eTIzlVOSUR+JxdDFepEYcBMtZ9Qqdef+rnzWdRZuMbOywu5tO2w2N7rqjoANZ5k9vywhL6Br1VRjUIgTQx4E8w==", + "dev": true + }, + "leven": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/leven/-/leven-3.1.0.tgz", + "integrity": "sha512-qsda+H8jTaUaN/x5vzW2rzc+8Rw4TAQ/4KjB46IwK5VH+IlVeeeje/EoZRpiXvIqjFgK84QffqPztGI3VBLG1A==", + "dev": true + }, + "levn": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", + "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", + "dev": true, + "requires": { + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" + } + }, + "lines-and-columns": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", + "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==", + "dev": true + }, + "locate-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "dev": true, + "requires": { + "p-locate": "^5.0.0" + } + }, + "lodash.memoize": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-4.1.2.tgz", + "integrity": "sha512-t7j+NzmgnQzTAYXcsHYLgimltOV1MXHtlOWf6GjL9Kj8GK5FInw5JotxvbOs+IvV1/Dzo04/fCGfLVs7aXb4Ag==", + "dev": true + }, + "lodash.merge": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", + "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", + "dev": true + }, + "long": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/long/-/long-5.2.1.tgz", + "integrity": "sha512-GKSNGeNAtw8IryjjkhZxuKB3JzlcLTwjtiQCHKvqQet81I93kXslhDQruGI/QsddO83mcDToBVy7GqGS/zYf/A==" + }, + "lru-cache": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", + "dev": true, + "requires": { + "yallist": "^3.0.2" + } + }, + "make-dir": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", + "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", + "dev": true, + "requires": { + "semver": "^6.0.0" + } + }, + "make-error": { + "version": "1.3.6", + "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", + "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", + "dev": true + }, + "makeerror": { + "version": "1.0.12", + "resolved": "https://registry.npmjs.org/makeerror/-/makeerror-1.0.12.tgz", + "integrity": "sha512-JmqCvUhmt43madlpFzG4BQzG2Z3m6tvQDNKdClZnO3VbIudJYmxsT0FNJMeiB2+JTSlTQTSbU8QdesVmwJcmLg==", + "dev": true, + "requires": { + "tmpl": "1.0.5" + } + }, + "maxmind": { + "version": "4.3.11", + "resolved": "https://registry.npmjs.org/maxmind/-/maxmind-4.3.11.tgz", + "integrity": "sha512-tJDrKbUzN6PSA88tWgg0L2R4Ln00XwecYQJPFI+RvlF2k1sx6VQYtuQ1SVxm8+bw5tF7GWV4xyb+3/KyzEpPUw==", + "requires": { + "mmdb-lib": "2.0.2", + "tiny-lru": "11.0.1" + } + }, + "media-typer": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", + "integrity": "sha512-dq+qelQ9akHpcOl/gUVRTxVIOkAJ1wR3QAvb4RsVjS8oVoFjDGTc679wJYmUmknUF5HwMLOgb5O+a3KxfWapPQ==" + }, + "merge-descriptors": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", + "integrity": "sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w==" + }, + "merge-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", + "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==", + "dev": true + }, + "merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "dev": true + }, + "methods": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", + "integrity": "sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==" + }, + "micromatch": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz", + "integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==", + "dev": true, + "requires": { + "braces": "^3.0.2", + "picomatch": "^2.3.1" + } + }, + "mime": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", + "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==" + }, + "mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==" + }, + "mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "requires": { + "mime-db": "1.52.0" + } + }, + "mimic-fn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", + "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", + "dev": true + }, + "minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dev": true, + "requires": { + "brace-expansion": "^1.1.7" + } + }, + "mmdb-lib": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/mmdb-lib/-/mmdb-lib-2.0.2.tgz", + "integrity": "sha512-shi1I+fCPQonhTi7qyb6hr7hi87R7YS69FlfJiMFuJ12+grx0JyL56gLNzGTYXPU7EhAPkMLliGeyHer0K+AVA==" + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + }, + "mysql2": { + "version": "3.10.0", + "resolved": "https://registry.npmjs.org/mysql2/-/mysql2-3.10.0.tgz", + "integrity": "sha512-qx0mfWYt1DpTPkw8mAcHW/OwqqyNqBLBHvY5IjN8+icIYTjt6znrgYJ+gxqNNRpVknb5Wc/gcCM4XjbCR0j5tw==", + "requires": { + "denque": "^2.1.0", + "generate-function": "^2.3.1", + "iconv-lite": "^0.6.3", + "long": "^5.2.1", + "lru-cache": "^8.0.0", + "named-placeholders": "^1.1.3", + "seq-queue": "^0.0.5", + "sqlstring": "^2.3.2" + }, + "dependencies": { + "iconv-lite": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", + "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", + "requires": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + } + }, + "lru-cache": { + "version": "8.0.5", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-8.0.5.tgz", + "integrity": "sha512-MhWWlVnuab1RG5/zMRRcVGXZLCXrZTgfwMikgzCegsPnG62yDQo5JnqKkrK4jO5iKqDAZGItAqN5CtKBCBWRUA==" + } + } + }, + "named-placeholders": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/named-placeholders/-/named-placeholders-1.1.3.tgz", + "integrity": "sha512-eLoBxg6wE/rZkJPhU/xRX1WTpkFEwDJEN96oxFrTsqBdbT5ec295Q+CoHrL9IT0DipqKhmGcaZmwOt8OON5x1w==", + "requires": { + "lru-cache": "^7.14.1" + }, + "dependencies": { + "lru-cache": { + "version": "7.18.3", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-7.18.3.tgz", + "integrity": "sha512-jumlc0BIUrS3qJGgIkWZsyfAM7NCWiBcCDhnd+3NNM5KbBmLTgHVfWBcg6W+rLUsIpzpERPsvwUP7CckAQSOoA==" + } + } + }, + "natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", + "dev": true + }, + "natural-compare-lite": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare-lite/-/natural-compare-lite-1.4.0.tgz", + "integrity": "sha512-Tj+HTDSJJKaZnfiuw+iaF9skdPpTo2GtEly5JHnWV/hfv2Qj/9RKsGISQtLh2ox3l5EAGw487hnBee0sIJ6v2g==", + "dev": true + }, + "negotiator": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", + "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==" + }, + "node-int64": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/node-int64/-/node-int64-0.4.0.tgz", + "integrity": "sha512-O5lz91xSOeoXP6DulyHfllpq+Eg00MWitZIbtPfoSEvqIHdl5gfcY6hYzDWnj0qD5tz52PI08u9qUvSVeUBeHw==", + "dev": true + }, + "node-releases": { + "version": "2.0.14", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.14.tgz", + "integrity": "sha512-y10wOWt8yZpqXmOgRo77WaHEmhYQYGNA6y421PKsKYWEK8aW+cqAphborZDhqfyKrbZEN92CN1X2KbafY2s7Yw==", + "dev": true + }, + "normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "dev": true + }, + "npm-run-path": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", + "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", + "dev": true, + "requires": { + "path-key": "^3.0.0" + } + }, + "object-inspect": { + "version": "1.13.1", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.1.tgz", + "integrity": "sha512-5qoj1RUiKOMsCCNLV1CBiPYE10sziTsnmNxkAI/rZhiD63CF7IqdFGC/XzjWjpSgLf0LxXX3bDFIh0E18f6UhQ==" + }, + "on-finished": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", + "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", + "requires": { + "ee-first": "1.1.1" + } + }, + "once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==", + "dev": true, + "requires": { + "wrappy": "1" + } + }, + "onetime": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", + "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", + "dev": true, + "requires": { + "mimic-fn": "^2.1.0" + } + }, + "optionator": { + "version": "0.9.3", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.3.tgz", + "integrity": "sha512-JjCoypp+jKn1ttEFExxhetCKeJt9zhAgAve5FXHixTvFDW/5aEktX9bufBKLRRMdU7bNtpLfcGu94B3cdEJgjg==", + "dev": true, + "requires": { + "@aashutoshrathi/word-wrap": "^1.2.3", + "deep-is": "^0.1.3", + "fast-levenshtein": "^2.0.6", + "levn": "^0.4.1", + "prelude-ls": "^1.2.1", + "type-check": "^0.4.0" + } + }, + "p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "dev": true, + "requires": { + "yocto-queue": "^0.1.0" + } + }, + "p-locate": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "dev": true, + "requires": { + "p-limit": "^3.0.2" + } + }, + "p-try": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", + "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", + "dev": true + }, + "parent-module": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "dev": true, + "requires": { + "callsites": "^3.0.0" + } + }, + "parse-json": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", + "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", + "dev": true, + "requires": { + "@babel/code-frame": "^7.0.0", + "error-ex": "^1.3.1", + "json-parse-even-better-errors": "^2.3.0", + "lines-and-columns": "^1.1.6" + } + }, + "parseurl": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", + "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==" + }, + "path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "dev": true + }, + "path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==", + "dev": true + }, + "path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "dev": true + }, + "path-parse": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==", + "dev": true + }, + "path-to-regexp": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", + "integrity": "sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ==" + }, + "path-type": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", + "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", + "dev": true + }, + "picocolors": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", + "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==", + "dev": true + }, + "picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true + }, + "pirates": { + "version": "4.0.5", + "resolved": "https://registry.npmjs.org/pirates/-/pirates-4.0.5.tgz", + "integrity": "sha512-8V9+HQPupnaXMA23c5hvl69zXvTwTzyAYasnkb0Tts4XvO4CliqONMOnvlq26rkhLC3nWDFBJf73LU1e1VZLaQ==", + "dev": true + }, + "pkg-dir": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", + "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", + "dev": true, + "requires": { + "find-up": "^4.0.0" + }, + "dependencies": { + "find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "dev": true, + "requires": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + } + }, + "locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "dev": true, + "requires": { + "p-locate": "^4.1.0" + } + }, + "p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "dev": true, + "requires": { + "p-try": "^2.0.0" + } + }, + "p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "dev": true, + "requires": { + "p-limit": "^2.2.0" + } + } + } + }, + "prelude-ls": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", + "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", + "dev": true + }, + "prettier": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.0.0.tgz", + "integrity": "sha512-zBf5eHpwHOGPC47h0zrPyNn+eAEIdEzfywMoYn2XPi0P44Zp0tSq64rq0xAREh4auw2cJZHo9QUob+NqCQky4g==", + "dev": true + }, + "pretty-format": { + "version": "29.5.0", + "resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-29.5.0.tgz", + "integrity": "sha512-V2mGkI31qdttvTFX7Mt4efOqHXqJWMu4/r66Xh3Z3BwZaPfPJgp6/gbwoujRpPUtfEF6AUUWx3Jim3GCw5g/Qw==", + "dev": true, + "requires": { + "@jest/schemas": "^29.4.3", + "ansi-styles": "^5.0.0", + "react-is": "^18.0.0" + }, + "dependencies": { + "ansi-styles": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-5.2.0.tgz", + "integrity": "sha512-Cxwpt2SfTzTtXcfOlzGEee8O+c+MmUgGrNiBcXnuWxuFJHe6a5Hz7qwhwe5OgaSYI0IJvkLqWX1ASG+cJOkEiA==", + "dev": true + } + } + }, + "prompts": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/prompts/-/prompts-2.4.2.tgz", + "integrity": "sha512-NxNv/kLguCA7p3jE8oL2aEBsrJWgAakBpgmgK6lpPWV+WuOmY6r2/zbAVnP+T8bQlA0nzHXSJSJW0Hq7ylaD2Q==", + "dev": true, + "requires": { + "kleur": "^3.0.3", + "sisteransi": "^1.0.5" + } + }, + "proxy-addr": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", + "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==", + "requires": { + "forwarded": "0.2.0", + "ipaddr.js": "1.9.1" + } + }, + "proxy-from-env": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", + "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==" + }, + "punycode": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.0.tgz", + "integrity": "sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA==", + "dev": true + }, + "pure-rand": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/pure-rand/-/pure-rand-6.0.1.tgz", + "integrity": "sha512-t+x1zEHDjBwkDGY5v5ApnZ/utcd4XYDiJsaQQoptTXgUXX95sDg1elCdJghzicm7n2mbCBJ3uYWr6M22SO19rg==", + "dev": true + }, + "qs": { + "version": "6.11.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz", + "integrity": "sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==", + "requires": { + "side-channel": "^1.0.4" + } + }, + "queue-microtask": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", + "dev": true + }, + "range-parser": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", + "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==" + }, + "raw-body": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.2.tgz", + "integrity": "sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA==", + "requires": { + "bytes": "3.1.2", + "http-errors": "2.0.0", + "iconv-lite": "0.4.24", + "unpipe": "1.0.0" + } + }, + "react-is": { + "version": "18.2.0", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-18.2.0.tgz", + "integrity": "sha512-xWGDIW6x921xtzPkhiULtthJHoJvBbF3q26fzloPCK0hsvxtPVelvftw3zjbHWSkR2km9Z+4uxbDDK/6Zw9B8w==", + "dev": true + }, + "redis": { + "version": "4.6.6", + "resolved": "https://registry.npmjs.org/redis/-/redis-4.6.6.tgz", + "integrity": "sha512-aLs2fuBFV/VJ28oLBqYykfnhGGkFxvx0HdCEBYdJ99FFbSEMZ7c1nVKwR6ZRv+7bb7JnC0mmCzaqu8frgOYhpA==", + "requires": { + "@redis/bloom": "1.2.0", + "@redis/client": "1.5.7", + "@redis/graph": "1.1.0", + "@redis/json": "1.0.4", + "@redis/search": "1.1.2", + "@redis/time-series": "1.0.4" + } + }, + "require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==", + "dev": true + }, + "resolve": { + "version": "1.22.1", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.1.tgz", + "integrity": "sha512-nBpuuYuY5jFsli/JIs1oldw6fOQCBioohqWZg/2hiaOybXOft4lonv85uDOKXdf8rhyK159cxU5cDcK/NKk8zw==", + "dev": true, + "requires": { + "is-core-module": "^2.9.0", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + } + }, + "resolve-cwd": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/resolve-cwd/-/resolve-cwd-3.0.0.tgz", + "integrity": "sha512-OrZaX2Mb+rJCpH/6CpSqt9xFVpN++x01XnN2ie9g6P5/3xelLAkXWVADpdz1IHD/KFfEXyE6V0U01OQ3UO2rEg==", + "dev": true, + "requires": { + "resolve-from": "^5.0.0" + }, + "dependencies": { + "resolve-from": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", + "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", + "dev": true + } + } + }, + "resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "dev": true + }, + "resolve.exports": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/resolve.exports/-/resolve.exports-2.0.2.tgz", + "integrity": "sha512-X2UW6Nw3n/aMgDVy+0rSqgHlv39WZAlZrXCdnbyEiKm17DSqHX4MmQMaST3FbeWR5FTuRcUwYAziZajji0Y7mg==", + "dev": true + }, + "reusify": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", + "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", + "dev": true + }, + "rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "dev": true, + "requires": { + "glob": "^7.1.3" + } + }, + "run-parallel": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", + "dev": true, + "requires": { + "queue-microtask": "^1.2.2" + } + }, + "rust-gbt": { + "version": "file:rust-gbt" + }, + "safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==" + }, + "safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" + }, + "semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "dev": true + }, + "send": { + "version": "0.18.0", + "resolved": "https://registry.npmjs.org/send/-/send-0.18.0.tgz", + "integrity": "sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==", + "requires": { + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "1.2.0", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "fresh": "0.5.2", + "http-errors": "2.0.0", + "mime": "1.6.0", + "ms": "2.1.3", + "on-finished": "2.4.1", + "range-parser": "~1.2.1", + "statuses": "2.0.1" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "requires": { + "ms": "2.0.0" + }, + "dependencies": { + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" + } + } + }, + "ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" + } + } + }, + "seq-queue": { + "version": "0.0.5", + "resolved": "https://registry.npmjs.org/seq-queue/-/seq-queue-0.0.5.tgz", + "integrity": "sha512-hr3Wtp/GZIc/6DAGPDcV4/9WoZhjrkXsi5B/07QgX8tsdc6ilr7BFM6PM6rbdAX1kFSDYeZGLipIZZKyQP0O5Q==" + }, + "serve-static": { + "version": "1.15.0", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.15.0.tgz", + "integrity": "sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g==", + "requires": { + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "parseurl": "~1.3.3", + "send": "0.18.0" + } + }, + "set-function-length": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz", + "integrity": "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==", + "requires": { + "define-data-property": "^1.1.4", + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.4", + "gopd": "^1.0.1", + "has-property-descriptors": "^1.0.2" + } + }, + "setprototypeof": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", + "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==" + }, + "shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dev": true, + "requires": { + "shebang-regex": "^3.0.0" + } + }, + "shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "dev": true + }, + "side-channel": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.6.tgz", + "integrity": "sha512-fDW/EZ6Q9RiO8eFG8Hj+7u/oW+XrPTIChwCOM2+th2A6OblDtYYIpve9m+KvI9Z4C9qSEXlaGR6bTEYHReuglA==", + "requires": { + "call-bind": "^1.0.7", + "es-errors": "^1.3.0", + "get-intrinsic": "^1.2.4", + "object-inspect": "^1.13.1" + } + }, + "signal-exit": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==", + "dev": true + }, + "sisteransi": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/sisteransi/-/sisteransi-1.0.5.tgz", + "integrity": "sha512-bLGGlR1QxBcynn2d5YmDX4MGjlZvy2MRBDRNHLJ8VI6l6+9FUiyTFNJ0IveOSP0bcXgVDPRcfGqA0pjaqUpfVg==", + "dev": true + }, + "slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "dev": true + }, + "smart-buffer": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/smart-buffer/-/smart-buffer-4.2.0.tgz", + "integrity": "sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==" + }, + "socks": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/socks/-/socks-2.7.1.tgz", + "integrity": "sha512-7maUZy1N7uo6+WVEX6psASxtNlKaNVMlGQKkG/63nEDdLOWNbiUMoLK7X4uYoLhQstau72mLgfEWcXcwsaHbYQ==", + "requires": { + "ip": "^2.0.0", + "smart-buffer": "^4.2.0" + } + }, + "socks-proxy-agent": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/socks-proxy-agent/-/socks-proxy-agent-7.0.0.tgz", + "integrity": "sha512-Fgl0YPZ902wEsAyiQ+idGd1A7rSFx/ayC1CQVMw5P+EQx2V0SgpGtf6OKFhVjPflPUl9YMmEOnmfjCdMUsygww==", + "requires": { + "agent-base": "^6.0.2", + "debug": "^4.3.3", + "socks": "^2.6.2" + } + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + }, + "source-map-support": { + "version": "0.5.13", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.13.tgz", + "integrity": "sha512-SHSKFHadjVA5oR4PPqhtAVdcBWwRYVd6g6cAXnIbRiIwc2EhPrTuKUBdSLvlEKyIP3GCf89fltvcZiP9MMFA1w==", + "dev": true, + "requires": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + } + }, + "sprintf-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha512-D9cPgkvLlV3t3IzL0D0YLvGA9Ahk4PcvVwUbN0dSGr1aP0Nrt4AEnTUbuGvquEC0mA64Gqt1fzirlRs5ibXx8g==", + "dev": true + }, + "sqlstring": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/sqlstring/-/sqlstring-2.3.3.tgz", + "integrity": "sha512-qC9iz2FlN7DQl3+wjwn3802RTyjCx7sDvfQEXchwa6CWOx07/WVfh91gBmQ9fahw8snwGEWU3xGzOt4tFyHLxg==" + }, + "stack-utils": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/stack-utils/-/stack-utils-2.0.6.tgz", + "integrity": "sha512-XlkWvfIm6RmsWtNJx+uqtKLS8eqFbxUg0ZzLXqY0caEy9l7hruX8IpiDnjsLavoBgqCCR71TqWO8MaXYheJ3RQ==", + "dev": true, + "requires": { + "escape-string-regexp": "^2.0.0" + }, + "dependencies": { + "escape-string-regexp": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz", + "integrity": "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==", + "dev": true + } + } + }, + "statuses": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", + "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==" + }, + "string-length": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/string-length/-/string-length-4.0.2.tgz", + "integrity": "sha512-+l6rNN5fYHNhZZy41RXsYptCjA2Igmq4EG7kZAYFQI1E1VTXarr6ZPXBg6eq7Y6eK4FEhY6AJlyuFIb/v/S0VQ==", + "dev": true, + "requires": { + "char-regex": "^1.0.2", + "strip-ansi": "^6.0.0" + } + }, + "string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dev": true, + "requires": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + } + }, + "strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dev": true, + "requires": { + "ansi-regex": "^5.0.1" + } + }, + "strip-bom": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-4.0.0.tgz", + "integrity": "sha512-3xurFv5tEgii33Zi8Jtp55wEIILR9eh34FAW00PZf+JnSsTmV/ioewSgQl97JHvgjoRGwPShsWm+IdrxB35d0w==", + "dev": true + }, + "strip-final-newline": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz", + "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==", + "dev": true + }, + "strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "dev": true + }, + "supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + }, + "supports-preserve-symlinks-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", + "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", + "dev": true + }, + "test-exclude": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-6.0.0.tgz", + "integrity": "sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==", + "dev": true, + "requires": { + "@istanbuljs/schema": "^0.1.2", + "glob": "^7.1.4", + "minimatch": "^3.0.4" + } + }, + "text-table": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", + "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", + "dev": true + }, + "tiny-lru": { + "version": "11.0.1", + "resolved": "https://registry.npmjs.org/tiny-lru/-/tiny-lru-11.0.1.tgz", + "integrity": "sha512-iNgFugVuQgBKrqeO/mpiTTgmBsTP0WL6yeuLfLs/Ctf0pI/ixGqIRm8sDCwMcXGe9WWvt2sGXI5mNqZbValmJg==" + }, + "tmpl": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/tmpl/-/tmpl-1.0.5.tgz", + "integrity": "sha512-3f0uOEAQwIqGuWW2MVzYg8fV/QNnc/IpuJNG837rLuczAaLVHslWHZQj4IGiEl5Hs3kkbhwL9Ab7Hrsmuj+Smw==", + "dev": true + }, + "to-fast-properties": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", + "integrity": "sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==", + "dev": true + }, + "to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "requires": { + "is-number": "^7.0.0" + } + }, + "toidentifier": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", + "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==" + }, + "ts-jest": { + "version": "29.1.1", + "resolved": "https://registry.npmjs.org/ts-jest/-/ts-jest-29.1.1.tgz", + "integrity": "sha512-D6xjnnbP17cC85nliwGiL+tpoKN0StpgE0TeOjXQTU6MVCfsB4v7aW05CgQ/1OywGb0x/oy9hHFnN+sczTiRaA==", + "dev": true, + "requires": { + "bs-logger": "0.x", + "fast-json-stable-stringify": "2.x", + "jest-util": "^29.0.0", + "json5": "^2.2.3", + "lodash.memoize": "4.x", + "make-error": "1.x", + "semver": "^7.5.3", + "yargs-parser": "^21.0.1" + }, + "dependencies": { + "lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dev": true, + "requires": { + "yallist": "^4.0.0" + } + }, + "semver": { + "version": "7.5.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", + "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", + "dev": true, + "requires": { + "lru-cache": "^6.0.0" + } + }, + "yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", + "dev": true + } + } + }, + "ts-node": { + "version": "10.9.1", + "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.1.tgz", + "integrity": "sha512-NtVysVPkxxrwFGUUxGYhfux8k78pQB3JqYBXlLRZgdGUqTO5wU/UyHop5p70iEbGhB7q5KmiZiU0Y3KlJrScEw==", + "dev": true, + "requires": { + "@cspotcode/source-map-support": "^0.8.0", + "@tsconfig/node10": "^1.0.7", + "@tsconfig/node12": "^1.0.7", + "@tsconfig/node14": "^1.0.0", + "@tsconfig/node16": "^1.0.2", + "acorn": "^8.4.1", + "acorn-walk": "^8.1.1", + "arg": "^4.1.0", + "create-require": "^1.1.0", + "diff": "^4.0.1", + "make-error": "^1.1.1", + "v8-compile-cache-lib": "^3.0.1", + "yn": "3.1.1" + } + }, + "tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "dev": true + }, + "tsutils": { + "version": "3.21.0", + "resolved": "https://registry.npmjs.org/tsutils/-/tsutils-3.21.0.tgz", + "integrity": "sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA==", + "dev": true, + "requires": { + "tslib": "^1.8.1" + } + }, + "type-check": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", + "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", + "dev": true, + "requires": { + "prelude-ls": "^1.2.1" + } + }, + "type-detect": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", + "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==", + "dev": true + }, + "type-fest": { + "version": "0.21.3", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz", + "integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==", + "dev": true + }, + "type-is": { + "version": "1.6.18", + "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", + "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", + "requires": { + "media-typer": "0.3.0", + "mime-types": "~2.1.24" + } + }, + "typeforce": { + "version": "1.18.0", + "resolved": "https://registry.npmjs.org/typeforce/-/typeforce-1.18.0.tgz", + "integrity": "sha512-7uc1O8h1M1g0rArakJdf0uLRSSgFcYexrVoKo+bzJd32gd4gDy2L/Z+8/FjPnU9ydY3pEnVPtr9FyscYY60K1g==" + }, + "typescript": { + "version": "4.9.5", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.5.tgz", + "integrity": "sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g==" + }, + "unpipe": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", + "integrity": "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ==" + }, + "update-browserslist-db": { + "version": "1.0.13", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.13.tgz", + "integrity": "sha512-xebP81SNcPuNpPP3uzeW1NYXxI3rxyJzF3pD6sH4jE7o/IX+WtSpwnVU+qIsDPyk0d3hmFQ7mjqc6AtV604hbg==", + "dev": true, + "requires": { + "escalade": "^3.1.1", + "picocolors": "^1.0.0" + } + }, + "uri-js": { + "version": "4.4.1", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz", + "integrity": "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg==", + "dev": true, + "requires": { + "punycode": "^2.1.0" + } + }, + "utils-merge": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", + "integrity": "sha512-pMZTvIkT1d+TFGvDOqodOclx0QWkkgi6Tdoa8gC8ffGAAqz9pzPTZWAybbsHHoED/ztMtkv/VoYTYyShUn81hA==" + }, + "v8-compile-cache-lib": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz", + "integrity": "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==", + "dev": true + }, + "v8-to-istanbul": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/v8-to-istanbul/-/v8-to-istanbul-9.1.0.tgz", + "integrity": "sha512-6z3GW9x8G1gd+JIIgQQQxXuiJtCXeAjp6RaPEPLv62mH3iPHPxV6W3robxtCzNErRo6ZwTmzWhsbNvjyEBKzKA==", + "dev": true, + "requires": { + "@jridgewell/trace-mapping": "^0.3.12", + "@types/istanbul-lib-coverage": "^2.0.1", + "convert-source-map": "^1.6.0" + } + }, + "varuint-bitcoin": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/varuint-bitcoin/-/varuint-bitcoin-1.1.2.tgz", + "integrity": "sha512-4EVb+w4rx+YfVM32HQX42AbbT7/1f5zwAYhIujKXKk8NQK+JfRVl3pqT3hjNn/L+RstigmGGKVwHA/P0wgITZw==", + "requires": { + "safe-buffer": "^5.1.1" + } + }, + "vary": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", + "integrity": "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg==" + }, + "walker": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/walker/-/walker-1.0.8.tgz", + "integrity": "sha512-ts/8E8l5b7kY0vlWLewOkDXMmPdLcVV4GmOQLyxuSswIJsweeFZtAsMF7k1Nszz+TYBQrlYRmzOnr398y1JemQ==", + "dev": true, + "requires": { + "makeerror": "1.0.12" + } + }, + "which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dev": true, + "requires": { + "isexe": "^2.0.0" + } + }, + "wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dev": true, + "requires": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + } + } + }, + "wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", + "dev": true + }, + "write-file-atomic": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/write-file-atomic/-/write-file-atomic-4.0.2.tgz", + "integrity": "sha512-7KxauUdBmSdWnmpaGFg+ppNjKF8uNLry8LyzjauQDOVONfFLNKrKvQOxZ/VuTIcS/gge/YNahf5RIIQWTSarlg==", + "dev": true, + "requires": { + "imurmurhash": "^0.1.4", + "signal-exit": "^3.0.7" + } + }, + "ws": { + "version": "8.18.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.0.tgz", + "integrity": "sha512-8VbfWfHLbbwu3+N6OKsOMpBdT4kXPDDB9cJk2bJ6mh9ucxdlnNvH1e+roYkKmN9Nxw2yjz7VzeO9oOz2zJ04Pw==", + "requires": {} + }, + "y18n": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", + "dev": true + }, + "yallist": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", + "dev": true + }, + "yargs": { + "version": "17.7.1", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.1.tgz", + "integrity": "sha512-cwiTb08Xuv5fqF4AovYacTFNxk62th7LKJ6BL9IGUpTJrWoU7/7WdQGTP2SjKf1dUNBGzDd28p/Yfs/GI6JrLw==", + "dev": true, + "requires": { + "cliui": "^8.0.1", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.3", + "y18n": "^5.0.5", + "yargs-parser": "^21.1.1" + } + }, + "yargs-parser": { + "version": "21.1.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", + "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", + "dev": true + }, + "yn": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", + "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==", + "dev": true + }, + "yocto-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", + "dev": true + } + } +} diff --git a/backend/package.json b/backend/package.json index 0695188884..24e76e3dde 100644 --- a/backend/package.json +++ b/backend/package.json @@ -1,8 +1,8 @@ { "name": "mempool-backend", - "version": "2.0.0", + "version": "3.0.0-dev", "description": "Bitcoin mempool visualizer and blockchain explorer backend", - "license": "MIT", + "license": "GNU Affero General Public License v3.0", "homepage": "https://mempool.space", "repository": { "type": "git", @@ -16,27 +16,59 @@ "mempool", "blockchain", "explorer", - "liquid" + "liquid", + "lightning" ], "main": "index.ts", "scripts": { - "build": "tsc", - "start": "npm run build && node dist/index.js", - "test": "echo \"Error: no test specified\" && exit 1" + "tsc": "./node_modules/typescript/bin/tsc -p tsconfig.build.json", + "build": "npm run tsc && npm run create-resources", + "clean": "rm -rf ./dist/ ./node_modules/ ./package/ ./rust-gbt/", + "create-resources": "cp ./src/tasks/price-feeds/mtgox-weekly.json ./dist/tasks && node dist/api/fetch-version.js", + "package": "./npm_package.sh", + "package-rm-build-deps": "./npm_package_rm_build_deps.sh", + "preinstall": "cd ../rust/gbt && npm run build-release && npm run to-backend", + "start": "node --max-old-space-size=2048 dist/index.js", + "start-production": "node --max-old-space-size=16384 dist/index.js", + "reindex-updated-pools": "npm run start-production --update-pools", + "reindex-all-blocks": "npm run start-production --update-pools --reindex-blocks", + "test": "./node_modules/.bin/jest --coverage", + "test:ci": "CI=true ./node_modules/.bin/jest --coverage", + "lint": "./node_modules/.bin/eslint . --ext .ts", + "lint:fix": "./node_modules/.bin/eslint . --ext .ts --fix", + "prettier": "./node_modules/.bin/prettier --write \"src/**/*.{js,ts}\"" }, "dependencies": { - "compression": "^1.7.4", - "express": "^4.17.1", - "mysql2": "^1.6.1", - "request": "^2.88.2", - "ws": "^7.3.1" + "@babel/core": "^7.24.0", + "@mempool/electrum-client": "1.1.9", + "@types/node": "^18.15.3", + "axios": "~1.7.2", + "bitcoinjs-lib": "~6.1.3", + "crypto-js": "~4.2.0", + "express": "~4.19.2", + "maxmind": "~4.3.11", + "mysql2": "~3.10.0", + "rust-gbt": "file:./rust-gbt", + "redis": "^4.6.6", + "socks-proxy-agent": "~7.0.0", + "typescript": "~4.9.3", + "ws": "~8.18.0" }, "devDependencies": { - "@types/compression": "^1.0.1", - "@types/express": "^4.17.2", - "@types/request": "^2.48.2", - "@types/ws": "^6.0.4", - "tslint": "^5.11.0", - "typescript": "^3.6.4" + "@babel/code-frame": "^7.18.6", + "@babel/core": "^7.24.0", + "@types/compression": "^1.7.2", + "@types/crypto-js": "^4.1.1", + "@types/express": "^4.17.17", + "@types/jest": "^29.5.0", + "@types/ws": "~8.5.10", + "@typescript-eslint/eslint-plugin": "^5.55.0", + "@typescript-eslint/parser": "^5.55.0", + "eslint": "^8.36.0", + "eslint-config-prettier": "^8.8.0", + "jest": "^29.5.0", + "prettier": "^3.0.0", + "ts-jest": "^29.1.1", + "ts-node": "^10.9.1" } } diff --git a/backend/src/__fixtures__/mempool-config.template.json b/backend/src/__fixtures__/mempool-config.template.json new file mode 100644 index 0000000000..3796b7f22e --- /dev/null +++ b/backend/src/__fixtures__/mempool-config.template.json @@ -0,0 +1,153 @@ +{ + "MEMPOOL": { + "ENABLED": true, + "OFFICIAL": false, + "NETWORK": "__MEMPOOL_NETWORK__", + "BACKEND": "__MEMPOOL_BACKEND__", + "BLOCKS_SUMMARIES_INDEXING": true, + "GOGGLES_INDEXING": false, + "HTTP_PORT": 1, + "UNIX_SOCKET_PATH": "/mempool/socket/mempool-bitcoin-mainnet", + "SPAWN_CLUSTER_PROCS": 2, + "API_URL_PREFIX": "__MEMPOOL_API_URL_PREFIX__", + "AUTOMATIC_POOLS_UPDATE": false, + "POLL_RATE_MS": 3, + "CACHE_DIR": "__MEMPOOL_CACHE_DIR__", + "CACHE_ENABLED": true, + "CLEAR_PROTECTION_MINUTES": 4, + "RECOMMENDED_FEE_PERCENTILE": 5, + "BLOCK_WEIGHT_UNITS": 6, + "INITIAL_BLOCKS_AMOUNT": 7, + "MEMPOOL_BLOCKS_AMOUNT": 8, + "USE_SECOND_NODE_FOR_MINFEE": 10, + "EXTERNAL_ASSETS": [], + "EXTERNAL_MAX_RETRY": 12, + "EXTERNAL_RETRY_INTERVAL": 13, + "USER_AGENT": "__MEMPOOL_USER_AGENT__", + "STDOUT_LOG_MIN_PRIORITY": "__MEMPOOL_STDOUT_LOG_MIN_PRIORITY__", + "INDEXING_BLOCKS_AMOUNT": 14, + "POOLS_JSON_TREE_URL": "__MEMPOOL_POOLS_JSON_TREE_URL__", + "POOLS_JSON_URL": "__MEMPOOL_POOLS_JSON_URL__", + "AUDIT": true, + "RUST_GBT": false, + "LIMIT_GBT": false, + "CPFP_INDEXING": true, + "MAX_BLOCKS_BULK_QUERY": 999, + "DISK_CACHE_BLOCK_INTERVAL": 999, + "MAX_PUSH_TX_SIZE_WEIGHT": 4000000, + "ALLOW_UNREACHABLE": true, + "PRICE_UPDATES_PER_HOUR": 1, + "MAX_TRACKED_ADDRESSES": 1 + }, + "CORE_RPC": { + "HOST": "__CORE_RPC_HOST__", + "PORT": 15, + "USERNAME": "__CORE_RPC_USERNAME__", + "PASSWORD": "__CORE_RPC_PASSWORD__", + "TIMEOUT": 1000, + "COOKIE": false, + "COOKIE_PATH": "__CORE_RPC_COOKIE_PATH__" + }, + "ELECTRUM": { + "HOST": "__ELECTRUM_HOST__", + "PORT": 16, + "TLS_ENABLED": true + }, + "ESPLORA": { + "REST_API_URL": "__ESPLORA_REST_API_URL__", + "UNIX_SOCKET_PATH": "__ESPLORA_UNIX_SOCKET_PATH__", + "BATCH_QUERY_BASE_SIZE": 1000, + "RETRY_UNIX_SOCKET_AFTER": 888, + "REQUEST_TIMEOUT": 10000, + "FALLBACK_TIMEOUT": 5000, + "FALLBACK": [], + "MAX_BEHIND_TIP": 2 + }, + "SECOND_CORE_RPC": { + "HOST": "__SECOND_CORE_RPC_HOST__", + "PORT": 17, + "USERNAME": "__SECOND_CORE_RPC_USERNAME__", + "PASSWORD": "__SECOND_CORE_RPC_PASSWORD__", + "TIMEOUT": 2000, + "COOKIE": false, + "COOKIE_PATH": "__SECOND_CORE_RPC_COOKIE_PATH__" + }, + "DATABASE": { + "ENABLED": false, + "HOST": "__DATABASE_HOST__", + "SOCKET": "__DATABASE_SOCKET__", + "PORT": 18, + "DATABASE": "__DATABASE_DATABASE__", + "USERNAME": "__DATABASE_USERNAME__", + "PASSWORD": "__DATABASE_PASSWORD__", + "PID_DIR": "__DATABASE_PID_FILE__", + "TIMEOUT": 3000, + "POOL_SIZE": 100 + }, + "SYSLOG": { + "ENABLED": false, + "HOST": "__SYSLOG_HOST__", + "PORT": 19, + "MIN_PRIORITY": "__SYSLOG_MIN_PRIORITY__", + "FACILITY": "__SYSLOG_FACILITY__" + }, + "STATISTICS": { + "ENABLED": false, + "TX_PER_SECOND_SAMPLE_PERIOD": 20 + }, + "SOCKS5PROXY": { + "ENABLED": true, + "USE_ONION": true, + "HOST": "__SOCKS5PROXY_HOST__", + "PORT": "__SOCKS5PROXY_PORT__", + "USERNAME": "__SOCKS5PROXY_USERNAME__", + "PASSWORD": "__SOCKS5PROXY_PASSWORD__" + }, + "EXTERNAL_DATA_SERVER": { + "MEMPOOL_API": "__EXTERNAL_DATA_SERVER_MEMPOOL_API__", + "MEMPOOL_ONION": "__EXTERNAL_DATA_SERVER_MEMPOOL_ONION__", + "LIQUID_API": "__EXTERNAL_DATA_SERVER_LIQUID_API__", + "LIQUID_ONION": "__EXTERNAL_DATA_SERVER_LIQUID_ONION__" + }, + "LIGHTNING": { + "ENABLED": true, + "BACKEND": "__LIGHTNING_BACKEND__", + "TOPOLOGY_FOLDER": "__LIGHTNING_TOPOLOGY_FOLDER__", + "STATS_REFRESH_INTERVAL": 600, + "GRAPH_REFRESH_INTERVAL": 600, + "LOGGER_UPDATE_INTERVAL": 30, + "FORENSICS_INTERVAL": 43200, + "FORENSICS_RATE_LIMIT": 1234 + }, + "LND": { + "TLS_CERT_PATH": "", + "MACAROON_PATH": "", + "REST_API_URL": "https://localhost:8080", + "TIMEOUT": 10000 + }, + "CLIGHTNING": { + "SOCKET": "__CLIGHTNING_SOCKET__" + }, + "REPLICATION": { + "ENABLED": false, + "AUDIT": false, + "AUDIT_START_HEIGHT": 774000, + "STATISTICS": false, + "STATISTICS_START_TIME": 1481932800, + "SERVERS": [] + }, + "MEMPOOL_SERVICES": { + "API": "", + "ACCELERATIONS": false + }, + "REDIS": { + "ENABLED": false, + "UNIX_SOCKET_PATH": "/tmp/redis.sock", + "BATCH_QUERY_BASE_SIZE": 5000 + }, + "FIAT_PRICE": { + "ENABLED": true, + "PAID": false, + "API_KEY": "__MEMPOOL_CURRENCY_API_KEY__" + } +} diff --git a/backend/src/__tests__/api/common.ts b/backend/src/__tests__/api/common.ts new file mode 100644 index 0000000000..74a7db88f7 --- /dev/null +++ b/backend/src/__tests__/api/common.ts @@ -0,0 +1,40 @@ +import { Common } from '../../api/common'; +import { MempoolTransactionExtended } from '../../mempool.interfaces'; + +const randomTransactions = require('./test-data/transactions-random.json'); +const replacedTransactions = require('./test-data/transactions-replaced.json'); +const rbfTransactions = require('./test-data/transactions-rbfs.json'); +const nonStandardTransactions = require('./test-data/non-standard-txs.json'); + +describe('Common', () => { + describe('RBF', () => { + const newTransactions = rbfTransactions.concat(randomTransactions); + test('should detect RBF transactions with fast method', () => { + const result: { [txid: string]: MempoolTransactionExtended[] } = Common.findRbfTransactions(newTransactions, replacedTransactions); + expect(Object.values(result).length).toEqual(2); + expect(result).toHaveProperty('7219d95161f3718335991ac6d967d24eedec370908c9879bb1e192e6d797d0a6'); + expect(result).toHaveProperty('5387881d695d4564d397026dc5f740f816f8390b4b2c5ec8c20309122712a875'); + }); + + test('should detect RBF transactions with scalable method', () => { + const result: { [txid: string]: MempoolTransactionExtended[] } = Common.findRbfTransactions(newTransactions, replacedTransactions, true); + expect(Object.values(result).length).toEqual(2); + expect(result).toHaveProperty('7219d95161f3718335991ac6d967d24eedec370908c9879bb1e192e6d797d0a6'); + expect(result).toHaveProperty('5387881d695d4564d397026dc5f740f816f8390b4b2c5ec8c20309122712a875'); + }); + }); + + describe('Mempool Goggles', () => { + test('should detect nonstandard transactions', () => { + nonStandardTransactions.forEach((tx) => { + expect(Common.isNonStandard(tx)).toEqual(true); + }); + }); + + test('should not misclassify as nonstandard transactions', () => { + randomTransactions.forEach((tx) => { + expect(Common.isNonStandard(tx)).toEqual(false); + }); + }); + }); +}); diff --git a/backend/src/__tests__/api/difficulty-adjustment.test.ts b/backend/src/__tests__/api/difficulty-adjustment.test.ts new file mode 100644 index 0000000000..a365d34290 --- /dev/null +++ b/backend/src/__tests__/api/difficulty-adjustment.test.ts @@ -0,0 +1,166 @@ +import { + calcBitsDifference, + calcDifficultyAdjustment, + DifficultyAdjustment, +} from '../../api/difficulty-adjustment'; + +describe('Mempool Difficulty Adjustment', () => { + test('should calculate Difficulty Adjustments properly', () => { + const dt = (dtString) => { + return Math.floor(new Date(dtString).getTime() / 1000); + }; + + const vectors = [ + [ // Vector 1 (normal adjustment) + [ // Inputs + dt('2024-02-02T15:42:06.000Z'), // Last DA time (in seconds) + dt('2024-02-08T14:43:05.000Z'), // timestamp of 504 blocks ago (in seconds) + dt('2024-02-11T22:43:01.000Z'), // Current time (now) (in seconds) + 830027, // Current block height + 7.333505241141637, // Previous retarget % (Passed through) + 'mainnet', // Network (if testnet, next value is non-zero) + 0, // Latest block timestamp in seconds (only used if difficulty already locked in) + ], + { // Expected Result + progressPercent: 71.97420634920636, + difficultyChange: 8.512745140778843, + estimatedRetargetDate: 1708004001715, + remainingBlocks: 565, + remainingTime: 312620715, + previousRetarget: 7.333505241141637, + previousTime: 1706888526, + nextRetargetHeight: 830592, + timeAvg: 553311, + adjustedTimeAvg: 553311, + timeOffset: 0, + expectedBlocks: 1338.0916666666667, + }, + ], + [ // Vector 2 (within quarter-epoch overlap) + [ // Inputs + dt('2022-08-18T11:07:00.000Z'), // Last DA time (in seconds) + dt('2022-08-16T03:16:54.000Z'), // timestamp of 504 blocks ago (in seconds) + dt('2022-08-19T14:03:53.000Z'), // Current time (now) (in seconds) + 750134, // Current block height + 0.6280047707459726, // Previous retarget % (Passed through) + 'mainnet', // Network (if testnet, next value is non-zero) + 0, // Latest block timestamp in seconds (only used if difficulty already locked in) + ], + { // Expected Result + progressPercent: 9.027777777777777, + difficultyChange: 1.0420538959004633, + estimatedRetargetDate: 1662009048328, + remainingBlocks: 1834, + remainingTime: 1091215328, + previousRetarget: 0.6280047707459726, + previousTime: 1660820820, + nextRetargetHeight: 751968, + timeAvg: 533038, + adjustedTimeAvg: 594992, + timeOffset: 0, + expectedBlocks: 161.68833333333333, + }, + ], + [ // Vector 3 (testnet) + [ // Inputs + dt('2022-08-18T11:07:00.000Z'), // Last DA time (in seconds) + dt('2022-08-16T03:16:54.000Z'), // timestamp of 504 blocks ago (in seconds) + dt('2022-08-19T14:03:53.000Z'), // Current time (now) (in seconds) + 750134, // Current block height + 0.6280047707459726, // Previous retarget % (Passed through) + 'testnet', // Network + dt('2022-08-19T13:52:46.000Z'), // Latest block timestamp in seconds + ], + { // Expected Result is same other than timeOffset + progressPercent: 9.027777777777777, + difficultyChange: 1.0420538959004633, + estimatedRetargetDate: 1662009048328, + remainingBlocks: 1834, + remainingTime: 1091215328, + previousTime: 1660820820, + previousRetarget: 0.6280047707459726, + nextRetargetHeight: 751968, + timeAvg: 533038, + adjustedTimeAvg: 594992, + timeOffset: -667000, // 11 min 7 seconds since last block (testnet only) + // If we add time avg to abs(timeOffset) it makes exactly 1200000 ms, or 20 minutes + expectedBlocks: 161.68833333333333, + }, + ], + [ // Vector 4 (mainnet lock-in (epoch ending 788255)) + [ // Inputs + dt('2023-04-20T09:57:33.000Z'), // Last DA time (in seconds) + dt('2022-08-16T03:16:54.000Z'), // timestamp of 504 blocks ago (in seconds) + dt('2023-05-04T14:54:09.000Z'), // Current time (now) (in seconds) + 788255, // Current block height + 1.7220298879531821, // Previous retarget % (Passed through) + 'mainnet', // Network (if testnet, next value is non-zero) + dt('2023-05-04T14:54:26.000Z'), // Latest block timestamp in seconds + ], + { // Expected Result + progressPercent: 99.95039682539682, + difficultyChange: -1.4512637555574193, + estimatedRetargetDate: 1683212658129, + remainingBlocks: 1, + remainingTime: 609129, + previousRetarget: 1.7220298879531821, + previousTime: 1681984653, + nextRetargetHeight: 788256, + timeAvg: 609129, + adjustedTimeAvg: 609129, + timeOffset: 0, + expectedBlocks: 2045.66, + }, + ], + ] as [[number, number, number, number, number, string, number], DifficultyAdjustment][]; + + for (const vector of vectors) { + const result = calcDifficultyAdjustment(...vector[0]); + // previousRetarget is passed through untouched + expect(result.previousRetarget).toStrictEqual(vector[0][4]); + expect(result).toStrictEqual(vector[1]); + } + }); + + test('should calculate Difficulty change from bits fields of two blocks', () => { + // Check same exponent + check min max for output + expect(calcBitsDifference(0x1d000200, 0x1d000100)).toEqual(100); + expect(calcBitsDifference(0x1d000400, 0x1d000100)).toEqual(300); + expect(calcBitsDifference(0x1d000800, 0x1d000100)).toEqual(300); // Actually 700 + expect(calcBitsDifference(0x1d000100, 0x1d000200)).toEqual(-50); + expect(calcBitsDifference(0x1d000100, 0x1d000400)).toEqual(-75); + expect(calcBitsDifference(0x1d000100, 0x1d000800)).toEqual(-75); // Actually -87.5 + // Check new higher exponent + expect(calcBitsDifference(0x1c000200, 0x1d000001)).toEqual(100); + expect(calcBitsDifference(0x1c000400, 0x1d000001)).toEqual(300); + expect(calcBitsDifference(0x1c000800, 0x1d000001)).toEqual(300); + expect(calcBitsDifference(0x1c000100, 0x1d000002)).toEqual(-50); + expect(calcBitsDifference(0x1c000100, 0x1d000004)).toEqual(-75); + expect(calcBitsDifference(0x1c000100, 0x1d000008)).toEqual(-75); + // Check new lower exponent + expect(calcBitsDifference(0x1d000002, 0x1c000100)).toEqual(100); + expect(calcBitsDifference(0x1d000004, 0x1c000100)).toEqual(300); + expect(calcBitsDifference(0x1d000008, 0x1c000100)).toEqual(300); + expect(calcBitsDifference(0x1d000001, 0x1c000200)).toEqual(-50); + expect(calcBitsDifference(0x1d000001, 0x1c000400)).toEqual(-75); + expect(calcBitsDifference(0x1d000001, 0x1c000800)).toEqual(-75); + // Check error when exponents are too far apart + expect(() => calcBitsDifference(0x1d000001, 0x1a000800)).toThrow( + /Impossible exponent difference/ + ); + // Check invalid inputs + expect(() => calcBitsDifference(0x7f000001, 0x1a000800)).toThrow( + /Invalid bits/ + ); + expect(() => calcBitsDifference(0, 0x1a000800)).toThrow(/Invalid bits/); + expect(() => calcBitsDifference(100.2783, 0x1a000800)).toThrow( + /Invalid bits/ + ); + expect(() => calcBitsDifference(0x00800000, 0x1a000800)).toThrow( + /Invalid bits/ + ); + expect(() => calcBitsDifference(0x1c000000, 0x1a000800)).toThrow( + /Invalid bits/ + ); + }); +}); diff --git a/backend/src/__tests__/api/test-data/non-standard-txs.json b/backend/src/__tests__/api/test-data/non-standard-txs.json new file mode 100644 index 0000000000..286fe29458 --- /dev/null +++ b/backend/src/__tests__/api/test-data/non-standard-txs.json @@ -0,0 +1,52 @@ +[ + { + "txid": "50136231cb7eeeffb17fc41d1cca213426abe5bf3760e3d6421cad0c0edad367", + "version": 1, + "locktime": 0, + "vin": [ + { + "txid": "c7f86fb7b830124057475b282809f3474ef3565daa3de0b599980fb9e84ab019", + "vout": 4217, + "prevout": { + "scriptpubkey": "001466197b5eadd8067ec194a457e1044b6d1fbdd3b3", + "scriptpubkey_asm": "OP_0 OP_PUSHBYTES_20 66197b5eadd8067ec194a457e1044b6d1fbdd3b3", + "scriptpubkey_type": "v0_p2wpkh", + "scriptpubkey_address": "bc1qvcvhkh4dmqr8asv553t7zpztd50mm5ang4na33", + "value": 106 + }, + "scriptsig": "", + "scriptsig_asm": "", + "witness": [ + "3043021f2af6060a142c6cfd7428adad6a50745d2424813d7ced5c0bbcca85e70de1be022021440ca1c8c3ed49ecd1b64dca6911adcd430c5d3dd60d77ffe0072953999f5b01", + "02ead5c34e3d2c506574b562f857576e11380b6ba15d9f0ad7b7303fdaa9c1513d" + ], + "is_coinbase": false, + "sequence": 4294967295 + } + ], + "vout": [ + { + "scriptpubkey": "6a023a29", + "scriptpubkey_asm": "OP_RETURN OP_PUSHBYTES_2 3a29", + "scriptpubkey_type": "op_return", + "value": 0 + }, + { + "scriptpubkey": "6a036d7648", + "scriptpubkey_asm": "OP_RETURN OP_PUSHBYTES_3 6d7648", + "scriptpubkey_type": "op_return", + "value": 0 + } + ], + "size": 186, + "weight": 420, + "sigops": 1, + "fee": 106, + "status": { + "confirmed": true, + "block_height": 836361, + "block_hash": "0000000000000000000341cc26cda4af82cd25f7063c448772228cbf2836915b", + "block_time": 1711448028 + } + } +] \ No newline at end of file diff --git a/backend/src/__tests__/api/test-data/transactions-random.json b/backend/src/__tests__/api/test-data/transactions-random.json new file mode 100644 index 0000000000..4bc0b731c8 --- /dev/null +++ b/backend/src/__tests__/api/test-data/transactions-random.json @@ -0,0 +1,600 @@ +[ + { + "txid": "13f007241d78e8b0b4e57d2ae3fd37bcfe3226534d7cadeba5a549860d960db0", + "version": 2, + "locktime": 0, + "vin": [ + { + "txid": "cb8f206f4e88bec97107089f3e9e61d50cde53d4541992ae19759b71103cf75c", + "vout": 0, + "prevout": { + "scriptpubkey": "0014fd6d15ff832c12f1ff04a5ccd5039f7227b260bd", + "scriptpubkey_asm": "OP_0 OP_PUSHBYTES_20 fd6d15ff832c12f1ff04a5ccd5039f7227b260bd", + "scriptpubkey_type": "v0_p2wpkh", + "scriptpubkey_address": "bc1ql4k3tlur9sf0rlcy5hxd2qulwgnmyc9akehvth", + "value": 610677 + }, + "scriptsig": "", + "scriptsig_asm": "", + "witness": [ + "304302205c430b36ebd2bb327951d83440af1f58f127871b2baada4c4dde2bc0b6721f56021f3445099f1a40e35baeda32e8e3727b505ffba0d882b11f498c7762f4184e9901", + "0236b5edd4fbbcfb045960e42ec8a9968944084785932e32940e8cd2583b37da67" + ], + "is_coinbase": false, + "sequence": 2147483648 + } + ], + "vout": [ + { + "scriptpubkey": "76a9149d32ef812385f3811634e0c0117dd153a5de10a488ac", + "scriptpubkey_asm": "OP_DUP OP_HASH160 OP_PUSHBYTES_20 9d32ef812385f3811634e0c0117dd153a5de10a4 OP_EQUALVERIFY OP_CHECKSIG", + "scriptpubkey_type": "p2pkh", + "scriptpubkey_address": "1FLC7Bag7okAkKPCyZbgZZg3Hh1EuGZ5Rd", + "value": 344697 + }, + { + "scriptpubkey": "00147dee8a7a38abbfb00dbfba365c8d6712934cc491", + "scriptpubkey_asm": "OP_0 OP_PUSHBYTES_20 7dee8a7a38abbfb00dbfba365c8d6712934cc491", + "scriptpubkey_type": "v0_p2wpkh", + "scriptpubkey_address": "bc1q0hhg573c4wlmqrdlhgm9ert8z2f5e3y3lf9hvx", + "value": 265396 + } + ], + "size": 224, + "weight": 572, + "fee": 584, + "status": { + "confirmed": false + }, + "order": 2953680397, + "vsize": 143, + "adjustedVsize": 143, + "sigops": 5, + "feePerVsize": 4.083916083916084, + "adjustedFeePerVsize": 4.083916083916084, + "effectiveFeePerVsize": 4.083916083916084, + "firstSeen": 1691222538, + "uid": 526973, + "inputs": [ + 526728 + ], + "position": { + "block": 7, + "vsize": 21429708.5 + }, + "bestDescendant": null, + "cpfpChecked": true + }, + { + "txid": "8e89b20f8a7fadb0e4cdbe57a00eee224f5076bac5387fc276916724e7c4a16a", + "version": 2, + "locktime": 800571, + "vin": [ + { + "txid": "35e16762459539f3a8e52c5dee6a9ccaa9e9268efed33aa2c6e1b7805e849f24", + "vout": 0, + "prevout": { + "scriptpubkey": "0014d4f16ef275b3e1c4a4ecbef55a164933e0f6460f", + "scriptpubkey_asm": "OP_0 OP_PUSHBYTES_20 d4f16ef275b3e1c4a4ecbef55a164933e0f6460f", + "scriptpubkey_type": "v0_p2wpkh", + "scriptpubkey_address": "bc1q6nckaun4k0suff8vhm6459jfx0s0v3s0ff4ukl", + "value": 1528924 + }, + "scriptsig": "", + "scriptsig_asm": "", + "witness": [ + "3044022019008b26e885bb43da25a11ffac147a057722072eedb68411f114f6e7eb82ebc02201b618264bb97756b88fc3bbc365b73044ac18b33b1067e31cfd5bcd0f50ed2c701", + "039b71145070bd3e8af28e27fa577f2e12ab6bb4e212d3eeaef08b4bc39e8cbc13" + ], + "is_coinbase": false, + "sequence": 4294967293 + }, + { + "txid": "67c27ed0f767526234bcd5f795a31fab8ec4d0251bf12c68f2746951f4110d90", + "vout": 3, + "prevout": { + "scriptpubkey": "0014a7c3d613b321375054b2ac9b6114367bc034ad6f", + "scriptpubkey_asm": "OP_0 OP_PUSHBYTES_20 a7c3d613b321375054b2ac9b6114367bc034ad6f", + "scriptpubkey_type": "v0_p2wpkh", + "scriptpubkey_address": "bc1q5lpavyanyym4q49j4jdkz9pk00qrftt0yqzvk3", + "value": 436523 + }, + "scriptsig": "", + "scriptsig_asm": "", + "witness": [ + "304402204e67285fc656bc45ed082499b076d5dba2fa21d0d7e64a0ae52b19d69a11760002200f037d81ee540b74397844513b72b08ed92b06db76bd20b08f7a0a3b36ab13d501", + "02a3ebae85f0225b6fbb5ff060afce683a4683507a57544605a29ee7d287e591b4" + ], + "is_coinbase": false, + "sequence": 4294967293 + }, + { + "txid": "21c38fb9a2521e438c614f53b19ddd7a5594bcc4b77480e762fd4b702fad3374", + "vout": 1, + "prevout": { + "scriptpubkey": "00149660e34ef88106536c816c037b5b28dd64a812e2", + "scriptpubkey_asm": "OP_0 OP_PUSHBYTES_20 9660e34ef88106536c816c037b5b28dd64a812e2", + "scriptpubkey_type": "v0_p2wpkh", + "scriptpubkey_address": "bc1qjeswxnhcsyr9xmypdsphkkegm4j2syhztgzxv4", + "value": 758149 + }, + "scriptsig": "", + "scriptsig_asm": "", + "witness": [ + "3044022021b556f0aa99329076bcc435338aceaf534963efcab306931b1b2b0461e16e0c02203a78942a3745c4da656bddfd8cf16b85dc04d652904e88682127cdd9ca63339001", + "0298963be4a8f66aca9fcf1c6dc95547aeaa82347543190c91e094c2321142b9f0" + ], + "is_coinbase": false, + "sequence": 4294967293 + }, + { + "txid": "aa998dbae65240a7386bf7d468459551d99c3de8e2f9057ff5f2d38e17daf788", + "vout": 0, + "prevout": { + "scriptpubkey": "00147bb7413a39943b21ded98ad5e6ad7a222d273e17", + "scriptpubkey_asm": "OP_0 OP_PUSHBYTES_20 7bb7413a39943b21ded98ad5e6ad7a222d273e17", + "scriptpubkey_type": "v0_p2wpkh", + "scriptpubkey_address": "bc1q0wm5zw3ejsajrhke3t27dtt6ygkjw0sh9lltg6", + "value": 1067200 + }, + "scriptsig": "", + "scriptsig_asm": "", + "witness": [ + "304402205e2269f7d4ee0513b34354c38e920aef2dabac6f4350afb2dd105ff3ee43ae7b02202870322f2cb85cb0b2b0e38152f018bfff271dc3ec5aed0515854d0b259aaf3d01", + "03b87320cf3263a644a0d3f89c1b4a7304d9dfda9eb8c891560716abcb73e88b99" + ], + "is_coinbase": false, + "sequence": 4294967293 + }, + { + "txid": "230253d195d779d4688ba16993985cd27b2e7a687d8b889b3bc63f19ece36f20", + "vout": 0, + "prevout": { + "scriptpubkey": "001439647bd997819d12dfc72b0fb9ff9ffcb84946f8", + "scriptpubkey_asm": "OP_0 OP_PUSHBYTES_20 39647bd997819d12dfc72b0fb9ff9ffcb84946f8", + "scriptpubkey_type": "v0_p2wpkh", + "scriptpubkey_address": "bc1q89j8hkvhsxw39h789v8mnlulljuyj3hc9zve97", + "value": 361950 + }, + "scriptsig": "", + "scriptsig_asm": "", + "witness": [ + "304402204f7ca868bb9b92a07fecdc6b9dd56e4e1d007ca1405952f98ed6bc416345b5f2022055320a97791417abf6628fcf6513ac5785b06c630f854d8595e96ea06c3841d301", + "03a3ffe8e3ef2eea129b227e9658164bae0a6d21c17da6de9973ba34d9e04b21a0" + ], + "is_coinbase": false, + "sequence": 4294967293 + }, + { + "txid": "670771e265a0b62dbd3c1fec2b865177eaf0bafd0ae49dd40a1c9fcd9a847a81", + "vout": 0, + "prevout": { + "scriptpubkey": "0014d45d1b0022c7387e42c5452ced561bdb8fd4b521", + "scriptpubkey_asm": "OP_0 OP_PUSHBYTES_20 d45d1b0022c7387e42c5452ced561bdb8fd4b521", + "scriptpubkey_type": "v0_p2wpkh", + "scriptpubkey_address": "bc1q63w3kqpzcuu8usk9g5kw64smmw8afdfpxmc2m0", + "value": 453275 + }, + "scriptsig": "", + "scriptsig_asm": "", + "witness": [ + "3044022071312921800441903b2099e723add8702dd0f92ec11526ff87acf6967ec64cbd02203deabe7ed56d5daaa9a95c5a607b1ab705ff1c46bc6984a6dca120e63a91768601", + "0257302ac8d9c4c8f9b1744f19bb432359326b9cc7bdddeeab9202749a6d92be58" + ], + "is_coinbase": false, + "sequence": 4294967293 + }, + { + "txid": "0af82159eee2b69242f2ff032636e410b67ec1ace52e55fb0d20ed814cd64803", + "vout": 0, + "prevout": { + "scriptpubkey": "001459e4d6bfefc6b45f955a69c4aeca26348e9d54ed", + "scriptpubkey_asm": "OP_0 OP_PUSHBYTES_20 59e4d6bfefc6b45f955a69c4aeca26348e9d54ed", + "scriptpubkey_type": "v0_p2wpkh", + "scriptpubkey_address": "bc1qt8jdd0l0c669l926d8z2aj3xxj8f648dtyn7tc", + "value": 439961 + }, + "scriptsig": "", + "scriptsig_asm": "", + "witness": [ + "3044022027540322e92c23c5513aa2587e7feb56a8ce82f879269d6b3cbd425634b44f8e022045572dee7262b02130bfe32d8aa8abbfaa64e101abfc819bba5380c78876692d01", + "03fe02262d87f4a5289d3dd66e3d9a74cd49fa1cad0249284a7451896a827249a5" + ], + "is_coinbase": false, + "sequence": 4294967293 + }, + { + "txid": "68cf9c784870a4f888f044755f7ce318557f652461db8ef887d279672f186018", + "vout": 0, + "prevout": { + "scriptpubkey": "001454822b2d5d52597a78b630921cf439a41e32f2f9", + "scriptpubkey_asm": "OP_0 OP_PUSHBYTES_20 54822b2d5d52597a78b630921cf439a41e32f2f9", + "scriptpubkey_type": "v0_p2wpkh", + "scriptpubkey_address": "bc1q2jpzkt2a2fvh579kxzfpeape5s0r9uhewhl5n4", + "value": 227639 + }, + "scriptsig": "", + "scriptsig_asm": "", + "witness": [ + "304402203ad511d6a8730748b8828bc38897d360451adf620ebdc1d229c08c097c80bef202202f50c793d95b5200cf2258e03896a3be7720df0eb3b8c810c86db74341a7e83e01", + "0294992e9f4546e6e119741f908411ae531e9d1ff732d69b4dff8172aaf2a4b216" + ], + "is_coinbase": false, + "sequence": 4294967293 + }, + { + "txid": "793f01dfdb19bf41f958fd917c16d9c4dd5d5e1a5c0434bfdb367212659d1b5b", + "vout": 0, + "prevout": { + "scriptpubkey": "0014f54edf8ae647b5300e2674523254e923d93d169f", + "scriptpubkey_asm": "OP_0 OP_PUSHBYTES_20 f54edf8ae647b5300e2674523254e923d93d169f", + "scriptpubkey_type": "v0_p2wpkh", + "scriptpubkey_address": "bc1q748dlzhxg76nqr3xw3fry48fy0vn695lvhlkxv", + "value": 227070 + }, + "scriptsig": "", + "scriptsig_asm": "", + "witness": [ + "304402206e807ab616f4f2887ba703ae744d856142d9aca8128698419bbb67fb4fad8177022060fc65c7cd66baa88ad1e1d317a6edd5f6cb52fe8bff6e5405ffa1acf9d945d901", + "02a0ad0167c6e9edf62677404d74d3b80ea276e47e758ffaa6ca17bd65ac79f7aa" + ], + "is_coinbase": false, + "sequence": 4294967293 + } + ], + "vout": [ + { + "scriptpubkey": "00148a5c45ccfc29d209940d94525e2edb7743a1ad8a", + "scriptpubkey_asm": "OP_0 OP_PUSHBYTES_20 8a5c45ccfc29d209940d94525e2edb7743a1ad8a", + "scriptpubkey_type": "v0_p2wpkh", + "scriptpubkey_address": "bc1q3fwytn8u98fqn9qdj3f9utkmwap6rtv2ym33zm", + "value": 5500000 + } + ], + "size": 1375, + "weight": 2605, + "fee": 691, + "status": { + "confirmed": false + }, + "order": 1788986599, + "vsize": 651, + "adjustedVsize": 651.25, + "sigops": 9, + "feePerVsize": 1.0610364683301343, + "adjustedFeePerVsize": 1.0610364683301343, + "effectiveFeePerVsize": 1.0610364683301343, + "firstSeen": 1691163298, + "uid": 120494, + "inputs": [], + "position": { + "block": 7, + "vsize": 93780091.5 + }, + "bestDescendant": null, + "cpfpChecked": true + }, + { + "txid": "20b984492b5264162a4c92c9a34bc7fa08b67d669de7b4c5982ad3cb28aaecf6", + "version": 2, + "locktime": 0, + "vin": [ + { + "txid": "3adda6afd547193793c248e667c2b7dbf26d705003de65e3a25e5be698286aef", + "vout": 2, + "prevout": { + "scriptpubkey": "0014989cf12774fc705609610c7b9419f2d1c4807644", + "scriptpubkey_asm": "OP_0 OP_PUSHBYTES_20 989cf12774fc705609610c7b9419f2d1c4807644", + "scriptpubkey_type": "v0_p2wpkh", + "scriptpubkey_address": "bc1qnzw0zfm5l3c9vztpp3aegx0j68zgqajyffr2r6", + "value": 27619 + }, + "scriptsig": "", + "scriptsig_asm": "", + "witness": [ + "304402205d7f1e0d928982645c2bcc4c730c4545c382d6520c2a14eebc71594702cd06b302200511d452ce51c79017536f50acb115eefe7c04506ad12b9307d2b5d56b999beb01", + "03716cb4f0430fe69c596a12c6680c55803150645989b406772838d548cde7cca5" + ], + "is_coinbase": false, + "sequence": 4294967295 + } + ], + "vout": [ + { + "scriptpubkey": "6a5d0614c0a2331441", + "scriptpubkey_asm": "OP_RETURN OP_PUSHNUM_13 OP_PUSHBYTES_6 14c0a2331441", + "scriptpubkey_type": "op_return", + "value": 0 + }, + { + "scriptpubkey": "5114d71c6c3ea7ba7e6ee477a0bfd82c20c78997882c", + "scriptpubkey_asm": "OP_PUSHNUM_1 OP_PUSHBYTES_20 d71c6c3ea7ba7e6ee477a0bfd82c20c78997882c", + "scriptpubkey_type": "unknown", + "scriptpubkey_address": "bc1p6uwxc048hflxaerh5zlastpqc7ye0zpvq7gq2a", + "value": 546 + }, + { + "scriptpubkey": "0014989cf12774fc705609610c7b9419f2d1c4807644", + "scriptpubkey_asm": "OP_0 OP_PUSHBYTES_20 989cf12774fc705609610c7b9419f2d1c4807644", + "scriptpubkey_type": "v0_p2wpkh", + "scriptpubkey_address": "bc1qnzw0zfm5l3c9vztpp3aegx0j68zgqajyffr2r6", + "value": 23073 + } + ], + "size": 240, + "weight": 633, + "sigops": 1, + "fee": 4000, + "status": { + "confirmed": true, + "block_height": 848136, + "block_hash": "00000000000000000002c69c7a3010fcd596c0c7451c23e7cd1f5e19ebf8ee6d", + "block_time": 1718517071 + } + }, + { + "txid": "b10c0000004da5a9d1d9b4ae32e09f0b3e62d21a5cce5428d4ad714fb444eb5d", + "version": 1, + "locktime": 1231006505, + "vin": [ + { + "txid": "d46a24962c1d7bd6e87d80570c6a53413eaf30d7fde7f52347f13645ae53969b", + "vout": 0, + "prevout": { + "scriptpubkey": "41049434a2dd7c5b82df88f578f8d7fd14e8d36513aaa9c003eb5bd6cb56065e44b7e0227139e8a8e68e7de0a4ed32b8c90edc9673b8a7ea541b52f2a22196f7b8cfac", + "scriptpubkey_asm": "OP_PUSHBYTES_65 049434a2dd7c5b82df88f578f8d7fd14e8d36513aaa9c003eb5bd6cb56065e44b7e0227139e8a8e68e7de0a4ed32b8c90edc9673b8a7ea541b52f2a22196f7b8cf OP_CHECKSIG", + "scriptpubkey_type": "p2pk", + "value": 6102 + }, + "scriptsig": "473044022004f027ae0b19bb7a7aa8fcdf135f1da769d087342020359ef4099a9f0f0ba4ec02206a83a9b78df3fed89a3b6052e69963e1fb08d8f6d17d945e43b51b5214aa41e601", + "scriptsig_asm": "OP_PUSHBYTES_71 3044022004f027ae0b19bb7a7aa8fcdf135f1da769d087342020359ef4099a9f0f0ba4ec02206a83a9b78df3fed89a3b6052e69963e1fb08d8f6d17d945e43b51b5214aa41e601", + "is_coinbase": false, + "sequence": 20090103 + }, + { + "txid": "cb9b47ac04023b29fb633a8ef04af351ac9fd74c57c9a2163f683516274767e3", + "vout": 0, + "prevout": { + "scriptpubkey": "76a914bbb1f7d0f7e15ac088af9bafe25aaac1a59832d088ac", + "scriptpubkey_asm": "OP_DUP OP_HASH160 OP_PUSHBYTES_20 bbb1f7d0f7e15ac088af9bafe25aaac1a59832d0 OP_EQUALVERIFY OP_CHECKSIG", + "scriptpubkey_type": "p2pkh", + "scriptpubkey_address": "1J7SZJry7CX4zWdH3P8E8UJjZrhcLEjJ39", + "value": 1913 + }, + "scriptsig": "46304302204dc2939be89ab6626457fff40aec2cc4e6213e64bcb4d2c43bf6b49358ff638c021f33d2f8fdf6d54a2c82bb7cddc62becc2cbbaca6fd7f3ec927ea975f29ad8510221028b98707adfd6f468d56c1a6067a6f0c7fef43afbacad45384017f8be93a18d40", + "scriptsig_asm": "OP_PUSHBYTES_70 304302204dc2939be89ab6626457fff40aec2cc4e6213e64bcb4d2c43bf6b49358ff638c021f33d2f8fdf6d54a2c82bb7cddc62becc2cbbaca6fd7f3ec927ea975f29ad85102 OP_PUSHBYTES_33 028b98707adfd6f468d56c1a6067a6f0c7fef43afbacad45384017f8be93a18d40", + "is_coinbase": false, + "sequence": 20081031 + }, + { + "txid": "cb9b47ac04023b29fb633a8ef04af351ac9fd74c57c9a2163f683516274767e3", + "vout": 1, + "prevout": { + "scriptpubkey": "52210304e708d258a632ffb128a62ecf5eebd1904e505497d031619513afc8bca7858f2102b9dc03f1133e7cbc7eb311631acc2dbda908fb0f0fae095da2f4dd427f51308a4104678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38c4f35504e51ec112de5c384df7ba0b8d578a4c702b6bf11d5f53ae", + "scriptpubkey_asm": "OP_PUSHNUM_2 OP_PUSHBYTES_33 0304e708d258a632ffb128a62ecf5eebd1904e505497d031619513afc8bca7858f OP_PUSHBYTES_33 02b9dc03f1133e7cbc7eb311631acc2dbda908fb0f0fae095da2f4dd427f51308a OP_PUSHBYTES_65 04678afdb0fe5548271967f1a67130b7105cd6a828e03909a67962e0ea1f61deb649f6bc3f4cef38c4f35504e51ec112de5c384df7ba0b8d578a4c702b6bf11d5f OP_PUSHNUM_3 OP_CHECKMULTISIG", + "scriptpubkey_type": "multisig", + "value": 1971 + }, + "scriptsig": "00453042021e4f6ff73d7b304a5cbf3bb7738abb5f81a4af6335962134ce27a1cc45fec702201b95e3acb7db93257b20651cdcb79af66bf0bb86a8ae5b4e0a5df4e3f86787e2033b303802153b78ce563f89a0ed9414f5aa28ad0d96d6795f9c63021f34793e2878497561e7616291ebdda3024b681cdacc8b863b5b0804cd30c2a481", + "scriptsig_asm": "OP_0 OP_PUSHBYTES_69 3042021e4f6ff73d7b304a5cbf3bb7738abb5f81a4af6335962134ce27a1cc45fec702201b95e3acb7db93257b20651cdcb79af66bf0bb86a8ae5b4e0a5df4e3f86787e203 OP_PUSHBYTES_59 303802153b78ce563f89a0ed9414f5aa28ad0d96d6795f9c63021f34793e2878497561e7616291ebdda3024b681cdacc8b863b5b0804cd30c2a481", + "is_coinbase": false, + "sequence": 19750504 + }, + { + "txid": "45e1cb33599acb071810ccc801b71bd7610865f5b899492946ab1bfbcb61cad6", + "vout": 0, + "prevout": { + "scriptpubkey": "a91419f0b86f61606c6eb51b217698ca7e8bff1e398b87", + "scriptpubkey_asm": "OP_HASH160 OP_PUSHBYTES_20 19f0b86f61606c6eb51b217698ca7e8bff1e398b OP_EQUAL", + "scriptpubkey_type": "p2sh", + "scriptpubkey_address": "344BBtYkhaCXgA7oYSXASUfh4bFieiponG", + "value": 2140 + }, + "scriptsig": "00443041021d1313459a48bd1d0628eec635495f793e970729684394f9b814d2b24012022050be6d9918444e283da0136884f8311ec465d0fed2f8d24b75a8485ebdc13aea013a303702153b78ce563f89a0ed9414f5aa28ad0d96d6795f9c63021e78644ba72eab69fefb5fe50700671bfb91dda699f72ffbb325edc6a3c4ef8239303602153b78ce563f89a0ed9414f5aa28ad0d96d6795f9c63021d2c2db104e70720c39af43b6ba3edd930c26e0818aa59ff9c886281d8ba834ced532103e0a220d36f6f7ed5f3f58c279d055707c454135baf18fd00d798fec3cb52dfbc2103cf689db9313b9f7fc0b984dd9cac750be76041b392919b06f6bf94813da34cd421027f8af2eb6e904deddaa60d5af393d430575eb35e4dfd942a8a5882734b078906410411db93e1dcdb8a016b49840f8c53bc1eb68a382e97b1482ecad7b148a6909a5cb2e0eaddfb84ccf9744464f82e160bfa9b8b64f9d4c03f999b8643f656b412a34104ae1a62fe09c5f51b13905f07f06b99a2f7159b2225f374cd378d71302fa28414e7aab37397f554a7df5f142c21c1b7303b8a0626f1baded5c72a704f7e6cd84c55ae", + "scriptsig_asm": "OP_0 OP_PUSHBYTES_68 3041021d1313459a48bd1d0628eec635495f793e970729684394f9b814d2b24012022050be6d9918444e283da0136884f8311ec465d0fed2f8d24b75a8485ebdc13aea01 OP_PUSHBYTES_58 303702153b78ce563f89a0ed9414f5aa28ad0d96d6795f9c63021e78644ba72eab69fefb5fe50700671bfb91dda699f72ffbb325edc6a3c4ef82 OP_PUSHBYTES_57 303602153b78ce563f89a0ed9414f5aa28ad0d96d6795f9c63021d2c2db104e70720c39af43b6ba3edd930c26e0818aa59ff9c886281d8ba83 OP_PUSHDATA1 532103e0a220d36f6f7ed5f3f58c279d055707c454135baf18fd00d798fec3cb52dfbc2103cf689db9313b9f7fc0b984dd9cac750be76041b392919b06f6bf94813da34cd421027f8af2eb6e904deddaa60d5af393d430575eb35e4dfd942a8a5882734b078906410411db93e1dcdb8a016b49840f8c53bc1eb68a382e97b1482ecad7b148a6909a5cb2e0eaddfb84ccf9744464f82e160bfa9b8b64f9d4c03f999b8643f656b412a34104ae1a62fe09c5f51b13905f07f06b99a2f7159b2225f374cd378d71302fa28414e7aab37397f554a7df5f142c21c1b7303b8a0626f1baded5c72a704f7e6cd84c55ae", + "is_coinbase": false, + "sequence": 16, + "inner_redeemscript_asm": "OP_PUSHNUM_3 OP_PUSHBYTES_33 03e0a220d36f6f7ed5f3f58c279d055707c454135baf18fd00d798fec3cb52dfbc OP_PUSHBYTES_33 03cf689db9313b9f7fc0b984dd9cac750be76041b392919b06f6bf94813da34cd4 OP_PUSHBYTES_33 027f8af2eb6e904deddaa60d5af393d430575eb35e4dfd942a8a5882734b078906 OP_PUSHBYTES_65 0411db93e1dcdb8a016b49840f8c53bc1eb68a382e97b1482ecad7b148a6909a5cb2e0eaddfb84ccf9744464f82e160bfa9b8b64f9d4c03f999b8643f656b412a3 OP_PUSHBYTES_65 04ae1a62fe09c5f51b13905f07f06b99a2f7159b2225f374cd378d71302fa28414e7aab37397f554a7df5f142c21c1b7303b8a0626f1baded5c72a704f7e6cd84c OP_PUSHNUM_5 OP_CHECKMULTISIG" + }, + { + "txid": "cb9b47ac04023b29fb633a8ef04af351ac9fd74c57c9a2163f683516274767e3", + "vout": 2, + "prevout": { + "scriptpubkey": "a9143b13a1f71c20c799d86bb624b3898c826d6c82da87", + "scriptpubkey_asm": "OP_HASH160 OP_PUSHBYTES_20 3b13a1f71c20c799d86bb624b3898c826d6c82da OP_EQUAL", + "scriptpubkey_type": "p2sh", + "scriptpubkey_address": "375PJxsKRtAq4WoS6u82jvgZW94R8Wx3iH", + "value": 5139 + }, + "scriptsig": "1600149b27f072e4b972927c445d1946162a550b0914d8", + "scriptsig_asm": "OP_PUSHBYTES_22 00149b27f072e4b972927c445d1946162a550b0914d8", + "witness": [ + "3040021c23902a01d4c5cff2c33c8bdb778a5aadea78a9a0d6d4db60aaa0fba1022069237d9dbf2db8cff9c260ba71250493682d01a746f4a45c5c7ea386e56d2bc902", + "0240187acd3e2fd3d8e1acffefa85907b6550730c24f78dfd3301c829fc4daf3cc" + ], + "is_coinbase": false, + "sequence": 141, + "inner_redeemscript_asm": "OP_0 OP_PUSHBYTES_20 9b27f072e4b972927c445d1946162a550b0914d8" + }, + { + "txid": "cb9b47ac04023b29fb633a8ef04af351ac9fd74c57c9a2163f683516274767e3", + "vout": 3, + "prevout": { + "scriptpubkey": "a914a3c0698f2300c7b2e8107d4c9c988e642110039087", + "scriptpubkey_asm": "OP_HASH160 OP_PUSHBYTES_20 a3c0698f2300c7b2e8107d4c9c988e6421100390 OP_EQUAL", + "scriptpubkey_type": "p2sh", + "scriptpubkey_address": "3GcrZrbUuvE4UtUdSbKTXcRnTqmfMdyMAC", + "value": 3220 + }, + "scriptsig": "220020a18160de7291554f349c7d5cbee4ab97fb542e94cf302ce8d7e9747e4188ca75", + "scriptsig_asm": "OP_PUSHBYTES_34 0020a18160de7291554f349c7d5cbee4ab97fb542e94cf302ce8d7e9747e4188ca75", + "witness": [ + "303f021c65aee6696e80be6e14545cfd64b44f17b0514c150eefdb090c0f0bd9021f3fef4aa95c252a225622aba99e4d5af5a6fe40d177acd593e64cf2f8557ccc03", + "03b55c6f0749e0f3e2caeca05f68e3699f1b3c62a550730f704985a6a9aae437a1", + "76a914db865fd920959506111079995f1e4017b489bfe38763ac6721024d560f7f5d28aae5e1a8aa2b7ba615d7fc48e4ea27e5d27336e6a8f5fa0f5c8c7c820120876475527c2103443e8834fa7d79d7b5e95e0e9d0847f6b03ac3ea977979858b4104947fca87ca52ae67a91446c3747322b220fdb925c9802f0e949c1feab99988ac6868" + ], + "is_coinbase": false, + "sequence": 3735928559, + "inner_redeemscript_asm": "OP_0 OP_PUSHBYTES_32 a18160de7291554f349c7d5cbee4ab97fb542e94cf302ce8d7e9747e4188ca75", + "inner_witnessscript_asm": "OP_DUP OP_HASH160 OP_PUSHBYTES_20 db865fd920959506111079995f1e4017b489bfe3 OP_EQUAL OP_IF OP_CHECKSIG OP_ELSE OP_PUSHBYTES_33 024d560f7f5d28aae5e1a8aa2b7ba615d7fc48e4ea27e5d27336e6a8f5fa0f5c8c OP_SWAP OP_SIZE OP_PUSHBYTES_1 20 OP_EQUAL OP_NOTIF OP_DROP OP_PUSHNUM_2 OP_SWAP OP_PUSHBYTES_33 03443e8834fa7d79d7b5e95e0e9d0847f6b03ac3ea977979858b4104947fca87ca OP_PUSHNUM_2 OP_CHECKMULTISIG OP_ELSE OP_HASH160 OP_PUSHBYTES_20 46c3747322b220fdb925c9802f0e949c1feab999 OP_EQUALVERIFY OP_CHECKSIG OP_ENDIF OP_ENDIF" + }, + { + "txid": "cb9b47ac04023b29fb633a8ef04af351ac9fd74c57c9a2163f683516274767e3", + "vout": 4, + "prevout": { + "scriptpubkey": "0014c0ca6e754e65d3ba59112d7abc33e500c00ecfa7", + "scriptpubkey_asm": "OP_0 OP_PUSHBYTES_20 c0ca6e754e65d3ba59112d7abc33e500c00ecfa7", + "scriptpubkey_type": "v0_p2wpkh", + "scriptpubkey_address": "bc1qcr9xua2wvhfm5kg394atcvl9qrqqana8rrmy8h", + "value": 17144 + }, + "scriptsig": "", + "scriptsig_asm": "", + "witness": [ + "303e021c11f60486afd0f5d6573603fb2076ef2f676455b92ada257d2f25558a021e317719c946f951d49bf4df4285a618629cd9e554fcbf787c319a0c4dd22601", + "032467f24cc31664f0cf34ff8d5cbb590888ddc1dcfec724a32ae3dd5338b8508e" + ], + "is_coinbase": false, + "sequence": 21000000 + }, + { + "txid": "637db3928a8fb1b22b81f92dc738ee7637e5b172d650363d0b327429578bd001", + "vout": 0, + "prevout": { + "scriptpubkey": "0020a9530a167fcada672c142ee636dcd171796e69ef8e37aa1f77f35c58edd7a357", + "scriptpubkey_asm": "OP_0 OP_PUSHBYTES_32 a9530a167fcada672c142ee636dcd171796e69ef8e37aa1f77f35c58edd7a357", + "scriptpubkey_type": "v0_p2wsh", + "scriptpubkey_address": "bc1q49fs59nletdxwtq59mnrdhx3w9uku6003cm658mh7dw93mwh5dts2w2kht", + "value": 8149 + }, + "scriptsig": "", + "scriptsig_asm": "", + "witness": [ + "303d021c32f9454db85cb1a4ca63a9883d4347c5e13f3654e884ae44e9efa3c8021d62f07fe452c06b084bc3e09afd3aac4039136549a465533bc1ca66967902", + "01", + "632102fd6db4de50399b2aa086edb23f8e140bbc823d6651e024a0eb871288068789cd67012ab27521034134a2bb35c3f83dab2489d96160741888b8b5589bb694dea6e7bc24486e9c6f68ac" + ], + "is_coinbase": false, + "sequence": 4190024921, + "inner_witnessscript_asm": "OP_IF OP_PUSHBYTES_33 02fd6db4de50399b2aa086edb23f8e140bbc823d6651e024a0eb871288068789cd OP_ELSE OP_PUSHBYTES_1 2a OP_CSV OP_DROP OP_PUSHBYTES_33 034134a2bb35c3f83dab2489d96160741888b8b5589bb694dea6e7bc24486e9c6f OP_ENDIF OP_CHECKSIG" + }, + { + "txid": "0020db02df125062ebae5bacd189ebff22577b2817c1872be79a0d3ba3982c41", + "vout": 0, + "prevout": { + "scriptpubkey": "512071212ded0ff4c9b1b0c505d8012772e2dbe98a3cae7168377b950fb6b866a849", + "scriptpubkey_asm": "OP_PUSHNUM_1 OP_PUSHBYTES_32 71212ded0ff4c9b1b0c505d8012772e2dbe98a3cae7168377b950fb6b866a849", + "scriptpubkey_type": "v1_p2tr", + "scriptpubkey_address": "bc1pwysjmmg07nymrvx9qhvqzfmjutd7nz3u4ecksdmmj58mdwrx4pysq6m68g", + "value": 9001 + }, + "scriptsig": "", + "scriptsig_asm": "", + "witness": [ + "d822f203827852998cad370232e8c57294540a5da51107fa26cf466bdd2b8b0b3d161999cc80aed8de7386a2bd5d5313aea159a231cc26fa53aaa702b7fa21ed" + ], + "is_coinbase": false, + "sequence": 341 + }, + { + "txid": "795741ecf9c431b14b1c8d2dd017d3978fd4f6452e91edf416f31ef9971206b4", + "vout": 0, + "prevout": { + "scriptpubkey": "512089ac120a490eee88db5588112f95f88093284c814f07c3ad943a7faefba2271a", + "scriptpubkey_asm": "OP_PUSHNUM_1 OP_PUSHBYTES_32 89ac120a490eee88db5588112f95f88093284c814f07c3ad943a7faefba2271a", + "scriptpubkey_type": "v1_p2tr", + "scriptpubkey_address": "bc1p3xkpyzjfpmhg3k643qgjl90cszfjsnypfuru8tv58fl6a7azyudqkcu66k", + "value": 19953 + }, + "scriptsig": "", + "scriptsig_asm": "", + "witness": [ + "fe6eb715dceffefc067fdc787d250a9a9116682d216f6356ea38fc1f112bd74995faa90315e81981d2c2260b7eaca3c41a16b280362980f0d8faf4c05ebb82c5", + "e34ad0ad33885a473831f8ba8d9339123cb19d0e642e156d8e0d6e2ab2691aedb30e55a35637a806927225e1aa72223d41e59f92c6579b819e7d331a7ada9d2e01", + "2a4861fb4cb951c791bf6c93859ef65abccd90034f91b9b77abb918e13b6fce75d5fa3e2d2f6eeeae105315178c2cb9db2ef238fe89b282f691c06db43bc71ca02", + "fc97bb2be673c3bf388aaf58178ef14d354caf83c92aca8ef1831d619b8511e928f4f5fdea3962067b11e7cecfe094cd0f66a4ea9af9ec836d70d18f2b37df0281", + "a5781a0adaa80ab7f7f164172dd1a1cb127e523daa0d6949aba074a15c589f12dfb8183182afec9230cb7947b7422a4abc1bb78173550d66274ea19f6c9dd92c82", + "", + "", + "205f4237bd7dae576b34abc8a9c6fa4f0e4787c04234ca963e9e96c8f9b67b56d1ac205f4237bd7f93c69403a30c6b641f27ccf5201090152fcf1596474221307831c3ba205ac8ff25ce63564963d1148b84627f614af1f3c77d7caa23adc61264fa5e4996ba20b210c83e6f5b3f866837112d023d9ae8da2a6412168d54968ab87860ab970690ba20d3ee3b7a8b8149122b3c886330b3241538ba4b935c4040f4a73ddab917241bc5ba20cdfabb9d0e5c8f09a83f19e36e100d8f5e882f1b60aa60dacd9e6d072c117bc0ba20aab038c238e95fb54cdd0a6705dc1b1f8d135a9e9b20ab9c7ff96eef0e9bf545ba559c", + "c0b1674191a88ec5cdd733e4240a81803105dc412d6c6708d53ab94fc248f4f5534a5e1e4baab89f3a32518a88c31bc87f618f76673e2cc77ab2127b7afdeda33bf4184fc596403b9d638783cf57adfe4c75c605f6356fbc91338530e9831e9e166f7cf9580f1c2dfb3c4d5d043cdbb128c640e3f20161245aa7372e9666168516a1075db55d416d3ca199f55b6084e2115b9345e16c5cf302fc80e9d5fbf5d48dd5d27987d2a3dfc724e359870c6644b40e497bdc0589a033220fe15429d88599e3bf3d07d4b0375638d5f1db5255fe07ba2c4cb067cd81b84ee974b6585fb46829a3efd3ef04f9153d47a990bd7b048a4b2d213daaa5fb8ed670fb85f13bdbcf54e48e5f5c656b26c3bca14a8c95aa583d07ebe84dde3b7dd4a78f4e4186e713d29c9c0e8e4d2a9790922af73f0b8d51f0bd4bb19940d9cf910ead8fbe85bc9bbb41a757f405890fb0f5856228e23b715702d714d59bf2b1feb70d8b2b4e3e089fdbcf0ef9d8d00f66e47917f67cc5d78aec1ac786e2abb8d2facb4e4790aad6cc455ae816e6cdafdb58d54e35d4f46d860047458eacf1c7405dc634631c570d8d31992805518fd62daa3bdd2a5c4fd2cd3054c9b3dca1d78055e9528cff6adc8f907925d2ebe48765103e6845c06f1f2bb77c6adc1cc002865865eb5cfd5c1cb10c007c60e14f9d087e0291d4d0c7869697c6681d979c6639dbd960792b4d4133e794d097969002ee05d336686fc03c9e15a597c1b9827669460fac9879903637777defed8717c581b4c0509329550e344bdc14ac38f71fc050096887e535c8fd456524104a6674693c29946543f8a0befccce5a352bda55ec8559fc630f5f37393096d97bfee8660f4100ffd61874d62f9a65de9fb6acf740c4c386990ef7373be398c4bdc43709db7398106609eea2a7841aaf3a4fa2000dc18184faa2a7eb5a2af5845a8d3796308ff9840e567b14cf6bb158ff26c999e6f9a1f5448f9aa" + ], + "is_coinbase": false, + "sequence": 342, + "inner_witnessscript_asm": "OP_PUSHBYTES_32 5f4237bd7dae576b34abc8a9c6fa4f0e4787c04234ca963e9e96c8f9b67b56d1 OP_CHECKSIG OP_PUSHBYTES_32 5f4237bd7f93c69403a30c6b641f27ccf5201090152fcf1596474221307831c3 OP_CHECKSIGADD OP_PUSHBYTES_32 5ac8ff25ce63564963d1148b84627f614af1f3c77d7caa23adc61264fa5e4996 OP_CHECKSIGADD OP_PUSHBYTES_32 b210c83e6f5b3f866837112d023d9ae8da2a6412168d54968ab87860ab970690 OP_CHECKSIGADD OP_PUSHBYTES_32 d3ee3b7a8b8149122b3c886330b3241538ba4b935c4040f4a73ddab917241bc5 OP_CHECKSIGADD OP_PUSHBYTES_32 cdfabb9d0e5c8f09a83f19e36e100d8f5e882f1b60aa60dacd9e6d072c117bc0 OP_CHECKSIGADD OP_PUSHBYTES_32 aab038c238e95fb54cdd0a6705dc1b1f8d135a9e9b20ab9c7ff96eef0e9bf545 OP_CHECKSIGADD OP_PUSHNUM_5 OP_NUMEQUAL" + } + ], + "vout": [ + { + "scriptpubkey": "210261542eb020b36c1da48e2e607b90a8c1f2ccdbd06eaf5fb4bb0d7cc34293d32aac", + "scriptpubkey_asm": "OP_PUSHBYTES_33 0261542eb020b36c1da48e2e607b90a8c1f2ccdbd06eaf5fb4bb0d7cc34293d32a OP_CHECKSIG", + "scriptpubkey_type": "p2pk", + "value": 576 + }, + { + "scriptpubkey": "76a9140240539af6c68431e4ce9cc5ef464f12c1741b3c88ac", + "scriptpubkey_asm": "OP_DUP OP_HASH160 OP_PUSHBYTES_20 0240539af6c68431e4ce9cc5ef464f12c1741b3c OP_EQUALVERIFY OP_CHECKSIG", + "scriptpubkey_type": "p2pkh", + "scriptpubkey_address": "1CuQsdrcgcmPvugo3NqEwh1kDcpeEnuFC", + "value": 546 + }, + { + "scriptpubkey": "5121028b45a50f795be0413680036665d17a3eca099648ea80637bc3a70a7d2b52ae2851ae", + "scriptpubkey_asm": "OP_PUSHNUM_1 OP_PUSHBYTES_33 028b45a50f795be0413680036665d17a3eca099648ea80637bc3a70a7d2b52ae28 OP_PUSHNUM_1 OP_CHECKMULTISIG", + "scriptpubkey_type": "multisig", + "value": 582 + }, + { + "scriptpubkey": "a91449ed2c96e33b6134408af8484508bcc3248c8dbd87", + "scriptpubkey_asm": "OP_HASH160 OP_PUSHBYTES_20 49ed2c96e33b6134408af8484508bcc3248c8dbd OP_EQUAL", + "scriptpubkey_type": "p2sh", + "scriptpubkey_address": "38RuNhSiZiftB6WVnStu5aUz6jXtCDXQZk", + "value": 540 + }, + { + "scriptpubkey": "0014c8e51cf6891c0a2101aecea8cd5ce9bbbfaf7bba", + "scriptpubkey_asm": "OP_0 OP_PUSHBYTES_20 c8e51cf6891c0a2101aecea8cd5ce9bbbfaf7bba", + "scriptpubkey_type": "v0_p2wpkh", + "scriptpubkey_address": "bc1qerj3ea5frs9zzqdwe65v6h8fhwl677a6s0hxhf", + "value": 294 + }, + { + "scriptpubkey": "0020c485bbb80c4be276e77eac3a983a391cc8b1a1b5f160995a36c3dff18296385a", + "scriptpubkey_asm": "OP_0 OP_PUSHBYTES_32 c485bbb80c4be276e77eac3a983a391cc8b1a1b5f160995a36c3dff18296385a", + "scriptpubkey_type": "v0_p2wsh", + "scriptpubkey_address": "bc1qcjzmhwqvf038dem74safsw3ernytrgd479sfjk3kc00lrq5k8pdqczl83q", + "value": 330 + }, + { + "scriptpubkey": "5120a7a42b268957a06c9de4d7260f1df392ce4d6e7b743f5adc27415ce2afceb3b9", + "scriptpubkey_asm": "OP_PUSHNUM_1 OP_PUSHBYTES_32 a7a42b268957a06c9de4d7260f1df392ce4d6e7b743f5adc27415ce2afceb3b9", + "scriptpubkey_type": "v1_p2tr", + "scriptpubkey_address": "bc1p57jzkf5f27sxe80y6unq780njt8y6mnmwsl44hp8g9ww9t7wkwusv7av76", + "value": 330 + }, + { + "scriptpubkey": "51024e73", + "scriptpubkey_asm": "OP_PUSHNUM_1 OP_PUSHBYTES_2 4e73", + "scriptpubkey_type": "unknown", + "scriptpubkey_address": "bc1pfeessrawgf", + "value": 240 + }, + { + "scriptpubkey": "6a224e6f7420796f757220696e707574732c206e6f7420796f7572206f7574707574732e005152535455565758595a5b5c5d5e5f60", + "scriptpubkey_asm": "OP_RETURN OP_PUSHBYTES_34 4e6f7420796f757220696e707574732c206e6f7420796f7572206f7574707574732e OP_0 OP_PUSHNUM_1 OP_PUSHNUM_2 OP_PUSHNUM_3 OP_PUSHNUM_4 OP_PUSHNUM_5 OP_PUSHNUM_6 OP_PUSHNUM_7 OP_PUSHNUM_8 OP_PUSHNUM_9 OP_PUSHNUM_10 OP_PUSHNUM_11 OP_PUSHNUM_12 OP_PUSHNUM_13 OP_PUSHNUM_14 OP_PUSHNUM_15 OP_PUSHNUM_16", + "scriptpubkey_type": "op_return", + "value": 0 + } + ], + "size": 3500, + "weight": 8186, + "sigops": 115, + "fee": 71294, + "status": { + "confirmed": true, + "block_height": 850000, + "block_hash": "00000000000000000002a0b5db2a7f8d9087464c2586b546be7bce8eb53b8187", + "block_time": 1719689674 + } + } +] \ No newline at end of file diff --git a/backend/src/__tests__/api/test-data/transactions-rbfs.json b/backend/src/__tests__/api/test-data/transactions-rbfs.json new file mode 100644 index 0000000000..4e5989cc90 --- /dev/null +++ b/backend/src/__tests__/api/test-data/transactions-rbfs.json @@ -0,0 +1,121 @@ +[ + { + "txid": "7219d95161f3718335991ac6d967d24eedec370908c9879bb1e192e6d797d0a6", + "version": 1, + "locktime": 0, + "vin": [ + { + "txid": "d863deb706de5a611028f7547e16ea81d7819e44beb640fb30a9ba30c585140f", + "vout": 0, + "prevout": { + "scriptpubkey": "76a914cd5b6566b455d043558829f6932edaae5d8f0ad388ac", + "scriptpubkey_asm": "OP_DUP OP_HASH160 OP_PUSHBYTES_20 cd5b6566b455d043558829f6932edaae5d8f0ad3 OP_EQUALVERIFY OP_CHECKSIG", + "scriptpubkey_type": "p2pkh", + "scriptpubkey_address": "1Kiq1dyVBzYLWGrBPWjChvKyzB2H95x5RJ", + "value": 799995000 + }, + "scriptsig": "483045022100aeeddfb9785c5a4b70e90d0445785c68b7a44e28853441134a70ddc4da39527602203dfe1ec1a377aaacb64ae65c7c944caf1398d2dc063f712251b4cf696d44d3cb01210314338e3e191aea3ac9e9292611faeedf0379bbe62c30fd76c7450722a1ac47c6", + "scriptsig_asm": "OP_PUSHBYTES_72 3045022100aeeddfb9785c5a4b70e90d0445785c68b7a44e28853441134a70ddc4da39527602203dfe1ec1a377aaacb64ae65c7c944caf1398d2dc063f712251b4cf696d44d3cb01 OP_PUSHBYTES_33 0314338e3e191aea3ac9e9292611faeedf0379bbe62c30fd76c7450722a1ac47c6", + "is_coinbase": false, + "sequence": 4294967293 + } + ], + "vout": [ + { + "scriptpubkey": "6a4c5058325b8669baa9259e082f064005bc92274b559337ac317798f5d76f2d0577ed5a96042fce8c33d841b6c47a99f9597000ab04a10b34cd419fc19784d9e36f1a33fd7b000c3bce00b6000c1d1e00614b", + "scriptpubkey_asm": "OP_RETURN OP_PUSHDATA1 58325b8669baa9259e082f064005bc92274b559337ac317798f5d76f2d0577ed5a96042fce8c33d841b6c47a99f9597000ab04a10b34cd419fc19784d9e36f1a33fd7b000c3bce00b6000c1d1e00614b", + "scriptpubkey_type": "op_return", + "value": 0 + }, + { + "scriptpubkey": "a9144890aae025c84cb72a9730b49ca12595d6f6088d87", + "scriptpubkey_asm": "OP_HASH160 OP_PUSHBYTES_20 4890aae025c84cb72a9730b49ca12595d6f6088d OP_EQUAL", + "scriptpubkey_type": "p2sh", + "scriptpubkey_address": "38Jht2bzmJL4EwoFvvyFzejhfEb4J7KxLb", + "value": 155000 + }, + { + "scriptpubkey": "76a91486e7dad6617303942a448b7f8afe9653e5624a5e88ac", + "scriptpubkey_asm": "OP_DUP OP_HASH160 OP_PUSHBYTES_20 86e7dad6617303942a448b7f8afe9653e5624a5e OP_EQUALVERIFY OP_CHECKSIG", + "scriptpubkey_type": "p2pkh", + "scriptpubkey_address": "1DJKJGApgX4W8BSQ8FRPLqX78UaCskT4r2", + "value": 155000 + }, + { + "scriptpubkey": "76a914cd5b6566b455d043558829f6932edaae5d8f0ad388ac", + "scriptpubkey_asm": "OP_DUP OP_HASH160 OP_PUSHBYTES_20 cd5b6566b455d043558829f6932edaae5d8f0ad3 OP_EQUALVERIFY OP_CHECKSIG", + "scriptpubkey_type": "p2pkh", + "scriptpubkey_address": "1Kiq1dyVBzYLWGrBPWjChvKyzB2H95x5RJ", + "value": 799675549 + } + ], + "size": 350, + "weight": 1400, + "fee": 9451, + "status": { + "confirmed": false + }, + "order": 2798688215, + "vsize": 350, + "adjustedVsize": 350, + "sigops": 8, + "feePerVsize": 27.002857142857142, + "adjustedFeePerVsize": 27.002857142857142, + "effectiveFeePerVsize": 27.002857142857142, + "firstSeen": 1691218536, + "uid": 513598, + "inputs": [], + "position": { + "block": 0, + "vsize": 22166 + }, + "bestDescendant": null, + "cpfpChecked": true + }, + { + "txid": "5387881d695d4564d397026dc5f740f816f8390b4b2c5ec8c20309122712a875", + "version": 2, + "locktime": 0, + "vin": [ + { + "txid": "b50225a04a1d6fbbfa7a2122bc0580396f614027b3957f476229633576f06130", + "vout": 0, + "prevout": { + "scriptpubkey": "0014a24f913f8a9c30a4c302c2c78f2fd7addb08fd07", + "scriptpubkey_asm": "OP_0 OP_PUSHBYTES_20 a24f913f8a9c30a4c302c2c78f2fd7addb08fd07", + "scriptpubkey_type": "v0_p2wpkh", + "scriptpubkey_address": "bc1q5f8ez0u2nsc2fsczctrc7t7h4hds3lg82ewqhz", + "value": 612917 + }, + "scriptsig": "", + "scriptsig_asm": "", + "witness": [ + "3045022100a0c23953ace5d022b7a6d45d1ae1730bf20a4d594bb5d4fa7aa80e4881b44d320220008f9b144805bb91995fc0f452a56e09f4ad16fa149d71ae9b5d57c742e8e2cc01", + "03dc2c7b687019b40a68d713322675206cc266e34e5340ec982c13ff0222c3b2b6" + ], + "is_coinbase": false, + "sequence": 2147483649 + } + ], + "vout": [ + { + "scriptpubkey": "0014199a98f9589364ffe5ef5bbae45ce5dfcbb873bd", + "scriptpubkey_asm": "OP_0 OP_PUSHBYTES_20 199a98f9589364ffe5ef5bbae45ce5dfcbb873bd", + "scriptpubkey_type": "v0_p2wpkh", + "scriptpubkey_address": "bc1qrxdf372cjdj0le00twawgh89ml9msuaau62gk4", + "value": 611909 + } + ], + "size": 192, + "weight": 438, + "fee": 1008, + "status": { + "confirmed": false + }, + "bestDescendant": null, + "descendants": null, + "adjustedFeePerVsize": 10.2283, + "sigops": 1, + "adjustedVsize": 109.5 + } +] \ No newline at end of file diff --git a/backend/src/__tests__/api/test-data/transactions-replaced.json b/backend/src/__tests__/api/test-data/transactions-replaced.json new file mode 100644 index 0000000000..e235d83e18 --- /dev/null +++ b/backend/src/__tests__/api/test-data/transactions-replaced.json @@ -0,0 +1,139 @@ +[ + { + "txid": "008592364e21c1e3d62ba9538ac78a81779897b52100af5707ab063df98964f2", + "version": 1, + "locktime": 0, + "vin": [ + { + "txid": "d863deb706de5a611028f7547e16ea81d7819e44beb640fb30a9ba30c585140f", + "vout": 0, + "prevout": { + "scriptpubkey": "76a914cd5b6566b455d043558829f6932edaae5d8f0ad388ac", + "scriptpubkey_asm": "OP_DUP OP_HASH160 OP_PUSHBYTES_20 cd5b6566b455d043558829f6932edaae5d8f0ad3 OP_EQUALVERIFY OP_CHECKSIG", + "scriptpubkey_type": "p2pkh", + "scriptpubkey_address": "1Kiq1dyVBzYLWGrBPWjChvKyzB2H95x5RJ", + "value": 799995000 + }, + "scriptsig": "483045022100c1fb331d155a7d299a0451d14fa1122b328e0e239afc9ba8dc2aff449ddc5a3a02201c1e19030d1efa432f5069cd369d7ad09a67f68501345e4db35f7b799605f55601210314338e3e191aea3ac9e9292611faeedf0379bbe62c30fd76c7450722a1ac47c6", + "scriptsig_asm": "OP_PUSHBYTES_72 3045022100c1fb331d155a7d299a0451d14fa1122b328e0e239afc9ba8dc2aff449ddc5a3a02201c1e19030d1efa432f5069cd369d7ad09a67f68501345e4db35f7b799605f55601 OP_PUSHBYTES_33 0314338e3e191aea3ac9e9292611faeedf0379bbe62c30fd76c7450722a1ac47c6", + "is_coinbase": false, + "sequence": 4294967293 + } + ], + "vout": [ + { + "scriptpubkey": "6a4c5058325b78064160b631b5a15d9078d99c0db066449fb4c59bbfa4d987ba906e2990088b2fce8c33d841b6c47a99f9597000ab04a10b34cd419fc19784d9e36f1a33fd7b000c3bce00b6000c1d1e00614b", + "scriptpubkey_asm": "OP_RETURN OP_PUSHDATA1 58325b78064160b631b5a15d9078d99c0db066449fb4c59bbfa4d987ba906e2990088b2fce8c33d841b6c47a99f9597000ab04a10b34cd419fc19784d9e36f1a33fd7b000c3bce00b6000c1d1e00614b", + "scriptpubkey_type": "op_return", + "value": 0 + }, + { + "scriptpubkey": "a9144890aae025c84cb72a9730b49ca12595d6f6088d87", + "scriptpubkey_asm": "OP_HASH160 OP_PUSHBYTES_20 4890aae025c84cb72a9730b49ca12595d6f6088d OP_EQUAL", + "scriptpubkey_type": "p2sh", + "scriptpubkey_address": "38Jht2bzmJL4EwoFvvyFzejhfEb4J7KxLb", + "value": 155000 + }, + { + "scriptpubkey": "76a91486e7dad6617303942a448b7f8afe9653e5624a5e88ac", + "scriptpubkey_asm": "OP_DUP OP_HASH160 OP_PUSHBYTES_20 86e7dad6617303942a448b7f8afe9653e5624a5e OP_EQUALVERIFY OP_CHECKSIG", + "scriptpubkey_type": "p2pkh", + "scriptpubkey_address": "1DJKJGApgX4W8BSQ8FRPLqX78UaCskT4r2", + "value": 155000 + }, + { + "scriptpubkey": "76a914cd5b6566b455d043558829f6932edaae5d8f0ad388ac", + "scriptpubkey_asm": "OP_DUP OP_HASH160 OP_PUSHBYTES_20 cd5b6566b455d043558829f6932edaae5d8f0ad3 OP_EQUALVERIFY OP_CHECKSIG", + "scriptpubkey_type": "p2pkh", + "scriptpubkey_address": "1Kiq1dyVBzYLWGrBPWjChvKyzB2H95x5RJ", + "value": 799676250 + } + ], + "size": 350, + "weight": 1400, + "fee": 8750, + "status": { + "confirmed": false + }, + "order": 4066675193, + "vsize": 350, + "adjustedVsize": 350, + "sigops": 8, + "feePerVsize": 25, + "adjustedFeePerVsize": 25, + "effectiveFeePerVsize": 25, + "firstSeen": 1691218516, + "uid": 512584, + "inputs": [], + "position": { + "block": 0, + "vsize": 13846 + }, + "bestDescendant": null, + "cpfpChecked": true + }, + { + "txid": "b7981a624e4261c11f1246314d41e74be56af82eb557bcd054a5e0f94c023668", + "version": 2, + "locktime": 0, + "vin": [ + { + "txid": "b50225a04a1d6fbbfa7a2122bc0580396f614027b3957f476229633576f06130", + "vout": 0, + "prevout": { + "scriptpubkey": "0014a24f913f8a9c30a4c302c2c78f2fd7addb08fd07", + "scriptpubkey_asm": "OP_0 OP_PUSHBYTES_20 a24f913f8a9c30a4c302c2c78f2fd7addb08fd07", + "scriptpubkey_type": "v0_p2wpkh", + "scriptpubkey_address": "bc1q5f8ez0u2nsc2fsczctrc7t7h4hds3lg82ewqhz", + "value": 612917 + }, + "scriptsig": "", + "scriptsig_asm": "", + "witness": [ + "304402204dd10f14afa41bc76d8278140ff1ec3d3f87f2c207bbb5418cc76dab30d7f6a402207877cc9c6a2c724b6ea7a1c24ac00022469f194fd1a4bd8030bbca1787d3f5f301", + "03dc2c7b687019b40a68d713322675206cc266e34e5340ec982c13ff0222c3b2b6" + ], + "is_coinbase": false, + "sequence": 2147483648 + } + ], + "vout": [ + { + "scriptpubkey": "76a9149d32ef812385f3811634e0c0117dd153a5de10a488ac", + "scriptpubkey_asm": "OP_DUP OP_HASH160 OP_PUSHBYTES_20 9d32ef812385f3811634e0c0117dd153a5de10a4 OP_EQUALVERIFY OP_CHECKSIG", + "scriptpubkey_type": "p2pkh", + "scriptpubkey_address": "1FLC7Bag7okAkKPCyZbgZZg3Hh1EuGZ5Rd", + "value": 344697 + }, + { + "scriptpubkey": "00144c2671336ca8761863b4c68d64d4672491fec1b9", + "scriptpubkey_asm": "OP_0 OP_PUSHBYTES_20 4c2671336ca8761863b4c68d64d4672491fec1b9", + "scriptpubkey_type": "v0_p2wpkh", + "scriptpubkey_address": "bc1qfsn8zvmv4pmpsca5c6xkf4r8yjglasdesrawcx", + "value": 267636 + } + ], + "size": 225, + "weight": 573, + "fee": 584, + "status": { + "confirmed": false + }, + "order": 1748369996, + "vsize": 143, + "adjustedVsize": 143.25, + "sigops": 5, + "feePerVsize": 4.076788830715532, + "adjustedFeePerVsize": 4.076788830715532, + "effectiveFeePerVsize": 4.076788830715532, + "firstSeen": 1691222376, + "uid": 526515, + "inputs": [], + "position": { + "block": 7, + "vsize": 22021095.5 + }, + "bestDescendant": null, + "cpfpChecked": true + } +] \ No newline at end of file diff --git a/backend/src/__tests__/config.test.ts b/backend/src/__tests__/config.test.ts new file mode 100644 index 0000000000..050213143c --- /dev/null +++ b/backend/src/__tests__/config.test.ts @@ -0,0 +1,294 @@ +import * as fs from 'fs'; + +describe('Mempool Backend Config', () => { + beforeEach(() => { + jest.resetAllMocks(); + jest.resetModules(); + }); + + test('should return defaults when no file is present', () => { + jest.isolateModules(() => { + jest.mock('../../mempool-config.json', () => ({}), { virtual: true }); + + const config = jest.requireActual('../config').default; + + expect(config.MEMPOOL).toStrictEqual({ + ENABLED: true, + OFFICIAL: false, + NETWORK: 'mainnet', + BACKEND: 'none', + BLOCKS_SUMMARIES_INDEXING: false, + GOGGLES_INDEXING: false, + HTTP_PORT: 8999, + UNIX_SOCKET_PATH: '', + SPAWN_CLUSTER_PROCS: 0, + API_URL_PREFIX: '/api/v1/', + AUTOMATIC_POOLS_UPDATE: false, + POLL_RATE_MS: 2000, + CACHE_DIR: './cache', + CACHE_ENABLED: true, + CLEAR_PROTECTION_MINUTES: 20, + RECOMMENDED_FEE_PERCENTILE: 50, + BLOCK_WEIGHT_UNITS: 4000000, + INITIAL_BLOCKS_AMOUNT: 8, + MEMPOOL_BLOCKS_AMOUNT: 8, + INDEXING_BLOCKS_AMOUNT: 11000, + USE_SECOND_NODE_FOR_MINFEE: false, + EXTERNAL_ASSETS: [], + EXTERNAL_MAX_RETRY: 1, + EXTERNAL_RETRY_INTERVAL: 0, + USER_AGENT: 'mempool', + STDOUT_LOG_MIN_PRIORITY: 'debug', + POOLS_JSON_TREE_URL: 'https://api.github.com/repos/mempool/mining-pools/git/trees/master', + POOLS_JSON_URL: 'https://raw.githubusercontent.com/mempool/mining-pools/master/pools-v2.json', + AUDIT: false, + RUST_GBT: false, + LIMIT_GBT: false, + CPFP_INDEXING: false, + MAX_BLOCKS_BULK_QUERY: 0, + DISK_CACHE_BLOCK_INTERVAL: 6, + MAX_PUSH_TX_SIZE_WEIGHT: 400000, + ALLOW_UNREACHABLE: true, + PRICE_UPDATES_PER_HOUR: 1, + MAX_TRACKED_ADDRESSES: 1, + }); + + expect(config.ELECTRUM).toStrictEqual({ HOST: '127.0.0.1', PORT: 3306, TLS_ENABLED: true }); + + expect(config.ESPLORA).toStrictEqual({ + REST_API_URL: 'http://127.0.0.1:3000', + UNIX_SOCKET_PATH: null, + BATCH_QUERY_BASE_SIZE: 1000, + RETRY_UNIX_SOCKET_AFTER: 30000, + REQUEST_TIMEOUT: 10000, + FALLBACK_TIMEOUT: 5000, + FALLBACK: [], + MAX_BEHIND_TIP: 2, + }); + + expect(config.CORE_RPC).toStrictEqual({ + HOST: '127.0.0.1', + PORT: 8332, + USERNAME: 'mempool', + PASSWORD: 'mempool', + TIMEOUT: 60000, + COOKIE: false, + COOKIE_PATH: '/bitcoin/.cookie' + }); + + expect(config.SECOND_CORE_RPC).toStrictEqual({ + HOST: '127.0.0.1', + PORT: 8332, + USERNAME: 'mempool', + PASSWORD: 'mempool', + TIMEOUT: 60000, + COOKIE: false, + COOKIE_PATH: '/bitcoin/.cookie' + }); + + expect(config.DATABASE).toStrictEqual({ + ENABLED: true, + HOST: '127.0.0.1', + SOCKET: '', + PORT: 3306, + DATABASE: 'mempool', + USERNAME: 'mempool', + PASSWORD: 'mempool', + TIMEOUT: 180000, + PID_DIR: '', + POOL_SIZE: 100, + }); + + expect(config.SYSLOG).toStrictEqual({ + ENABLED: true, + HOST: '127.0.0.1', + PORT: 514, + MIN_PRIORITY: 'info', + FACILITY: 'local7' + }); + + expect(config.STATISTICS).toStrictEqual({ ENABLED: true, TX_PER_SECOND_SAMPLE_PERIOD: 150 }); + + expect(config.SOCKS5PROXY).toStrictEqual({ + ENABLED: false, + USE_ONION: true, + HOST: '127.0.0.1', + PORT: 9050, + USERNAME: '', + PASSWORD: '' + }); + + expect(config.EXTERNAL_DATA_SERVER).toStrictEqual({ + MEMPOOL_API: 'https://mempool.space/api/v1', + MEMPOOL_ONION: 'http://mempoolhqx4isw62xs7abwphsq7ldayuidyx2v2oethdhhj6mlo2r6ad.onion/api/v1', + LIQUID_API: 'https://liquid.network/api/v1', + LIQUID_ONION: 'http://liquidmom47f6s3m53ebfxn47p76a6tlnxib3wp6deux7wuzotdr6cyd.onion/api/v1' + }); + + expect(config.MAXMIND).toStrictEqual({ + ENABLED: false, + GEOLITE2_CITY: '/usr/local/share/GeoIP/GeoLite2-City.mmdb', + GEOLITE2_ASN: '/usr/local/share/GeoIP/GeoLite2-ASN.mmdb', + GEOIP2_ISP: '/usr/local/share/GeoIP/GeoIP2-ISP.mmdb' + }); + + expect(config.REPLICATION).toStrictEqual({ + ENABLED: false, + AUDIT: false, + AUDIT_START_HEIGHT: 774000, + STATISTICS: false, + STATISTICS_START_TIME: 1481932800, + SERVERS: [] + }); + + expect(config.MEMPOOL_SERVICES).toStrictEqual({ + API: "", + ACCELERATIONS: false, + }); + + expect(config.REDIS).toStrictEqual({ + ENABLED: false, + UNIX_SOCKET_PATH: '', + BATCH_QUERY_BASE_SIZE: 5000, + }); + + expect(config.FIAT_PRICE).toStrictEqual({ + ENABLED: true, + PAID: false, + API_KEY: '', + }); + }); + }); + + test('should override the default values with the passed values', () => { + jest.isolateModules(() => { + const fixture = JSON.parse(fs.readFileSync(`${__dirname}/../__fixtures__/mempool-config.template.json`, 'utf8')); + jest.mock('../../mempool-config.json', () => (fixture), { virtual: true }); + + const config = jest.requireActual('../config').default; + + expect(config.MEMPOOL).toStrictEqual(fixture.MEMPOOL); + + expect(config.ELECTRUM).toStrictEqual(fixture.ELECTRUM); + + expect(config.ESPLORA).toStrictEqual(fixture.ESPLORA); + + expect(config.CORE_RPC).toStrictEqual(fixture.CORE_RPC); + + expect(config.SECOND_CORE_RPC).toStrictEqual(fixture.SECOND_CORE_RPC); + + expect(config.DATABASE).toStrictEqual(fixture.DATABASE); + + expect(config.SYSLOG).toStrictEqual(fixture.SYSLOG); + + expect(config.STATISTICS).toStrictEqual(fixture.STATISTICS); + + expect(config.SOCKS5PROXY).toStrictEqual(fixture.SOCKS5PROXY); + + expect(config.EXTERNAL_DATA_SERVER).toStrictEqual(fixture.EXTERNAL_DATA_SERVER); + + expect(config.MEMPOOL_SERVICES).toStrictEqual(fixture.MEMPOOL_SERVICES); + + expect(config.REDIS).toStrictEqual(fixture.REDIS); + }); + }); + + test('should ensure the docker start.sh script has default values', () => { + jest.isolateModules(() => { + const startSh = fs.readFileSync(`${__dirname}/../../../docker/backend/start.sh`, 'utf-8'); + const fixture = JSON.parse(fs.readFileSync(`${__dirname}/../__fixtures__/mempool-config.template.json`, 'utf8')); + + function parseJson(jsonObj, root?) { + for (const [key, value] of Object.entries(jsonObj)) { + // We have a few cases where we can't follow the pattern + if (root === 'MEMPOOL' && key === 'HTTP_PORT') { + if (process.env.CI) { + console.log('skipping check for MEMPOOL_HTTP_PORT'); + } + continue; + } + + if (root) { + //The flattened string, i.e, __MEMPOOL_ENABLED__ + const replaceStr = `${root ? '__' + root + '_' : '__'}${key}__`; + + //The string used as the environment variable, i.e, MEMPOOL_ENABLED + const envVarStr = `${root ? root : ''}_${key}`; + + let defaultEntry; + //The string used as the default value, to be checked as a regex, i.e, __MEMPOOL_ENABLED__=${MEMPOOL_ENABLED:=(.*)} + if (Array.isArray(value)) { + defaultEntry = `${replaceStr}=\${${envVarStr}:=[]}`; + if (process.env.CI) { + console.log(`looking for ${defaultEntry} in the start.sh script`); + } + //Regex matching does not work with the array values + expect(startSh).toContain(defaultEntry); + } else { + defaultEntry = replaceStr + '=' + '\\${' + envVarStr + ':=(.*)' + '}'; + if (process.env.CI) { + console.log(`looking for ${defaultEntry} in the start.sh script`); + } + const re = new RegExp(defaultEntry); + expect(startSh).toMatch(re); + } + + //The string that actually replaces the values in the config file + const sedStr = 'sed -i "s!' + replaceStr + '!${' + replaceStr + '}!g" mempool-config.json'; + if (process.env.CI) { + console.log(`looking for ${sedStr} in the start.sh script`); + } + expect(startSh).toContain(sedStr); + } + else { + parseJson(value, key); + } + } + } + + parseJson(fixture); + }); + }); + + test('should ensure that the mempool-config.json Docker template has all the keys', () => { + jest.isolateModules(() => { + const fixture = JSON.parse(fs.readFileSync(`${__dirname}/../__fixtures__/mempool-config.template.json`, 'utf8')); + const dockerJson = fs.readFileSync(`${__dirname}/../../../docker/backend/mempool-config.json`, 'utf-8'); + + function parseJson(jsonObj, root?) { + for (const [key, value] of Object.entries(jsonObj)) { + switch (typeof value) { + case 'object': { + if (Array.isArray(value)) { + // numbers, arrays and booleans won't be enclosed by quotes + const replaceStr = `${root ? '__' + root + '_' : '__'}${key}__`; + expect(dockerJson).toContain(`"${key}": ${replaceStr}`); + break; + } else { + //Check for top level config keys + expect(dockerJson).toContain(`"${key}"`); + parseJson(value, key); + break; + } + } + case 'string': { + // strings should be enclosed by quotes + const replaceStr = `${root ? '__' + root + '_' : '__'}${key}__`; + expect(dockerJson).toContain(`"${key}": "${replaceStr}"`); + break; + } + default: { + // numbers, arrays and booleans won't be enclosed by quotes + const replaceStr = `${root ? '__' + root + '_' : '__'}${key}__`; + expect(dockerJson).toContain(`"${key}": ${replaceStr}`); + break; + } + } + }; + } + parseJson(fixture); + }); + }); + + +}); diff --git a/backend/src/__tests__/gbt/gbt-tests.ts b/backend/src/__tests__/gbt/gbt-tests.ts new file mode 100644 index 0000000000..561963aaa6 --- /dev/null +++ b/backend/src/__tests__/gbt/gbt-tests.ts @@ -0,0 +1,68 @@ +import fs from 'fs'; +import { GbtGenerator, ThreadTransaction } from 'rust-gbt'; +import path from 'path'; + +const baseline = require('./test-data/target-template.json'); +const testVector = require('./test-data/test-data-ids.json'); +const vectorUidMap: Map = new Map(testVector.map(x => [x[0], x[1]])); +const vectorTxidMap: Map = new Map(testVector.map(x => [x[1], x[0]])); +// Note that this test buffer is specially constructed +// such that uids are assigned in numerical txid order +// so that ties break the same way as in Core's implementation +const vectorBuffer: Buffer = fs.readFileSync(path.join(__dirname, './', './test-data/test-buffer.bin')); + +describe('Rust GBT', () => { + test('should produce the same template as getBlockTemplate from Bitcoin Core', async () => { + const rustGbt = new GbtGenerator(4_000_000, 8); + const { mempool, maxUid } = mempoolFromArrayBuffer(vectorBuffer.buffer); + const result = await rustGbt.make(mempool, [], maxUid); + + const blocks: [string, number][][] = result.blocks.map(block => { + return block.map(uid => [vectorUidMap.get(uid) || 'missing', uid]); + }); + const template = baseline.map(tx => [tx.txid, vectorTxidMap.get(tx.txid)]); + + expect(blocks[0].length).toEqual(baseline.length); + expect(blocks[0]).toEqual(template); + }); +}); + +function mempoolFromArrayBuffer(buf: ArrayBuffer): { mempool: ThreadTransaction[], maxUid: number } { + let maxUid = 0; + const view = new DataView(buf); + const count = view.getUint32(0, false); + const txs: ThreadTransaction[] = []; + let offset = 4; + for (let i = 0; i < count; i++) { + const uid = view.getUint32(offset, false); + maxUid = Math.max(maxUid, uid); + const tx: ThreadTransaction = { + uid, + order: txidToOrdering(vectorUidMap.get(uid) as string), + fee: view.getFloat64(offset + 4, false), + weight: view.getUint32(offset + 12, false), + sigops: view.getUint32(offset + 16, false), + // feePerVsize: view.getFloat64(offset + 20, false), + effectiveFeePerVsize: view.getFloat64(offset + 28, false), + inputs: [], + }; + const numInputs = view.getUint32(offset + 36, false); + offset += 40; + for (let j = 0; j < numInputs; j++) { + tx.inputs.push(view.getUint32(offset, false)); + offset += 4; + } + txs.push(tx); + } + return { mempool: txs, maxUid }; +} + +function txidToOrdering(txid: string): number { + return parseInt( + txid.substr(62, 2) + + txid.substr(60, 2) + + txid.substr(58, 2) + + txid.substr(56, 2), + 16 + ); +} diff --git a/backend/src/__tests__/gbt/test-data/target-template.json b/backend/src/__tests__/gbt/test-data/target-template.json new file mode 100644 index 0000000000..d16f717a24 --- /dev/null +++ b/backend/src/__tests__/gbt/test-data/target-template.json @@ -0,0 +1,7070 @@ +[ + { + "txid": "5ffbad40ab3f5100677bc6464c0d3d754d0ae1aea1fad597efd2b15964bb7cb8", + "weight": 892 + }, + { + "txid": "f8c3bf8e8c83e342f7ad5b18fd946cf99b05057f752a01076489dc3ed230ce5f", + "weight": 840 + }, + { + "txid": "80055b225e78b15d462178cd04e5065eb07fc2fe567836d169a1ec7da6e39259", + "weight": 1266 + }, + { + "txid": "f96aceb659ea8b78674dc8589bba2072f375d09a8fd22bdcd5e77fbf24f798f5", + "weight": 900 + }, + { + "txid": "9ba924cba0dcfe149365d2a6188ea060a3a11cfc18e685e7856e85517c7a6e65", + "weight": 561 + }, + { + "txid": "bf7065d708f4ced48f1cf3e7146336591029a1427880e2664ec5d80bcc04b3a6", + "weight": 561 + }, + { + "txid": "2030ee722a7241e62804c3aaf830b127c29fd299f1ae9c23ac99b650c573617c", + "weight": 573 + }, + { + "txid": "a1e940723ab44707fdf72c20342df361b00b32733dba6bc4ccafd67628b91f0b", + "weight": 686 + }, + { + "txid": "79d52e06b6544d101496383a3cb343c4550f816eb499d86ad826c03581e3bd8f", + "weight": 697 + }, + { + "txid": "67f3fcd7881870a6582d49473b154794070444597a7d44f11fb87586c25cb9e6", + "weight": 933 + }, + { + "txid": "d5dc3d03d2fbd7463aad963e729221a540fac3f7ca21343ae2d1450307678e10", + "weight": 1257 + }, + { + "txid": "9d4ff8fe740310e78c46825d554d3ef7b60de710d2836242329a37ea04c30e32", + "weight": 1738 + }, + { + "txid": "d68ad8e9b8078238b3ccb93141026a53506d60209e44351176b3b28188ab3319", + "weight": 561 + }, + { + "txid": "be1e4e48717741c8b3ae8429d38a311400b5f4e7dc7242ab6419995cba8ab862", + "weight": 685 + }, + { + "txid": "c64c90422a3bf3d9e3eb7c05abcf67b872abf9c8bca4eb5ee9b4eda9f8a736a7", + "weight": 685 + }, + { + "txid": "cbb0da41f1198d5eaccd905faea19aa80913b2de22a2d4c3d1f26ea280f8684f", + "weight": 737 + }, + { + "txid": "c545474d081b17a37b7fd9da57c4320547b75f7af3eacff300f6ef6449536345", + "weight": 1094 + }, + { + "txid": "13db0c88910edc12c0a8ab53b520d06bd6e9281bae192f469e62bc802d5983a9", + "weight": 1181 + }, + { + "txid": "34775cda09e514b0406266483a95f62239484a23567242dc1846575976e57527", + "weight": 573 + }, + { + "txid": "50c57ec53e491d24cacb50127e6ad69832e658a956b3136fcd7ab506290dd9ed", + "weight": 832 + }, + { + "txid": "cf56c244972305d27627e2ed38c094a5743519f4eebd84140f03ca57f77ba85c", + "weight": 888 + }, + { + "txid": "ee17c3b697d1756f1ab0c1e636ea97e7d117d15a5b43f3edb423a2be278d53e9", + "weight": 838 + }, + { + "txid": "8816f390a70f07673451f6a9dce3f75532b818884844142c42fb5ca3827c58b4", + "weight": 442 + }, + { + "txid": "70e7fff6784e58f15974e0fddf702c8447017401915b9bc175694017ec31fbf4", + "weight": 1936 + }, + { + "txid": "56b13b0a9a4a50a9dde6d37b30123b57cb62f3db5e6e7d82ea0bdd9680dc1d17", + "weight": 3041 + }, + { + "txid": "ac2f826d694bb8ffb0f79bd0e25d05ced0af2ae00bd6db6c2728293d7130813b", + "weight": 3237 + }, + { + "txid": "32ab642801fcfcc83ee24d15d6403a635ab51a5cebec98f39fbb7e2ca49ba4b3", + "weight": 562 + }, + { + "txid": "332317fdaed7b837c8a063f90de86a6ca0b5e8cc5acf88579a7c8fce465da7a1", + "weight": 438 + }, + { + "txid": "99c2fed3d6ac2fa88865a71f80c34fee536128618353cd8d337866e0b56debf1", + "weight": 437 + }, + { + "txid": "71ab4941581850b2614c9b3f8e4581986c4995e24cc6f1cc7bf0ee05cc60703a", + "weight": 661 + }, + { + "txid": "075b59a0f148a498a859b601f6a8b63b987ff6f9e5b41c61d500cfd0ecb90bd5", + "weight": 1195 + }, + { + "txid": "37fd3408532a32d161edf9ff6d9fa989c369546049510e0e32b39d093630726b", + "weight": 441 + }, + { + "txid": "eb34386807af74fc8f504c3a5ab70e8e64e834de51ce4713a842b43a95cad1a9", + "weight": 437 + }, + { + "txid": "87d479b1e4e92272204ba360294649c4417dfadc119c3a91aff4254f80bc0413", + "weight": 2113 + }, + { + "txid": "ba6960c8e263a0e02be6718651b8f076564f193b9f090325eda48b5465eac56a", + "weight": 561 + }, + { + "txid": "ec715fe2ca9b9d72d1fd27c8319fdd87bac99f4a1c593df58ba8884dbaf70fe3", + "weight": 437 + }, + { + "txid": "5a0977cf2a6e313e69b82f38c631369d2693a68068c4fda1adee66e43a30cff3", + "weight": 561 + }, + { + "txid": "4c400cf1a3f23c57e90b56afce9ce06f3ef3d7d270a3a4559677de0f51faae29", + "weight": 561 + }, + { + "txid": "5557bdafb403dff28374dd864de50ae66cf06db081929c34025fc23a30c46305", + "weight": 1022 + }, + { + "txid": "05f6fd30bdd0854212fc5ac95405bf9b250494746b1960e993b0ec123a42bdd8", + "weight": 896 + }, + { + "txid": "fb4b7e41ab3e0160db3d683ae23adb1362c8e38f6acb258e7522cbc7f4ccb2f6", + "weight": 768 + }, + { + "txid": "5b02bfac52992ba1624c19c7d0af870b527d42f703579aa70df1fa6c3905c053", + "weight": 892 + }, + { + "txid": "72c32527ec8aff746cbeb2e1c3c582b58b0caab31c083d31a4fe1641f4fe1d64", + "weight": 441 + }, + { + "txid": "e98ac78ae7e93b625ee30bf7d73dd9106d921c264426a8d045594c342dbc9447", + "weight": 752 + }, + { + "txid": "4ff239864f85e6c65583c2dec05b77ad673d59202be746aa6cd772c05ad8c553", + "weight": 1022 + }, + { + "txid": "098a41e6a200bc2415d7fdb05eeeaab711048665e2e4f9299076aa67e92a9bbc", + "weight": 900 + }, + { + "txid": "e4c436a2494c533872a985d4397fba63267b15ea3d1714649649eaca3a355e03", + "weight": 697 + }, + { + "txid": "0f162825fc8793f4060ad1b4a9ab33009425a128d8b288649b0f5ac09d1df26e", + "weight": 450 + }, + { + "txid": "9521203fd6c50d6ce636983957b5c9723f7e2e71ade074dd974e57ee6da9eb97", + "weight": 661 + }, + { + "txid": "b37c8a1edf984bb32a0eefd2985db7506a806e58fb1baadcaffdf4e09cd5d2ac", + "weight": 790 + }, + { + "txid": "4a257f26ed4a34f449da6a263c5962d86dc4d540debc7774de6bd482fcfb1e17", + "weight": 541 + }, + { + "txid": "39b23ca945d6a9944f6549fd727fc404957e5a4fe49ad5f968d6176c22cb133d", + "weight": 541 + }, + { + "txid": "fbee9e2dbd754c3b0175f3a190e2c53fc86bfc4220875abe3dc945a51c010a53", + "weight": 541 + }, + { + "txid": "1d2d78a5206941ee470038536af37b27814d82980817b9943220ed60ad0f9294", + "weight": 541 + }, + { + "txid": "ebf6b6d4d6bebddc55e0f21a72c4114fb7d4d600eb4932f2fe850bf828e09f95", + "weight": 562 + }, + { + "txid": "105c1544fefcd3f63e630c8a64a412b5dc89950ff9f825fd2285bc154602aff5", + "weight": 566 + }, + { + "txid": "406223d3dd71b0a8888a1acfcbdaae33fe3f5434545e09a25b0ac0fb12ff8664", + "weight": 561 + }, + { + "txid": "5914823b8fe5ac9355c3faf4304eb93cf0a8ffceaf7c4d40c3ffa2993100b77b", + "weight": 561 + }, + { + "txid": "ea1c0d5646ea169a9cf41c2e2492b3616234a9493108ddf7634c5feb0af445dd", + "weight": 3256 + }, + { + "txid": "b049ddfd581830a3d2d1ba6f7b672f48d71f0f09bd73a9fa9e0a629f396fbed8", + "weight": 721 + }, + { + "txid": "a9cfc6d10cb4063eaf4b647fac1eb372cfaa0ffebae8477160956aa8dc4e3a26", + "weight": 1397 + }, + { + "txid": "9dab46c9eef3e07750cd0e0653c7a1d68cc5a0a016cb88dee38f9f7ac6506bfe", + "weight": 449 + }, + { + "txid": "26e5902c18e977f0cbee7f6cd1299bacbc52b6ee3c61c55aad18f22b7fedd613", + "weight": 708 + }, + { + "txid": "1c8c86fcd811460bfe29a81028c18f8b9b04bd9ab1681575e3c596f545124ea4", + "weight": 573 + }, + { + "txid": "20d3aed522573c41e4b665d2dc447215627c3949ec5085a933235b6c61f90f67", + "weight": 574 + }, + { + "txid": "f92c18bdedabe2c0db6f555665ca86651bc030d52b03954d88e13af6c9e97f74", + "weight": 900 + }, + { + "txid": "b35dabba8bbe0c0bb484daf6dd85864168497e2bb56a7821236ce1ec354975c0", + "weight": 896 + }, + { + "txid": "d224ca2e58d16f087c139eed82c48e0d1ab0df5eb4caa032e9269f68c06991f5", + "weight": 566 + }, + { + "txid": "140795d2e9bb78a6db87e62b31d6a607879d354f735401e43a71cd49d0acbe5f", + "weight": 1250 + }, + { + "txid": "1a2ac5018d3c19f6556fb5aab7ac914cccfb973a19ce4287b781cf90157e4f8f", + "weight": 721 + }, + { + "txid": "6697bf05d9736e11d50dd1211ee6ed595cc64df8bad9ebfbca79ee5fb9b23e60", + "weight": 574 + }, + { + "txid": "45a64f6f8248d6c6c9dfff1a7fb75c91f8de57b08eb16a79b350b41b3bcf8a4a", + "weight": 661 + }, + { + "txid": "ede0f922e6a29f79ec0ab089c7ca4a1390127d56d0d2bfe819b4d11ddaeda667", + "weight": 661 + }, + { + "txid": "ad55b8b077a751d52ef04ee9af912143e5e1ca5dbc690740c53594f147033359", + "weight": 562 + }, + { + "txid": "7be1be3ea502e0de0d5636d4c85b7bf7e096e4445cad801c927cafbe11912b53", + "weight": 578 + }, + { + "txid": "52bd5990e3a153a88f420b8afa954ae13f5ff8a836bee493f022d6fb18cfd669", + "weight": 689 + }, + { + "txid": "adee059d57c10501df17394916a2928053702d02e6c87bf646d72e0ff387bec3", + "weight": 566 + }, + { + "txid": "18cf8bdf3f69f8763518b387ba2d7929ecb675e199e1e70d8cc8b8f000a086e5", + "weight": 561 + }, + { + "txid": "380ebde92db6dfe2ac4ff5b8a0b68d87294a1916e0f5929fafe7dbacdcda8f00", + "weight": 6398 + }, + { + "txid": "84a23aa4fad40b12c42c01c66c1b692028c483d7099c5dfd05b32cd4bfae7e28", + "weight": 5404 + }, + { + "txid": "5c0d5f7b15f8b455b67f53891709a21ecdb741e0474fa35ed32b18a163b35c37", + "weight": 5098 + }, + { + "txid": "26ab0fb99ad69497cd76ae2373fea3308512f128bfd24fcb661f599d32c8e45b", + "weight": 561 + }, + { + "txid": "c5cae938fcf2373a9ff11d35851f172c2c752a5e7a18fbb748a4ac1c9b5c1a6b", + "weight": 437 + }, + { + "txid": "ef63bedda5630253250add6d99cd4263759f551d5843282a1f5be8f7f934cfb4", + "weight": 5169 + }, + { + "txid": "4079901eea1f29049aed9dc569c9caebf310b05ac471ea00b81d8ee37117d9c4", + "weight": 677 + }, + { + "txid": "b66a55897f785311f315b05c2ef85e309dbaaabc385c9b3314927724f33a7ddf", + "weight": 566 + }, + { + "txid": "051598d5911c7a732b541efe75a94b3263375604894e82d078bbbd9552928db4", + "weight": 449 + }, + { + "txid": "1430e2f11a18de62e869181a22d92e7fc135f66290b1fca9fbf1cabff6097cae", + "weight": 562 + }, + { + "txid": "e94d11f0f0dabbcfe15930080179ca18542b1388473cdcad4ee8b2f8d38ccfd6", + "weight": 438 + }, + { + "txid": "3c8476a12c706ffb218ab11a8c8e6a03153e99325ed48515944a982389dfed3c", + "weight": 2075 + }, + { + "txid": "97649f8a0ac03c02078bac1a9427a6261cdce254a639da438f012c4c2e3cf268", + "weight": 670 + }, + { + "txid": "e57931909e509d1ef06dffeed0a320570431db49185c92b11764341ba9ac84f9", + "weight": 685 + }, + { + "txid": "4cc5f2f35c81cd38654aff2abc972c5257c5bd389a3d67f788132c358d3bf87d", + "weight": 832 + }, + { + "txid": "21110b58dfe9ad767d737f990cc484daf8beb5ed028cacd9032025c776efce8f", + "weight": 541 + }, + { + "txid": "3d31b668f1048d0254d7e441cef77abc3e803379431e2c51ad0de33ddde6c6c1", + "weight": 694 + }, + { + "txid": "83b34b69f2b0e822d37af309ec969294b13a542ff0e76fc64bcca4f0a26431f6", + "weight": 693 + }, + { + "txid": "2d979f70f3bdfd6502a60eb333f41af6c650cafa4f3804892dc46c2ef9fb2714", + "weight": 2300 + }, + { + "txid": "1f2748595786b692e227c8de71b356d91b6acf737adccff1d864650152e67d5f", + "weight": 8292 + }, + { + "txid": "7c03fd73a2573424b948b85d937a78cd27a45402f801b67f04db0ac7bf280c0a", + "weight": 441 + }, + { + "txid": "7d81f929e9897b2e5348b24597bb733c1efe189971f23510e983120d15760a51", + "weight": 561 + }, + { + "txid": "98813b4ee05c5d89dcf52542b14485e34f3855b6e3133515ff2b077b341e6227", + "weight": 437 + }, + { + "txid": "d71e408cf7aac112792edc16709fd8e5b2a6fd62aac213a87e536565cc3fffa4", + "weight": 437 + }, + { + "txid": "c21b147413676433d299d145479983c37d6ee8b18b726df85697d1e192fb958c", + "weight": 565 + }, + { + "txid": "a7ef17d077a697b511cea861832f19fa385ad633b490bbdf579d56ccaab7f320", + "weight": 818 + }, + { + "txid": "79919508d86fa67310986e0a2bdb7024b1465a58facbe5afca28b6ed6439117a", + "weight": 1484 + }, + { + "txid": "4731d35bc131f8c49a687b5896884d05a3f90eed1c1876152f90b1bf83b60806", + "weight": 760 + }, + { + "txid": "408b7735116df5aa2b588813bf56622dbcffda178b450c4290a6fef9009cc701", + "weight": 1250 + }, + { + "txid": "6531b7298884f5f6bc9f6f8ed352d41f2d6345ebc1e23adc5458297961845ba0", + "weight": 892 + }, + { + "txid": "0cc228fac12ec245cd9d34aaa2d5cf0c0fd38cf21c2980b776d422054b1daffb", + "weight": 892 + }, + { + "txid": "4090406e5a16a798f2c425b97f50a948de7b49450510f6c10b433e9cef4e3cc2", + "weight": 1472 + }, + { + "txid": "912a98f21c014026fcbbfc4ee098196b16b79986fbcb6b1036dd73ff3f6e3100", + "weight": 1949 + }, + { + "txid": "6442c99ac9b073058c286b51fc1e7ac2bb4115f16a9680b9bf41aeecb408f301", + "weight": 1309 + }, + { + "txid": "f7054b7052ceaafd36afbf89d104b9d58fb5df7cb3981a7fa741204fab26914f", + "weight": 661 + }, + { + "txid": "82d9ef49db22fc7c79c525ddb96cd69865744d6764556ef1c99a7a0393e7214a", + "weight": 721 + }, + { + "txid": "3b53afe38e3b22f03bcf01bd7b940e27be5011e12321795796628cb760a09801", + "weight": 752 + }, + { + "txid": "f5bea686e98c3f76c9f18d4446895039b403ceb1a6ce4cfee249dc6a4318859a", + "weight": 1065 + }, + { + "txid": "a6463f468ea409e681eb2bdf3cb9e6330f423587b83ca27300321861565173cb", + "weight": 1277 + }, + { + "txid": "7699a299ff1b19a8c7252f0fcc664009f86131d3955685598dcb739e9f4d7e55", + "weight": 566 + }, + { + "txid": "8d95f46dd684d3075f14f365c7f0a529288e5f72ddc9c3a05dcbfd69472d1cf2", + "weight": 2299 + }, + { + "txid": "d4155c0916e2a8f23bdd170dc02c392786dec17ddbca81840f891a2664a3ec69", + "weight": 935 + }, + { + "txid": "43aceec8a9d665a8a541da12b21ed9bd5d1d357f2ef452537df9084bec2061dc", + "weight": 533 + }, + { + "txid": "274884686e2608052e4c682c55b6ccaf973dc5e66345f115eb8a9d5356893add", + "weight": 565 + }, + { + "txid": "65c30c0609a7939202cd4f2ed19ebfe29fe5910ebee6c7b617303d17da2bb837", + "weight": 442 + }, + { + "txid": "22b765bf9bc20a33b44aeb2b9a90949569ff5a28f62f4590d2c54cc807df13b6", + "weight": 1352 + }, + { + "txid": "daf79e2c299ae3ada1c23fec2cc878df5d1bc1a38bbacfda75d841b1986a5707", + "weight": 561 + }, + { + "txid": "248c6447ec5f3c5624bff8b10da059b99358d8bf5759ea078bc177e1d5e1c35b", + "weight": 561 + }, + { + "txid": "f602405d62d81d1c74a96895d66138de480fcb052c63c5c92a5e744667f17a7c", + "weight": 561 + }, + { + "txid": "41b7d3f15da84b161158f12f140218025d20a28cc0ebd27608fe2985209c40c2", + "weight": 561 + }, + { + "txid": "998ad5aa35a85e081ebd62222d9ed01b5717cdaa53b2e64eccb4a3b0a54e12f3", + "weight": 561 + }, + { + "txid": "b6b7d33e11185d8fb7397c02550f90a222b21cd84003d3b70afe452b7a11ffd2", + "weight": 561 + }, + { + "txid": "0f9916e9e93544a7fb0b51dfdcea67918e3b1260b78739dc001b21565b9351f7", + "weight": 437 + }, + { + "txid": "b82e3f7021a423279e4cd560127f0138d0e7d88d6c26774204e553ec627a1f34", + "weight": 561 + }, + { + "txid": "a720004f24d8984272bbf6ef6346d9f1c38bc43f06e013bc1de207f28196caa6", + "weight": 755 + }, + { + "txid": "411e50511034daae1ef0d512b6e34b7bdaf273f74ac716e75265a8dba73aeaa9", + "weight": 1103 + }, + { + "txid": "3c300c070ccb8bc64490c660df2f4213b18af6b0936fe8b17efe689d32199d0f", + "weight": 832 + }, + { + "txid": "766e6bdad62c4ed39ec0556c519c3d3e737fcaae589d9d88b23d27735ae5323f", + "weight": 832 + }, + { + "txid": "286cffece22c137fb2cca1e0ff3b0b5aa62466ec010af77095073fc86e506e9e", + "weight": 1476 + }, + { + "txid": "fd659900cd2c6f3f844ecf7906ff5b6a9aed2bf0fb527ff838e0c7e15d4eca57", + "weight": 708 + }, + { + "txid": "d6645684dcc3333a46b3e943e16f1e1a3facd0ccde3794628e43d2fff3826616", + "weight": 561 + }, + { + "txid": "3f8112e5270870d902fe54080c2251aef8d8c78e64b1d72fc679baa5ab0fd086", + "weight": 758 + }, + { + "txid": "0a0e87f7c69f489c5ccd47b4003a83037a035f71921b16e6ed49ab200a7b0032", + "weight": 609 + }, + { + "txid": "7f8ea2c819e2a3ac437dfd46886c1f05e383629a45286b509ebac4cb009ba912", + "weight": 610 + }, + { + "txid": "db049d495c03cc9df148b8ee1bf35cd168ec538c578785c7da34b007c7d47efc", + "weight": 610 + }, + { + "txid": "982a0ce80caec69d5c628b0d3a448fa60ec897492f8456395e42c0456e6f0b6d", + "weight": 441 + }, + { + "txid": "c1e6137f2ed05c492fb0b2b82db74479b9e908ab4cc76a5e6ee9fa3297d75f0a", + "weight": 573 + }, + { + "txid": "6f425f3b1e83c72293f80bdd197cc18af36d6b0e56eca8dc5a66db8526f43096", + "weight": 565 + }, + { + "txid": "81a2dcaf4177540202fa3c38eb22f153879748fd133dba04d4bd2abfb3705bac", + "weight": 561 + }, + { + "txid": "eec1e47bc72b4d368a14ecbf792fc99d78e128b5153cffb8af6dbc7d44965d7f", + "weight": 561 + }, + { + "txid": "894ccabecfdb255ca833039be5295ba7870c59d4b09b44fcf9b8d0cf3c6b53bf", + "weight": 561 + }, + { + "txid": "5e2bb46fefc7ef56b0aa312a9c392a5013e671b661a4437807066fdf72af1cdb", + "weight": 561 + }, + { + "txid": "b4b6b947b1a96564698f2c986dd1150848e21559db67a9f47e7217c6053231a4", + "weight": 449 + }, + { + "txid": "82275be95487453c07f9d2c35948d1f0132a1cd9f4e8c3a2cf4ac6174c75d710", + "weight": 616 + }, + { + "txid": "03f24b91945558bafacca53e375ed02d5e19208b56908ff245bac329a50e207c", + "weight": 662 + }, + { + "txid": "eae1a6e15598b9ea9fd4bb100a60919850e6dd36182b8133b8073c1a9e1857c0", + "weight": 24636 + }, + { + "txid": "c2bd110c1cf140a7190f4accc7459c2f93c83a6eb1f663d6e047722c92a1aa68", + "weight": 1080 + }, + { + "txid": "c4cb4cc27b95d02c7fab5c5023e902bb2769d2fa084db575a08d754c01da54d4", + "weight": 893 + }, + { + "txid": "39aff51a224a75374e6059cc31744ee021ed90ce6091421c55083523cb7ce3f7", + "weight": 658 + }, + { + "txid": "72c61bf6c43daeb118031f046c72e8138597b124938c4c18f54962ec13bd3e49", + "weight": 437 + }, + { + "txid": "3602d42a5ccbb58f40b844c1fd6e7e70d58b90e19333afecc328ce752ee9f6d0", + "weight": 437 + }, + { + "txid": "a744595b12a1caf04b0aef909f69457cc2fbe1b3c5319e502227a23f96452bb6", + "weight": 708 + }, + { + "txid": "181a4e3e63476e2779f351c37fcf63076db6b1ed3c2d399283897028d3ca113c", + "weight": 438 + }, + { + "txid": "8b4009e97f28c992d12a9711523f583a5f3a9a2f561a3c84aa9e27f9c61f6643", + "weight": 438 + }, + { + "txid": "66e2d790a96e3a3c83fa9c04cd4d9974c83afda67d238ecd74c471b3af7c946a", + "weight": 437 + }, + { + "txid": "79a4a383caf45975f27a5fa57a92752856353183973029264884a8280e564c34", + "weight": 573 + }, + { + "txid": "fc9fb727a3d908e2f04f20aef23dc96d4f0add1e1481d1920709c590ace953f0", + "weight": 756 + }, + { + "txid": "27463a4e7fbbf7c86c1432889fbcf0a7244d35794de9663eec4a0ab512cbb2d5", + "weight": 2676 + }, + { + "txid": "6ec07bab41c78d101dde3a2abdab9b9a0cdfc2bafa02bc2ed6e4089dc17d6ed4", + "weight": 1677 + }, + { + "txid": "4069035e1c16b492b3262a0aad2f094e5fa3cf4e06351aae4c5de5908a465fb0", + "weight": 2007 + }, + { + "txid": "f9b09fb06fc61440559ff2103a51183823a4efbcaeedefeb288dabbfdda8f3f0", + "weight": 561 + }, + { + "txid": "c106f09ea3850ad1940aaac7658ebf810abc90d799d723ee35716a40f78ce2d8", + "weight": 561 + }, + { + "txid": "849c79035605f11d041e98cc2305d131e25ff676e9e7ac77477737feb82c72dc", + "weight": 562 + }, + { + "txid": "e7b1cbfed796fbfa60615053dc149dc27c7d82fcaa8e173c479c89593c1b8bd8", + "weight": 561 + }, + { + "txid": "b2994a76119cd5f929f8ac24dc200094dc63cbb1b570bdbafad18fec7562319d", + "weight": 609 + }, + { + "txid": "4ce90bf0fcc1f202140020028a249245e4f9d9db8f7f2b765024d740e89e91b1", + "weight": 565 + }, + { + "txid": "f35995f5cd7ceb45f1f59af1c95dd2e3645d93fe0b67df1f168b5e50ea1c088e", + "weight": 562 + }, + { + "txid": "a15d15b6b49fcfa1fe7faf4a3d4ac9745db3b664f3cfea038a8e7357ec40bbf9", + "weight": 566 + }, + { + "txid": "69283bcc0798385576983bc22ecc291bf38368261ce6301ce571042b7c91bad3", + "weight": 610 + }, + { + "txid": "cee466e8f13f11053a8cc60d57d2ba9b8e8bdf0ef988a73f259b177a4af4a870", + "weight": 562 + }, + { + "txid": "0120c0aefd86e8c46d5e883666c85b24dc094571c7c699d15e5411a2758b0db1", + "weight": 562 + }, + { + "txid": "50b2d9bf39692ac3b30cb09aec63a3b66f3d597c73fa2b5961dff7ca2a9245f0", + "weight": 561 + }, + { + "txid": "abdb4c4ec05d94de74411bf95797b030b435cac1e6be7cfbdb5f52320372c06d", + "weight": 562 + }, + { + "txid": "cd4cbf6032fc444def1c55825a7165a2ac35ff6da3b084f7842223a9c64599f4", + "weight": 561 + }, + { + "txid": "fc69fd672c049c85530896ff12419c0c43718eb0dbfb36c1af9744ab86cea4bf", + "weight": 561 + }, + { + "txid": "bdebd3c7adb592c39866940bdc2472bde70caec99f227bf78143280c824c357f", + "weight": 562 + }, + { + "txid": "fd811f85f5883481dad71c82b40d487552a29f596cd814dbde3fa7e346ec2db2", + "weight": 561 + }, + { + "txid": "2b5125751caba332db4f14d2683302ff53591e41cf589eb3c796507157fcc3ed", + "weight": 574 + }, + { + "txid": "4197fe0ec6383171456a868cbcaac86fc118208934d2c6ec0d4381c86eb49eef", + "weight": 562 + }, + { + "txid": "8fd75292554c311c46bc0077965d8a0866c9b380c156722165c40c86c13afdc7", + "weight": 562 + }, + { + "txid": "6ed824c1752fbff0aec991180c440eeb4722739f87fa2a82ddd94fc89328f932", + "weight": 561 + }, + { + "txid": "5a1be765d06123c15a04cba41f87a59c9413b3bbadf39567dfb50c4d30d5f2f4", + "weight": 562 + }, + { + "txid": "49d61c0b0a8edc95daff5da4602d0f044c5dfeeb1112f1d63fc26ff5514e7d22", + "weight": 442 + }, + { + "txid": "55eabcd38f2e7c8231ecee6094f6d0a2757fdb212844028b9e955741739e3ca0", + "weight": 437 + }, + { + "txid": "c8f5faebe054e0b1f5417be6e8cc94516012624261294e39cf08fb8ad8898f34", + "weight": 566 + }, + { + "txid": "3934db2dacaa451a62767dc8a28ef1cb107aed523f3ec4573bd45b8ad477f338", + "weight": 450 + }, + { + "txid": "b68aefbe1fb0250d8ee582c9bbbc10e3a8793c0d70eeb2079eeba96025dfee83", + "weight": 450 + }, + { + "txid": "45feffebd4f80185f20a9b739c8647b801add6dc044456318d194ce6512a25a9", + "weight": 450 + }, + { + "txid": "1ccb9f9492c466133138a7d8af3ebee15d6187c14680031121c362d9fe9e1026", + "weight": 438 + }, + { + "txid": "73052d52b85f1a97fae284bc45a08916e6f97e26f8c3f9e4b2b08e09cb082c88", + "weight": 437 + }, + { + "txid": "935236a570210d6c498036377b61f2b6232c16a9788aeb388b9955e23018c1cc", + "weight": 438 + }, + { + "txid": "2ebc18abc7eba638cd1c542b4ac2785259b435050ddfb02aebe0197ebe2dbbff", + "weight": 438 + }, + { + "txid": "999a1b372daa11a5e82a68f58cfe519236b5566081c3b55c0a7dbfe976db5a91", + "weight": 888 + }, + { + "txid": "64821a2015fe71bbdce655c5665ce1711067a1fad76b4606b5b2da0c71060636", + "weight": 892 + }, + { + "txid": "8d79b849deca33a97b6041664a0bc802ae31bb3e37136c4b8772d032f8234555", + "weight": 710 + }, + { + "txid": "28cea429d8446768bdf1ec124805c4c134dc9360cd9edf6a7654fe797849198a", + "weight": 542 + }, + { + "txid": "9de866a85f8b70892a84b696a033dee57b05c7d6531be63fe80b047ba9537d34", + "weight": 1388 + }, + { + "txid": "6ff82200d7c5135536f3cd376c1953900f113edd3fd9d45a6a94022d643fba37", + "weight": 1329 + }, + { + "txid": "08938b2abd26615731693b6e813bf3b992c428346a05ee969ee4c1f1cd0da462", + "weight": 904 + }, + { + "txid": "d1c7c1e5f77c29489e3746a75a36b7b96569031e762a28357890e1016233a1db", + "weight": 1217 + }, + { + "txid": "b41eb76ab460ba9799aaeef44f5a36e2fa0d856ff05cfef1f973b27472d8cfe9", + "weight": 844 + }, + { + "txid": "6e3f998d3ef25da153d4461b1aad66d42cfa816df0193e8447d913f1d550be0c", + "weight": 836 + }, + { + "txid": "95f05361d0ec1d53c9c5659f2f253f42ac9b3a16b41833c95292ee5200bd45ac", + "weight": 1918 + }, + { + "txid": "806ee16f522ab91d076890fa111fededd0b72eb3e09fa7bbb43be8ea3d4e8694", + "weight": 11465 + }, + { + "txid": "2fcd9d30f49d2614e4fbd25ea92a11c5a4aa032b5ba5770716a70b76d4721865", + "weight": 441 + }, + { + "txid": "df488aea4a2f5244d165b4d9d50c415207ebb20e168934b618c37b0ac15e735a", + "weight": 438 + }, + { + "txid": "69deb11622500796204a2b69d1d5b9b5ddd8e6d750617c5e6473d3c07d4a70a4", + "weight": 832 + }, + { + "txid": "117e063412203e883821ba5d4aaacd674eee11c505d058231148a60f10ef0425", + "weight": 1496 + }, + { + "txid": "68eb7e49e0462520f6bc19fee08102068343992e6a02f73d17b964bc2f91b674", + "weight": 573 + }, + { + "txid": "4266c5504c1c7c7d7108da8012198c7bd5bc646d6041c92b626f7b9649786315", + "weight": 574 + }, + { + "txid": "360c6956b21eb53e980131cb22c555da05d1b8a5934e5d637072730ebba82f8b", + "weight": 574 + }, + { + "txid": "37787b255e0ee6f5f1f86c8c555ca1ab9128377ec89934a85d379192e20aac3e", + "weight": 833 + }, + { + "txid": "a4fdb8f8f36e34ad14989fd13caae0176a9aaf779404229d164970bd8f24e804", + "weight": 566 + }, + { + "txid": "5343ae08685216e7e1d1717cd17ff6f6c819fc548ecc6133d21118d3e0a3b91b", + "weight": 566 + }, + { + "txid": "881e95cba709055cbedddb04477a7079969c78aa5db91afbc1630e38df28a81c", + "weight": 565 + }, + { + "txid": "08644f04efe429ce5f002b7627c4ed890a192fbc694e51c68e2e6d3b9185781f", + "weight": 566 + }, + { + "txid": "a99d48faf09714f637485b0657febe757ef6f061f7e0a93c00ad413998cab94c", + "weight": 566 + }, + { + "txid": "56459a2d1ea58b166a74e3ad8b454b38ac48bd17be6979d627c59ddd66ac2d52", + "weight": 565 + }, + { + "txid": "1ab9d37011eec802183b75694ae3ffdf07a2589beb71440ec2a7d5629f06d7c2", + "weight": 566 + }, + { + "txid": "cf89371d01ed244a59a12f393a0011dc8cb5d7abec1a636bb9062a04b931a7e4", + "weight": 566 + }, + { + "txid": "b1656cf2cef025a8139622e1f10d5b0b51b683c082ebc25b90dbdf167fedd20e", + "weight": 561 + }, + { + "txid": "b7f18cda12d09df7fa79fff88a8853a4b5b9303025de466ca1efcc6179ed65fb", + "weight": 566 + }, + { + "txid": "7025ea897994aea627748bba87cb07b55f97665b72196cf77197241ea7b85324", + "weight": 845 + }, + { + "txid": "b68c73c41173a4539d59ad88cb704661b88a36479b5ec0a514060f26d3a8f2b3", + "weight": 845 + }, + { + "txid": "70d01d76ac57c950e260f8f7653ed4b32d5efc23e29649d420372b37361f26f2", + "weight": 845 + }, + { + "txid": "46406270b90c084b2937763eef8e0717bb563e6805191d92fc49fa942a8fa008", + "weight": 562 + }, + { + "txid": "21e472b114c1a3e7d922331f7d47de73addb6db1da199569aeadbb19da395b36", + "weight": 562 + }, + { + "txid": "bfd876b0b4ad0e66c1a2dc6adf36573335f382ac0c880c789007c353a08afe86", + "weight": 561 + }, + { + "txid": "0890816b93a44a1847d3f7ba57e1523ad8b5751ea6bd00719f27688b5c0e698f", + "weight": 562 + }, + { + "txid": "5ed497a8544d2789863805674cfc8db075b8f61566451af60db2ea5cdb8348c6", + "weight": 561 + }, + { + "txid": "3a79123edd869a857106229adc4e6693fc9f5dddd8a22487f64bab065e3616db", + "weight": 561 + }, + { + "txid": "dea111b8d2c9fe1eb66ba80db5e71a8591a4044f3a318f411dbd6cbb79c691eb", + "weight": 562 + }, + { + "txid": "42c060dec5e0e71652af393c5cf98174ae8aa6a653989b1a5999d52758d9a9ab", + "weight": 4526 + }, + { + "txid": "026fb3ea7c8edd1175002f548c39a7ddb4562ff824d32e8da8c384671eb488b4", + "weight": 561 + }, + { + "txid": "36ee75e4e6bf756e496ed328d8c71bf23237a069fd86692fca7496e7c910650e", + "weight": 1159 + }, + { + "txid": "372e4fe80b0e203e940bf44086845a74b866c7090edd488b40953fa353d4c372", + "weight": 838 + }, + { + "txid": "161956096751137ef8b2692219e0cdaf71d199bfd2145aa3bb5d53e0094c3db6", + "weight": 837 + }, + { + "txid": "5fbea6554c4eea866a2ce041c5ea0c99fab803e1be973fddd7aea08b4dafc07b", + "weight": 721 + }, + { + "txid": "c65572d10a128c8ef8959661702acdb0a0e013fd8e94e02f1963dfacae244d7d", + "weight": 450 + }, + { + "txid": "1035c3e8059e810cbd365b07f35553db33c4ebbd2c705103ae4ca14536d6dcaf", + "weight": 450 + }, + { + "txid": "ee71d79af30fb006bf649f203366f2b18e1b7d5e9ce241c18a8845db6450450e", + "weight": 437 + }, + { + "txid": "6115a4b9a9440695a3b39e54d61e6f058004e7489e7e4e9d230010a9943111eb", + "weight": 756 + }, + { + "txid": "3274d07d28c04b07ae78a23ed2acf06e427fe66a892ec9992c3f460e923fc9f3", + "weight": 756 + }, + { + "txid": "6a786257792eb9f1df22ff98badfeabf5b6a3a2d589cb14e2c09411cd1091ac3", + "weight": 438 + }, + { + "txid": "12d7efb712576fbaa4018c74755ffd2114a7b318d9c9ea937ccff361efc92a0c", + "weight": 437 + }, + { + "txid": "a0207eda6a31ba18ce52830db589fdcef8e13b76c72011dcdf113c3d878d3797", + "weight": 437 + }, + { + "txid": "753fa12ee401fe466d6e8fb882274a34cb74292efe1978da20ea16bc012bbad4", + "weight": 1344 + }, + { + "txid": "a95482d5833bd0d482b67dc91eb96c5f56a399b8d2b7ee57a5e48559c9ee31a2", + "weight": 764 + }, + { + "txid": "d20a7c520ad5290afbcf297011fcccb7a4e4b68c9e5a9d34243e2a640704cb64", + "weight": 1760 + }, + { + "txid": "81bf837be7ac3025c8b9f1deca9fd26749d2b9a69f38315d3cf0dc1b9df9b38a", + "weight": 442 + }, + { + "txid": "c7459fcd778cf1eeeeb7d875cee56b328f7938c17378bd806c55a0e54fea5555", + "weight": 2664 + }, + { + "txid": "26c69ab8a807176b6fbfccdbe5c9879446e8da7eb7a78cfa12eb2018dec9df9e", + "weight": 752 + }, + { + "txid": "74fc822e9f9b7b97dd62ccdc02eda0a72445647ae1c93c05797c3d1caae8fe7a", + "weight": 2479 + }, + { + "txid": "93f46f360eab9957aa1cff7694e48ff91afd7883d2fca07cfedbd26d998b5092", + "weight": 3204 + }, + { + "txid": "d3afb5735e84cd1fc6f6370e76442fdac69ed901f9092c47720501d3663a219d", + "weight": 896 + }, + { + "txid": "8c8c4d77533c61546c4fe9715bc837f7de8bb8ad6268514048ff3b0f81cb73be", + "weight": 441 + }, + { + "txid": "804e21b303c9465f712b60a9134271a8bbc12e7b6de4057cfd17cd60bfb2b0cc", + "weight": 657 + }, + { + "txid": "ca1bafeb300bcb92703feb5633ae05d6ae91f6f049a5d1d5be85a05d7adc66f1", + "weight": 658 + }, + { + "txid": "6b0710a0fab17f5e62fc776c6bbbe162fac03af93671e321d0a2e77a2304c52c", + "weight": 710 + }, + { + "txid": "470536feebe9d642d8c65f8651cc9bbec10d1058cdd966fcabf8817bda47ce48", + "weight": 709 + }, + { + "txid": "9f421aaa0d49d96f2a7182049adc1b142b150a252dfd3840fc505eb0b47e02b3", + "weight": 5069 + }, + { + "txid": "16edb2473937ebb3803f9f1a99c3baa917378891bb424dd30090d27f59f6258c", + "weight": 2158 + }, + { + "txid": "d2af0ec7973d3ab95581025152bab1c3881b5e435337384ba52c482dbd017776", + "weight": 4705 + }, + { + "txid": "1edff661efce733aca4c7797c251bcba6d390749cceaa6a72e43e29478c5aae5", + "weight": 832 + }, + { + "txid": "978d680bff9b8e092f955503766354ffc73e7a619b733c1bd960bc7225bf676c", + "weight": 1672 + }, + { + "txid": "9832c0694b1a910066e49d8433c52b2853868aab307b619b0c5844ed5150f55b", + "weight": 768 + }, + { + "txid": "799b47d1c593f370d1c76974615a1a955031d2398d5c7f5ecfad2402fab1565e", + "weight": 768 + }, + { + "txid": "1f0c542c4763592a9eb7438f5322b8d1483f97427ab91f8c0ef09a71fdd69261", + "weight": 573 + }, + { + "txid": "351058d46cb93a0d2448628900ee1da82f42f81e896d1b1a9e86678fb94d27e8", + "weight": 573 + }, + { + "txid": "ffa6e6ec8e325f8ec0c6ac75ba8f3ced9053782f53a175306b3825b47f1eed46", + "weight": 574 + }, + { + "txid": "56b45d67e10a760e3c48307d5773f07bc4d33efcbb981ced82c06ee3693d6b69", + "weight": 561 + }, + { + "txid": "9ac6f1bf910c6a85ee163062c2632ce07fb78b5437356a8b7f4ffb7283085094", + "weight": 561 + }, + { + "txid": "ba368600dd69f6e0cb1e43463960a21a52fba1c4a007746d9d4acc6a3e8f2dc2", + "weight": 1116 + }, + { + "txid": "0be72753cb86008343bf8b918ddf4cc3fe857b896aef3d698f329c1c7b60c90d", + "weight": 880 + }, + { + "txid": "c00dcfb6a49ed3be60994b9631a04b62ed1bc8ce8609b1e14785cfff8ecc9bd2", + "weight": 833 + }, + { + "txid": "7bd1c3d089edc05a972278978a54aa8288846671fd3c74da2dc68b527b21cda4", + "weight": 573 + }, + { + "txid": "865c512d057d41cce4b7b51559f486c3cc46324abb2a88ca4b796507bf34c710", + "weight": 904 + }, + { + "txid": "bf918837ee2194b6333e0e91b3b437bbb5c3070c3ab502a788e45ba8bf013a3f", + "weight": 900 + }, + { + "txid": "4b81243ca197d18b6405d8243ad06d825bb12bc6e79ad5375d87118243d4f544", + "weight": 708 + }, + { + "txid": "888fac3854a76e6bbc7d0adb823211d82a1a8eb426bfa5fc2b0bc87b7f365eae", + "weight": 1814 + }, + { + "txid": "150a011d116fd2876c593038df6d542e9c2879bf828ea76a5a15b6675c724efa", + "weight": 2301 + }, + { + "txid": "870753b2a09f0bb70a5622a41cdd8d41ff7de7cf583e87f428c32698a8bec664", + "weight": 1254 + }, + { + "txid": "199cc502c73943a261684ed504242b86ad63cc5cea0e0d01e8d5b3c269873b8d", + "weight": 2113 + }, + { + "txid": "fa8649ad2397750562b3cbf79370c9105b2f038fc34fe24544537acbecebb9ec", + "weight": 3806 + }, + { + "txid": "43558393c610dd8f65c6f51bcfd6c4f2862b7c4c6ffd05c6b3c0a4c8de43a722", + "weight": 1026 + }, + { + "txid": "f1fb88e1550c5013419374df61930a5f9d37c32eaf3fde97c68dfd0544cc5ebe", + "weight": 1057 + }, + { + "txid": "aaa54c8ed7513b340b5c80d439691709b0a790242baded9a6561e10c198e21f3", + "weight": 950 + }, + { + "txid": "3eb6170d0168b2d5fd102ceba55f5d06eac49309a94edacb02233b2dda689bce", + "weight": 1305 + }, + { + "txid": "62d4721022a31c59c0da9cea7fffed827ef3d3d30ab7c4ec9b64d52daaa649d3", + "weight": 705 + }, + { + "txid": "dfc7fb7a32271b9d858bbcf8cd60cc61482732b78927c04f318610336db1377d", + "weight": 2191 + }, + { + "txid": "65e688b3a4b476c52ab49dc80aa136ca92c8b533572aed62d26fefd3be8c1ae1", + "weight": 836 + }, + { + "txid": "788d7bd016833df03f7e50f2ac01d73c85088122bfe9c5fe24b148335515cd77", + "weight": 937 + }, + { + "txid": "c7b99477b7a452de92d568521d83222a3442997f04de91f33acfc38f55524650", + "weight": 437 + }, + { + "txid": "a1bc31a2f24c47e8be40707781bf0b9467c92324d42dc0a6b311d54e5fd0868e", + "weight": 1917 + }, + { + "txid": "091ce1d4e2312cbc8cbf1853584c237d73a012cf058604e021008ca1d79c97aa", + "weight": 1105 + }, + { + "txid": "99ad9e13662fc027c7757ecca6afba240c1f23cc6f64b114f5e54781b395af51", + "weight": 1377 + }, + { + "txid": "930d1ceae5c53fc9c29441972a0a48d96e847bf306b36cd9cdda304c920697bf", + "weight": 1721 + }, + { + "txid": "3e7ec56816169f0b20767c2c67bac94872f908f3c212b40fe014600575c55008", + "weight": 1747 + }, + { + "txid": "677d17890203b0e86829e366ec0a0b0dfca8b24ca306369af5bd32bf869d9ead", + "weight": 609 + }, + { + "txid": "3b8d7293c8bba586fde191dcd8de78afde9a021a6a9aa2e69ea2e08d0c9dde30", + "weight": 437 + }, + { + "txid": "cbc448f2e20030e2b238b9648fd081a968032cc428ce6cf89d1aec882ee34a45", + "weight": 562 + }, + { + "txid": "c19b714a369c77498498abd2481ba0793abde4fe18e5769e82ad7efd6b33ca31", + "weight": 566 + }, + { + "txid": "3161764aa216210d5fa495672c4f54601007120717563718811527138e7b04e7", + "weight": 566 + }, + { + "txid": "6f028c5b706d76809465a7a922e9b9c5a6771f66234f4b71efe181124be0263f", + "weight": 566 + }, + { + "txid": "1b0193965528e766342fcf5c58b5c56efc86acbe4c1aa856f8da811ca6ae4665", + "weight": 565 + }, + { + "txid": "c4bd88181530bbf602a0ba7f2d6e59332f9e123c891f6a8514216a351d11cc85", + "weight": 566 + }, + { + "txid": "59fd34ac5f9f0b9141a65e9fe6938828c7a55ca537f2d75786cc13ed7a4a2499", + "weight": 566 + }, + { + "txid": "de15d81bb3fc5a16e9d0000a64ebd15bf9fe8c85734ee08a7579ddd24eb8d3b0", + "weight": 566 + }, + { + "txid": "5ab405019cf2d1381692a308c535df5e24198a52e2841404047fb4a09beb2aed", + "weight": 565 + }, + { + "txid": "0aa24dfc46748096e13a742bd01005de98cdf21e67a6288ff0f05e390da35526", + "weight": 833 + }, + { + "txid": "b3665903305a5a0890b19f11243bfafb48c920f49c956f735dc63e6f48520666", + "weight": 833 + }, + { + "txid": "e957c8ce55d8cd99c5b97f593cc53700a7702f64601cecf6ab713dd091c09c1a", + "weight": 845 + }, + { + "txid": "4a874ab5d55a4233e14929cd4f1b3298adee6178e148ea540868a97622d596cc", + "weight": 845 + }, + { + "txid": "4def41a3a335a2509e6ed296598b3958944579c4e64cd054c0c8e38f179ec723", + "weight": 562 + }, + { + "txid": "81012be8476d57d44aefcf380e1eee6f9a351c6c025f326e4c7eb5e0abf057bd", + "weight": 562 + }, + { + "txid": "546d6ac5ecb3a0540d14a2e9b4ab923f99ba042ba378e6ed640909e917fe2890", + "weight": 561 + }, + { + "txid": "355270a6dc46ec1cfb678b786e9f82ae4689cb359190a2514e7bb53d3b3b2ee7", + "weight": 561 + }, + { + "txid": "4dd8d0339f10baa0351a90f2cc9759d7dc84637a105ad17d2b58922368e95cec", + "weight": 562 + }, + { + "txid": "ff83221a0417432ae99dfcd4787d3775fde864af0b6b1675e830a872425f5783", + "weight": 574 + }, + { + "txid": "3820437332b66db7f8aa13580b3290f132a566db778386f08907cc08341655d9", + "weight": 573 + }, + { + "txid": "8ce2c6cbdb8552bda6ae2147b408e373a2492f9e0ef130dd9feb8e17f864960d", + "weight": 561 + }, + { + "txid": "e326e299d2333841d64b2cde4764701768604ed41afd5ec9280b5e56f0700e75", + "weight": 561 + }, + { + "txid": "037ae25fb9e66489845bb29f418b938cd657e4a83c49c040e5076405d23f5272", + "weight": 562 + }, + { + "txid": "20c106ad9f27b17bd39cac690d292d1930f0346946681177f7b414aae9582b19", + "weight": 561 + }, + { + "txid": "744c3f06132da9382319d979daeeb1e1cca8c2f5fc9d28cc44cfe3782e5d551a", + "weight": 832 + }, + { + "txid": "b6aaddc9d4129973753e0d5f788d796a843d8ac7fcc3944458e4fcf8778f7c84", + "weight": 1462 + }, + { + "txid": "f7c3b6c85a00002c3ff9e70288c20e1126fee5a10100f517c9128aaf4f4ba421", + "weight": 1701 + }, + { + "txid": "b7796025cd12a8124ad38ae145ce05748416c05d745d1150f419d27044df9d9a", + "weight": 449 + }, + { + "txid": "acb5e120725750b554449fd2d69876eddaf642de85299c910fc70e62804ba8b1", + "weight": 900 + }, + { + "txid": "bfdf7a1798e991c0c0b05c98a9d6d83987a04b270a3f165155bdd5dfb5e88587", + "weight": 714 + }, + { + "txid": "1875edea499372dc37e5c907886949b0190fb60ee4ccb8b8a1feb4ab4805ced9", + "weight": 562 + }, + { + "txid": "33e3ff205f6ee35c3f6f28e984d6e5934fdcf4d1bced8e4efa666a04c934e246", + "weight": 561 + }, + { + "txid": "ace6b791cb4ad2ceb63d84febbb08f5167d06f6f6f41dc613dcaeb940d44dd11", + "weight": 561 + }, + { + "txid": "35d71d462ebb8924344150bd8e6b65187167255d5266ccd5fa5a74cef0a17d32", + "weight": 713 + }, + { + "txid": "2efcc7314bf1399f38d12230ea65975bacb652f1ca071a0db5f55db29fb58425", + "weight": 566 + }, + { + "txid": "51dc806446567460117fbc61f4b57f392f091c66b6d4067c2d7ca49db0c98552", + "weight": 566 + }, + { + "txid": "cfa7ebd54ce719e40c866b18613b2599420d7673b5b676556143b2010041907a", + "weight": 565 + }, + { + "txid": "2586a90634cfba28d48acbf5dbb67b49a2f84eb9af236fc6a90f92f04ceaef98", + "weight": 573 + }, + { + "txid": "6619edad45b8536c877e01f1f35d23adc90deb4c5957c8b30a2c586c5fdd99b0", + "weight": 573 + }, + { + "txid": "4ce2abc121fde997424364a3af5a1b8cdd1f55b4960579fcf493c6fa4c0cf00f", + "weight": 561 + }, + { + "txid": "4fd1f46e8d7358e435f7b284014ec19ae1ef943165ea8b66895c608d31fc3a10", + "weight": 562 + }, + { + "txid": "7b5934190543b43dfea668c87abbec0c928764eefa5c81254aca7ab68aad7235", + "weight": 562 + }, + { + "txid": "fdc58cbd9abfe97c70b69f610de36e8422ea04b18840287b5368158b36ee3e46", + "weight": 561 + }, + { + "txid": "03ab6bdf473e255a4834c8b5b9a368a5b880b69f1cf20ab1b0f74bf2506c0873", + "weight": 562 + }, + { + "txid": "9fe2f57fff7aba97570f8ec01d297f46624efcb99a79d7617746301b7d187fbd", + "weight": 9618 + }, + { + "txid": "5499a8a738d01438a1e058701da936f1b6390350f548b967fcd5d414c66de87b", + "weight": 562 + }, + { + "txid": "d50261036e20833fce3a53a1ce29cccb3f139e6084509da8e57bd510167c025e", + "weight": 449 + }, + { + "txid": "5d9a86244d8ad118d37aee3a9c7b292d0ff573253506f369239357a497d49bb2", + "weight": 768 + }, + { + "txid": "2491dcbf1b379df0cfa67b40d0ceddb950706fe4d08928865cd1933a32844192", + "weight": 2075 + }, + { + "txid": "28c8399e410fa5ab5245331f5a89dce0bcc111f0bc5dbe00e496740bf44d52de", + "weight": 529 + }, + { + "txid": "0cbf632e8e87825fff3048a25e9952fce55dde016e877d8d838b6054baf34b20", + "weight": 1060 + }, + { + "txid": "b90cc4176a5de5a5c29c5845a2683b15399ac4ccfa5787d6573f9ef4c79db1dc", + "weight": 764 + }, + { + "txid": "b8a71335f702f69cd3aa4df0ec4508e2434e6a9d26c6f64f3458bc464e984a05", + "weight": 441 + }, + { + "txid": "edf3a2217c3b4bf9d3a1018d0ec6dc40486bafa7c0c53c5c38f1988cb4509130", + "weight": 437 + }, + { + "txid": "7f6919c7c31d4419d665bd46907516a79cbc405fed50a25e33574e0161e9a4c0", + "weight": 438 + }, + { + "txid": "a2d703a77e1a3a7a41321408cfe1f927a90dcd5b7c7ddafa813d42237c02bcae", + "weight": 566 + }, + { + "txid": "1a131a1222e6f82d7aa099ad91de57f4fe22b447c28dfa625abf32348994bbc0", + "weight": 565 + }, + { + "txid": "3eb0dfde0c3be47cb5f599eb9d650e7d3518537d074913276ea402348f6a3e6a", + "weight": 573 + }, + { + "txid": "f393e383c1123e8d9ee438c61409e9ac816a693af77739632575139c21b9186e", + "weight": 574 + }, + { + "txid": "e50b79af53bb21132e709057c2fc21a58650ade4d3cd9e34e760369b386939c3", + "weight": 573 + }, + { + "txid": "c918606ab9145c9d232b6482dc4ff0424746a9c93c76f52221c7f2964a7be2b0", + "weight": 1492 + }, + { + "txid": "c42a71007a3ee51642cb2faea3c1cdfdc031f6a6976c2ddb2b68f440a09ec7d8", + "weight": 2174 + }, + { + "txid": "2cfd204c9248466bb7e7a096cf6890b16c8c1815fd0af78ce66e72052ce563b7", + "weight": 1259 + }, + { + "txid": "85b67326878a24f9fdc3a61e6658d0ff0ec95bb4e83ca85c4ff95f9197f01e88", + "weight": 877 + }, + { + "txid": "2e3d56013896596103fb6c8407ed176d3eaa2a89caf05069085953411a45e834", + "weight": 441 + }, + { + "txid": "7e4e105aece4b6ccbcd52c23f3b1821d0ed9a9d22e282e50d9ddc82862a608c5", + "weight": 441 + }, + { + "txid": "e206a4f391f0d0800aad66514dc57599df8b1fe2559ebe3f9f714282f5cb446e", + "weight": 673 + }, + { + "txid": "fa063fc9f3f7c6ee599154b0cf878bb212a385e5125b546c00121d19c3dd011d", + "weight": 685 + }, + { + "txid": "f7aa1629494696fdd8b71bd1db764ae4b69a611249b80d006d2aff4e9ba126dd", + "weight": 836 + }, + { + "txid": "8870963be21dfc3af7729a7411970ec6c49195fe85ee59b32a97e1ae9451e3fd", + "weight": 738 + }, + { + "txid": "22ee70ffaf70a43e45ed7f7b7aa1488116d285f990561cdf662b918195fdb7fa", + "weight": 1264 + }, + { + "txid": "3f3698bcf8a5935b12bc662fcb9908a9c1c4efa48e9a6f886d5b3a706d4ce519", + "weight": 760 + }, + { + "txid": "bf4468844942d765e9ab6951cc34aa0224768b7338fa22484226fb14cf6d2a51", + "weight": 712 + }, + { + "txid": "08890e7e3b06101f690b41e0a152e59334ec1ab262b8ee93a864921c9e056085", + "weight": 565 + }, + { + "txid": "0ec714750f5d2178dfaa7f95c4434499a2ebd8e203b92514d909fe984eb6faf6", + "weight": 438 + }, + { + "txid": "970b685834e9c32fd90f955bf8020a72c0edd609aaf1730ed2d54cac3422934c", + "weight": 720 + }, + { + "txid": "f1f98d2086155c2031a4cd25bdbf808bf477c95e74ea9a4ec0eaa2d7f0b79b51", + "weight": 562 + }, + { + "txid": "f3fd9648c59100b776cee5e9129ca4dc3f2e35debad743930acf3c31c6dbb5ce", + "weight": 1144 + }, + { + "txid": "e4bf23fd405671b5cc4a77623baebfc1e63fe64a3bd0ba49bee66bc5ce9dfb8b", + "weight": 2063 + }, + { + "txid": "0d8449c04e357010d3ca6736464fae486aa04d3613985fc848c4fb9a0ff51947", + "weight": 832 + }, + { + "txid": "77af857a9eaa60eadda903515fa34c3575ee467775bf6b014069189e4b093313", + "weight": 1086 + }, + { + "txid": "c278a369ffa9aa466e026e019c42144445f24f8487b4abb264b62dd7003e5aa8", + "weight": 962 + }, + { + "txid": "c600ae7496253d45e56bba0413590d4b69dc5cb700f3cb63cb4a4e1acc42aa88", + "weight": 892 + }, + { + "txid": "f154c16f50c49604141da10df91951bff26e741f9638641aee090265518486cb", + "weight": 1496 + }, + { + "txid": "f4fcec01e587a539e55b05a8decb258c0c574d27e46738ab9c8cc0c1b5b1a698", + "weight": 438 + }, + { + "txid": "f6ca157137330899b0d77c131257fcd71475eb5fda5135a48f5cddaae2a1c551", + "weight": 441 + }, + { + "txid": "2ffeb1d67657b7268a105dd6458d08515bbce54ce6f050afdbff53d2dc09d6e7", + "weight": 3437 + }, + { + "txid": "48037653423c6baf4f9e78b1033fd606a453bef825128f9290cd964c781d4d3b", + "weight": 845 + }, + { + "txid": "406bb01ad8ec462d456b234f643613ca6f8e13ea05abd3c0c4938338225f10c3", + "weight": 573 + }, + { + "txid": "6c107f9828dccfd67c9bb9e86e56f41be81bca6b415d87589730cea3b172eda0", + "weight": 983 + }, + { + "txid": "4bee050694ecb91e1dad51db6645ef766bc781bb7af94df1fcf5dc117b7a4d4e", + "weight": 437 + }, + { + "txid": "02a8a0f62e0aa8acc7f18a1e36f8786c659057eeb52fcec641b7ee30651b3dee", + "weight": 88491 + }, + { + "txid": "1065289496643785985041838cac3ceb0d24214cd7ddfd3067e9e97140daeb1c", + "weight": 708 + }, + { + "txid": "5b5030d41eff64d5278699754457096a037d9a2af086baa2fdb39e460a113829", + "weight": 441 + }, + { + "txid": "4a4195846a1e0e19c4c4b5d4a15f1db0b2c6c5d4ee19eab28c5b08c22bc09dba", + "weight": 789 + }, + { + "txid": "6e6031c28c24a5c51ae7385f41fa922ff1c6860d20ecec91b82cc31d1d218bb9", + "weight": 1380 + }, + { + "txid": "f52e7163f65d116b8782c43011edb4afeddfcbc8bd8a6073de8332289d008a1b", + "weight": 832 + }, + { + "txid": "684b2fde14a9bd5487796c3cfab0ead68859bed87b5768620beaac0c5c526b4c", + "weight": 880 + }, + { + "txid": "7808fb8c9b9a732a82309148fb384ebe605d7d08e8ea63b92f98c099a5dc13bb", + "weight": 4889 + }, + { + "txid": "28a41bbfbc6bef8c74a2313852a75e845be395870192f86b3946edad46c08e74", + "weight": 559 + }, + { + "txid": "05d2579a023d8eb0ae4bf16b08dc9ca5c3e0bb3bb73ba7ead8bf53a84bd930a2", + "weight": 437 + }, + { + "txid": "00b41af1b74e54cd93097070faf8d213387be60ed415ede16e2b1de9db5b6b5f", + "weight": 1629 + }, + { + "txid": "2f08948f542b3c3a9107f92d3fcaef56f7191294664f582fee475f5510def241", + "weight": 6098 + }, + { + "txid": "354ec7ed720420da7f86b1afba28761dfa5508ab116de3faeb48aaade84a171e", + "weight": 574 + }, + { + "txid": "4e1399cc7374c05c0202da7ce9cb62ae1a5bcc8acd1b850ecddf45809bcb56ed", + "weight": 573 + }, + { + "txid": "152bfdc15c411320af8a7e043fdf52bf2a6e3ef4c9da8a7ac6320bab62089d68", + "weight": 832 + }, + { + "txid": "2d5df9cafdcb4d5cccfdce272c424041097b00b71cdf72be962c89a3d25f3f59", + "weight": 2837 + }, + { + "txid": "b1ff9b34b20218eae3bb6e9e944a77aa8e3d9e9c369d5ca9b6cbecc880fe544b", + "weight": 940 + }, + { + "txid": "f342d88ba1fce84594821b3c8358bc2266b18df0652b3e1a57b82d532eb9c34f", + "weight": 574 + }, + { + "txid": "afcf09acdb7e7d96087c00f40c61b1756ca364df60e9101ddb45321b5067b417", + "weight": 561 + }, + { + "txid": "061d0c2f04609478376d9b255e4b57c03072e12b86caaac96b210a4ed4579840", + "weight": 561 + }, + { + "txid": "eb493a326db78f77cf485efc62b5d84a0b540adcc20ee2e6d6e165381fb51d31", + "weight": 561 + }, + { + "txid": "9d3bfebef98e1d934e4328504be0af873ed0915be6cd4576775ed0e6c7085242", + "weight": 561 + }, + { + "txid": "f54b4fef317175a0abc70ba042849531ce393bb0792ec1a24a80f0a8bf3fa548", + "weight": 1480 + }, + { + "txid": "d081b0c08ee591b31a7895c067105831d57e1af8274947440d4d912f1e6aa35e", + "weight": 562 + }, + { + "txid": "b5474f1f8496e1b64729abfb5ec100561fe9c4aa97f389acf7ddf7391ef99d68", + "weight": 833 + }, + { + "txid": "78cfa954973d92d3039fa5bf8607ecbcea0aa52abc6c7857bdcecf01e67b63ad", + "weight": 860 + }, + { + "txid": "d9ad9dbccf14381d65a3e1f7951a32494e5e91cc9b988ddded25143e448e0b28", + "weight": 574 + }, + { + "txid": "35120e2fb776288ca2e3c90df803a49ccb39144d2e8a62144df2df431a27ebf0", + "weight": 1029 + }, + { + "txid": "7d8c4f2f261e6a5b85b9c3b43a93573a5f0040e9323b47f29191110448331814", + "weight": 900 + }, + { + "txid": "025265b76ffb3b2ef792fec31b5b9abaf54e74cd27e9be1e51f345edc5c44957", + "weight": 1356 + }, + { + "txid": "aef4632e0d56e7dd4ef827182f927433db63bacaf8ca05ef4bad4a4c2dd79b13", + "weight": 884 + }, + { + "txid": "a5410b464ac9e49e9acb1ba279ce9d31b133ed94e4a00d6d676105d51fbaa29c", + "weight": 876 + }, + { + "txid": "646ba27cfe17049c2c2084e5ac94c2fac7d1243743067dd748463d8ed5d45b29", + "weight": 561 + }, + { + "txid": "aabab91fec84f0fd25e87362a5022255787630fe4e29806915b356f40b51265f", + "weight": 669 + }, + { + "txid": "fdb667ebd404f7110fbbce0cac0053f64eec5235c66307dcb2aac214ff8f15ee", + "weight": 844 + }, + { + "txid": "eb81105c972ddefd6edcaebfcd16ed52bce0f74f82a84c7a14af1476d95703f2", + "weight": 892 + }, + { + "txid": "41f0be227f2ed9efc47f2a747e8959422716e59cdf78f2a3532f708e505974e1", + "weight": 892 + }, + { + "txid": "119618f020e528c2349bc7f7f9600b47255b24ffceb0462e170659d8f5fedd58", + "weight": 900 + }, + { + "txid": "26fd6ba71be91e7ba132fbcfcb0b6b9636124879e739f28b388b8df00975d9f0", + "weight": 936 + }, + { + "txid": "47e6a4b91523c50e260d95f9e2f875842e47cab7cce11174ce5001b0e12e1792", + "weight": 565 + }, + { + "txid": "aa8f3508737a85485052a2b2939705c98f589f72d7059ebce68745b081f29168", + "weight": 561 + }, + { + "txid": "2f3d320e252110a4b398de21f0758e92a18f9868a25cd61394aa12b1582ec878", + "weight": 449 + }, + { + "txid": "a2fd84f51e5e6f6821c2404141e6378aec8db9bacf909e6238c46c8872b0449b", + "weight": 940 + }, + { + "txid": "68628f8a07d3aef0a395f883b2459e504f4bec735e1f953b804ebdbfd95e8fa4", + "weight": 697 + }, + { + "txid": "3f93fd4e0fa759884c488242c1c07875da2125f634b334d254cecd9148be73c0", + "weight": 1265 + }, + { + "txid": "37d902e1cd39c99c26b3b1f9d58a120f1bbbad18d07e0a7149417668f879bc84", + "weight": 766 + }, + { + "txid": "b4777281460b4098ec94e827e3f7b3245ce36d9975eb327fcbedd372cf3c4de8", + "weight": 562 + }, + { + "txid": "401ac6370783b550a89702cec8a8238b67b7fedb3985c5d8da06a4b6d2bf93dd", + "weight": 565 + }, + { + "txid": "942a291850570238671fb8ab30f68078b839c5392c5456508b05fba415bf4ddd", + "weight": 764 + }, + { + "txid": "5f1b5bfeb5e4bb6c8b335953af0359d774c3949abebbb2141df84d08ba1aa1ae", + "weight": 566 + }, + { + "txid": "a199ec28fb461f5a36b7a56d882637e5d2d5bf0eca8b4ba4741f7040a15e753e", + "weight": 764 + }, + { + "txid": "8206d485ad13330d2bac25f8d23e0e96fc77a453e5a3d193fa93e4ff42d0979c", + "weight": 896 + }, + { + "txid": "73b800376a89eb39a869dbcbe3a656f0007411f46f8646081f39d21eff97c3a8", + "weight": 832 + }, + { + "txid": "52fd25735c0fe58e629406d815a410cecaea7dc364a47072663beb7a688122f3", + "weight": 574 + }, + { + "txid": "00a84577e72e7e8a0799a443be674898be9ffe2c44eb6c7bc1235a99e4da07d2", + "weight": 752 + }, + { + "txid": "b93142cd0e8937e82e247211167bbaa883826475f0e8a2f882b162d3789fd10f", + "weight": 713 + }, + { + "txid": "904b65106f2403d610877fcdc8fb9143b8ccc9ed77ea46742a956a17edfacc75", + "weight": 713 + }, + { + "txid": "9832abbd9d534d2a4ca9fd18a20eb6cb9f1d9568edfe6d4a3960686a0c9c754f", + "weight": 1660 + }, + { + "txid": "9092f4c4052d9d5f1b9aec4aa3027e5c66371a445091458e5876e17440a3dee6", + "weight": 834 + }, + { + "txid": "42fb3052075ee6a0af2433a102cad5a041c5157badf783d1a041db64f162afec", + "weight": 833 + }, + { + "txid": "5e97f11b629b899b88648845d932692e6ae4fac8303ad7dd85df59a2e44414c5", + "weight": 1032 + }, + { + "txid": "2447e8676f2273562a04886048347d2785b588943273e94bc2f0d3298c589b9a", + "weight": 441 + }, + { + "txid": "4e03ca78ed507b576c60c521925f9923da7651b6fe32ef8900106209d99f4595", + "weight": 2560 + }, + { + "txid": "44e180f9aa64c4269befb155d64d2ae7c1090e91893919374479c2badb35ae1f", + "weight": 1919 + }, + { + "txid": "852c32ae26be80e11fc602d34c3c1decb0bf917d2c5b2996d92285f3409b1638", + "weight": 904 + }, + { + "txid": "839a124c15d5d073a7624294e7c309b8c9362a2e9d4baf2fc5d8318339996b64", + "weight": 836 + }, + { + "txid": "6f117ae8f3f21acd812e9d5b183544840f29eeb414f349622559af0b2c10f548", + "weight": 985 + }, + { + "txid": "32890eedf05f9777ba479ec42c440fd318de022c2f62fdc604b7e8a214b1ba61", + "weight": 1172 + }, + { + "txid": "14630fad9d641c9f60bb139668c6b103d868f66db094fd46af00cb0587350531", + "weight": 1117 + }, + { + "txid": "760f63e648547d04c26faa84576524eafca6f0c5a973cf1f7319aa4fe706403d", + "weight": 562 + }, + { + "txid": "e4b35b4005227609540c20ec689ab95da27dc3e43ca683ac6cc9295f3715ede8", + "weight": 561 + }, + { + "txid": "83eb44a6cbf6292c6fca38ebdbe04f0d65818be5986d16d42bb4632ef285db1c", + "weight": 845 + }, + { + "txid": "633e2f07e17f6e6f0d4d0b73b5216a7188e461834837fb8b20b2cf848bddd74c", + "weight": 837 + }, + { + "txid": "873b65cdfa714939de0829f679a1ea5ffaa78ea4f12327cbbc7b11658b1b4cb6", + "weight": 838 + }, + { + "txid": "74e1da38eebd7eb45dff3708e900a4544c400cb4b289e2fc477cd56a3e8cee2a", + "weight": 562 + }, + { + "txid": "b6b2b708702555c0540d9f223e2e0061035cf0ff7e31e4884126f84096c7d290", + "weight": 561 + }, + { + "txid": "d6f113a8d75176d6eae6ab59a3f312943a5cace9c0f28975accced3d333a3f04", + "weight": 565 + }, + { + "txid": "ed55ddffaadc79169fc94d2c09993f199140ef516f1c21aaf0065939b056e715", + "weight": 566 + }, + { + "txid": "ee3ed7396d9f6219b2f853f178315d2ee9e95b4e50292edd24bc61c6cc67553a", + "weight": 565 + }, + { + "txid": "66a36b235db773f46f630bd9713afb7fc420024286ff7d0cebe9a8deac5ac33a", + "weight": 565 + }, + { + "txid": "2d6c378306d75d49c0c3c1bccca02ffc972cc7bf347a24e2dfc07eac7e6dde6c", + "weight": 566 + }, + { + "txid": "0cd4610c521ead0357ed4cd7f69a12d4f844ba005572357dc837b15dad3f2dc4", + "weight": 565 + }, + { + "txid": "8ce714141ebe912f093fb70e0f224499b096d90690430243f9aed35da420eb95", + "weight": 562 + }, + { + "txid": "c4fc8a045ea2f3d35136c7124a48b968529e69e13db8796216440f97506c92d4", + "weight": 437 + }, + { + "txid": "877b2aa8dee92879ea02762d9936dbc63f0dc5d6e6ae440ee9b3fd185a03db44", + "weight": 565 + }, + { + "txid": "52d0451822c5950be973cc045326bbf63716a48beeac58f542e41c2cbbf65c72", + "weight": 450 + }, + { + "txid": "d7d72b4838278443d694eb48d57936a8e0b4356bc8e89013b5b18628386e76b3", + "weight": 449 + }, + { + "txid": "c4d979632983074d884a2adcf8b90ffe0cabbc9d44677ef47bc7ad83b2194a6b", + "weight": 884 + }, + { + "txid": "6980d7e5f8742c084970eb372827cece462fda42282303aedf74e4ea2cfa9432", + "weight": 709 + }, + { + "txid": "d1371617fe92099e090fb7212a23dee274a978bc634c8fc7516561eb01e0ee39", + "weight": 892 + }, + { + "txid": "46139f36a2c40b8c158e046ec52a4e6dec9712ff7621ebebaa680a9f71518a97", + "weight": 574 + }, + { + "txid": "462b1775f7e24462135d8332a679083a2f29a3c8a0d0884b101dd633514219ec", + "weight": 573 + }, + { + "txid": "7a1db081626128e4af95382c427f2a707ae58bca343c9963f8ceb846bb16893a", + "weight": 574 + }, + { + "txid": "1fc1c0db956c5396454747c6aae05426e956d852d020c380d6ce7b394e6d9bc6", + "weight": 720 + }, + { + "txid": "b56de655df8bc2cb0ecd0ffdd398078f81e08314553cea71d1fa01a6bea77622", + "weight": 1116 + }, + { + "txid": "5624d8799075c84f0df4041a65d47d131069d84d6fa20496cce8d4dff5a3ca49", + "weight": 983 + }, + { + "txid": "4a59b792aad9dbbf1e7cf94dae111df92fecfc1bd3a504a7b1908569e19773a8", + "weight": 1108 + }, + { + "txid": "514aa0385f30ad556a67c8c4843f15b1a86783bb1d66b9bcc428cae1d3763fba", + "weight": 1115 + }, + { + "txid": "45e56456aab34fce519ba4af789c610a289a690d0dd738a56075fe46ef08f15b", + "weight": 1252 + }, + { + "txid": "8c6aa7a55a0af177a19976ec97d48ac12d73d5ab4209fc82f1ba4556b87332b4", + "weight": 1251 + }, + { + "txid": "a72e6706c2958c39b6d5718b4e16cb24e8930853d123aa2d100b37b4b2b10875", + "weight": 1263 + }, + { + "txid": "a412b7301a3ccae5979c0776009bce21c6c43249162e95670bd52e1826f23001", + "weight": 2556 + }, + { + "txid": "f4ce5fa7b5c314b3011a12c7d79624730292b44c73c843a739b956656734f066", + "weight": 1660 + }, + { + "txid": "5b248d1408798dd1f18479a9314e44d52aa2e40c164fc7647ebed922a020c9e5", + "weight": 1660 + }, + { + "txid": "7cc639174fce1534b98ba9e26ac46cc87125506f24d2fdf6c60a20cfb6f706b5", + "weight": 1032 + }, + { + "txid": "2ffd204f3df63cb87061af076b23980186ca2829222182232078b78ae709dbdc", + "weight": 3200 + }, + { + "txid": "9ca10c4b861544606205800824f770bc408f0263d9eb4fb9e5dfb72a2d122ca2", + "weight": 752 + }, + { + "txid": "1f4155af8626c83fc2c8b9deb1a226c3a62dca507f2fb3383be68e0ffacdbad1", + "weight": 1422 + }, + { + "txid": "5f6bead29c1e618057d6d521a369fc8ae6ede73c8b6a013536f653475e6de80b", + "weight": 1257 + }, + { + "txid": "6ca3a330d72a6309d93df2c44c6337a1117376de35eaa78308af888dcbe7a90d", + "weight": 565 + }, + { + "txid": "a912a2fc160e43e54665bd73ff677c3bb72db4b563c45b962d67a34a716a810f", + "weight": 442 + }, + { + "txid": "a6542b4c79de6990265f2961d2db4a5135f67927bc13183e1f990c9856e66410", + "weight": 450 + }, + { + "txid": "b9e7ad026bf8c01ceaa3fa35c86b0330cb5058381c9203fbb078f79d866ff511", + "weight": 566 + }, + { + "txid": "96aa7753ade8a985cff321b1e42d6ec58faf2b32d7197ae8c7e1a7b7a6245b13", + "weight": 562 + }, + { + "txid": "3b63fc670cc7deff36af53ffe36cc1f0786b3e5d344f3abfe213f9884e6ea915", + "weight": 566 + }, + { + "txid": "3d64743d07077312355817fbc5ba039c68f799c6132698453f40897ab3b32016", + "weight": 441 + }, + { + "txid": "e0d24720f5af64c37a16d4dc563b16640332496d47c87c49560680c926f61117", + "weight": 441 + }, + { + "txid": "f3da3721d8c3acb11df21cdba198e2c051564c45b873c164f23d073bc8637a18", + "weight": 565 + }, + { + "txid": "3384de65b9e4ffeb56ee99a7cdea3568f51c6ac5caa3bb8a4d3c4ee4b648bd18", + "weight": 562 + }, + { + "txid": "34a4cc3f318f635a8d9296468a77cce93adbb469b054245fce23f1103e2b6319", + "weight": 449 + }, + { + "txid": "168b080efea52c247de282cb13067c8b73f8ce6fb6dd5bf9e376142971a98c1a", + "weight": 449 + }, + { + "txid": "4f1b334eb32a082ba05256c95c256cc9b1237e91da93136fb4af1282a46907cf", + "weight": 900 + }, + { + "txid": "8811a1c8e93408542646d92a621d463bf3b34b21918a7cf14de310e8fd6f4d7f", + "weight": 900 + }, + { + "txid": "1f5ce761f97ef4ab81c5eddc374342b68df80513e5a049c084f7f7d611f9ad61", + "weight": 900 + }, + { + "txid": "21b6211b11615dd6ad133ce663ec026abc6e37a443df4e131a5503f90ea1b0cb", + "weight": 900 + }, + { + "txid": "85e09c6e57749900358b517da7f73b45ff7c44abdba871344033ecc85c6492b5", + "weight": 900 + }, + { + "txid": "5b6ec33d38b1b00fc62218872dfb08ab593e60ab14fe4fe5e0f7191e7f8905f1", + "weight": 900 + }, + { + "txid": "f8ea6dbcd78051a625f814adc3490b6b7d9f120d0928596ed04c564ca9b13973", + "weight": 900 + }, + { + "txid": "3a747dda6b322ded1cd6091aec102af0a001cb667200e99db26ec59f8d5efe41", + "weight": 900 + }, + { + "txid": "31bfcdc52c451a865678cf0c5e04f36d518b80f585b0ab9a347257eb62fc611f", + "weight": 900 + }, + { + "txid": "f931587b1edf90e633cb7e7b125f49d7a005ef27e376c343782405b7d7340b20", + "weight": 574 + }, + { + "txid": "c36c46b5948a3ee38cc73fe0d6cbb53c7b3412bd51c194fd9c6f307c3f139e24", + "weight": 574 + }, + { + "txid": "9382cc71fed46bdd2092a03d26c861731fd2f624f66090897f5a533836b6c129", + "weight": 562 + }, + { + "txid": "2bb9889b56fbc55b8f7d332a0392b53e7e54aefb888c4e35cc23406e21e51a2b", + "weight": 449 + }, + { + "txid": "84c0204b2bda2a75bd97e03d47c754ef65fdde60c584004d3e2750334ed87e2c", + "weight": 573 + }, + { + "txid": "33e86c991b608194f26a2fdb0978af8a2caffc8c31af77ce44b6d12f15a8a42e", + "weight": 566 + }, + { + "txid": "44a482ae1bd8ecb996cbcf3af496793dab5c9fc13754dc94a1babc9c764eb234", + "weight": 449 + }, + { + "txid": "b13374de9c373782a07b3447dc069749190cf479fe139b7dd095ff5146a45d35", + "weight": 449 + }, + { + "txid": "1affc21daf6dd14d7e12518eec31247381f5baa7fbb027ccb59162040a016b39", + "weight": 441 + }, + { + "txid": "68ad8a25d6a5e1a75e3eb79f4405e065304d675a6965b0a145a1559ea8537d3d", + "weight": 845 + }, + { + "txid": "f2a4701385e99156620fa467645c58d34f3c21681147175933b0fdfb1f99a742", + "weight": 574 + }, + { + "txid": "145d62d612517aff21e8977ce0b0b1d41c566eff0c43d934dfd911ff25f46743", + "weight": 573 + }, + { + "txid": "c3dda171e15d19cd5d8b6f74d50bf0e2771d033888f7192ce29bb29b5659ad45", + "weight": 437 + }, + { + "txid": "fe8910d5277a26e229737012df51369171eab88b181463521e110303fd242647", + "weight": 881 + }, + { + "txid": "f3b2a06271031ffed624845420a4f11332f093def132384b860cd9f653b63c4d", + "weight": 562 + }, + { + "txid": "1794a7ed7ec8218ae132ec677bfbc1b8147f3d8a2181b8000ac1d5cfeb990651", + "weight": 441 + }, + { + "txid": "4509b21646f08605a930f3ed36ec09f87cf3781e67c8a8e657925e909a261154", + "weight": 437 + }, + { + "txid": "72f2b044fe30910edfd45bd99102cdb5168b15335846d38a7be4e307a8d89d57", + "weight": 438 + }, + { + "txid": "935e092be559c869dd8ca0bb84fc85a90d6e12be7cda91b984d5d27dd9761f5a", + "weight": 438 + }, + { + "txid": "8d375e4e7587bc6ceac4f7cc947c841795fa621429fe1a47c805f15d92daf773", + "weight": 900 + }, + { + "txid": "087703ecb47629dfc06dee7e93e851e3d38ebe6477fbdf859cd6c43141f6a05c", + "weight": 900 + }, + { + "txid": "f90d0de1c0d3c7864fc2e7d3fbb63d5d238e64bdf5a3ed39dedeb2811e3adc5e", + "weight": 562 + }, + { + "txid": "199032680fec6d02bfd21e2bc93d3a3dd4a47f505ae402935aa5dca1927a5d65", + "weight": 561 + }, + { + "txid": "7ea456808d2a889e9cfa144aaf2c8f89da3af36927c2beb3bb4b438e6b5f3067", + "weight": 442 + }, + { + "txid": "03f03ed42f1105be68af51ca56b45c1f3617da8d8acb131d47f7c048ec483568", + "weight": 442 + }, + { + "txid": "67cd92c146837c101d5e374df6c49a0d8e2690190b851584d645a462d8e48d69", + "weight": 1109 + }, + { + "txid": "db2430484956c8da0a911b666517dc4693fb23a944ad5b926d9a0ae8acc13b6b", + "weight": 846 + }, + { + "txid": "e8329d14befe457124a55c1dfe778e09aeb5267dff67eb2b5589941162076871", + "weight": 574 + }, + { + "txid": "8ef38c05c63dc69ff95e47c37319f120e1043c7accc11e21a4df3c597b4a0b86", + "weight": 450 + }, + { + "txid": "27fb9925aa6b183e01c69aeb3e211964e44a16f618a0b784c97b7471da078d86", + "weight": 438 + }, + { + "txid": "b0eb01c7eb8cc1d3b88720c8bb0db83c58b2061cd9090a4d590854532a18d787", + "weight": 450 + }, + { + "txid": "02d4c42735ea003832a8b505bcb1dd5c115daa10ad585a1ea072940b5b3f258a", + "weight": 845 + }, + { + "txid": "489d245e2d8e7b95459ef0d038385ea42bd730c4fe8e079781f0e5734192a58d", + "weight": 449 + }, + { + "txid": "a978a558d22da0c460957b9d92354d1a82cd88dcb55c00b9e46ad2eaece10d91", + "weight": 561 + }, + { + "txid": "7b81a0ad636639385625f988567b04719a8ef6656dd91a09eb02263db9e91593", + "weight": 562 + }, + { + "txid": "755d5f9edeb965c4cc49c6f3d1e98b71e01d639ebb46f87b38b0ada0fcfaa495", + "weight": 437 + }, + { + "txid": "f9a24e35365683f9b5b99630673a608bc7cca52516c39b9e3bce56a2681d5897", + "weight": 438 + }, + { + "txid": "2541a2fa095cb5126eb111150f2e5258059f7074bbc7d1fe776ca8c29185e599", + "weight": 450 + }, + { + "txid": "2de3a4c6626542b5252dbf2bfcc4518fcb05c6322b1c539904d4a4e0649ad0a4", + "weight": 449 + }, + { + "txid": "b5af91cdc2a0851f6a25bc9df54e68ee4a1ca071909235e5692ccc3e2ace5fa7", + "weight": 573 + }, + { + "txid": "3d3ee49c7f95f1814dbc528b53b10d3cca8e244983d23dc8b175f5a4f35ed2a9", + "weight": 437 + }, + { + "txid": "908b6584968a80d07af8853e78db5b34fcf7fd74f6b4896c991cb18be8aaedac", + "weight": 566 + }, + { + "txid": "106016fc68c125838d57097196635659cd2b209a5cc968d0ebc5b3ccf1aa08b0", + "weight": 722 + }, + { + "txid": "9088a201578d863b92571babbffc19e82395a974df3ecced5e435694ffca11b2", + "weight": 562 + }, + { + "txid": "4b19444aa6435705f18f24ceffb8338b2b9461f8de29527c43acfab270a267bc", + "weight": 565 + }, + { + "txid": "ad972a87640ac12f93f73c323933a650689d86e9edee1b94ff2da1098be3d0be", + "weight": 565 + }, + { + "txid": "39de2f6ba9cb991cb9a62a5d55e395b4897d483982096356a5558bb424f15bc2", + "weight": 561 + }, + { + "txid": "ecbb5baa2d387b8d8f5a59936e415ede78137ba6c645fac4c716f568b033d0c4", + "weight": 438 + }, + { + "txid": "63aba44f07df8fa2beb59e19cd8703ecf752c1bb0dda24e762e925e7036d44c6", + "weight": 437 + }, + { + "txid": "8dcc133750eef368064f303087ec6b77801675957727207f9b1b9d59767ac3c7", + "weight": 566 + }, + { + "txid": "e3ccdf18409050f3fe4a78cbf210bf2f4da691104854449e0bc4cc9a47f420c8", + "weight": 450 + }, + { + "txid": "bed2db35dbf673f2914cbddc7610c5c543ba0e7712f354b12fac7afb123452cc", + "weight": 442 + }, + { + "txid": "e25bffbc9b054d7803242185066dc797a0fde6be200f3d69d62fccf729d1dddf", + "weight": 565 + }, + { + "txid": "f486d5ea0491f42a3f339e580f0d8e0fa0d2338cb2f4d59c41d6a8cf5971efe0", + "weight": 574 + }, + { + "txid": "a3b0feaf504481103a5ab00cbf93681b9ad32c6abdff1566b18de59819ddf6e5", + "weight": 833 + }, + { + "txid": "c29a5d3608da7d94a0da89030d31b10e410db82b593c15baa10e6dfe61d6c8e6", + "weight": 574 + }, + { + "txid": "b8dae176fb239a8f55c4dbf4b1f75030328870e94a52f954124626d78bb158ed", + "weight": 562 + }, + { + "txid": "2fa5b58380c4ce1832e5fa61ac56da041d060eb6e5aac6e3d9819ed04bebf6ef", + "weight": 449 + }, + { + "txid": "766cf3ae5f0cfe09125146d62f457db5d0d2e964996087451c31b05dcf02a3f0", + "weight": 438 + }, + { + "txid": "9d6cbe1aa2f293352d2e36ee764a0e71441b216e54a4a5f1f7f2a0ac5c1b29f3", + "weight": 837 + }, + { + "txid": "f1242b211ab7cc9636202a11a15d7790c71db90e2de1bdd0057803e7f2421bf9", + "weight": 574 + }, + { + "txid": "e23dcd929d6d7019c955adc4c57da9918ffde4fc1fc0e931d1fbf10f66b80cfa", + "weight": 562 + }, + { + "txid": "e4148d8d558e3fe8e16a8227231a7f1fb9639a56bed1884bc4c2ecaa43515ffc", + "weight": 562 + }, + { + "txid": "2ba0459a68cfa0582cc96caaaa2452678138ce3d9b381f106e6026c4b5050dff", + "weight": 574 + }, + { + "txid": "32caaf404cc502254f94eaaea3e1b62aa804ed5feffa0e0430443b52b66c8bff", + "weight": 450 + }, + { + "txid": "9be71d596a7f7ab41868ad89408abef7b6cb06aa7f16d92be5016a6062fd9bd8", + "weight": 844 + }, + { + "txid": "fd91301ef847370b875f501c53c980d851c892d1083e48cdb8211e7f803f24ed", + "weight": 836 + }, + { + "txid": "8f009005a505a688ef2b8b345c12a98a810a677f8a4fb1899783d9c427eb6050", + "weight": 1116 + }, + { + "txid": "ce99dc297c3f9ccaabadce211a9d05ebd5434a953389e317b5c4142cc4f5a547", + "weight": 566 + }, + { + "txid": "0877b5e1c1625be1f5bd2ba5cc939b22a2585bb51e07346bab3bca272cce0411", + "weight": 756 + }, + { + "txid": "3b6eb80d4c4e58ed068c99ab82b294f1a06816a962f8a91a283237bda50ae43c", + "weight": 892 + }, + { + "txid": "13e3a0e9188ef9f94199dd3c922d1b6a17116848b6bfbbe43c6e243d8691e0c9", + "weight": 892 + }, + { + "txid": "4194cd868b192be982fa7cef729ff1d297ea6619e2810077acb929d0755418dd", + "weight": 441 + }, + { + "txid": "2f13ac6eef15a5e1d209af6d6809cb1975d54fad1bd919732435bc6e654c2eaf", + "weight": 437 + }, + { + "txid": "5be23bd031a19446449c9a0329d981e5e105333408e9efe93650f3e6ee000318", + "weight": 881 + }, + { + "txid": "1364f22578c77e5b777152b673f2d826068a8550de79476bdaeb19efc1747d43", + "weight": 846 + }, + { + "txid": "5edac6127d768390b459e33c15b8417010ec417d93077b3e0c84e306e56c8954", + "weight": 846 + }, + { + "txid": "90aeb90be693ff3df0c5b1c86c3749c222b87a4b92103c11e1076828f89e6ee5", + "weight": 845 + }, + { + "txid": "c14966ea76429fe75f1a9c8b2d62a80147fd34cb0e4698fc75f9120d9148bff6", + "weight": 845 + }, + { + "txid": "80567310df37f722da04220988c5fb86b3e8e7aaf7171145bcd5fc6e02d7744b", + "weight": 838 + }, + { + "txid": "0cbb77ee7250670d65469758a531b859320cac96c5f05754c02a7439ec13c735", + "weight": 609 + }, + { + "txid": "8276ebf506ed125102bbfcbff9f9c7ebde427d3540ddaacba23bf2e71a89768d", + "weight": 1650 + }, + { + "txid": "a0b727f250f1cc73e6319addc75453d308a837f6eacd2b0175e1dbd6f7b5ee14", + "weight": 574 + }, + { + "txid": "0c1ed4ad999f3aa0c093ae16227a0c5d7eefd58c0036978861deafcf56308088", + "weight": 573 + }, + { + "txid": "4256998192f3d32b429866ec9bc52e0460a8938a89c5eef1c7970578f60a9d8c", + "weight": 573 + }, + { + "txid": "3bb44db87f4bc7138b7098d6466810fb5a7d3215b4d90ea4b23a324bfed5e294", + "weight": 574 + }, + { + "txid": "31cf5a63e25c365962ce6af01c0b97bba292da5de4908e72d56f8c783f00bfb1", + "weight": 573 + }, + { + "txid": "272410e4fc6852fd939bc21b9b007b12e922744fe1252443c148dff04c49cc57", + "weight": 566 + }, + { + "txid": "e9afc73b666fb60b96ef5319d075f6541983743983c40307e9d19a23b7e5b7ba", + "weight": 565 + }, + { + "txid": "c70470d60403fe33c365129f67d5a50252a60d377813f92551292dff3ec02ae5", + "weight": 566 + }, + { + "txid": "aa3a27b2ab1f79d7247a0ddcbcaa81b9d5b630a9feb345581d9e3e1548c7eee5", + "weight": 565 + }, + { + "txid": "5d77aa164afa8ff231e0e6ebc6f24a7d7681f4e095545d407439e98e2b3cc66a", + "weight": 561 + }, + { + "txid": "f75ccef5cafb2b84cce2979a1f2e50f91bf39330b1b804dddf0a7a94bdfe557d", + "weight": 562 + }, + { + "txid": "edeab627867af9c1c93b04ab32cbb4cd9273ac702f0bd8d7c643102d9d5eac7e", + "weight": 561 + }, + { + "txid": "84ed83a4d1466b987bd5934d4af3a2fd1e31ba4474c539533efaa866c93c8e94", + "weight": 561 + }, + { + "txid": "3be1e204a8a9019232cea6968f923ca41198b4dc33c8467bcbcf15e5e78e35b6", + "weight": 561 + }, + { + "txid": "31bde144cae852a2d234883c58a8b7ef359118d488b05b6db12e60a1598e6ce0", + "weight": 562 + }, + { + "txid": "cb2c63448bb3e56efcaf24fed6827a6e84bfc5fe766d6842758f3110dc32a3f4", + "weight": 561 + }, + { + "txid": "be526d40a66c2dc6d43d87a18abff21e41a8f30b87e5bd6bb3dd8d946e998618", + "weight": 837 + }, + { + "txid": "85e38456d5fa48e188c8d605cd473be9affcec0065326d2ebc04fe8797cb075f", + "weight": 562 + }, + { + "txid": "4221acbde7cbb07fed7f52a6fcb09f459236514dc0ce869b6efe664a69ab9c63", + "weight": 561 + }, + { + "txid": "adc6d53c231d0a9ad1f823e062b5c01613d3c8f38b2a1cd46be66ab3234b185f", + "weight": 662 + }, + { + "txid": "8e9146be3073a34f1b0d93f64c4e6b95c058171c82fe7b65e33eb1ce60e468c2", + "weight": 561 + }, + { + "txid": "b6f4bb5021980064169d0295c0e63fd436fd8082060e3b733eba4b1b6aded127", + "weight": 756 + }, + { + "txid": "44e5b710adf71710a3e8aaccaef1e7cae2814ca22ad25bfaed5325dd649d1925", + "weight": 573 + }, + { + "txid": "4cf97fd16fdbfef149c2bef522cc360cb75aed735dd8ce80095cdc0331dc87d2", + "weight": 574 + }, + { + "txid": "236dc9f97ff3b74285e5b7a0920d9311ea06a39f1d12c2f80f10dfa3fcf59c44", + "weight": 960 + }, + { + "txid": "cba59bdd2513de0cd9698cacbdb8477a9bfb32f5d0913bd6a19a160a883cd617", + "weight": 562 + }, + { + "txid": "fc69db47102fd8b1c3002d9e896ad2c7257e7aa3d57569592e18f342cd532c74", + "weight": 450 + }, + { + "txid": "642dec5553480366aec04e97fc97e1a8725f07400bdb9a67b814bc60726146e7", + "weight": 888 + }, + { + "txid": "44b91b7ce613bad864f239e24f212808dd4aad1761dbbd827aad28236b911f66", + "weight": 892 + }, + { + "txid": "9a9561c5896cc140e9c8e72cbcbed84d21116d73d823b5d5022bd94da82a5f69", + "weight": 6068 + }, + { + "txid": "680632b26ecc323e0fe3a1223ea0365077737a893fd635abcbcc3ff09d735b60", + "weight": 437 + }, + { + "txid": "d54d1e09b81c146b18cbc936fd7236fc0cf90e12ddd516ba17b67da2f8e7aa8a", + "weight": 900 + }, + { + "txid": "5989a8a6e3637af5f3ad3b1f6bddca26a4c2ab4b251e6e44c999ebf5d5890c2d", + "weight": 574 + }, + { + "txid": "61a2bd7fc9cdbe5345eb002c9a2653660ed921a5e5c309b8381444aa29e8f62d", + "weight": 573 + }, + { + "txid": "ad3e61fc3828e9e1ef284d4a9ee85d0ef64da92306ffa447ee8919faab2c733b", + "weight": 2061 + }, + { + "txid": "77db77634d51085a8caae3dd1ed3c1aaf9ac0377d7e3107ded15027217306f6c", + "weight": 8049 + }, + { + "txid": "65336a7ea01fbadb433e505a3c818d2f215ebdc8673f5793f62a1e59b4cc2150", + "weight": 789 + }, + { + "txid": "15e6371087e5684c14a65f80f516e2b0351de3013cf4e860b19bdf41b5f66144", + "weight": 1352 + }, + { + "txid": "3a1a88a959b6a2d7554d5890627cd6dea88c31da3c1f62f1ec81a0901f84e6df", + "weight": 720 + }, + { + "txid": "49fb495069b8ec61c8453a1a5359427518e82aa3246fe51897cfee09e16b358b", + "weight": 3131 + }, + { + "txid": "fa0a78ef69cf7e7817d00c948f22f73db6bf6aec0b8f28674e82d49260b8ff41", + "weight": 760 + }, + { + "txid": "d9d5d16eb335baf6f0e1a9cce2aa848e9ff54f139355a69ec1268215065726c2", + "weight": 900 + }, + { + "txid": "959cd9d9d99d5476025e5d0f2836808fa3c8f01898cd0f0deaa8ce6f56ff3ffb", + "weight": 904 + }, + { + "txid": "557a47a7fdb88f1d7fd6e1ab7152a9ae6c3ab12ae3b682dd79a8ba795d046ffd", + "weight": 541 + }, + { + "txid": "f31c2c38d39f694feec5bc68f884bbfb3ba543c532fe6dc409dde426e5b5b10d", + "weight": 2462 + }, + { + "txid": "7eade46c6659d55c0224b93b56dae9ae7b8da231909bc7c534172295b75211cd", + "weight": 1084 + }, + { + "txid": "fbf578755c535fcad3dc0968db9b9dfc5d9ebcc538811771ae4518fe8cb3874d", + "weight": 36917 + }, + { + "txid": "a3db6d228e0447905875b80910298831a18bfd38214134b4de5e623a4c11225f", + "weight": 1344 + }, + { + "txid": "6d2468c31aa3b0361c1a8e372adaf24aafcb6bd54dacbaffe2207eaef87d7013", + "weight": 566 + }, + { + "txid": "4a6778661c03df2bdb699a4b8fdc43f638ec416ab051cc96513600e42f62208b", + "weight": 6694 + }, + { + "txid": "d09fb2edb8863cd641143f1237d16948c5ddb385d37e90c190162cd4271257f2", + "weight": 1620 + }, + { + "txid": "168d41c7c490021722dd13fbf11bb0ee0df5a54f33788b81e2d56df79750f094", + "weight": 809 + }, + { + "txid": "3f1ad78fb4dba97c6434a75a5fa94752b5faced6d5d470adab7b77ac5b032bde", + "weight": 4261 + }, + { + "txid": "f5607e7f5cfa8782f67e86e36742800de91f8dda6d22474a1dccc27885f37301", + "weight": 561 + }, + { + "txid": "48c71023ae7dff49c88e25a39759122630859e06f9fda860f8ac39924fddc31d", + "weight": 561 + }, + { + "txid": "982cd68228d9012172dfe7cfe7cd8fea0580bf562bf3f0acb0ecb90e29352059", + "weight": 561 + }, + { + "txid": "f1c5b712e2965511761ffdcb3365f6dfcefca1b527c5c02d7e40732649ca5f73", + "weight": 561 + }, + { + "txid": "42e03a41a27eface802263442160de4fbebb9fe4b937eb23c997e60a83ad53f7", + "weight": 561 + }, + { + "txid": "bed215d08f7bfb6f0674355e596ee92a10be2e071a5ba278a2fc96d5d65d0415", + "weight": 565 + }, + { + "txid": "d77b9ac564a664fa53d4bcf951d822b6c342b77531230e46e3d3da8001ef2296", + "weight": 573 + }, + { + "txid": "3ad33a6da69f3276c52c3ca60c9d0f748d49e3f46a9cdc2e74a63113bd1bdaf6", + "weight": 573 + }, + { + "txid": "f9ab1a0d55bf7587ad7e1100d5786d2a4a0211d55afabe5746964b23050587cc", + "weight": 609 + }, + { + "txid": "2334b0561d236a27d8615a9f0a3eb64eeb0a2c2eebdfaf384e4398f6738104a2", + "weight": 653 + }, + { + "txid": "c9e586370ea8ccbda65a67e159ef327ae89f4520efc7cc13cd651875ce34021b", + "weight": 689 + }, + { + "txid": "6424093b9304b308360043423c8df6ba029d2109fc5dc3d1c309b4b3be5d8aa7", + "weight": 814 + }, + { + "txid": "4af7dc9f2d8851cf51f5b76b2013229034c80e9bb7801bd6370bd9927f81f706", + "weight": 832 + }, + { + "txid": "ae54d0e33b648fe9ce0a4a6e82299eab68d16079adda623bf8f02d7f61634b04", + "weight": 561 + }, + { + "txid": "e31257a3ef46feb9cca41de61c198fe0ff0aa2d2d48f034c452f019636842714", + "weight": 561 + }, + { + "txid": "e1e2d9f4e129dcbf1d7fca01e9010d85f68e169ceabd1e612cc7117ae660cf42", + "weight": 1915 + }, + { + "txid": "166d0802d8caa07039094d92b2531572f75c66bf0d2307459899320e61965e7c", + "weight": 573 + }, + { + "txid": "3def8f90553fd2128d3967e39373b34b9ce7b5d8bb607f4251dcf3fb1d06c498", + "weight": 561 + }, + { + "txid": "8b6079a1524bf833be87d3186edc00aa1ecd3c1b84aadaeb5770b50b305178a1", + "weight": 1057 + }, + { + "txid": "c54f1393a0262b9e9e8015dd23d18796d61ce396249ee3a86b801b379651d9b6", + "weight": 437 + }, + { + "txid": "bf9be44ac59826a2321ac4377228e98a1da848f709c47d0e738be787d30865bd", + "weight": 833 + }, + { + "txid": "9667fa1e32cb9a277cecd2aea018bcc4215601fa907841081b7b1236f05f24ea", + "weight": 574 + }, + { + "txid": "920d95529cc414786f812681d9addabd1ffeaa1afac14e5387efcfaba0b95960", + "weight": 3760 + }, + { + "txid": "f841493e23338c8d2bb718d930e2d4c8b3876336e77a6752b4ce5486cebb04fc", + "weight": 3521 + }, + { + "txid": "27035eacf4bbe868e8d92c757fe8bdc3161a9180c587d6cb7f1941d1a8fc357f", + "weight": 11293 + }, + { + "txid": "c57eddaf25c86a555d49747bd4cb0792cc3bce3d1395adbed146ee2da14a2507", + "weight": 609 + }, + { + "txid": "15343118e3abc1a4a497314832bc2ca58b989570cc60e5d33efab5dc48c7b5f0", + "weight": 895 + }, + { + "txid": "d531e9f0bc9293e30b5021f169c3e4fa0899611f8c3cd0e996359056f3c65e00", + "weight": 766 + }, + { + "txid": "ff70c2e80d44c8f3bc6e0c221d8de8b0e59b93b4a6828cc0f7c4d34260280f1d", + "weight": 767 + }, + { + "txid": "e7921d379c06c9af7d043c6f984b81d64d291eb4bfe979707db9dd10b7122625", + "weight": 767 + }, + { + "txid": "a0223ed4f38ce195c5608c55690c139cd2eac22f51024fa7e135315c168407b8", + "weight": 758 + }, + { + "txid": "9e67f83dcb99b13e27b49ae9b85363f981738cd1c20e519617c206d0bea61ff9", + "weight": 759 + }, + { + "txid": "cc3dfc427e769652bc55bcdeabcf155997c3150f3ea1c71b01d7c3dcad77ff5a", + "weight": 866 + }, + { + "txid": "8ff2be0cdcb971154735ee60c2c4e3287adbc8b54853f5ed5ba80296c6c36263", + "weight": 442 + }, + { + "txid": "a3dba27a17b4bfb9638091b228d5faee9f73237af7721f3f914e05814df2cdad", + "weight": 862 + }, + { + "txid": "97c9ca1bd96c63a76f9149ebf98627c203c5e0b8521aca9ae8b5257c24ea2264", + "weight": 1036 + }, + { + "txid": "b8cfa32fcc1d425599fd6bd4dc0715d914bc539d1c8210b50133a519f983b267", + "weight": 694 + }, + { + "txid": "1e9ac67d040dc1684b23732f40c43ece008ecd862a92e1d6131ffbf87b4e521b", + "weight": 442 + }, + { + "txid": "ddd759d8694e1f744b9ecd7ea53551a21aea5d0555e731824a36404451237be8", + "weight": 616 + }, + { + "txid": "ee5875b495cc860109d072219e1bad77c89fe278574cbe970dafa50742c2533c", + "weight": 4813 + }, + { + "txid": "2d4e94db305ce434fe19f8b6b555eef594eeef29f36ef07e5e493a7c3deddacd", + "weight": 562 + }, + { + "txid": "52242e82aec78d91c962579f6c5f140839c850caed5b5a22548ddb16b00c26dc", + "weight": 562 + }, + { + "txid": "8988947fea2cb6abdce3553a8afde35f130d62586e24ffe1b6f89a5c637fe31e", + "weight": 598 + }, + { + "txid": "eb95dd816c78cb958d7c1e6a236e0fc40fac904a3f4e61c4f0fef7a243a2d98f", + "weight": 892 + }, + { + "txid": "35b7c4c8eaa7a9794955897be296671f9b2f712cb7e037fa21aba91fc9c6d6bd", + "weight": 449 + }, + { + "txid": "0a48a964a80f125c1a4a3dad0fc98f739f754fc9e84698be50243b2d7c12ee0a", + "weight": 581 + }, + { + "txid": "f325336c6651519c238e33470f2e8818b83ec93a2492e57391ed7faa6f81fbdd", + "weight": 2876 + }, + { + "txid": "c6b30ee5823664ef1020240932156109a673f428c39c0203b8e1eb591ca86d46", + "weight": 979 + }, + { + "txid": "7d5cd89d5a06b5e55566edacc72e3ed572b17cf099985666c2b85a44fdb8ad90", + "weight": 529 + }, + { + "txid": "7e7d85cc08eafa926ee04e607c1bc1201efad71808cd0e2f81a21bef1ced5644", + "weight": 752 + }, + { + "txid": "ec8d7099c924a57ba9fa4699cb773beb1f5bfb6fe5157769a552eb1457ac9f78", + "weight": 708 + }, + { + "txid": "132ab20264465aca8cfa9ee6fbe1a08f7533360714fdcb8231925490ed7f4a9d", + "weight": 836 + }, + { + "txid": "d55d4a2e92e3c870e4a9999ba32ef6e4434238417e39bd52bc4bf09cb84d7328", + "weight": 1266 + }, + { + "txid": "548e934fbeee4a66690deb2022039acd1eed147e60e38d3408d88fc944c1e543", + "weight": 680 + }, + { + "txid": "1035545e44793aa6366fe6671b6449a428dc618ced0f7241623d5dc1d4134067", + "weight": 1103 + }, + { + "txid": "060bda3f4072b4e7406f8fadeffeeb8fbce383f2d8e507aa4a492c65d0f43104", + "weight": 1108 + }, + { + "txid": "04be7da0c11309e19e119dec0fc9bc2bf7f3c5a60aff2ca1ea7d9e1a01b177c8", + "weight": 832 + }, + { + "txid": "403d6939fdf2a734796fdd154b91b1a1c697140eb1fb94facf1cee8403d66a98", + "weight": 562 + }, + { + "txid": "0e5fc35092211406d8cbab21c986914981d95e0107bf6fc83a19300b7c9e0c2f", + "weight": 3973 + }, + { + "txid": "324773a85f912d5099485b996392b9796609ea646f3a6b2e13995c94f1b50203", + "weight": 18456 + }, + { + "txid": "86ae351c3755de9ca5692a7815aea01656b8538a7bc2d8b515bba1a490a78b00", + "weight": 437 + }, + { + "txid": "74bab55304ab09c0e44edef7d10a32e7ecfb56f92bb2b564bfebc0c7bddfc305", + "weight": 562 + }, + { + "txid": "a0c93d2e6b78fd8e4a8ffa5d7263683f691997161edb6d10b9d2b0af95e60f07", + "weight": 565 + }, + { + "txid": "85fa397d821093d9d5ddaf8cf3ec8a134994abda1fbdfaed9a300395474b3108", + "weight": 561 + }, + { + "txid": "fed77dfc26915c96341720cb5f83f871da89a80868513828d5ea28ece1661d0d", + "weight": 565 + }, + { + "txid": "48d2c9017753ec8b03af555d594f12f02ba1cad15a09246383012e32c6e03a0d", + "weight": 441 + }, + { + "txid": "9ebc48c8752c7d747f2582a97ab9a216be0bee7998cd311fd37528868334df12", + "weight": 449 + }, + { + "txid": "de867d99162cdf67fa478fbb77a1a8448dcff8c8fdabdef4f8c1a020c5290118", + "weight": 438 + }, + { + "txid": "8c73498fbe701e48a4ca7131d85aaff0671f0cf89303bce97d8c8acddba45f1a", + "weight": 838 + }, + { + "txid": "c50c6981dd73fbbdcbffacaa176425ee12f838eeacd2620b9efef2f188a77d21", + "weight": 442 + }, + { + "txid": "7b01e1a415ba7162a7a150304a3f0e26bd7847a8837b0c1e22f48f8b2e991428", + "weight": 845 + }, + { + "txid": "8569f78b1514f91a4db6dd218a52fc86f345ff20422a161adcc70891a39c1e2d", + "weight": 449 + }, + { + "txid": "b297b973313bb8d05b3562b05edad79cbe94f8e7ba2476ba3ceca0bbc857a837", + "weight": 713 + }, + { + "txid": "6268ca1e0f7a3485ef3da074daebdafd907be746a0cc687d4b04215b7df7113b", + "weight": 565 + }, + { + "txid": "2647bd174ec217c7c5498b7b9d6a661582ad59dc7396fa7951f85927fefc553d", + "weight": 562 + }, + { + "txid": "7696f6d2f115bd299e1080e3cb2ac87e4b42bd509254628acc0179c714a88a3d", + "weight": 573 + }, + { + "txid": "0c055bc9d305e70eddacf4603d42c4ca50d045faca7281fff387a1dfada62044", + "weight": 670 + }, + { + "txid": "1c954a2909ba93949d26974596dd555cf2a5f00f64ae8cfab4d80db379d75c46", + "weight": 562 + }, + { + "txid": "a513f70268ee9d58ae48313839ca5c1539d936bb55deb448083214ff07d93647", + "weight": 438 + }, + { + "txid": "d97ca9ff2dbca7e24b590d5da3f68c9780109c5f4c325d3b97c99b0bf2faec49", + "weight": 561 + }, + { + "txid": "be2cbe98e0faec5f96b233f75002a26959f552435ade406e5516b630113a804b", + "weight": 561 + }, + { + "txid": "3efa37754cc59210d6b0d8dddc6edb8be98799ebc8c62ca4e07028c03f31c34f", + "weight": 561 + }, + { + "txid": "be71554e24da80aaba212c41134bb79a3f5d050cb55ff277eb6c4322bf480558", + "weight": 562 + }, + { + "txid": "9a25d25fc31b1383dc4f4f86ab8f3c4032b6979bbe4985460d9b6b1b0ad06a5e", + "weight": 574 + }, + { + "txid": "aa32b8cfe806a88e34ca9b49232f819c1e87503ea982d3001a0736056d8eec64", + "weight": 449 + }, + { + "txid": "9a30c9b1d531ee8111c6ccfd873f276f3c3f835ab64fc29501da4838541a5367", + "weight": 562 + }, + { + "txid": "c6c3b99997da3d67597a498e9f691e86e383853c54cb0c1995f201dfd368b06c", + "weight": 449 + }, + { + "txid": "f5beec9381baf07d8eca7091737cfd83dd38acc9a98d80f1745266950fc01f6f", + "weight": 2988 + }, + { + "txid": "2a42a5bc4c8c849aac7fc4b00e536a0f344be3cff362aa1ee8036a5a9c4eb470", + "weight": 833 + }, + { + "txid": "b0940a7ebb2b253a5d7e64733b31f1a249587d6c3a7f07d31a99faba10d8a574", + "weight": 566 + }, + { + "txid": "5aa7bc9b4d01d0d1798218a20701608cf307667f6db2f9b6fa94e64284304a7e", + "weight": 565 + }, + { + "txid": "2167135f0d7604b90cc32083a9252563d5ca4cf576029a2104cb69d3ffd6ef81", + "weight": 562 + }, + { + "txid": "210c1739ad081604c4e5d9a073825c4c09da2c215b94816bce065abaa863c985", + "weight": 573 + }, + { + "txid": "2ebca6209ebe9ef3ca7fbc00b6d04150bdaa8bae2a664b8779f894df14d50c87", + "weight": 450 + }, + { + "txid": "3ec62e15da7f17a33981e3ca5af07349f743a0be0d3a3a396fa49810eeef3e87", + "weight": 565 + }, + { + "txid": "ef9cf892f7c0c9ce3ecf9635e01529d40bf003a5edf4c8ba73803b488f8c6e87", + "weight": 438 + }, + { + "txid": "c06abff5a61fd462a365dc82557a45c076357323a5014b69e2df5b6f521a8987", + "weight": 834 + }, + { + "txid": "a698ad45d305d1962972491d81e7541c37140ff576a0cca6e3b4f802c519f287", + "weight": 442 + }, + { + "txid": "37b0469b41887bf1bfee3305c79b34ef97f1675074716f767b2638e1c2604e8b", + "weight": 566 + }, + { + "txid": "cd4246c9185eab57e981bef5e6f919586affb9da39fed9685db0639059601e8c", + "weight": 838 + }, + { + "txid": "fe6fbd53291009969272f598a10e74412e758784a68148e8f962d74714a59090", + "weight": 574 + }, + { + "txid": "72be8562ae05b07d600bf5666a9258e642ecf209c1486439b7c63d7e6e7cae91", + "weight": 565 + }, + { + "txid": "2264bb68ea59c0454826a26a60f1f501550fb34d5582a410b6c478934227499a", + "weight": 561 + }, + { + "txid": "1142d71ec50b1e55e7dd5e0876d4570b1e7bc1c14825a8cd422901170d374f9d", + "weight": 566 + }, + { + "txid": "384f8e45ffbbabb1d2f66d29aac58633cb379ac24706877070b79640f3e1a29d", + "weight": 2704 + }, + { + "txid": "c0476acd964ee5de4ced7b07aab4d7ba2955f16c0f26dfeb0efe7cc8901503a1", + "weight": 566 + }, + { + "txid": "9a1b2b83a3b76bb393b605ffaf816ea275c7695b3fb0ae31c83fbec5db1554a5", + "weight": 442 + }, + { + "txid": "5fa26e79796c39288f8e4bc896d9a73f09f78048031ca6efc979ee3c91b1c0a7", + "weight": 450 + }, + { + "txid": "d9fd1796150ae4f0686c3b9b890953c9fd8b6429a5f3b436e090be0f56ed49b2", + "weight": 721 + }, + { + "txid": "652fa5808132038b41483db8f96d8adf4cb3c8cc0a80ee54d679593fa2bb37b6", + "weight": 574 + }, + { + "txid": "6747ff970762beccf2c51ef56cc74354193e5360e1b9c8f165f77ca23e3270c1", + "weight": 561 + }, + { + "txid": "042315efae42244d3c2559b4e5a9c4e065314845b3a5c9e2e0cd18dd7cc921c3", + "weight": 566 + }, + { + "txid": "7edfbd7181b03bcad226136a72f6abd68a5e00361e5ce4582d8037519512d8cd", + "weight": 2445 + }, + { + "txid": "78111a277df781c1a26d4af11170a3a7892eadf45da6a5ee381ffeef3db0cfce", + "weight": 561 + }, + { + "txid": "0b3d4d86e9d788e2b3b8ab200991d8bf9f7776443221c126764d8f3b66df7ad0", + "weight": 574 + }, + { + "txid": "75a7067dcd1fa78400f27551d69f431b840cad2446bab36640a63a9004d8f6d0", + "weight": 561 + }, + { + "txid": "c49fffa55a87641c5f95598de541b8a5fb3d895674ce0fcee118d19296ab89d1", + "weight": 573 + }, + { + "txid": "48781b9f16f7ef5b5d2b988ecca297dacaef38aecfa2fd307fbb6ebeb2e6fcd2", + "weight": 450 + }, + { + "txid": "78c6537e3d33cadcebd99a37145ed5ed6bf0751ee04a191145a5fb08df39bddc", + "weight": 562 + }, + { + "txid": "e05eae3f224b08dd746738890b4204fef8e293ce5643f4bde7e0f99c81e5e1df", + "weight": 565 + }, + { + "txid": "9936df691cb2b8f8f1cc2066b266ed6c1513e6527ca1f3c10e85cfe3176dafe0", + "weight": 449 + }, + { + "txid": "cac95f9d39fedce10da9685401c58429722e8910b6c8b780548b47d81d78a4e1", + "weight": 562 + }, + { + "txid": "0cd47f11bf34df93d2a5bf405edd8b5789dfacb7a641300224befd23f640d2e2", + "weight": 838 + }, + { + "txid": "4b23ea6b15d03fbc326727065c74bab8794bd824a98da192a3f713884918b7e3", + "weight": 566 + }, + { + "txid": "a979aab1c6ffd23a041b01390a18fcd7eb7367b92e5d551946ffab535c7dd5e6", + "weight": 834 + }, + { + "txid": "2c3a3584af272bbfe5967fddc379ea986d3a074d76eca65d025ecb523ae091ea", + "weight": 562 + }, + { + "txid": "f1e09cd4628c3df91d9b5644e175cd2c646745ae31af907b0f1fa06fe13e41f0", + "weight": 449 + }, + { + "txid": "ed35b3c5bf8b7540c6d9914ef3302400a19a0f4f283fd2c8aec785a019c476f0", + "weight": 834 + }, + { + "txid": "9d6d179def2664760a9033ccdb160d66314c942b76357f16d35b154ac568baf1", + "weight": 573 + }, + { + "txid": "dfa8480aed5dfddde5230549c75b9c46cb0a511cd8bb6aba1062ed626b02a7f4", + "weight": 449 + }, + { + "txid": "f4a79e4225f511aae20a0d524dac5cf436777e33ff71badd00c6452cec35b7f8", + "weight": 845 + }, + { + "txid": "1b20ff9963559d320ad593383ed9505531bb85b79949c76dfa0647c1af7340f9", + "weight": 450 + }, + { + "txid": "6d033b5c1f4586373afac965c90c91202da8359a7daea1f4c0e1d15a36317efc", + "weight": 562 + }, + { + "txid": "be30d4adf0dc6ead658b379e8b8cf044f6d6f9d9c7acde16f17143e24e0795fc", + "weight": 450 + }, + { + "txid": "fdd59f3080acb4bd73bc14a424a7de8cc7dac1848a0a0ee8b162bb7e5b86b865", + "weight": 5618 + }, + { + "txid": "a40ab8c0df05949c27e098e616b41c48e66d22d5ca8dba3572c6809671925282", + "weight": 1323 + }, + { + "txid": "b0d8fc958778362e422c50898bbe3725539cbc8b94b20e9e78f05f38af64cc54", + "weight": 1312 + }, + { + "txid": "fc1595fa80414e7d47ba1e9b1944aebc70ff256a9244a513e9febac143f6bc8b", + "weight": 1452 + }, + { + "txid": "ab09b9a76723912cb901e0ca09fb834adc46710a1644c85e8d65994868494a08", + "weight": 767 + }, + { + "txid": "900b82379e84a64e34e5cf1fd433cc90dbcd6a35607b3012847cd2704d1acc14", + "weight": 766 + }, + { + "txid": "14ca0b164e6356cd93691aebe8f63278c1977473c95c9217cb417db886ef3f38", + "weight": 767 + }, + { + "txid": "4cd7a6cc284abb9c40a9559c1f60244f6679bd470bc6b5ae2b0f949835e5a34f", + "weight": 766 + }, + { + "txid": "67b3f01511f5bc087f3a3fada9c2fbef52160d5f0a6930addbbd09afe367806e", + "weight": 758 + }, + { + "txid": "9de9b9178481cd689f6a0b5ca0b57842bcbe91896d5a5e3b6243d92a4ce29fe8", + "weight": 759 + }, + { + "txid": "b5bb9c81b5b9e28c3061b7ab22f89fd2afea126ea2ce0075b3d14012e7a4b6fc", + "weight": 759 + }, + { + "txid": "073c0bf0cdbf973417a0e3c25cd208c3f462e5b3d49dfe367c7ccb8272cace4b", + "weight": 754 + }, + { + "txid": "3e22a369903b3757aeb25c1c4906fdf6a533d9c825364cc55906930fa876bdaa", + "weight": 754 + }, + { + "txid": "f719d75fd9246d964b11adc447ef2e0d8e74fee5c45c3f4604f4e3a7a9ebfc1a", + "weight": 2383 + }, + { + "txid": "d68242bda218ed39f6bb66a9445b3b0dfdfd68089cf1f6d9f8a1208de9cc6cf6", + "weight": 1488 + }, + { + "txid": "ec7837c553621ba2baad016bf3dde27ffa5cc29c9791eed821996a8d77e0e4f1", + "weight": 826 + }, + { + "txid": "f538de5def35e688140b21394967602828892d0b8901007d9f75b93063e713e3", + "weight": 882 + }, + { + "txid": "89c6b4621bb6d092b165e56ef07198297205ba7c793bcc381ddd6b875e0797c2", + "weight": 927 + }, + { + "txid": "125c6959658450066a62078eb4767e3a5f3915ca2b847081cd6287ffd81ce499", + "weight": 1018 + }, + { + "txid": "2a760356541a55ee0079af6e77aa37e68409ba9d007e3c95db1e46ed1ee349f5", + "weight": 1130 + }, + { + "txid": "f0493d8d7fa523d952082a42c09494251ba6f6d72b69d914736fc35fe77ffbb8", + "weight": 2006 + }, + { + "txid": "0a548400f41f612a1e4edc9f6e0001b3161715436de19dc9f483a59679ebf89b", + "weight": 34957 + }, + { + "txid": "203ab70f46031739a529c36dd5332639550ddca22bf0b7e3eb23d53290ee02d4", + "weight": 1895 + }, + { + "txid": "e84fddc332e1904f0cf36b577456e7721de52500aa1b9aace552d45f3007b556", + "weight": 2143 + }, + { + "txid": "3e95457a7b373b1eaa7447eb332f759fbae73bc04028652424f7d4d4de516163", + "weight": 2298 + }, + { + "txid": "4d7e1ff6597905463d138cf4857bffeb3eb541c774e5579bdda8b96f67ceaee9", + "weight": 661 + }, + { + "txid": "68fda30d9acb105dcfe00c12082bce3bb93f0bb937cc7e02804cb4f742b30c6c", + "weight": 900 + }, + { + "txid": "8a8ef09609532fbf71e04b866fd63c7a34c4b839f01ba331f28a3f3d28d54b31", + "weight": 876 + }, + { + "txid": "211eb0ffe6a78f7b4697c49bafa223c415481249e73328fbc8680eb9d291a09d", + "weight": 876 + }, + { + "txid": "e1adec68f1b798a3876d4ebba852931cc7b6f1d03c0f6d0b6ff44edc637e1340", + "weight": 565 + }, + { + "txid": "3355f60f79989c5e109676687c26784b428a93e391975ea683e78fc47a605446", + "weight": 565 + }, + { + "txid": "c2dff0b697d542c8d6325cdb33495990ae8c396a9ab1bddf1d45ac05cf9101ea", + "weight": 565 + }, + { + "txid": "913d102d419a04acf821fd8cabd4bef2568eba31677d55b8fdcef897fcd12497", + "weight": 1387 + }, + { + "txid": "03ed1ce3bc9db95655c4f3013e200a363a4bf229a03a1a23ab1c8e669de5dd76", + "weight": 562 + }, + { + "txid": "d7d96688f7e158c1a68070e22334627447433791d8c3cc661f7c67b2f96d26b7", + "weight": 561 + }, + { + "txid": "9360c787a01dc1e33d46b90257c658b4f98841370557ebce78cc2ca83d6a0da8", + "weight": 892 + }, + { + "txid": "cb73c369723e418dbb9bde9e9505493cd6bc1b6036a8ad46dd2a5e9752fde2c4", + "weight": 892 + }, + { + "txid": "e624275dffa9685b065bc32ab90d601b2e286820650b0530e8348e125a0193de", + "weight": 892 + }, + { + "txid": "464684a9c8aef7ef93f223a4e5af97de4aae37443bc5765e532249a27338a242", + "weight": 653 + }, + { + "txid": "0ab77ee5c954500675a5f3425ab1234b952f9125da80ca8098781d8bb1dd6c51", + "weight": 4202 + }, + { + "txid": "6c3ad30342982930a4b34578b8d00081c0b6ffa69e8d3956a7acd9f920092702", + "weight": 4482 + }, + { + "txid": "242bab51f78473b5928d765ced924e8326c0d829a3176f1da1ebcd179e1f327e", + "weight": 4598 + }, + { + "txid": "81bd620f875330e7f55bd8a5cf62650fb7d2de3c68befc6d785ebc9c45343cef", + "weight": 4878 + }, + { + "txid": "52ab7e581582e582bafa83a0a8d416856505181d8206f1c3a25ae83d91ceb9bc", + "weight": 5621 + }, + { + "txid": "14672528f63649d7e1a0b7b1cec330422136bb68c52928c75f5fe0fd45845e01", + "weight": 5498 + }, + { + "txid": "2dbe4ff4763d05516208aef4241649d495ab7dd287608f787da9408d3ee946e9", + "weight": 5278 + }, + { + "txid": "211eb999838c8a7ec9319c46f3705f1f881ff7899111d3e936adb7304a362038", + "weight": 574 + }, + { + "txid": "21b5ff74b893685fc4355a80b5fe7fb7352c27a19983ae0f483432761b0183b8", + "weight": 573 + }, + { + "txid": "754ab2b7b05eae9dd2dbba7297aa904f0689899725e58e67127687b989c182eb", + "weight": 573 + }, + { + "txid": "0de7dc39943e9c9b2c78d3d8cdb1707958bb58a28e6e0e7ebeda65f9f7d1287a", + "weight": 609 + }, + { + "txid": "c117742ad06c956d478b7f36fdee79a87228fbd210183e7d880c4bee7d0b32b0", + "weight": 609 + }, + { + "txid": "fd90c6327db8fb7db7c62be05dc3b7e178325c1aa3082fc29e4aa9f85031e01b", + "weight": 441 + }, + { + "txid": "4f91293ffdff1f31145e6c2e304e3024442e0081b2801171baa7127589297f38", + "weight": 442 + }, + { + "txid": "f9b202a65cb7f7178f3ce2620262ed5987ad76b5af9f1a0e81b3bbc1f301bd70", + "weight": 562 + }, + { + "txid": "f4b95fb19bdfca226bd30ca824c48bf58dbd91229cee25eb41ad71b80c6fee98", + "weight": 1437 + }, + { + "txid": "a9038c89091e5d121cb7e6742f9b0ec8e7e2dee57da454047dfac2d7a4c101c1", + "weight": 1838 + }, + { + "txid": "aac7f97d4eba3f084170e85fcde9d4e8183d6a898019869c02f17df98e06142a", + "weight": 832 + }, + { + "txid": "4ebd1676c0b13bbe4e9fa6c18a812bfcd537b5b266cda0bb07cca072df857ab8", + "weight": 832 + }, + { + "txid": "018e51e66ebea58ffc6e3d8eb7a1fc5b52414455ea3e3133ed43b97d2f702ecb", + "weight": 855 + }, + { + "txid": "d5a201d925c273c82298ec437aa6014e9a00fd20df71602a8f5a808a424ca525", + "weight": 561 + }, + { + "txid": "e828d313e3a94eef22891b86da7d2c4bf3f22f090925cf83102acf75a06d2996", + "weight": 1334 + }, + { + "txid": "e372f597bc3f732a9b6b351cf3c12334868d5f1e15f680e6b9bd3c9612d3b2e0", + "weight": 2344 + }, + { + "txid": "bf5ecd1ab4c38237401da85d586af56900afda606571d69558b951cd5e4964fb", + "weight": 3006 + }, + { + "txid": "dc4cae556a68de69af00669ce5c5982bae768dfed6be756f0713746e65c8c90d", + "weight": 565 + }, + { + "txid": "d8ceed13733dca67d9d55c96f95fbcb0c0351b58b862371cd9df053072aee9d0", + "weight": 836 + }, + { + "txid": "c4de5809868ad034a18971662784a9ba0a5d891dd1f06769ee84c4c64e81032f", + "weight": 706 + }, + { + "txid": "1e8716d034bdf75de19909d87b4107904c89902e249dbeaaedab11e3b69fbc69", + "weight": 573 + }, + { + "txid": "cd0ddd428e5119d94d53daed8b4cd78bbb23d911213d5110074a08f96fad0288", + "weight": 573 + }, + { + "txid": "e133335b075c4fe81a4e2e3361d36a2c27adffdca6b0077e759ea20289512cd3", + "weight": 574 + }, + { + "txid": "b1be0a43638cb87aa1f5ad7d9d19d53ae5dcaac5937f05858b1eac3ad63e86dc", + "weight": 574 + }, + { + "txid": "e6e36ff8c0ac171c9e1e74984a2916d7bef7eac77c1901a9e92317454e56e7e6", + "weight": 441 + }, + { + "txid": "44f3949f54e2563bb9ecf4ae237bfe41c6c0ed37de3d4c16e16041c0306d9b21", + "weight": 561 + }, + { + "txid": "96408bdd88ae70942ba99a46602b117bfe3fd98207ecaf26eb80b6e327aa0832", + "weight": 562 + }, + { + "txid": "7507d90dd7c2b0b98d7d085a929e159bba2f54397480f821848d50a748ecb343", + "weight": 561 + }, + { + "txid": "a4dc35143dda4db4f8431b299e4d9a467cddbbf0faf1636248da088acc1c444f", + "weight": 562 + }, + { + "txid": "41af934dadc39902f70df0d3c77bedcea56057c8d3b896f0c51087a880eedf76", + "weight": 562 + }, + { + "txid": "01f4b791d3875ad2cebffe06f8d2d1706d873d76edd7f3f755e0162b9954fc8e", + "weight": 561 + }, + { + "txid": "d9f63c049d8aec18e6a15bef88458d3203856c9bb6805c61fc86f088281d7ac4", + "weight": 561 + }, + { + "txid": "1a455e87593f13fe35dccc224fd3477c66e3f1e818ca45350d7cb335d6c3df12", + "weight": 1753 + }, + { + "txid": "7cc0bff1338116f0c51c48017c3ac7e42dd431c6587c030766c18941af4d4e34", + "weight": 2921 + }, + { + "txid": "8c501b53573b1fd3105f4caad97547c5b4dba481ffe3f930ed8c7ea9a8ec5615", + "weight": 566 + }, + { + "txid": "17fdc0b94b97aa91e04b11bc289c71dac2ebb1ff4e0b6234ffc816c92254081f", + "weight": 565 + }, + { + "txid": "a9169ee8672b27342ae01c93481fae86980beebba9c4bec67ad4b8e1f130f69b", + "weight": 565 + }, + { + "txid": "364e0ba4d0ae8af423496db75d51551722dfd3bae60d218d545571caeb647642", + "weight": 566 + }, + { + "txid": "1834c3c6abde7afc093dc83f29bd56f91ddd325a9847c53b9e8fdffb69b9074d", + "weight": 565 + }, + { + "txid": "78142070bab16110c84b88da1fa3ac399961193e83c662cc7aa2daa2b7b0a660", + "weight": 566 + }, + { + "txid": "66cb563335ca8b483a235c5ff0700c92a66bb56b42f7df09409a6750155f2966", + "weight": 565 + }, + { + "txid": "e2a184b5990939d1960dc365311e32da5d1a78b894a09bc24ddda88840a2f90f", + "weight": 2629 + }, + { + "txid": "8ab1227dee18c2d538ea024bd32b6d4e2fa9ae729194cf8640df6eb8597f4b36", + "weight": 569 + }, + { + "txid": "b45346c8d8e4d81b3d5bce8bb4ff25e80880bc543d19998c5158e693bf1573db", + "weight": 1484 + }, + { + "txid": "b00b11939705de762645b8046b0aa84637850e0893f2ef97512bce33bb420b76", + "weight": 561 + }, + { + "txid": "ebe12990fcde3268b68260079952c80a25859c60d5cb159860665c94bc0afd14", + "weight": 565 + }, + { + "txid": "512ff899ec86cc3fcdf9fddd139399b4c7b5e865c34073c617f90d678642c9e2", + "weight": 2928 + }, + { + "txid": "efd3001a8bb1a4b169e964cbde18e9c151bc07920a1e9671a6a8dee632d79c36", + "weight": 764 + }, + { + "txid": "f7868411ee2d3d8418adae6f33b54ed0557a5f6f2ccc647f54dfdd54a7c24852", + "weight": 1352 + }, + { + "txid": "b4bc1e8a96bad158e1eeecfc2853bea08ca3c545d97666ae5b377d959eeec883", + "weight": 701 + }, + { + "txid": "9506e5efb0a39900226f415aeaaff00044c9bf0525dc4829de6e68b261ecab06", + "weight": 444 + }, + { + "txid": "0cfceb75a161a7f576bda3fe899150e77028cd41580c2df6d5a9070236e3cb06", + "weight": 904 + }, + { + "txid": "2c4179a77ad847c5aeaf2fdd1516f21703b4c903cd43f8f612f751ec00d98d07", + "weight": 444 + }, + { + "txid": "49e5f6ced7e6c05e9f3955d1f567d89cf77bd5c82f33b4faf4b2c3956b5c010a", + "weight": 444 + }, + { + "txid": "7a1bcfd2a98a3aaac4ad6c44318d8bd4292cd4f343a21f7b8d79318c7f15bf0c", + "weight": 444 + }, + { + "txid": "b6666a8751b3c6f72ffd86f968c7f61bafc5ba7cacc4d9db24a1bf59d101a813", + "weight": 444 + }, + { + "txid": "e062cf81d5106d07a8481842c25d459f769987b11acf8f3cb90defb43cc8ef18", + "weight": 444 + }, + { + "txid": "222914edb48938e10338f69e92aa6e386a0801e502dd141634db482f821eef1c", + "weight": 561 + }, + { + "txid": "fca19c07a4f6f501cb2065ffa47819371d6df7b142d81010427891c190b4bd21", + "weight": 444 + }, + { + "txid": "40169b18558f2b514df070829ed93dd05a05d0ecc145e5fe009f5d300d65ad29", + "weight": 444 + }, + { + "txid": "e8a5d3afe69a3f5943540228d5197ce7af6c450cc5b243b44f5135c062f8422f", + "weight": 444 + }, + { + "txid": "535f1f20c15f297af9c4f87834a10f388a36b43ecc6253e4157484116b4eaf31", + "weight": 444 + }, + { + "txid": "862de439f9c6b4649c5541ac1b80e72b0a28e046bffc764b71246dba8799e639", + "weight": 444 + }, + { + "txid": "99849cf76acdc97a9a5afa976eb2300bbf6525b7e133e7da0456c4554ab8bb3d", + "weight": 14134 + }, + { + "txid": "c06bea880bb85edef0a3ef07778d61ae9e71040448747ac97a54edb332f7f743", + "weight": 444 + }, + { + "txid": "6df164e24cc4f8563d7300f60389b13397c58de6d15f1f4cc68413cf604b6c4a", + "weight": 444 + }, + { + "txid": "6460807632bfdd2aa272add4628e54e14c03534a50be64cff385453e3528094b", + "weight": 444 + }, + { + "txid": "44d8d49d8883bd322eb11b99be2b9229224f7c8e8e4969d9031d4cfb3a55e64b", + "weight": 444 + }, + { + "txid": "a9e2393f4bf649c4674bf5f9061acef02ee0f3cadd6698cbff57d7399a352157", + "weight": 444 + }, + { + "txid": "26e7214b1e2e6c22e946b86babf1ea773dcfb99bdb918181faac000cda5c255a", + "weight": 444 + }, + { + "txid": "48b94707cca592eb226c8dc70fbb9475fc972ef6be4ccfdc93de8e340877a35b", + "weight": 444 + }, + { + "txid": "2fd7241161d6a0870ac4c8852c84c64b70348cf955e82064f418cfcc08139561", + "weight": 444 + }, + { + "txid": "f8959b0a6ab36d7f647e4d2abdb5bc9afd9f45022529d0d71d0d1106872c3f64", + "weight": 444 + }, + { + "txid": "a69f4e65e4387292fe8d76f3502dde11dac4f32f5e99abbb08f982400cf4f96a", + "weight": 444 + }, + { + "txid": "39767478259033cf7ca4c1225b654be611dfe7b4a59497527efc3694d7ad6478", + "weight": 444 + }, + { + "txid": "7ab90d5813eed8000afa1015bf37a2ff7077357b501887590b5eb09c36e7fd7f", + "weight": 444 + }, + { + "txid": "b6d04c848ec42969325d8f34c041839ddc3975596b3a66b08c8125aab7231780", + "weight": 444 + }, + { + "txid": "096a40099fd37b0af55e939efb4e24029702009966b6fb16589c892128f90181", + "weight": 444 + }, + { + "txid": "ce0572eeb14196a2e446ee00a028d88c03cce94d00f0b6851b6f6c5140204584", + "weight": 444 + }, + { + "txid": "ef516ecbdfd2e23944e65c4d670d2fb2525711cd2f0704d3e89875f8608dd28d", + "weight": 444 + }, + { + "txid": "fffeabcebc451e7ba08326a2faf0005905fbc8e9f180164f913089d52a49e2a1", + "weight": 444 + }, + { + "txid": "f5fe7e5b7d35814329e3840e349cb17cd638ba28d0caff42c7f65e4602f1a6a2", + "weight": 444 + }, + { + "txid": "6de05e1429117254315a5fcce89a693365711c679921fde4fff2b8ca6f8131a3", + "weight": 444 + }, + { + "txid": "b99b4e154742cdc8649b86887513fa01cd27a58a5abf251c21eba54dcc1e20a4", + "weight": 444 + }, + { + "txid": "4273c064805cfe0be0380b8e9ee42d16817ee98efef2ef69d514b24b645e11b2", + "weight": 444 + }, + { + "txid": "58f4315487f9158736f0279d00f42f0ed9ca06c59c01693b2333b89de416a9b7", + "weight": 653 + }, + { + "txid": "7bbfbbc65b7c97846e76206b27099aadb962b5c32fd4bc9de4ad449e5ac142c0", + "weight": 444 + }, + { + "txid": "8ff47f4f1b3c0030e493c0bc7eef8d903f8c9ee39e53166d9e876d2e9e2a98c3", + "weight": 444 + }, + { + "txid": "eb4e7398229616ac7fc2709c76b456f6ecefaa0b2603b60f3e1da41cf9bd93cc", + "weight": 444 + }, + { + "txid": "fd70d8e1fd83ac596473770604a71b1f9ab163f1e073c57d96b5d3f8391107ce", + "weight": 444 + }, + { + "txid": "02c581af30d4a6e6b362847ac11e5881b787d9958010e1d03a8c9530d91921d2", + "weight": 444 + }, + { + "txid": "fc733c7a699ddcf9e8849e0d23bbd6a4d5929faf40f320d904c6a3c94e1a8fdc", + "weight": 444 + }, + { + "txid": "54c730b27ce3351d95411d44585ccb8546133c279848182b974b0bb4cf3f0dec", + "weight": 444 + }, + { + "txid": "2b5bc9f033fd262655201f09be47c22930a637bbddac2fd841357cd87851e0fc", + "weight": 444 + }, + { + "txid": "67c3df0039c46ab1f013dec290204f7bd2050184a814f9ee972b8085c70fa5b8", + "weight": 1222 + }, + { + "txid": "dd43afb9504229561b30cde0d0a9940f183b95f80e0a86825b3a3ac2e56aa9f5", + "weight": 657 + }, + { + "txid": "92fb5bee1b4b3ac7125783756b01c9280aa4f98a65c353351ebfd11ac9f91f74", + "weight": 10759 + }, + { + "txid": "8f7c982f35380ba04d0104d83cb2dcde5da364c6d6209462f48867ffc1baf63f", + "weight": 720 + }, + { + "txid": "7ec5d415a20fa8587b6c29ec6fa1a2aa7d1ada843832e7f663a35c07ba8b9b6c", + "weight": 4512 + }, + { + "txid": "d1a735d34adc1c6e70b40ed72737fb4352581ac4c4e7071e9716462e439dcf3a", + "weight": 1176 + }, + { + "txid": "0846a22e9d063823669e4605b75a6daf13584b70ac4f58eb73b5f9894619bf07", + "weight": 1171 + }, + { + "txid": "c8e71b253420f072d02c7e0da93488e7ec53d6e303b29794cfcc369255d3e77e", + "weight": 542 + }, + { + "txid": "1f29a306b65dec80398e66b9ef656833dd274998f4f1fd4b99f30bac4edb0d22", + "weight": 764 + }, + { + "txid": "576256cf933d895be4e8769448514d039bf03f634b8661fbe6c6dc647e4f76c4", + "weight": 760 + }, + { + "txid": "253f9754d25ff27c9f2285883d10eda1aae2b427586e19d21b9ecf9a9ab22a48", + "weight": 8417 + }, + { + "txid": "61e123853d3c16d7ba136fe7b2df474775e9103849f5f5e3e8bd725385b462ac", + "weight": 1630 + }, + { + "txid": "ab794e6c0b0aedf0ba13eecd181ade5da4e728f741923eb0ff2479cd27dd15b9", + "weight": 561 + }, + { + "txid": "a894bf6d4b158f25e594106f96623bc9e7eee59b82f775864ec982cd722f947c", + "weight": 585 + }, + { + "txid": "3b43bb583ed1eb634d85aa14912bdb101bfe765eca1df437fbcfd21cf7d63b06", + "weight": 561 + }, + { + "txid": "e372a2af4e0d52a0f1b2fc6da3575df2fd342e36f374e6050b9205564964d444", + "weight": 1032 + }, + { + "txid": "50436d5575eb98fd010de24e91a425a98d06c8222c6a0f6a5d1093e429d12abb", + "weight": 1032 + }, + { + "txid": "f187a7cf40b653d697915bec0840eab21c5be5d29d3e5112b6b2efe4f20714f6", + "weight": 1080 + }, + { + "txid": "a49d1624762dd064516ebb413ff56b46d598726710db95bf0b047d459ff77822", + "weight": 657 + }, + { + "txid": "a55145732ddd46c217946b58206a154205832be1ccc345b6bf576b19d2d45fa6", + "weight": 658 + }, + { + "txid": "93dc5e78c8a3b48888c5b045653f2751742926143a142e795c5d1d15d011f520", + "weight": 768 + }, + { + "txid": "deeaacc4d4dd94d41dad5eb4591b24b1b7c048b9b4fd0cea1bf3552db3b2da61", + "weight": 943 + }, + { + "txid": "bf52fbb6c8a7e7c268225eb230f269f4571b3684e5bff73ada81e37244ab5ecb", + "weight": 436 + }, + { + "txid": "d8f0228c079265018c36968de67f50da04955611ae2185756bb8fc8e142430c0", + "weight": 573 + }, + { + "txid": "8b1947820dd007c16020b6d5453aead483049d08af97290be0e40010faab2760", + "weight": 561 + }, + { + "txid": "0299a03272075e30fb1ba1cecc4c64b4a7a17162d28357cddbae6ac44e9eeea1", + "weight": 541 + }, + { + "txid": "5291f12fa80ac003667ac56288343e971a9dff66c936779dc615d9da1cb22d95", + "weight": 953 + }, + { + "txid": "6b6e24b589b3bd6ad15383e7ea6791c4d8a60bbba9e8ba923a6bcdbf87088f67", + "weight": 2164 + }, + { + "txid": "2731b88928390ee4a10d88f0404503e4e7e844ab6461dd0086779cb1eeb08631", + "weight": 2119 + }, + { + "txid": "425f5d160732e95153929530b3bbb85e084ff15b3e431025bc91156dfb690cc1", + "weight": 616 + }, + { + "txid": "9e0bd2fff8e716c2ccd69f876eacdc172974a2facc01ec3db237fc922fbef957", + "weight": 585 + }, + { + "txid": "69d09f55c3b2be00e8dd493468b60fc8079257fbd0d6c156fef009a1d9759203", + "weight": 1480 + }, + { + "txid": "8fe2a6d4c8edf4475eb94ee5c5633c0cc7dc1c9322bc3d7e6b625c9834e5108b", + "weight": 529 + }, + { + "txid": "bf1637435bbb2a6ae51143d7fd44b602884c60d9bf6babce36df0007548577bd", + "weight": 845 + }, + { + "txid": "27517f5232a64178869c85d1e0c66b4710581153c80bdf17e35bda9a43f3d872", + "weight": 2112 + }, + { + "txid": "810f2bd9bfb4ba23e2de17112638b6adc3ef3f88981036ff4f6a62f8bf892336", + "weight": 1197 + }, + { + "txid": "c831caeafa55d1ccbb3597535c234d500519c657389d09194c1d45b7c94ade3c", + "weight": 616 + }, + { + "txid": "44ede340e2e2a7b4c5049fd776a8eebb52a19b6982ee28883bbcc292f6cf6f74", + "weight": 662 + }, + { + "txid": "04d9f47dd46cb306fcbaa74e31a2ab52815f2ff7caeb2294f978a1a365bda87c", + "weight": 851 + }, + { + "txid": "01cbcc2718193dd6fb869c97571ee2e9b1566fe8e673a1f5d016230e4428f98e", + "weight": 438 + }, + { + "txid": "82e3bc4a460324443c65fbd08d93b5963902155e98e27ceda09eea315fcc94be", + "weight": 662 + }, + { + "txid": "72f48e53b6146a88ae2c015086b1005e736dea301b4ef4f428ad7483b92726d8", + "weight": 573 + }, + { + "txid": "3a449e981ff6ee80fd7f9884e4aac3678bc3ce7a3688ed52fab71c7f5ba7c8ef", + "weight": 31618 + }, + { + "txid": "cd81d7cb54d4ec3ff2d1b6cdfb8bdd696b88fb2406e8c288acea326a37e72941", + "weight": 437 + }, + { + "txid": "93cc63d1d6254b1b53ad6d0a923e24c9729302ea40855e568240bcf8b0f2502e", + "weight": 1309 + }, + { + "txid": "f342fb0c8b9dc0b91fa35ecf8712b59c660b374d9649e87aa011fd3fea140633", + "weight": 993 + }, + { + "txid": "6e15f052acf8ca73e4a7a1723360296b6f9eba67167d7048dc04027052ef1302", + "weight": 662 + }, + { + "txid": "6316816af814b6a9661df496e9495ae6b851f3846636767130967b89031e762f", + "weight": 566 + }, + { + "txid": "b5f938fd7f0b017d8f311301c1ce12e305e7e6999c731f28a29c0c775ba226df", + "weight": 566 + }, + { + "txid": "0180f47f94e251c8c4ea99bf9b2b06c63050088a80fb69b74ec3b8166b4f4316", + "weight": 892 + }, + { + "txid": "2b7b43c0ef947e6642ab29edad8e9c01f9efaa1819291877ff55754363c902d5", + "weight": 2192 + }, + { + "txid": "4c06d0cfe8c068002dc39cda0a64a79909b491ddc7105cd60403eec3122d7f99", + "weight": 562 + }, + { + "txid": "b8685dda935bc907fe0bc6522f186a0ad04331428b280df7063d68427a30d2b0", + "weight": 1105 + }, + { + "txid": "4e37b8e576e36512e97058e1b0f0f5ae3530e2aff85f3519deec67bb50774761", + "weight": 609 + }, + { + "txid": "e28cd06d7b2400ebd4a94d1f3d42dcdc0031eb02910754109056f7e9a7cafb24", + "weight": 688 + }, + { + "txid": "c59c9ce2fc3bbba9a780cf7cb804d58f1d86f2e3f3407745df6f4b1dc4682b7a", + "weight": 529 + }, + { + "txid": "7328a1b35abedd74c096222d27753f1756e584a327ea19fb98622a0c3abb4b96", + "weight": 529 + }, + { + "txid": "1d9baf97ce03412876e43f8179870ca9fc52637812e981228e45ffa4bc3cf643", + "weight": 888 + }, + { + "txid": "e8eb4917f19305aacd17d96609fbc2d88a13f2fc85c10e976ee74879437df8d2", + "weight": 609 + }, + { + "txid": "bf0eef0e4bf41a1f90e0ff15e12b13211c2d7dab771d5648beabfb88b018dd10", + "weight": 689 + }, + { + "txid": "4dac2e29256756299f94e5963b8ae09dcf43d970cf9d61ad0827433fd38b10c4", + "weight": 574 + }, + { + "txid": "68dd1572c1dd7d3539004bfd35e15a029a0d4c9729b9a1dc529aa5d6b2b1692a", + "weight": 888 + }, + { + "txid": "8e416847e0bc24ae33a46fc044cd7081ae422b5c234ca81bce2a3ca8ea49d34c", + "weight": 658 + }, + { + "txid": "947131ba9b504bb911476e17c838d399f9ae5e1a40505f394456f405ac70da17", + "weight": 1936 + }, + { + "txid": "eebddb8ad9eefbc6fa33e1b548cbf540042f3196af600b47a219f8461f5ca832", + "weight": 566 + }, + { + "txid": "d992d3b452b0a317d56450899d01bb6ce349614e29acf5cae1b77721b6ec691b", + "weight": 888 + }, + { + "txid": "3d4b60383c8cb8ef66f5d4c063973aa0eda1629b2b0ec7244fd2cafb348dc7d6", + "weight": 892 + }, + { + "txid": "5a33ad230b9041f9dac402fbbf9adc8d91060ac8b5bf151da5f541b095d14168", + "weight": 5252 + }, + { + "txid": "a46bd598ba457e8a6a266ad87e03fef0ccbfb967f11a63efc6f9972be4fca877", + "weight": 616 + }, + { + "txid": "03beca5cc04891afa0fd1e75c2dc8fcf0ed3b5941de43bfac45b3f5079ad1d07", + "weight": 896 + }, + { + "txid": "f25479816e702da9bb6a4e14bb1a38aa58487cd7d85989b6c5e1e93ec3b0f20f", + "weight": 565 + }, + { + "txid": "41e1332076963d5429492f4b148d6633384df9b4829d0bd503664f17fc913dfc", + "weight": 565 + }, + { + "txid": "9dba29b5297a51991b4e2452fdfd78dc597c07e7a246de95dd9c819e4beebfde", + "weight": 573 + }, + { + "txid": "a8a3ac5ed0479b09da53fcf382431656bd2f017e64ce968a25d22467996d4a2d", + "weight": 924 + }, + { + "txid": "adcd3562308080ca8f647fd53c4c9c6fb4ecca43fdb7e20858abd3b90e368b4a", + "weight": 1060 + }, + { + "txid": "74055df153e129879c672f046dc7b6bc5a20a00e0a416b2bf1f6fd2968f292ca", + "weight": 565 + }, + { + "txid": "dc09b1f4ed462ea9b2af1db8eae90d52909ae3a8b4101c2c0cc6e5e3b287edfd", + "weight": 610 + }, + { + "txid": "562f432c9946108a8fd26a303ca092526f18bbddddaa37a3321f3c5cec3d0d14", + "weight": 561 + }, + { + "txid": "50e5eaa53230d399e2f67f20d7a27978b038dffd099085309eb386e0a37ca787", + "weight": 573 + }, + { + "txid": "881a04c81711312c9512f4f91294a7ce06c23c4b847e9d9cbf3dcac9aa561a01", + "weight": 781 + }, + { + "txid": "9f85ee19a86ea205b5d568f8c586dd8e6ea3a6bca411e968a0677006868ee028", + "weight": 573 + }, + { + "txid": "48f5e3aebfcceb58d33ce43baddb8bc60a3961129d2370d435c2b0f539d6bb3e", + "weight": 561 + }, + { + "txid": "8775870a8f83141529e2d55d0e818638acf4d22d2c28d1e3c4804ab7ec9e403f", + "weight": 781 + }, + { + "txid": "13b6f10ab4402f345b24c6d6e8884fc5c75a8c9f5f9da480c7c6db1fe76715a1", + "weight": 658 + }, + { + "txid": "d869a64522141e1e35a0a7d27d9b006e52430b67968a0a86a55fabcd3098a1b6", + "weight": 739 + }, + { + "txid": "1d8633729f24a64aa98b3ee013cd5044f35d6a223dc84d0b4ca4b75027a7af21", + "weight": 609 + }, + { + "txid": "a395855d1dd6908ecbff00d74ea3deb35c9feaf50db61eb3de1ad753e8d2f1a4", + "weight": 689 + }, + { + "txid": "bb72ffba8e6c88bde86badf7a65d8b307e5aacd490738b2bfc74e489d63063b6", + "weight": 441 + }, + { + "txid": "2d8f9f69b2b8db02ef92791658f3afb20dcad86ebf9550d8897a11763a6d603a", + "weight": 437 + }, + { + "txid": "cec4b1a55b4769dc41e8b8bc9df4e048cd296ac228fc64de79d81252dfc12cdb", + "weight": 485 + }, + { + "txid": "4ae937bc30c148571870ec9cb63de668e41ce4ef9c9317d116a21e0943759e51", + "weight": 573 + }, + { + "txid": "d04545198a98db7e0fc1ce9da2141707625e87e2b98edd4a2593f5ae89e756b2", + "weight": 574 + }, + { + "txid": "616bf5407cc415789b8e564fafcb65a8bf500fce6011db3aef6ef3bfba8863e6", + "weight": 573 + }, + { + "txid": "1ca4190b29cda641f4be7e156265f8ae8b7c51aecf186a6f465a3fd4463b17f1", + "weight": 2026 + }, + { + "txid": "61e5faeb1710475782d7961b5e9b952a2dbaf54230a3b0a4d97968187e92d4dd", + "weight": 833 + }, + { + "txid": "7af186e20fba479917ed4dbee7cead30140cdf86b17f7ef7f9035cd3a20d1535", + "weight": 562 + }, + { + "txid": "eef7a9bfaeb42e3342c11c3589c84ab5b42aaa293656d112901f526defef1503", + "weight": 565 + }, + { + "txid": "e9aedb857862af3eed42e2798c49894f3283d83d5bc3b2e3563d55f3ef1751ac", + "weight": 561 + }, + { + "txid": "68427e7797c3dbcb326111d389498afa50793ee7f7e8d398cf81dc7d3a9b6386", + "weight": 665 + }, + { + "txid": "fbc9583f58fb8e3c35cddb5ef99d9ff25afd0b8d0d2702a630a3cb575f681aaa", + "weight": 665 + }, + { + "txid": "b9f55681b437e4329ea9c54d9b38ba70b7122e2178462a43ae36ab02df7c7a0f", + "weight": 2268 + }, + { + "txid": "50f08765a58d07e43c14f506e5ba3d8338b790c40767794c56a0639b8d04b493", + "weight": 991 + }, + { + "txid": "f673a57687b00a1b642dc10935a4bd8f65e534c9f046e57ad5e9606df00ff00b", + "weight": 616 + }, + { + "txid": "2341f7e7b55462fb1372e29de52979ff68cbd240d0ca546cf56e60f2f277afd8", + "weight": 979 + }, + { + "txid": "07c36cdb6d5c3e96900756e6620ffffd6259587cc9e4ac000139cdf8ffe68474", + "weight": 1151 + }, + { + "txid": "d614d331fcf1ff82c4b078c352e6405f1b02b5e81d07e88d424350b7bd654191", + "weight": 880 + }, + { + "txid": "84a6d1158f0a8c14e5dd54d5cb0a3784e18090ee91a394bba4e4fd61d0efa10b", + "weight": 669 + }, + { + "txid": "6467c4a2b16a4db53960801cd27abf3a051a0c90d955d5498198399f93026713", + "weight": 689 + }, + { + "txid": "0b4f2392f9c97ecbb0cc1e33b4099d4c3ea78d578ca8314a2b259b6a888d73ee", + "weight": 812 + }, + { + "txid": "57ea965ee96aec0c3660f742f0a9c3be13679be1928d507f5144ba3b264a5395", + "weight": 609 + }, + { + "txid": "807d92084b06de0ece1734edb75898dd2d317352aa311b7cb94b92df5e817c5f", + "weight": 689 + }, + { + "txid": "ebd5089ef1064a2036a7c64f5559905b05da99874b463dd33a6f9b13953e254d", + "weight": 573 + }, + { + "txid": "c1c01783894e62236972cddd994707300566ec15b35598ddb5221c53fc2315eb", + "weight": 561 + }, + { + "txid": "e18bb373685ef477cecf226f9ff314b33c61dc5313c308407e7b6622dda34a07", + "weight": 561 + }, + { + "txid": "4eb51154ca6bb8f44a274896c3b058a54f6c552d11ac824816d6b4dd244c7020", + "weight": 1521 + }, + { + "txid": "c627b6d5ffcf9eda6d0693369a9aa314369e9677a314de5bc5bf07fd5e8ba3db", + "weight": 561 + }, + { + "txid": "b4ef6716a73b8d8a40727cf171594575184691748046decddfe3212c5c92be19", + "weight": 979 + }, + { + "txid": "d7529e44231b62365e33879274e7041933d54b32d750bc842087ce66ea302428", + "weight": 834 + }, + { + "txid": "2910018f0db6fd529df9ef94ee347426815cc672dc20e618fc1d0d74d7e02da2", + "weight": 838 + }, + { + "txid": "a2f451ef889340fe975e38e61049c4fa3807768d29a5a811ded399612cd66d54", + "weight": 562 + }, + { + "txid": "9fea8cf6eeefd9e1be9c2874a52d92471f838b46e708cab4eda67f88284c7831", + "weight": 1107 + }, + { + "txid": "a4b945ec837d1aecac68eb7830af925247b7eb45be01bbb1e460b4192ce2f4db", + "weight": 1519 + }, + { + "txid": "3436416fde24510f9091131a26ef5499007dbc233964132e87d8b961107297cb", + "weight": 609 + }, + { + "txid": "a2535557ab656da17d5802e8450da2d318485175bc334d4cf592d9c70079fbdc", + "weight": 687 + }, + { + "txid": "10a64f8e11085bb7d3eb902a6e527127bcb83fc4e50e5f30c0f3c4a543658ae3", + "weight": 804 + }, + { + "txid": "ec76d52a8d2763dcc99821850c95b9abe07318c8758718bf4164935185791f23", + "weight": 888 + }, + { + "txid": "b3019fd60f897f72a046ca410329664813b2f339d48edd87bcf28e9ae6b973f5", + "weight": 705 + }, + { + "txid": "33172fdc2fb4dfd1fe8be3d437b8765f75ec650ce2db4be8585f84976580913e", + "weight": 892 + }, + { + "txid": "b4401142bfdcd48ae2062fd12b3ab846f03ec8ede47c5d195655a17958355a6a", + "weight": 561 + }, + { + "txid": "eeb6ffd7acbf96f45dc265eaf5ef9038b09ed1bbc005f76e66e2ddcf3ae00a08", + "weight": 616 + }, + { + "txid": "43a94fea2f01c16fdfe8aebc3bc51d30bf4370fe9ca134b24ff7e9bb6d10559d", + "weight": 780 + }, + { + "txid": "32958875459caa94cd832e55c6eb1bd4820b494a13811c750cd7fe3864f56cb9", + "weight": 573 + }, + { + "txid": "cad5782b72d51036bebb5521fc25d9b35a696c2cb1f664dc993b18d9ab25850f", + "weight": 1350 + }, + { + "txid": "aba020405364ff24795c98d44de6457b1c9cc940d384041215d28d9277ad8e2e", + "weight": 1350 + }, + { + "txid": "2d79eeaef3ec3ed93192be2a244e0c0fb39d46079bfd88bf1d780b72733a54aa", + "weight": 817 + }, + { + "txid": "d24f9969916b2ef6142d57a4b0e8e0dd3ee0c2da04e48af226692958a622522f", + "weight": 828 + }, + { + "txid": "5ba965cf277040c478d2668cf938c64f2e92841c26b88aba8624be1bd6ef7642", + "weight": 561 + }, + { + "txid": "8f9dc33e5472167d7828b50a71525592017be295f151a09e1d3b7ea8cc4e9beb", + "weight": 2191 + }, + { + "txid": "ab1458ae6778458c1ffb344f1c1eec2f82af7d3a008d0932b25a7a1001242006", + "weight": 836 + }, + { + "txid": "1f8ac752d7dadc8d5f9b7192c5e707e3667f506e2db7b7749e026b5843c87507", + "weight": 1484 + }, + { + "txid": "64c6947011f46622d169f492563de90094f07c314aa324604b961ae311342f0d", + "weight": 985 + }, + { + "txid": "d3f23f029181feeddbac5903895fe560cb9c5e17df96cb2622693bdd0bab5c0e", + "weight": 565 + }, + { + "txid": "3644b34230f5715d89021b4a9694715207cdc1ca3afae826646a75d3d72d0f21", + "weight": 710 + }, + { + "txid": "f4875b5c64af36bf162887f78e60f2516f19486cbbdeb7575b0f86eca4bb5a2e", + "weight": 837 + }, + { + "txid": "355ed36bacdac0bb16517565ad09e90b4b9e8409973142234db1abcc64789140", + "weight": 1645 + }, + { + "txid": "2fc6afcac5c0e3780ddcbe0c7ebfe50c3d39d2c513bd0eaf9c1c5f3465d95e46", + "weight": 441 + }, + { + "txid": "b2b8ab159193e025a70c06ecc94d6efe828fceb350fbeed0c877c236e052fa54", + "weight": 561 + }, + { + "txid": "8a3b5eec0253e64641e64fefd94a85238ab16264876448f5feef5c9f490dc488", + "weight": 561 + }, + { + "txid": "53364527a2e1a2278d0d968a7efa69994d7139ad663afcd3c56ed203d525918f", + "weight": 739 + }, + { + "txid": "cc74e8b33de6e9397a410048032899b8e0591d6a1d1b912ae8545734df14b393", + "weight": 662 + }, + { + "txid": "3c1b0fd7c5a4fc419420d3438de848ba01c36c5cc8d85b3fcd61c8872ddc17a3", + "weight": 694 + }, + { + "txid": "f97c27dda92c5a559adcbfbe37479b4f4f16cef21a5e5b8930d3fc415dcdbdae", + "weight": 2462 + }, + { + "txid": "68eb5b66465445117a8b28d73486335f7c2c2b1e24971a825f08ce2e4715b1af", + "weight": 1645 + }, + { + "txid": "6666aab9f3321faffd2de436dc52a07995a693fb9d7f1a094041c7332fc0a2de", + "weight": 1374 + }, + { + "txid": "3468ae8f0d7a0d1e28c5ecf97810443e763089cf96d9f90a43e2b00d3c3d6193", + "weight": 566 + }, + { + "txid": "1e24b23430813d2be795dd1ed8a162970a3bf9a5831df3ad0e4776e9add119b5", + "weight": 1645 + }, + { + "txid": "7e8ef69be33d71d0c1739bf5b465a11585542fe3a5d6d688a77a8906e234b253", + "weight": 441 + }, + { + "txid": "886c33b0d1c38451bf5f0fa3fbed7ca065613853b7332d4076c50ec2046917cc", + "weight": 562 + }, + { + "txid": "6ee3a77848df2c5d467c406cc85675a4b361ac97b0f44df35a7338fa3c5c6dd9", + "weight": 2014 + }, + { + "txid": "c25551fcfd2bc7cd88f28337048f6ff5faee7d706712bf840d1709da0f526a5b", + "weight": 609 + }, + { + "txid": "22f13c71cf2fdedd95b12b7a6ec72ffda2ca294e27e04555f8b2fa5c2d280f10", + "weight": 609 + }, + { + "txid": "763287fe5ead7779cc06f4b76cc36bd95c358da98bfd72d7772ed384cc902fa6", + "weight": 609 + }, + { + "txid": "550f37296c685835087c3b3403df6981fc7ca6c0ed8302450c80fdbf1dfe2bfa", + "weight": 609 + }, + { + "txid": "2a4e96b0f786252b8ed17ac81231d51ccd816ce199dbf9fd8103af373b3bf71f", + "weight": 561 + }, + { + "txid": "350bae35e1b947d3fbdf9c3f280bf17c185f06d3dbcc82d69169ab8f074c15bc", + "weight": 609 + }, + { + "txid": "dcef9e9d5bed7cf8708b711477bef796fd2fea760c32de3795224b98d3ce0e56", + "weight": 609 + }, + { + "txid": "edb98eb6634043041bcaedbc69ae681638dee29c6bf9804c515e0929f6085756", + "weight": 1334 + }, + { + "txid": "731455d3215330465cb521b7281dfcaa47cc6abf05c7b9efbf9dda2b3302dd7f", + "weight": 522 + }, + { + "txid": "34cd60accb2202418544a35fb3d3b0376c1c8de951adc7127019f0a37d33828a", + "weight": 522 + }, + { + "txid": "921493178c149d7a8a5f5115a9d22fb7c7b2e9c08a71be40a1eee000a6cc9ebe", + "weight": 522 + }, + { + "txid": "009e7b664467de3283527c5783b4fe873a28bef5246a21400d0196f3ec94a2c6", + "weight": 522 + }, + { + "txid": "2ba5d77ad850527cd94d629b7290e2de1af07625c1e142ee9b15e1cbdcd958f9", + "weight": 565 + }, + { + "txid": "9740f318c36f5f514dcade4c556d736c9292df248f2e5f1b92292373a5a0a9e0", + "weight": 561 + }, + { + "txid": "45e0f0c7b7be84f2452d622c0391f90d4bddfac417b0e41ba5d903fe2adb3148", + "weight": 1856 + }, + { + "txid": "b1664abaacab7ed584c65a5dd9dad01580c08f9cf6b04b9b461429e4cbbf04db", + "weight": 561 + }, + { + "txid": "2238fff47accc8f34fd57a138199da1295067e852efa7d006648cc05b3e69d1e", + "weight": 573 + }, + { + "txid": "558ed5f72ada65a7907019bf94670b1e8d4e6d22ca7a8d454cabb5e3520cc407", + "weight": 755 + }, + { + "txid": "e8cce755b9eb40e037dab31833731927b356636cba1204d4f90ccb336bd7bb81", + "weight": 562 + }, + { + "txid": "a018878e012c8333518333d9936f20006f50f527b528c52122ecc1bb1fd4a943", + "weight": 561 + }, + { + "txid": "04ae830bc38a7886ae9624dc446b6ca644a835d8afb56decd797c1b3798c5391", + "weight": 1115 + }, + { + "txid": "3f614109bc24839fe27978123d2dd9f33c4180d1b03e16d56544ebe7deff688c", + "weight": 7426 + }, + { + "txid": "0fbbe8d7bda1885fcac531f107a6b8cf85236add093395af2b023f1c6aae20df", + "weight": 3671 + }, + { + "txid": "5627e701e91f350c056d030883c9375161053243354be7c282bcf07088b728e5", + "weight": 1383 + }, + { + "txid": "aee38756fa70cc645702c760b9fa6f1b66714f7d469c08cdd8be260e0aaeef77", + "weight": 568 + }, + { + "txid": "3c7d721752654f71e697e67827522636feafb2e42caa8bcac775a260b85f2985", + "weight": 900 + }, + { + "txid": "ecc47cdca1db338e4f6361eadf7b8905ce096101bf446778767e490ad208b76e", + "weight": 24015 + }, + { + "txid": "1df144f619a5eb0ccdb04045081860c2cc86ae501181b147d7c3de6bef0a1046", + "weight": 3865 + }, + { + "txid": "2c0a434260a9dfc76cf5f274ccfa301fd8d3c5cd686534907d76597a85a11459", + "weight": 826 + }, + { + "txid": "82d49164d7c37763d3a271f8189a483bc154c7247bfbed2b0892edb0696ee45f", + "weight": 834 + }, + { + "txid": "278873cc033943ed3c2913ba4a43150cc4813fc295c937b037b2092b299a0b22", + "weight": 752 + }, + { + "txid": "8e63233b02470da33c45a138006a801ede6dbb03662840545ea993afb9276d9e", + "weight": 3070 + }, + { + "txid": "bf893d3090fe3f9614e328264227327cf7ce016cd6f8f21e88f6c0bce6910a44", + "weight": 846 + }, + { + "txid": "715a19d55c34c90c9a0be11d837cff833cc471fc26c013a1236e0e1a004b806c", + "weight": 1032 + }, + { + "txid": "a66f999b8f08e2b8728487ea4bee095835a44d5bbcfce211befbaabd12c391a6", + "weight": 14680 + }, + { + "txid": "4f8d0d29516cc44ed1e780335adbfa7162d745813d6c03b514ef95ec10085f59", + "weight": 616 + }, + { + "txid": "cb373cd384f218827a1863ca72be70c65d5dbaf3032998537af54a330a03f1fd", + "weight": 6086 + }, + { + "txid": "299cde8a50a3c7735d7715fa9cabdb5ee09609346be7801190fb438184ce1eda", + "weight": 926 + }, + { + "txid": "37ea47751dd05f7766f81ef4626d4ccd4798346902548e04a5820efda6dcdd3d", + "weight": 1010 + }, + { + "txid": "e88eaf4166f601c278e4c479eadd98ddd8c20e9ac7caa5d7f69454f8ee15fa5d", + "weight": 3279 + }, + { + "txid": "9dc0a0edbe1fd434c6f6884c13e0961fc9e2ccb139fd87d9394ae043c5dcb88c", + "weight": 561 + }, + { + "txid": "86f9a4ccdca93f03c2c9dad6cfb504585b08b67ac1a826dfaa4d1e8daa7517c0", + "weight": 561 + }, + { + "txid": "736ba3b5a377fbeb15f185c3ea34fce236097ebd15aec9fe65a756962697b1cd", + "weight": 813 + }, + { + "txid": "2135d051130b0a2e26ede68dc204c36e7e244279e57eba595b29706f066e2b66", + "weight": 562 + }, + { + "txid": "814c962ddbb02e2d97d551b1a12c7822f24d009da9b802f4f72bf9afb05b4582", + "weight": 566 + }, + { + "txid": "de1ea13af91fc4cf57b068e706f206b109c7dbfd5c099387d0d70df4b3cb6692", + "weight": 561 + }, + { + "txid": "d91ea2c160e23d04414e3b571c8097f8fff66a312741f8e9e5ab289e6d00f91b", + "weight": 565 + }, + { + "txid": "31171449983e1ba654089bfcde8600e96caaf01a17f520d0e7b94795f2cb6f86", + "weight": 565 + }, + { + "txid": "526087ec690331bc65cb9fd12bb409de37fe4acc03c5d2abd45a46047d0106ac", + "weight": 565 + }, + { + "txid": "01f9626a8d41298dbfd4df47e31d386357d551721ec4e5d2e0c5fee9d9c16bc7", + "weight": 565 + }, + { + "txid": "310baf01277cf635ba1cb81eb7af5f9b545adb43c4c688feff86cb8022e18beb", + "weight": 565 + }, + { + "txid": "5e3f0ad1a548d01f20953902cff1ed0fda869055da93b781cfa3fe939c87e410", + "weight": 1303 + }, + { + "txid": "02de6f22c0d0c13153d3defb250b085f65951623c734276d01bbc00273e6c813", + "weight": 561 + }, + { + "txid": "8d2b753be8018c5232f806251d62a00ae1643edc65442c78c2dab87e424369ee", + "weight": 832 + }, + { + "txid": "251e6a25eefb85f9f094f796a9676751e61aebf6b43c443488f97f6daab077ff", + "weight": 832 + }, + { + "txid": "73085fe928fae02ac011f15723cd0ef5167e70f15c54def5015d47c736777f3f", + "weight": 561 + }, + { + "txid": "d1ac5c9393d0b96b59e10f00d776649ebde75477b77d68d21ee71d05b83ca1b7", + "weight": 561 + }, + { + "txid": "8ceb053700e9da00dc47985330d5d2734603fd719a3b0d565296a8a73964b3da", + "weight": 5548 + }, + { + "txid": "8620c798f90e20d8db2771cb8c758cc66e7974f86bd584336a6b712cec73d974", + "weight": 1349 + }, + { + "txid": "0c5c7187e492501a6e63bb5946bc164c5f6f53b52f99a15293bae51aa64b9b23", + "weight": 569 + }, + { + "txid": "f6d9b5b98ff70831ca3385a85cad5815d5aed9a9b93229513fa67054085123ef", + "weight": 669 + }, + { + "txid": "0f4c94b8a2b84ec09e691dbea7d241cdfda2489cf2c6e4a7614eef59407e76d1", + "weight": 561 + }, + { + "txid": "1a3f655317a3ef4434c91b74758c20f9687ed12fa3c2885f50578da4ba5f9bd4", + "weight": 764 + }, + { + "txid": "4eea7d7f73720fed1fec766ba49233cbeb864294d9769be8b7dec81d8ba4e337", + "weight": 583 + }, + { + "txid": "6c363dbd16690fd2b5676655c229b5b362f2bb3a9cfc0d250b1b267b10214835", + "weight": 706 + }, + { + "txid": "749e825c5e320bf9e9ba85451b2c0c5e7f867dfd386666ba64a478d422b49f21", + "weight": 825 + }, + { + "txid": "26e849d147291f0e6b66dfc9138ef11628e17b8a80ca7c0f1934bad4f2bcdb5a", + "weight": 1032 + }, + { + "txid": "1d216d01c9051e29b2095e60a5361e10e9376576a8a423d3e392fb1badcfba10", + "weight": 437 + }, + { + "txid": "7d9d6ff954953cecbdc69dad4bbee9775a7315c68f0b76b0398cfeaadd3da66f", + "weight": 437 + }, + { + "txid": "2cc4e918f4ee652f5ea22aeae34faf79584503a4d6152ea7088ce24f13cf20fe", + "weight": 437 + }, + { + "txid": "0cd5501c5efb8cc00415f1e734fa89bcfb85a5db6ddcb946da279c7e26d55934", + "weight": 561 + }, + { + "txid": "03909f3132736b3b4def39aef223adbe36da539f5cbd1e4f8cc1ea827790a778", + "weight": 561 + }, + { + "txid": "634b0884abdeace92409719ef7a4efb67f0af04e80090688c41d17deaf0af58c", + "weight": 561 + }, + { + "txid": "aacb88ede6873af8f36b31fd9699e4c9b99d27fc801fed693e7a851537cbf1d0", + "weight": 561 + }, + { + "txid": "59bbee8a1df3add4e0501ca1fdb59d5761855a2662dc66f3e33335b7d65b4e5a", + "weight": 441 + }, + { + "txid": "d20d89cbc44dd4f8f85144b768d4abd1b1363c7ad35efaee1da77dde4a2c8f5a", + "weight": 565 + }, + { + "txid": "c3ea54edad24df67db3cfd117794d7ed74f08875c9e6acb4fb9c74f93a700766", + "weight": 565 + }, + { + "txid": "4a157a2991a8ec478148312cd3c66be5d785390527c7c2fea28cd3d51bde4d6b", + "weight": 565 + }, + { + "txid": "a62745e3799b318c4aa5f494fd4e06fe4fea29f4dc9120119c1f501368502582", + "weight": 565 + }, + { + "txid": "7fd5134e66d741e879ba5d813fac64b4f44c902c14d5aa51615871c3f3fdb8a6", + "weight": 565 + }, + { + "txid": "18b7b838262bdfd4b9304870a10d1f28d3e53fa9a76c0211554092cfef6cc7b7", + "weight": 485 + }, + { + "txid": "83d276f2ec9313b2f949236ca2e80e5dacb21902925766887a9446d8dd1809db", + "weight": 609 + }, + { + "txid": "5d2c01daef06b9238bdd2996c1e22c5b0f869558919f5aca341611775d7786d8", + "weight": 610 + }, + { + "txid": "000907b63b59fb3b581be96993f4e05f5cd5bfc4ef23a504c44a6153a89e07c5", + "weight": 573 + }, + { + "txid": "978fb7e1aa69c7e2750ef7771ebc8f7061cbd09a8b326dcce2c51297c7a35555", + "weight": 1521 + }, + { + "txid": "dde4dab45508e7ec8992783e7dcb5d66a0abb3c7a7ea09bd5e2c291c83b447aa", + "weight": 1792 + }, + { + "txid": "c5d344bd7c5cbe2ec255e353b2c88d1a4dfc8aa43f3fc6d3c60660b4e31b2060", + "weight": 2876 + }, + { + "txid": "bbc565bac017467ec6d1d554caa92bc8268a40de9e6d664847d3daceea51732d", + "weight": 1250 + }, + { + "txid": "54fe5850174827c5354fa670cabec84646ca805a0109614aef1a2f3d0ae3c9d0", + "weight": 2605 + }, + { + "txid": "f8d87430812e23a2d7fdc5429258688313824dba74752761e93134c62c556176", + "weight": 836 + }, + { + "txid": "94746e2352b125b935f86c355f240f568422d5a7ecc5ef0f880b2d2e01d1b144", + "weight": 721 + }, + { + "txid": "081c7b6ef8c5e62138d0e4d0640fa81bb3420e753f0aab9ac763be111403f429", + "weight": 8028 + }, + { + "txid": "a216c06ade9dad56ee19acb2209b77041c865673fa9e532d77b7a0473ff14df3", + "weight": 1255 + }, + { + "txid": "036637fca0ed297172f42ce8965a1821ba4d8f80d1f3ecd1bb0a5bda021d2827", + "weight": 1383 + }, + { + "txid": "61080f9cc7c2140cc3d7f4656a5255ca1f425a20b2ee22707e6fe59b07f79d84", + "weight": 1395 + }, + { + "txid": "99ce5a1a789bb4a22e93d522ca1e8cd3fa67e0b95e4f709d95ef77d0f6e5c2df", + "weight": 2839 + }, + { + "txid": "fde85b479fc01d76001e27f1662c69e0d22f97dbcf41fd0bdedd01be2407c5ff", + "weight": 3437 + }, + { + "txid": "b6331efac5b8d82837f58b604f761a2e7a5c4b16231b065c01b42d98708cacb8", + "weight": 16268 + }, + { + "txid": "eb79487fa637fc21e4f16f499589aed732256b80b41bcd38f9d42bd99eb6010a", + "weight": 548 + }, + { + "txid": "6e7121ec686c48feab143b667aa75e29dc9e4d8d1f6883819c279e828122bc7d", + "weight": 2586 + }, + { + "txid": "0cdb321cc38a41e5deeb5747d3261a651b4c866482b8c697fc86c63ac2209f10", + "weight": 570 + }, + { + "txid": "398c1f5c4b250ca1429c019d98824790952e49d74507dabe80fbfae204662b13", + "weight": 1162 + }, + { + "txid": "45f5b403f29bdd8c9a72ccdb7d494ab1bb80948053cc709de48c4478709f661a", + "weight": 548 + }, + { + "txid": "df60e8888a24b0f90b8092ce90b01c3ae6c1329d30027135304f3cf9fdf96b25", + "weight": 548 + }, + { + "txid": "b6b4b64a583126dd5504364bb9a82c94cbb287ae2e92644276d2278656152a2f", + "weight": 570 + }, + { + "txid": "1f381b5b6bef099194aacf7725ff44dc54bd1969d7d01bc167413129e8f95d2f", + "weight": 548 + }, + { + "txid": "98cea56c631e1f87ec979eb4014bdfbb358780d73d6b9e088a2671ba53e63632", + "weight": 548 + }, + { + "txid": "1decbec18fb61a7cbaa55790cca53bc290a2365c71b5f2669d21b0ae0e13ee35", + "weight": 570 + }, + { + "txid": "591416d6573deffd4cbaacdebed9e55ad6c563ad37345c5f924908b823791038", + "weight": 548 + }, + { + "txid": "3ee8913a59532d7facfadad89ca1fda152cc4858363a5803be03eca99928733d", + "weight": 548 + }, + { + "txid": "401305e234dd1b336692f18fbe3321a7fa5f0a5f242eb97790e6cc773604463e", + "weight": 565 + }, + { + "txid": "1164cd1d09331adb8566740273a0f409b2837f7a3ca8d3a242e2c1f6e5b21e3f", + "weight": 721 + }, + { + "txid": "6cc705a2da987bc8a9dfa01a70859c75b8f798b7c3d88a6ba561450b7955264b", + "weight": 565 + }, + { + "txid": "20817398c985cf27a5d531a2673e435d86ddfc907d6f7c7cbeee84306e7eb94c", + "weight": 570 + }, + { + "txid": "31ff5d8781bdccb11d9ccf4fae2867846b466c2c32c4574b430eb76ef1b1a74e", + "weight": 561 + }, + { + "txid": "e1a94f0ea00130a647ad5581123b5fb1052c241954b1c6c39efd5e6ee2e64355", + "weight": 548 + }, + { + "txid": "6f3b270e144f45d6e0b5787938b72a17d023633a467790568aa258456578935b", + "weight": 570 + }, + { + "txid": "96204ff29e8afb92af71fd11c70bf5efa0f12a10dd5854cbc2836544e69ccd5f", + "weight": 548 + }, + { + "txid": "7b262fc1dfd84fd6fdb757f883c893de5e4a8fd63823f45f542341c847d01b65", + "weight": 548 + }, + { + "txid": "e852666cb12299212de35a0c5645a3d3b035d162c053fdcf6601367dff8d2666", + "weight": 570 + }, + { + "txid": "d110315835b0974336e7f0d2a79e96a317bdf1b8574898f0bfd9af5e89463a6e", + "weight": 442 + }, + { + "txid": "f73772f04cfc4acd0a06930012183278779f812bbec16dcdf555a8b5bee3e876", + "weight": 548 + }, + { + "txid": "04bed3397b883c4cef0f83d64ae780f5704b0f30baf050bdc415c25d7453a678", + "weight": 548 + }, + { + "txid": "0d0f4ede151a99e6fba4ca99a0a0aa89b7126e96ce500d93945058c5f558af7d", + "weight": 548 + }, + { + "txid": "bcbecae7227224dfb525fb05fd3aabfb38c7980f357d876ee6ae44ed12d2f17d", + "weight": 570 + }, + { + "txid": "5bd96255dd5b7f5d1a5bf28e9e68f473209800c71757b2a3ec3d745fbf96db7e", + "weight": 548 + }, + { + "txid": "ad685e8287793d86452fd66685d3149b6dd8bd7408a3976db64da6a453324a8c", + "weight": 548 + }, + { + "txid": "e8f7eb2d77cf01170c50f6b135d30b48245062bdc2d84c9f18ecf0b98a872b8f", + "weight": 548 + }, + { + "txid": "e12912ed4b8bbb69583b1fa87df862440e7e2b9ac39c2b137a5f8d25b2953994", + "weight": 548 + }, + { + "txid": "8952e3d80d3dd239b80773d08c4f61f51d706abca2199028f9f46bbdcf5a4c95", + "weight": 570 + }, + { + "txid": "070d06d528547d70d8185ce2fe33c9773e746bc9211e9d41660f4653412c8d9a", + "weight": 548 + }, + { + "txid": "e11fac2b04e0617a9ae25d39ded7dde5af76f4c264e6f2140e01dd7d6d8679ab", + "weight": 548 + }, + { + "txid": "0fc83e2ea223f96040da50bb296ca0bb7043189d661453c4803ad772605eeeab", + "weight": 570 + }, + { + "txid": "8b683d3a5fff739190b2cd06f6bab6928559b89dd1b4406e87470f011661eaac", + "weight": 570 + }, + { + "txid": "809b79268e7e7a820031a64709e79107cd38a70b11f9da9aa4b7ea1d8fd96dad", + "weight": 548 + }, + { + "txid": "1b48b2c1592d3d7f81691f967d7e447134750024ff145d8e44e1a705926165b3", + "weight": 548 + }, + { + "txid": "fc3e3af67e6bab8032895a2d59b12bca264f45e59503e1319520cb71bb8faab3", + "weight": 646 + }, + { + "txid": "856e978203ca52a626b7b00dbbc3128a30104767e24216876d70daef4d9a63b5", + "weight": 548 + }, + { + "txid": "505582998e07edea1052e9b739772c28d73c1ce3dfa4084f0b73342889c441bd", + "weight": 522 + }, + { + "txid": "6eab19d1944d4c6ff2ada1519b2dc0e342872436286c0f82e93c637ecd7527d0", + "weight": 522 + }, + { + "txid": "e09954f3eb3463e0509b7f7f9b78750220a993b29aec0065c8b41992bd35b9d2", + "weight": 570 + }, + { + "txid": "e5ed3ab5db1354abe7b85bbcdbc1b04b16f11cf7ce3158571ed1a5f71d8075d9", + "weight": 522 + }, + { + "txid": "738b4d4aed7b6867522327d858ddcbaf1b74a1533a50c1b7498841563cc22fe1", + "weight": 548 + }, + { + "txid": "4b8cb740bd448cb29df582c635599b13ec14cda8f48e1b1a62930b050c297de1", + "weight": 548 + }, + { + "txid": "f4b281c0b547c992323aef037dc7d70d2f77df602a704c26ed2831f99d57d0e1", + "weight": 548 + }, + { + "txid": "a4d8530789efb8bd391615192eb409da93639344cf27712f3daea135b7bd8ef3", + "weight": 705 + }, + { + "txid": "8816e6ea65d35be43659a9f482a30a20a4f43096c6967bcbfb3083fbc8acaabd", + "weight": 438 + }, + { + "txid": "5d58dff0295875fd25b3513593cf381a43280f5ca1ff0ba2268aab10254803b6", + "weight": 562 + }, + { + "txid": "dad98a335ec42e78fcec9a33d2a320b91bc17adece3a9d33f6656c80224b2fd6", + "weight": 1201 + }, + { + "txid": "89f7c346981be4b1433863885b797a9825e7e134e9ebeac5008fb5a2672e77e1", + "weight": 437 + }, + { + "txid": "e115433342c6b232616eb1f8ffd29c1a26989c8a1c605c1e5518ee06c06a6d4f", + "weight": 710 + }, + { + "txid": "49e00187c33fdd54f824ad617c9130c68da1fb626eaac9eb03fbbcb579d8b485", + "weight": 662 + }, + { + "txid": "cd20d1aace5242b669ed7af8dc6ce52b1eca83c4ca4f0a62dd51458f2bf5c0d9", + "weight": 687 + }, + { + "txid": "03d132751f94a3ecec8b12176482acb4d6e02867f02b2e0a3c610101e6415726", + "weight": 1072 + }, + { + "txid": "65a6fd00bccabf5aaee94de747a98a4e445d6f380c6b23668c1de5759586d1fd", + "weight": 437 + }, + { + "txid": "a830dad94ff278fa67dd4404485b09e9256b72463fc7fec56e40f68b94f4d0f6", + "weight": 2298 + }, + { + "txid": "4b12e756b7a937ad0ece7f3c1fc84287f1637a070489dd1b5237daa1f289b37f", + "weight": 832 + }, + { + "txid": "b56e4607c55fa7ac8c58cdce4e998fc771d9f11b816522802583d352da444793", + "weight": 1809 + }, + { + "txid": "014cf0330d8b36bbc398db3a639f3d500fba94768dcec974bc6dfecbfb3279cb", + "weight": 788 + }, + { + "txid": "64331b05c252c8dc125318c9a9cda9e3a17e182b7f34199fdce247b5944415ad", + "weight": 1377 + }, + { + "txid": "c3fbcbe63596f003eaf0ceb2b8e02c7bb81e9b61646a91379217ea6054d40ae5", + "weight": 1995 + }, + { + "txid": "bf8ea042e91e668eb225dbc7e551549e1581449fbc226f4a279df6296247e441", + "weight": 1995 + }, + { + "txid": "9b68404cbfcd753e66e04f6bcea89a6bd730eaff8d7a1ff7c3d1b0374f3dbe10", + "weight": 1995 + }, + { + "txid": "4b8cbc1cc674c46d65fe5d5dff38d0302013f10a22809e72274fc9b76e8a5458", + "weight": 760 + }, + { + "txid": "d2059a1ffb494a098463d9b4be8bb23f050305ad79b8ea06e1c22973ca49799d", + "weight": 826 + }, + { + "txid": "b08c86cca7fcba9b6ccbb5c6f437912cb6ae29c61f984d8238c7083eb5c17722", + "weight": 688 + }, + { + "txid": "f97019ba42a15b8839d4ccdf174148ae261dcba920fdb264841d3ac25ca10478", + "weight": 687 + }, + { + "txid": "3e07e65ed762bb29b92e1c551c3f0bfb591aec59b977b01afe8f673aac84c6fb", + "weight": 687 + }, + { + "txid": "f71b3a69798e3c68e47edec23b86e85c026c24b377b2029b512290c6e5d6a3d0", + "weight": 1274 + }, + { + "txid": "01b5e3bd28397465e1cfc3a98d70908451c20ba33f7675bdf6ba76d51ff1ee44", + "weight": 574 + }, + { + "txid": "1d7a1c6028297d31d1e06630faf9d452e67d41ea83ba6f2b5e614217fe5e20b4", + "weight": 2064 + }, + { + "txid": "f73510aad1e88680cffb8358ec046fb37d06ba7a5a834b19b2a4ea1c4f122cb5", + "weight": 2652 + }, + { + "txid": "864f11c01e36e7ee747e38304e1e3984e338d5ecfabf23023d85cd44961a8c61", + "weight": 3104 + }, + { + "txid": "e2d81b07f3e55b3143f109c8a3502c0db03bdcda00b2f91d379321432c278cc0", + "weight": 16266 + }, + { + "txid": "66ff17d690347742f0a452242980dc3af94c346e513abd06e12ca4ac36f5581f", + "weight": 714 + }, + { + "txid": "bd079d29315cbd890ee221fd0511d40b6fa11e84f62a960a5eddc301d7c81a05", + "weight": 3700 + }, + { + "txid": "c9befa48d8e2193617f1c50175ab629772008625fe7ad349f7bf20f3fe0aaaa0", + "weight": 609 + }, + { + "txid": "94506ec1fc85f020555d5394dd9d8108d0a56a02e4ee08623dc9332e616606fd", + "weight": 4292 + }, + { + "txid": "695a08bf533d5b2c4f38e89ee94c997ad30c557cfe061482891c4e58d5bd93b3", + "weight": 3704 + }, + { + "txid": "6b633348ea897097e82a8e7ac5819350daffa58596d38ea02f040228761f33cc", + "weight": 3704 + }, + { + "txid": "076c9833ac503b1d3cb07202156bbd8935382458eb0c95130940aa2ed9d2692c", + "weight": 657 + }, + { + "txid": "3b9e26d4733269a60a6785f1a858c0e9e97c1e9b1c867b47a23623acb2aaec52", + "weight": 706 + }, + { + "txid": "99875b0570bfe80d7eef35d8fe6a42a832ebe6b953ca1d322aa58444be8361aa", + "weight": 4296 + }, + { + "txid": "1c8614fd377942a2ef10a0fa2a51c571ac4ad7cef05bdf69f9f7187562f44c93", + "weight": 4300 + }, + { + "txid": "2de86a1fb0b07f0e1b164d7257ddc77bec7f3c68563fcd35397ce21918a2a74b", + "weight": 900 + }, + { + "txid": "c5d368f33adafea14ac401da80ec4ff2ab9a9816e8ba8abb46a12f3fe7382130", + "weight": 3712 + }, + { + "txid": "cb36e1d4c3b6335366d1f8a160979844f6e35e87d95a6a7a4236470d3a9d5531", + "weight": 1018 + }, + { + "txid": "c8d4f82a275427ca97655c77049da9a34e87adc25846a2c21e7500ca93a6ed84", + "weight": 2536 + }, + { + "txid": "d8a3d3bde469724f057a62157c2acb4fcf4744c7494cbc9d73dfdc7b55f53095", + "weight": 2224 + }, + { + "txid": "856fd65a42ca577e009806dd4080781c2be5e9945b74de41ea4113a0acd6d538", + "weight": 552 + }, + { + "txid": "0cd89d2659d2d6ca842b4000900c59a08d0d4b2f89fe1aefea604736e7c40941", + "weight": 552 + }, + { + "txid": "3d22e18e6966f0b3790845a68e675309f07902ff869758c74353c142464e9441", + "weight": 552 + }, + { + "txid": "485576e067cf4c734b5dc3ec08ef7b169da13459e8b7ebf958b1b6822138a285", + "weight": 552 + }, + { + "txid": "a0002c20f1b4dc8df05cfdcf89bda23f9bbff6d44dd86adb34f3e502b6d590aa", + "weight": 552 + }, + { + "txid": "24b88df061be7d1f9d9b86048b112cf1901290f3435fd42d5efd8fef888690e4", + "weight": 552 + }, + { + "txid": "0de6a295a1062f0ed7b3168e36763c12724307452d36faad373ddb11cddaeee4", + "weight": 552 + }, + { + "txid": "91deea6285cb6b5614d4ab6a146dae89892c4876d3d40e3b6b1151759eb949ea", + "weight": 552 + }, + { + "txid": "15c7c16f1ef11a5bc8fd3fd21b4e9dceee4314fc639218bb4d1746d50abc65f5", + "weight": 552 + }, + { + "txid": "f47db26258cd7ccfa5344c788200db264ade28e2b8f027087d326ce43c412e9e", + "weight": 561 + }, + { + "txid": "27aa493ace3139e206f91f18cf1dee38c867d72ec2219779192f83cf7a325fd0", + "weight": 1466 + }, + { + "txid": "eb74b113c91ee036607d7023035be6e480ea6f9eb700059255c8771ddc35100e", + "weight": 1016 + }, + { + "txid": "334aeaf2a3bcfad0d4cb8bdeb39c2005604fed6152d8e49b6b93ccd4d3301ee3", + "weight": 653 + }, + { + "txid": "3dfa02748a709e0ea4163a9edc5a3a50dc06cf56636944504b9162e522c0a555", + "weight": 657 + }, + { + "txid": "dc78ea0f453bbc30c502f4fe8fd14c031987d5de4586580c620390b1c8231c2b", + "weight": 26091 + }, + { + "txid": "890025de81e0fcdffa6382164e8bcbf16b5b53f1b9360bae91de639b4c53f41c", + "weight": 437 + }, + { + "txid": "3761b1f62d28aea02c6fe9884bbdc9199f5d551fba9e340dba22e8f8affbade1", + "weight": 1488 + }, + { + "txid": "37fd1509cabffbc5cdff4c04bbae3c7847d006693885d5a478d7cdd1e958d125", + "weight": 892 + }, + { + "txid": "f78007424dd75baf611d7afba5bd15ec4413dd57c3eb9b206310ffb1e73a6f18", + "weight": 834 + }, + { + "txid": "81d33aa4a0347b8e3462d2f5594d9e6f9da73a04e28ee5e406584e362e614f23", + "weight": 574 + }, + { + "txid": "a4b3620c6faa90a22719849160f13ec54930bd0182134ca82264348bade2512c", + "weight": 565 + }, + { + "txid": "49f0061cb116a42515063c197a25a117c86f6f8613b9986e2f01bd035a1a7029", + "weight": 1162 + }, + { + "txid": "e91215885277973c9ca07b3973198e243e66ad33c000808cf77e02fd732f5f08", + "weight": 522 + }, + { + "txid": "dc9fb65a5a24a5e70b1bb82d9ab884ef56699abb3d467707c2c6111347d5da08", + "weight": 565 + }, + { + "txid": "42c66faedd4c2e60f2c5c120ca348f66c45d8bc6f5c30ba200d0c2bab681a34b", + "weight": 928 + }, + { + "txid": "cc5e3f383c2822ac5f1bd755e5753e90c6b2c4dc05a0da5b58df8fa7602a9a54", + "weight": 561 + }, + { + "txid": "4f66d02254195f20011b68671d311b011a198df091d8031d162a65c2f813dc59", + "weight": 522 + }, + { + "txid": "309d3ac06b555208b9ecb6e1cb4fd54f923fee72d67b204ba1bc6bb7dd6c88bc", + "weight": 616 + }, + { + "txid": "9c0088d2d98e83db2d4d7f0b0fcc5f0b1a8d7d3a608ea7c2520a09c6fdbbc45b", + "weight": 606 + }, + { + "txid": "0a4803e3d1d2081c8783df169d2e27a7b1a75c6d246422647be1b533dab3c4eb", + "weight": 788 + }, + { + "txid": "431e8883dfcb5ca7f87d66b2f4ba2848b619c0dccb2248687250060902417b63", + "weight": 1995 + }, + { + "txid": "0701ba8dbfaea542c9272185b71e2db4de517e41f6ae63b1b5ce10e689afe17b", + "weight": 561 + }, + { + "txid": "79ad87a779adf8ab5bec543e284783f80642032b3101d681ec42698fd48fec8a", + "weight": 561 + }, + { + "txid": "f362475c168d319c91e7325bb2cb1b88a1c3266a19cba0b453900bdf29da1295", + "weight": 561 + }, + { + "txid": "c4fb3a765ec15d408378d9dbaa808206eaed97e0b534ab6ee2d92cce583510b8", + "weight": 522 + }, + { + "txid": "2e4e8753660b4e99c6995ddaee1ae4159998f9f71935e36cbcbf13395b16798d", + "weight": 33471 + }, + { + "txid": "6f2bb26a4ebb0c3a912d7533cd37672df0d8b6ddb02aa7efaa444a290a1a613c", + "weight": 437 + }, + { + "txid": "25e4818059acd4b2e502fbae2de0754b38f986d1cb244809da596b5bafaf44a6", + "weight": 1421 + }, + { + "txid": "23ab96bdec579be9ed6588f3710d5b69c7df8d723facbe0d191f45f225a2fc0c", + "weight": 892 + }, + { + "txid": "f003e7b792574f218476db5a7ce672abd2b1de67bc5ae96204d06caf43c1b95a", + "weight": 666 + }, + { + "txid": "8555e3284a46cc5e691ac66cef8071138f6d8b8c6a5f8a79bf1b2fcf077ce405", + "weight": 662 + }, + { + "txid": "5bbe0ed54d74c760ddf18b771f406af7971310475e472c70d5b6f196c737446e", + "weight": 561 + }, + { + "txid": "91b1c1f33dfb54a730d4cbb768044006aed6fa96b26f88f039d31736df1e0af7", + "weight": 530 + }, + { + "txid": "7b9cfe60f5bd97f77a351a78697dbe538f8138d7b0bd58c8187eefae25106e92", + "weight": 981 + }, + { + "txid": "187a40e60b835ad9c67d0f48726f4ea3426a8ddedf497f76f3c016a04699079b", + "weight": 437 + }, + { + "txid": "fece33ba798f6a559cbd4a1d20f5bff8f08d818e8f9ca729f68857c090cbb88f", + "weight": 450 + }, + { + "txid": "cc372df07be4ea68033f67c427d2c41dab8cbe3fe2888916fa344f25b1203165", + "weight": 674 + }, + { + "txid": "02751cf5bbc6982969c814d1579b32e889f452a337c155fbda05fb913debc87d", + "weight": 5917 + }, + { + "txid": "1832e347a54f36da3e78e4f17763ce9be5e352d268675d114d5185f3f11ead3b", + "weight": 2082 + }, + { + "txid": "3d15905fd5c4fcd766a87e7d42b353a0b753f485129126b032174a5269dd8dd6", + "weight": 832 + }, + { + "txid": "a2b005cbbe153fd21517727c923319612d99a64f0ee02961dfa5c6da77ca1ae7", + "weight": 1899 + }, + { + "txid": "213fd267c985296019bcccaf8be48d17e01686c4a342d0b06a911d5b2cb16825", + "weight": 1900 + }, + { + "txid": "64ae82d2681a92383bd02b8d97123ea21234b767101ce25d3d71b3680099b238", + "weight": 1901 + }, + { + "txid": "0d59c503f9ef466d6167abed25e6578c084770a5cc5aba593825d86efe6c7dec", + "weight": 1900 + }, + { + "txid": "3dc6b6c3c8520074f70e05f35d8491b4236381f24d8a23d82dac00e0e49c085c", + "weight": 585 + }, + { + "txid": "8a4029f57bc5286fdf41850236b36fd6bcbacf6f49bdf2cb42d6b65f50479987", + "weight": 888 + }, + { + "txid": "7d54882760fb3347305b0e6ac478bb79de6590e577c107e106b891a65e0c4c77", + "weight": 756 + }, + { + "txid": "97cb31ea818ecd09ba09b8541a3e3f09e84e0e920492da63294969d3aa599c72", + "weight": 3018 + }, + { + "txid": "795f3f943ede06823166cdea073e6812f8711b65589a8dc37a112fc2581721ac", + "weight": 34240 + }, + { + "txid": "d54ef609bf2558bc8152c8591cc391825ec0686cdabc9e7c30e5c1d9167b37b1", + "weight": 486 + }, + { + "txid": "54707c8b507af1100ad4265b71af2d30229aebbe4ee7a82e804ee096db41c63c", + "weight": 437 + }, + { + "txid": "8fcb87233243fb85713528307f93788bba0264f5936c61fb4928bd9642acba65", + "weight": 616 + }, + { + "txid": "1d9fb6df11ea353193fadfd7483ed54293c70f231be4e1cd320d43cec3df281f", + "weight": 616 + }, + { + "txid": "63230d8d49948a39a0c96b0292f083461312088f88ed64fc31429bcfdadad193", + "weight": 616 + }, + { + "txid": "47ce4d0527345cc5bdf8c3864c18acdc6a57a3fb111d7221375eaf27f7fea5d6", + "weight": 524 + }, + { + "txid": "508ae1640f1b7144ad189c9c781c4f5237ae6741191452576a31df1f307eca83", + "weight": 609 + }, + { + "txid": "ea971d302d76e6b9f8ae3cd5845f90a98c14c1e24f6c097c37c46b0ee0633ad4", + "weight": 610 + }, + { + "txid": "fee8034c04e1e1d557296de7f168150b8c568f608de330a8dcbba4d61bb3cc9f", + "weight": 880 + }, + { + "txid": "00d32fe21ecd8f71bf84fa90174ae53ee8c057a43aecea0a4aae8694c29256cd", + "weight": 7654 + }, + { + "txid": "058bc6cc5f81ce2fcd25b7f47e17e09a042a499542c05967acd992126b04fa36", + "weight": 1928 + }, + { + "txid": "e9cae5d4e0746e06684404666806195639b9e7347ee75819e092bb50f5969223", + "weight": 36580 + }, + { + "txid": "ef450ebc3b1b04415a7caed65873cef46273035659c3bc1591996bbf5f9b7976", + "weight": 36806 + }, + { + "txid": "4bc920a5bafc42d2a2aed1e5252c07ef85477ec8d1bb098e39774d1a21803433", + "weight": 437 + }, + { + "txid": "fbd24ba6a238828c9d4cd292fbcd3379fa7a98306ccc2910fbdb1068cac6966d", + "weight": 529 + }, + { + "txid": "c5fe5723967d3a30411ae7a8491d553d25d54603a98eb28887e4ea170b534234", + "weight": 36933 + }, + { + "txid": "5fb4b9c8c334cf6fa8bd1f088d40a5fb2b85a0543f7cace4bb035fc9fa7d4537", + "weight": 437 + }, + { + "txid": "50d1ffec8481a95bf34feb5150791a844429a83e69a947a159708e823da247c5", + "weight": 441 + }, + { + "txid": "2d8160b7e83ce3d8e1451a4f5b1ab35a8c0bc3fe4c564145062c6a9da083247b", + "weight": 561 + }, + { + "txid": "041fa97fbfe4fa3377acc2b6c3e2cd9bd188171cdcd10dc73bb4c6bcd35dff78", + "weight": 1103 + }, + { + "txid": "496b188b946a6406564a73c07abbafb16a2cb5d2fe7ac3faa73fd4db9d6de60d", + "weight": 449 + }, + { + "txid": "472ed68af50bf1927d536d96533fb033bdf99e6716d5b3ab7705eeafbf5d8143", + "weight": 687 + }, + { + "txid": "84cb43dcb60ccaa426ed028165cd455f08bc418e2e2e5dc974d2d148f657f758", + "weight": 565 + }, + { + "txid": "b76f880390efc8d2d0c43ff6851cbbe8907fae584c8a5d7fb24f319c053db095", + "weight": 1104 + }, + { + "txid": "708748c111b40daba63a8533575d2a9b9ab4d4377c85141e8635cf7b5ccc8eab", + "weight": 566 + }, + { + "txid": "0d5b8efaf5adb33944ffbee1d92070048f2df5d715dfc5cd3e8835ef886c5d08", + "weight": 562 + }, + { + "txid": "6b3337710a9ba2b2fa1f85b882abb0857f0ae88cb5d483b331d77f10746c6716", + "weight": 566 + }, + { + "txid": "aa086d4dbca77ca6d3f3c6fd9cf0bd5ebfc9af77aa99c9a3aed61484a8f15e10", + "weight": 561 + }, + { + "txid": "e1f8d495f5431a10f549937289e032b3b44c69a7df5201ecfcf7c25d8a4c8b49", + "weight": 561 + }, + { + "txid": "a2a0efe8555bfcc3d77a7fdc7917e3c300a0c60edb5c9b9d18f0bedc2d7d5d8b", + "weight": 566 + }, + { + "txid": "a88ecfcabe797f14063238cf0d2df86aa71573f4aa181a4d6b184b830933e8cc", + "weight": 566 + }, + { + "txid": "22d1ecbd46a0dd00f792f55277e890784f569680a7c8856e038f764e72642a07", + "weight": 698 + }, + { + "txid": "7995534d0c07840f87a6704c4ec632b6421020fe4a09705d3f1ca4424fb9e10a", + "weight": 561 + }, + { + "txid": "84fa738a6e8bfe1e390967f5639340cc7435dbfac1b2fcbd2c02ad02a081617c", + "weight": 1255 + }, + { + "txid": "416ba2b4a961829f2fac92eb21384826141c4696820a8519dee1e431f60e8913", + "weight": 615 + }, + { + "txid": "67ffcec8943baee3cda05e33cb270de2092b402fbfb10930a4ae845360bb6082", + "weight": 561 + }, + { + "txid": "f721981260d5a08db71fc78b69170ee6ebad5ca0b196b8ddb50595f9f4125317", + "weight": 561 + }, + { + "txid": "e3081866e233e212495f004cd85cf46fa7a643d0633eb8f5f3de360ec1259125", + "weight": 615 + }, + { + "txid": "62853d2494daf1543152ef0beba80330fb91ff9dd0e67504009ad75128619144", + "weight": 616 + }, + { + "txid": "762f1af32a28b353eb1ed7da9ef69c01369fb1497d0f6f649ea2f44c5d8a3248", + "weight": 693 + }, + { + "txid": "da5198b6ea868cc895cf2babfde331a09cae7d7ac44df43a82abb1b0946154fb", + "weight": 616 + }, + { + "txid": "41ab1d55ca86eaba058c896d952bbddc62aae5611bb7132ef0a3884887063955", + "weight": 606 + }, + { + "txid": "fbed2c18ae5a832d93c09608afd30309ef137061da5460208d5e59bb41aaf157", + "weight": 561 + }, + { + "txid": "2cd7eaabfbcaec9f5fd348ed97a56ea41c7d3bf8ba8622305b41cbaed6ae5d5c", + "weight": 613 + }, + { + "txid": "ee0f7e7060ab4fa009f78140d63016e5f836395b1b7fa1db51ad177d7f1e7165", + "weight": 616 + }, + { + "txid": "429a36f321c4ac12f0afdf948cd26f07fefba966b011500ce294310aee11056a", + "weight": 615 + }, + { + "txid": "cdff49b8bd21182e3b8d134600a3de19a9f6907f123ca1bffc8e6e7b007b8d73", + "weight": 573 + }, + { + "txid": "bcf79c553ff1770a3c6dd31b3628ca993b028cba5a4e60e7b1acc09c68da347b", + "weight": 606 + }, + { + "txid": "2bae66e6076190f622bd670a5c5fdef873d9c2b2215563ab09f1f144127874c7", + "weight": 573 + }, + { + "txid": "04af9962bc19247382f6ea82ee1f58517b045858627be818f8ce423fc9496be9", + "weight": 561 + }, + { + "txid": "a94be5e06ca36a59b0586ca5b60e4c1493ec9cb0787a04f3e35cb5a8575757eb", + "weight": 613 + }, + { + "txid": "2801e8df6a1f027e14fcc9edb2dff5570b8b50b70a2de5cd924faec49a30d421", + "weight": 673 + }, + { + "txid": "b03857979fe2df53f6cacbb1d3723f87a68b89e2480b405525253ed4432ad722", + "weight": 1299 + }, + { + "txid": "f3caf7673221adaf4033f93b84f7e9116fce8742e69fdb6cf92d878f5ac41621", + "weight": 658 + }, + { + "txid": "7f7c12719146e4ccbe36a8e276852579765f1e7fbb92f67b95b14580e0d0183d", + "weight": 1102 + }, + { + "txid": "e9267d362df835fc04d6d4892c55a79335e6d93cb0312926045b744230a05054", + "weight": 561 + }, + { + "txid": "f071b66f9190704f338fab565bc96f30dce61230cdd2556aa46c91875731dc95", + "weight": 562 + }, + { + "txid": "4fd29322f139b19f811445cbee63bc0fd2481690682a9cb3d785eaa00dd5df92", + "weight": 534 + }, + { + "txid": "7c74d24a92f6405803eb29856be8ecd1014e5bdc1ca9695944e7076121ab891d", + "weight": 442 + }, + { + "txid": "afe749943915ceda3355379cfcd89b59b95e846be6dfb9965baffd867f5d8023", + "weight": 1356 + }, + { + "txid": "a23aae226b81b167c08a483c49c8610fecc2ff7984e9aeaa3f91aa3309226bd9", + "weight": 561 + }, + { + "txid": "6962bd60905c84cb62305b82856b85fdfd70b7f8f770114e5a7bc59087c4d2b7", + "weight": 565 + }, + { + "txid": "d32445a7c92202902f5ae5c99bd83e53b207f9a9483c043c140863f5e0d86472", + "weight": 581 + }, + { + "txid": "3cefe9adc8a50ba9bf69183ec4ba9c05a3989809b69ede46dcbac65c9c5eaa02", + "weight": 437 + }, + { + "txid": "b9935385c4359dc2883d5b5846eaaa2a725949819614ec0101a09a8fc1e46f8d", + "weight": 449 + }, + { + "txid": "7059a5a3c27b8e4427f530e2eb854fb40d7f13e19116e92fa8c4927d919d5c47", + "weight": 437 + }, + { + "txid": "a393544818185b21a68e381fdf7cdd155d3dc87e092447ab70d29eb20e7bb56f", + "weight": 1110 + }, + { + "txid": "ae4bb428e7f268cb4876b1429cea26ac654af5478cbce501bb6f6a750d0e1301", + "weight": 892 + }, + { + "txid": "bb81aae72d0854332d4d27a163750947124d1cb9316e5f5370071ec320c8e3fc", + "weight": 896 + }, + { + "txid": "67c032054eed2091d2190b8858fb953f930513fa2dd4ad018707a225b9d3353e", + "weight": 892 + }, + { + "txid": "a25c63afc58b9789c7fc41efe3fdb3b36dcf7873acbfcb5aaef13c63d478aba9", + "weight": 1794 + }, + { + "txid": "5060bfb2393e9835a25d2bfb3a6ebbc192bb79041c3fa17eea00720864a79612", + "weight": 768 + }, + { + "txid": "619be8fc800f0896b7a25e36c68d5ca78b1215e49e3b53c0e56b2790b2596ebd", + "weight": 616 + }, + { + "txid": "18ce969251ad4b59d0fed12fc9c195c2d35173cfdeb8faf8a6e847d769345dbd", + "weight": 896 + }, + { + "txid": "aa1a4386999e5a17fc03015750b4c24cf0aa49aee4147a8f5f85f730a1c85329", + "weight": 561 + }, + { + "txid": "cda859c835dcbb47a065fd61b707d101b9f7fcff3d85513af8613677b5788cf4", + "weight": 562 + }, + { + "txid": "b2f045da699900482141f06b12f19d4359764ec9473b23ccc0a10d948ea99224", + "weight": 566 + }, + { + "txid": "87f523e417bad6d151a962a70291311fb6d742c42d19daf98f7a357baaa32be8", + "weight": 565 + }, + { + "txid": "092bdbdcd2af6c80d983565a09f0e5c584ddcac95644f6840cd678ca4c7b8b40", + "weight": 900 + }, + { + "txid": "692c1daa0749b1b72b59424bde4ee1224486e241996e19103c28fbb81ff7cc89", + "weight": 896 + }, + { + "txid": "3b4bf7472abbf74666ddac151872325c7f7bc4c4254c5116ab1d1881b1ef2448", + "weight": 845 + }, + { + "txid": "3ee75cc642b3384c01f3b5c8ea2954dec066eb0fd167c4d0a2f8663aec37f078", + "weight": 892 + }, + { + "txid": "9d20b9ee92dcda0d6d49c47ee53def83531e6819f98de91b858de66a0f80aebf", + "weight": 900 + }, + { + "txid": "f9f12381fc751a59966c1e590526def4f9b91e4d55ec821daaac7385b4f50b97", + "weight": 1620 + }, + { + "txid": "e53ec6828c4122d9f966d496b75ced906cb9b6b1c2e6af7d949315032058b2fb", + "weight": 1108 + }, + { + "txid": "3e9d295cee6f2c59cae667607bb8efc5ec2a444bdfe62cf53df3e572d8bf922b", + "weight": 1468 + }, + { + "txid": "cb28b2b43889c5a8f467414a5c1b30376135a794d35521bb6c0a0c73721a1a16", + "weight": 573 + }, + { + "txid": "6071071c5f561acf2d72dbdd67ab74315a903add8911a7bb8d5ae04a2f9b359a", + "weight": 2242 + }, + { + "txid": "0239841f96eeabd5d74d4e71023059b26778b2a253ca445c676b85e0ce133a26", + "weight": 570 + }, + { + "txid": "f6eed99f25e4fb1cb649a6c5d763c317f1801287433cf3c3468233ad27c59147", + "weight": 570 + }, + { + "txid": "5ae0ab33b3275624b3ae816787c07ebbc5cca7f3b68d908e6d75949946d24958", + "weight": 570 + }, + { + "txid": "6b2c4f5eea50f6bf1bdf2881080b09b735f9ec168f41dedbd97a928ac39c525a", + "weight": 1155 + }, + { + "txid": "47d58cf9f029372b69f034a0766d51e18703b7b6830054f22d627941d44f2460", + "weight": 570 + }, + { + "txid": "e8bab7d1ae599f66c45b148324d44472f767d9d3b433eab33188667638d4bc6a", + "weight": 570 + }, + { + "txid": "87795305b9573505e9ed5a7eb24d8a8e8dffd9b54df3708b6fa2ad35b3f9096b", + "weight": 884 + }, + { + "txid": "bcfd4004ef9764915c8338c329b97da967169b8dc69bcb8321d16764645f7585", + "weight": 570 + }, + { + "txid": "e849582e4083f706de71fa859d27f918cdaba4fddc4ce67a1ef5a301e56bb987", + "weight": 570 + }, + { + "txid": "b245855c3547cb8aa66297bb1c30124fe63c1116875ffd4de42b4ddd0723e8ab", + "weight": 570 + }, + { + "txid": "50f29cd840a26ca11760ce0ef64054afe064d25580cabf09c172437dbd609ce6", + "weight": 562 + }, + { + "txid": "f16df073dac27a97a71bb7b9f883c522aaf20dfc4b1bd95f23565394a50b3cef", + "weight": 570 + }, + { + "txid": "9d35d5c18ff03c07b090e6804428a4f96cd5ddb905e4a2af407c5ebc75bee7e6", + "weight": 2191 + }, + { + "txid": "6b7a3cb133733babd2c115436967a037a707ac06d7d685b606840c9171a911f6", + "weight": 450 + }, + { + "txid": "6eed15c0403223d740e2196b6bf43e7f7106d44d2218828c479985e1e743cf7e", + "weight": 836 + }, + { + "txid": "a52a52ca9ca69359f56252748a73392b1a647aca4ef996d98040a42a9e66413d", + "weight": 832 + }, + { + "txid": "c4975459e5efaab792a7b04966b5105c9a4f0c9e0c0ec5eaadc5ab2a711def7d", + "weight": 1104 + }, + { + "txid": "bf18b4b067e6787f9e90d33fab012d542f7698d581f1214a0dfb81a058a89889", + "weight": 1388 + }, + { + "txid": "062ff09709a75251354c888f597d60cfeffb7e13b141c4f8df31858708522c47", + "weight": 1660 + }, + { + "txid": "be83a6908138f7aed984d3b1a205a4f115c05ef5e453b618389c8eafa42bce74", + "weight": 709 + }, + { + "txid": "b22fdf4653eee57b0b58d8fd332ba2902bfe103486404f9146948a8c6c3adc8a", + "weight": 709 + }, + { + "txid": "b9a95c6e8c0fb5dc367d44d36fb76f89cfdf0a314b55f9a2ee8cc2e837cdab02", + "weight": 449 + }, + { + "txid": "a374f9a0e8925e91e40b270bbb1ccb3be2cc88d606bb5dc869b5568b970e0181", + "weight": 450 + }, + { + "txid": "020ac9f9b0418937d0942fb8a96411a85b8b2eea9d826c11582e8610e5d274b6", + "weight": 450 + }, + { + "txid": "b1699b44c8eaf7be054b562b34db92e9af5ac2e73e7f4b6ec28ace6dbf9c232c", + "weight": 561 + }, + { + "txid": "9cfefdb628e60daebb8d7787a1afe9888212c26b42355fecc56f95a06138a668", + "weight": 442 + }, + { + "txid": "459593b780dc06ab5d120d0042ce726350cc83aca4a0ef0753572c116742f8f6", + "weight": 441 + }, + { + "txid": "9f28952007de49edd74b98d2148f1f7fee8d9c44c0b5f2c0a6e0fce796e8ca76", + "weight": 437 + }, + { + "txid": "f492c68cef083d4f4bbc90ef5f71f836ab06fbd034dbdfcd13be5228085a179e", + "weight": 438 + }, + { + "txid": "40d4a8e258bc936fae302556f52dc547c40f2e112ed756a09b5bfb466c75f85b", + "weight": 574 + }, + { + "txid": "edd9e65afaeb9db028fc6d01b90a4021c95bb08cf84013916af60b21093a74e9", + "weight": 1104 + }, + { + "txid": "3d095a0d2ba3ab4bbe92ed91357e9e19b97f7e45b2cad79cc2cd42c4a510c7bb", + "weight": 845 + }, + { + "txid": "367e7c91f411979f20a893d3f806096bbeb15740ab96e299544d88c8de3866ee", + "weight": 846 + }, + { + "txid": "105c3c004aaa96d2cd4eb171e313ef3ec441c401832dd8c94aa2602aa8c3d541", + "weight": 562 + }, + { + "txid": "e8e678b6a528169491435f5c1c3bd63d71232cc88ac36ead432e9dd24c95f351", + "weight": 562 + }, + { + "txid": "6f96657e2e9ea3e4087fe67ab0242370e77d783147bcda2caa33d47e61e96269", + "weight": 562 + }, + { + "txid": "a9c9a0131f3486767882329f68646810dde7cda3c5fc12efedbe2b53145d14d9", + "weight": 561 + }, + { + "txid": "53a155c6df51987c1153594f21f9b51741e7aab6e169c99bfb9b774847f21282", + "weight": 838 + }, + { + "txid": "821c92de04e05ecf50ef493de9eae0fad83a4267bcb2c117a02f606335414b0f", + "weight": 833 + }, + { + "txid": "e3b0abe916c2ed086864863a285a195f43547c61e1218bba5b101f67520c53fe", + "weight": 609 + }, + { + "txid": "7d32ef12c6e753fb34f5c25906e0ff80bcdcce5dde9cc3bf5699e1cb60156a41", + "weight": 573 + }, + { + "txid": "bc94290ec2ed444aa17b99dc5d34299d5f34db4179df0c612106240cc30490ea", + "weight": 573 + }, + { + "txid": "44b1fa69786ae62caf71e9f9ca11d65444c088f252fdb4b1e1bde926f51118a2", + "weight": 562 + }, + { + "txid": "b7398d941f686375a7fec010c7e989013f42de3cad27197979892ee8376c7e5e", + "weight": 574 + }, + { + "txid": "d63cfa51eb7afb372c780c78be4d30178d38cbf2b7432e882b4111875b0e8521", + "weight": 566 + }, + { + "txid": "8f56229af4c4ba035a1d71809239280c1f7b98e8ee560b3034b4f59580460d3b", + "weight": 566 + }, + { + "txid": "d7b33e7c7305fc063e7dd8d75565728de4209ed33216bc07437ab2e8626ce24d", + "weight": 565 + }, + { + "txid": "2982d6cfed391292c8b6c4917c5d17b2ef67c941106f6e7552c48e454a811e83", + "weight": 565 + }, + { + "txid": "f7aa3a7ddbd9276f81b59e33a2581d7d5b6ac43822fd037d10c46ded74dcf488", + "weight": 565 + }, + { + "txid": "ca6b1ec1a7ca350d177322b50cc2b084674d86ed5d394e71c022c116681a23be", + "weight": 566 + }, + { + "txid": "92ba4bba985d78dac784101d7fb39706b5e760744fee07a986044c5c727653f7", + "weight": 566 + }, + { + "txid": "3361a5b65626314840662a0fa124c135976c587aaf79cbcf6cac0f71a039171a", + "weight": 449 + }, + { + "txid": "df138bbe511689ac11fcd64cb95978296d02ebe1ad5213fdd7ae665d82d6d80b", + "weight": 561 + }, + { + "txid": "d8cb0d59df889d14a9d482c51bbccd46519b945df256e7dcc5180940e40b4a32", + "weight": 562 + }, + { + "txid": "7c2bfbad000e21dee39f19c0e72db0825c690ccc54d71328e002599d68d1803f", + "weight": 562 + }, + { + "txid": "d38cb451c788f1c75e070a26d6bfc97448573a0680ed927ba4102c781880188a", + "weight": 561 + }, + { + "txid": "6cdeabd982136b5d3e818f6e6d1b7cb1839e74245748e050f0e25a4d3f608c96", + "weight": 562 + }, + { + "txid": "615e86f378261cf774ed34fb2d965b140674461a983a216ed727dfaede7534af", + "weight": 561 + }, + { + "txid": "9fd125e9d84b2d7548ee35d7f1a68330de3dcc1e0f7d3998fcc7d91dafdb82c9", + "weight": 562 + }, + { + "txid": "f39c14126fd7f335dab30e7e23e01c3406a3740450b42c325431a538874a15de", + "weight": 562 + }, + { + "txid": "f7cde3ba01582ee1725e1986f46295491093ce900ac61b83e5ff20d24833c8fb", + "weight": 562 + }, + { + "txid": "e98bc417164943f1217bb1b487458af151c25d94028e91e22148740c34816ca3", + "weight": 565 + }, + { + "txid": "7cbb72e74618ffd1b62745531511486a08835672a3b1cc65636261f893757567", + "weight": 562 + }, + { + "txid": "ace13aabe698b60b80e57a8d843a2c731c172894417909b0fd015d2bf09e0874", + "weight": 565 + }, + { + "txid": "077a9b1c342dd54504a9bdba12ab636b463a464db626dbecb32ec1dd2c4fb423", + "weight": 844 + }, + { + "txid": "5d290063ded01c2c59ce16247ac5080659bd3096415d78fa25914a3b174f0250", + "weight": 573 + }, + { + "txid": "a3ad5410cbcca2cf19a57c696f33a6e97e523a69548d6a1f211317dd94dee88b", + "weight": 574 + }, + { + "txid": "f2c5bf735220aae0658ab55c6c6cb6032b3910045562aead8fbfe95d7f22304a", + "weight": 574 + }, + { + "txid": "5ebc95c286f222b887fa436c38f553c5d4bf7e44a0eea8ad9859aa9d0eb4a14d", + "weight": 574 + }, + { + "txid": "b891df80e3ab7f807a152c60a36a25c4a8dce978377b38c5726ae89d124187a8", + "weight": 2188 + }, + { + "txid": "92ccd0a6a3eacc97ccd3366ec4aed15948238ba0508ccb16cc992e11d7f8c85a", + "weight": 562 + }, + { + "txid": "efc4b0574e6249ce3fbc67e22faa3b966f26720a94ef09ded96297950ed7da5b", + "weight": 685 + }, + { + "txid": "d93d4822abfd309428adb37a5ddb3565d70b1f9bf52e382671cfdce94fc8c7a8", + "weight": 561 + }, + { + "txid": "d9fc1d7c2dc0208d106262c3ac0f289dabce3d9c37a0128d80943a1664f1cb8b", + "weight": 685 + }, + { + "txid": "1230de14ba41c69f307e217d0072dbde6741026126f218f384ba887143ea2280", + "weight": 933 + }, + { + "txid": "b7898ebce3d9cf34deb1859aeb6b8202bb488d8a40e308489eb191e4d3674da2", + "weight": 572 + }, + { + "txid": "d8fe9120e1909a0b8523611209bf26abb83e37261cb4494da78976af8cb236f2", + "weight": 11034 + }, + { + "txid": "97115a397802227b4903bb3f4068d0f46f3a09098060b54d707ffd9b6d3a5196", + "weight": 820 + }, + { + "txid": "cdc40e78c5cb4622a14f05a809967b35169577abdc7abebdf8301d196a6e5c20", + "weight": 816 + }, + { + "txid": "53d9754bb11d966494463bf13dd1d4ba02412bce277de10776b40fb430aae019", + "weight": 816 + }, + { + "txid": "7e1d3a7743835d5d463a8d3fa055b1dc10d3bff28869788b8876171612bbcd2f", + "weight": 820 + }, + { + "txid": "7c18689a4b02c39aea91c488c2be8c930e4ba9b89fd7cd6fb7e42081a7338074", + "weight": 820 + }, + { + "txid": "b31456e6d1f5d272d7161a1dfd203317b7b88db9719e3fa41e0b271096ec4a7c", + "weight": 820 + }, + { + "txid": "30cbecaf0de3d23d436865cdcfcbe0f6d4fafaa625ccb95bb8528eb8fa691e25", + "weight": 820 + }, + { + "txid": "0122a175c1623054ebc1ba8c9cc04210124ae867cd9707a2a51a1b7ad8d1ed73", + "weight": 828 + }, + { + "txid": "c588b42d8768fccaa19a72428f134166a8dda967d4d4f3898e1383d4517f12f8", + "weight": 828 + }, + { + "txid": "3dc0d6429d49fcf7f5a5bdb3636927c79290ccb652e4427ac2723cf32c03746f", + "weight": 845 + }, + { + "txid": "31fdeccfdbf97b4d90175fecfd7d372cdbb368c6a8d65b6e3c606a483a6df788", + "weight": 1114 + }, + { + "txid": "3aa12e183bcbef0563531473410bea04784a937340e976e8620ec008ca71332a", + "weight": 829 + }, + { + "txid": "a2e12ba330c414e2a2b721b6070ce20e270b3dc95909a9835d534f9338b4c2e5", + "weight": 828 + }, + { + "txid": "65c24f8dae5a34c071ffa62563b9dcd91b6e8359b5657ed542acb205d88ddd95", + "weight": 1722 + }, + { + "txid": "551f338bba3f8b6674128de318d41c82b39fddbe785dae7971afe7ca96b84c55", + "weight": 568 + }, + { + "txid": "84440b65e46952b8c62039feb0a9ddcdcf59ae15db1968b8e4679ac33200f5bd", + "weight": 568 + }, + { + "txid": "facd1ba877fb337fe7e67c72c56ee525241ab430c334006490ad9d5bf048ffdb", + "weight": 561 + }, + { + "txid": "7fda85746df4b3c3049b16e646c79797b64f2a6b189e13d02e48e6548c35ef01", + "weight": 567 + }, + { + "txid": "c300bb284b8b3d613cf5b3e7d077f9f3c6cbbc55b06a446029ead1d64c66ed74", + "weight": 573 + }, + { + "txid": "3b0b79a1b1eb58f1a707fcf620f916f01e176b3f44c40e9482c8b67f89262a24", + "weight": 565 + }, + { + "txid": "7cce70035c953b45ad87842c7de03dc786ac3a2bf61b63452733af415821fb25", + "weight": 569 + }, + { + "txid": "bc3fe0dc8d83884f901c8e3525b49f45fc52397cb002c4cc28e800b2a9d02c60", + "weight": 2426 + }, + { + "txid": "0abe9469de54ca1265587c4c87d32abeaa55dce94286e27ddd9602dc0cfd7c45", + "weight": 548 + }, + { + "txid": "cee56887688b72eb11fa7faf75f7c9115a904e692814d94ee26fb707a295ac4c", + "weight": 817 + }, + { + "txid": "cc88f4c5070cc02f013adc774c5139bd0b16050938185a19becc499ad9bc4353", + "weight": 548 + }, + { + "txid": "a78cf9c0926d37f69decbce3ad8c0598784f89d108ab6259277135651dbab35b", + "weight": 570 + }, + { + "txid": "5b3074920f8e991fb3ed82d0904ef3899e40db16ced9228a5081e29c0712935d", + "weight": 4400 + }, + { + "txid": "845df5a612507b921203bd917bd0b24966f03b4f3d430a9b3824083e9b76a05f", + "weight": 565 + }, + { + "txid": "522de228f89e2f9487a5f40425b3742bde91beff0702a448abbe5bcaa9f9166a", + "weight": 548 + }, + { + "txid": "2fddaf22a6a653d97f808701057e0a8d3aa61419146c2b65571d4690d17ed188", + "weight": 567 + }, + { + "txid": "a34799cb2b7c54b57f19e88019426c0bd0957736692dd46ea62719dc317f7199", + "weight": 548 + }, + { + "txid": "497b0e8d55ed1b1e177e54d628cac88cd42f49c4b76e2f84112eb808a07d1bad", + "weight": 548 + }, + { + "txid": "88eb3fb14f8a4c1dd4cbae5e09e30daf684f7d8323911b6845bab86101fd2dbb", + "weight": 548 + }, + { + "txid": "78d8a1f4a8bdfe541e56bd4990773276908e1d13405c97585eb15e628ce516c9", + "weight": 548 + }, + { + "txid": "d41094ce6f50c3e9a6e1dcea4b4333f7195d56046676a8b3084e4cc11b95a6cf", + "weight": 565 + }, + { + "txid": "677f4d2e58069d352413e575dc7dd463a0bb81e38bc932c34df40fa6adf018e3", + "weight": 548 + }, + { + "txid": "de035fc326325e39909c126b343fd9d4d4d1a4badc6d028999dadf7f98f0bae5", + "weight": 548 + }, + { + "txid": "88e317c03068c54bc1f393f5e40ef0b8fd9f47121d4bf7d13fbb1438ce067bf9", + "weight": 548 + }, + { + "txid": "bfdc485035df02f398a60e7664f8a9d74ec48e4b41b1af1bd616979a3ca78c9c", + "weight": 1747 + }, + { + "txid": "4953247d893a38fa426c7d6c7f47192aebf64615b8539f7df98e72be2a84c106", + "weight": 602 + }, + { + "txid": "e132afffcf4bb2f0005bf6be03a014f11867e0134112020ab3a70581b7a70e08", + "weight": 602 + }, + { + "txid": "df39125f47023c4c5c95b0b90d13b043ed488b0bbc953c3884d4fffddfe1a41e", + "weight": 602 + }, + { + "txid": "06df0d3530cf88769d3c6634b828bb9940b6cfab49cd08891049d81982298c22", + "weight": 602 + }, + { + "txid": "fb2a428c3f0b47cae990fa40cd35b4f1ab78eea7f797d255059978279e16652c", + "weight": 602 + }, + { + "txid": "28f60702ebc66df82d419281a5a660269dc0c55113526a462d53e77e52831e2d", + "weight": 602 + }, + { + "txid": "e738d2e779e85db927d8b9d845ce892e8a531980e13349f02d2213a269378054", + "weight": 602 + }, + { + "txid": "3e608f90b6e2eb0ce327b40cd122e3c357634b93b32c9afb6b1e0ed1dfe25b57", + "weight": 602 + }, + { + "txid": "70960d811b9ce69a43de8678044d1995df9ca6d98e5c6f95f8efc5451d2a635e", + "weight": 602 + }, + { + "txid": "3ea125f3d382d36620dba554008cb670b87faf024ac27d4152c5aa37ee645b5f", + "weight": 602 + }, + { + "txid": "956448a2d3e31bb3ccd41ffc34fcc5c57343c4af34e42cec144ea080df95a178", + "weight": 602 + }, + { + "txid": "be19dc491fd1997b3d2913caa9aa412c5733ea212638c64206ddcd026548d67d", + "weight": 602 + }, + { + "txid": "9178253201c74a1d5d425cfcc7fafaca0f59fa6865cf493ad64410db60b6c28a", + "weight": 602 + }, + { + "txid": "1a63fa3c56f0c5c24c575a3e4e556c6782ed595ddad7b54f5908650eee4f38a0", + "weight": 602 + }, + { + "txid": "a25013fc53e4425253738df9a72c668e07942c0b07ae722bee612a72209204a2", + "weight": 602 + }, + { + "txid": "7cca13e64d0f3b1a30b0a22c85e70490a56637d8586b2974d6d8e80f5169aaba", + "weight": 602 + }, + { + "txid": "2baf1d6ba7729728102b1e37b2a0ce240e3d4216ff842b3878c70a5b9fffa9bb", + "weight": 602 + }, + { + "txid": "60dc51627d155bde752361621fae4998ffa8f1f5e66fd88e0f7ec60af2770ece", + "weight": 602 + }, + { + "txid": "0e398a827c8ae0d35457d298bfc2962a703b368cc5d15981ed1d3879aa6a74d2", + "weight": 602 + }, + { + "txid": "4ea37baaad02f3ca13cb3f789deea50541cece89b1b61c8d300742acfbcbf5e4", + "weight": 602 + }, + { + "txid": "0fb32e6c93c38589d71501eb0f0372c45ed0689377d6cef7fae80c2d438728e6", + "weight": 602 + }, + { + "txid": "6b8815ece5f0b704e35ba7a4b5663135eac753b0d1c4ffa90aa15d7617600de7", + "weight": 602 + }, + { + "txid": "59d468b07bf5d3038784e597a0b6429a4a70bac35a6e4bb00ab0b7b83e6b69f1", + "weight": 602 + }, + { + "txid": "74a205982d1cafc02f3432f07dba0a539db2415f5c6bff23b2b36e3e4d076e22", + "weight": 880 + }, + { + "txid": "8f0fabf330b594a02eba2cf3cd9e93ffc5ab16904c53193fa3e5b22b4e149664", + "weight": 880 + }, + { + "txid": "ca4b6e3ae6c838c0f444d321febd06c597b70d08dc10f34c3c8930ffd4ab4276", + "weight": 722 + }, + { + "txid": "f958d8890cf536972de8d915c03f685926cbb6b4263260fc9ade6a952815ae24", + "weight": 845 + }, + { + "txid": "f6a3b7ddd7889068ca5178388a2c81540791ba5d0eac8330dab4da9e0ccecc2a", + "weight": 449 + }, + { + "txid": "6f58d7067b085ead8cbeddb23d2b7cb6277a14f2862b581ab10a24f47c7f908b", + "weight": 561 + }, + { + "txid": "bb1767229fe5d587b95c7a1d7d57b119f701e639ec91d6285b8997f0b4cfb7ca", + "weight": 562 + }, + { + "txid": "506d7cc40a6cf9e8fffcca52d24a60ebda0b28b9bbadc07b79a4a0d13f1cc4d0", + "weight": 562 + }, + { + "txid": "42e519ead126aca07811a0b25e35e9c46393eba2b46cacbd12ea23458f04dbf0", + "weight": 561 + }, + { + "txid": "d87f4b09d00b9cdfb231189abdbc57a0b66b18f091a92c7b93fa5a40f1716b24", + "weight": 884 + }, + { + "txid": "5cce0cb66b167c65f03cd701244051eecb3aa9fee4b03bf5c24d8e9859a6d03d", + "weight": 884 + }, + { + "txid": "dae85f8f503a98a65d6da42820926a4cc07eeb887cbc5679f621b072ca402275", + "weight": 884 + }, + { + "txid": "7d2dbe41afce15b0515e9d9519d1f8a6df014001a3c824cc777f08ec6d767bda", + "weight": 884 + }, + { + "txid": "f7c42f03300cf69a815d2bf6da8eab67fa71c0390fc5b98b126a6a1569b7f442", + "weight": 530 + }, + { + "txid": "c459a3f766ac29180694e0d8b966d41825824528a467dfc002df2f8a663a2008", + "weight": 617 + }, + { + "txid": "45ca87732e08bb2d7798d2f549cdea1d96ffd38a9a3f3fab9b3495af89e2bfff", + "weight": 617 + }, + { + "txid": "dd69d577c4fb2b20e72bea0cec6d4fd3f39a50b1915ca622aaa9d65718e7665d", + "weight": 562 + }, + { + "txid": "748ca6ce7ed958f3e4c5277abecd5cb5f4989b93c594c48f45c79a1a5289460e", + "weight": 561 + }, + { + "txid": "d17a47ad9f356a5e8ae852773ab442db27d26c3f0bad8eacc594188e458eebe2", + "weight": 1082 + }, + { + "txid": "51dac90c9b6c54836e03e011422f63b7f13aaca8e0748f0d2121c2b8c9005f70", + "weight": 5327 + }, + { + "txid": "40dea0fe3abc9781a6ef01e1968a2cf09850b865096211f4b20e7bab1b9923f5", + "weight": 561 + }, + { + "txid": "926e886206c70674122cc0bbbe841bec338a509deacf3cbf1839abc35b66baab", + "weight": 561 + }, + { + "txid": "71943e3dc08cdbc89b04d5027e1c0a7a8d9eb30c76bf9441ca1dfa51689600bd", + "weight": 585 + }, + { + "txid": "a87119c3c00a220c1800b48adf6428f67d8e0a3a8e85b0b67a5159603a50d477", + "weight": 3132 + }, + { + "txid": "217df805071c7b852792e8f9f82584516b4ed0b94e70edccaf3d169db1edfcbe", + "weight": 848 + }, + { + "txid": "9319f8bb744d834ff26575d8ab1b2250324a6a39bbda59f2fdc9142f3b6710b6", + "weight": 809 + }, + { + "txid": "937085446a933913cc055bb7268f2fdcfdd9e44e3aeb7d446b5ae2f1cfc25124", + "weight": 561 + }, + { + "txid": "e8406e952f25dda6a934f155b3a5ec96e17e61d20955a17b9e4577ec2049bd17", + "weight": 561 + }, + { + "txid": "036ca35afe50aa4bf4a793439151b1e09548f17cdd71ae934fccd061fc7d448c", + "weight": 437 + }, + { + "txid": "092789fdf1a98ce76d4ee55a6ea068d8b7c45f05963548c5a48c94aa27f028f7", + "weight": 562 + }, + { + "txid": "fabaf38ce71a044256f7cd97414d5be3f4531df50f9a465c724f22488705468c", + "weight": 617 + }, + { + "txid": "f464ac171ededf8a61f6f52e0f9d66c52ca233dbd3bb28724dbdb4bddcbb3599", + "weight": 1338 + }, + { + "txid": "bba74b3c001951ba71f1a9ec2c64b18842d1d75680e1da2eb5acef451cade1d2", + "weight": 817 + }, + { + "txid": "cd5d5f6cb7fc320307cb6f6b83e26da9980cba039734a2b0b71c37d7ecf56ed1", + "weight": 1484 + }, + { + "txid": "9b7784e3eb8274c9679d4d1a4db3395dc031c19d143a9c0d499c767d3cc060e6", + "weight": 1093 + }, + { + "txid": "8485724f54dd445f68af647938c6e0f121ba99b888ed0592f341732b80b90f68", + "weight": 653 + }, + { + "txid": "79d6c6ca4eb6f16fc2c170701fdb2ba62976825a61024164fdd512ad47351c7e", + "weight": 561 + }, + { + "txid": "2857fd90f03d1cc9c8790166e980eb1fc3b3f221d935e94f478d53ad89374d17", + "weight": 585 + }, + { + "txid": "66e801a7afcf9c9730bad3d41ceaecc25c45a4d83b22966e1f0280c8b199d39d", + "weight": 561 + }, + { + "txid": "fddf595deb9e8bf4cf59bee9cbcf710734b67b898f9acb5f6d032db57989392f", + "weight": 585 + }, + { + "txid": "56c731754f4fd34682a7fad492052c976819f6a686b6a1236edf6e779b630abe", + "weight": 561 + }, + { + "txid": "d427efe28d0600fd355da9957890320a9e5f24079a98646197c94ccf3c9a9a92", + "weight": 561 + }, + { + "txid": "ec17647f1e83587a2acaeda1b428f89fd84930953f5080db755cb4736b265604", + "weight": 585 + }, + { + "txid": "3800ad77c183bd27e826b3ee739f6f879683becfdb4a7e6adbfa0b2b77ef41be", + "weight": 561 + }, + { + "txid": "bfaa4e32d71a4eaaf4d62312a3fdef447fb18311b4d426908533be042e76106d", + "weight": 561 + }, + { + "txid": "9913fa3581feb781e84a4e249da026c0830ed7fc3fee99b7a93ce501270467b0", + "weight": 585 + }, + { + "txid": "cdd9c9fe5ba0384fb9f3c8ace444e156cbdfe2f8bdc4db5851ec272f280e2508", + "weight": 561 + }, + { + "txid": "b62f615a918965a3552902b575c0b2a627e08b0e0dd71f4ab9d185df5b7b197f", + "weight": 561 + }, + { + "txid": "ca2e5d2687fadd564b77b5bef000fd9441b360db0331c91341f3ce316e95a7d9", + "weight": 708 + }, + { + "txid": "0c797156a765634cd7db0f4466fa00a9a7a2e40286d90343a8cdbabbed503b28", + "weight": 569 + }, + { + "txid": "a771915cb42099164268b32af32f52e3c24c012eb856082c38818a1a10132a51", + "weight": 4649 + }, + { + "txid": "6d788692b3cf9435788f2c9529ffd4484de422fff8dab8f46acc2969038675a5", + "weight": 561 + }, + { + "txid": "cd6a40c37ef67f4888efda9ea68da956ecb8efc463fcaec246e6fc134f6a18cc", + "weight": 1101 + }, + { + "txid": "3fc05a7eda27dadacbb72798107ea0a8f9460df1a4f50d632d6722a73e424237", + "weight": 616 + }, + { + "txid": "6520bdd59e2e60b3a874a0449883c6c2c20595b703231992a0582e6356f823de", + "weight": 565 + }, + { + "txid": "e0cef311838da0629915a38530eb04c55695d0c054531cf5e3120bba3234a203", + "weight": 1132 + }, + { + "txid": "2e24ebe194d27708efed803715065254855049a861a7b8018ceaae9919601570", + "weight": 2336 + }, + { + "txid": "074712160646d6787ec40a721b3c1b975480c36182d85e6fbfbb93e70831c809", + "weight": 548 + }, + { + "txid": "4f932be9d7bafc2e52a27d68e9f35655eaefdd43866cf560bc2a5b35a4de363d", + "weight": 548 + }, + { + "txid": "6a5558cd874ca1dfdb67388eebfdbbfdc59baa7f19d2981f2eea5cde3013ed42", + "weight": 548 + }, + { + "txid": "a600de5f846bf73aba0272f0e7a38fce82454cbd90c0e3ee508bc524d7e2d943", + "weight": 548 + }, + { + "txid": "48997d84c72e863b16e983b9c40af0312123de5696493b72dc36304ba748b15d", + "weight": 896 + }, + { + "txid": "a171b857e01b0416022761a061882ef9714bfe13e21dca2658d325a1213c3166", + "weight": 548 + }, + { + "txid": "e23fe256f4fe3b70c720e1a440cc4f0d86916a418100381de5f054dd0b77897b", + "weight": 548 + }, + { + "txid": "59738a2ba1c5473ff852e8e5377bf78df3acc1eab3ce7cadca0ea790d26e8c8c", + "weight": 548 + }, + { + "txid": "9159d6b6bc3836eb84db2aa54773d1ae60a8b2cc9730d8f45c6b3d5b67dfa1c6", + "weight": 878 + }, + { + "txid": "dba855ad422ab68234d493b979f5d4ba947b27d7281d4b84e86dcaeb4ee034b2", + "weight": 548 + }, + { + "txid": "db69d1a3758223b2d90833b644791ba052ddb7b8c0670e2900e4aa4ed24348bb", + "weight": 548 + }, + { + "txid": "e477ce1b289db7b27ced508db9a7f6632658444d0c60930e7cdd771d825ca5cc", + "weight": 548 + }, + { + "txid": "dc2925a868c702e9e59015c2e21abce435478b9daf0fdc4c0ccb087ad60fb2d2", + "weight": 548 + }, + { + "txid": "e3ce0c62eb27fffad5ae9bb91638d669a1beaa8147b6b9a481c0452b9fee84e2", + "weight": 548 + }, + { + "txid": "dcc61d066b828074190ceea6c1de007a684367938d4d17ae371d5a99dcb93cfd", + "weight": 548 + }, + { + "txid": "3f3c110a0d114dfe9d69928bcf7005fb158653c53f738ea28fec9c8aa934a5fd", + "weight": 548 + }, + { + "txid": "1d5457343ec887b54b687704a726720307f4f6862756a475a0f8bf9bb29a8872", + "weight": 28773 + }, + { + "txid": "e359a3bc274abeb52053ac68e5d37a21f4e3c96862f86d5a75f30e8203ec4211", + "weight": 24412 + }, + { + "txid": "4faf8ba290a73e67891686fb15a45ed4c4f7ecae3ff78ad3aa9957f4cf53edb9", + "weight": 17866 + }, + { + "txid": "93ad9c7595804d6c5e81994637f1939622c4ce21c4b1e8b121e26ba75af07cd1", + "weight": 7494 + }, + { + "txid": "0c810d200e525b4060a4eb67f2d3cc69d16ae814d04e6a44c5613d8678646108", + "weight": 4440 + }, + { + "txid": "3068de8c802011639c9b864302c5268cdf626cfee40a1992d3a2f6b9bf18e88d", + "weight": 565 + }, + { + "txid": "6553d05f4ecf3e6bbfe2ac55efeeab418aee107280a0a8113c69cb8110d35c3f", + "weight": 888 + }, + { + "txid": "d3e25b1c67c6a588728694446b769b56317ffbfdc23a52a9f8fb6278b93f72cb", + "weight": 892 + }, + { + "txid": "7f3de4fe48b7330ddca3bfbe5b1359dc29a6a16e5aba3486af33b64e8bd1a256", + "weight": 752 + }, + { + "txid": "4654b009031cfe00c3ec1fc77e4ab1a35d2792e190a1fef820cf7d9da31e0fee", + "weight": 565 + }, + { + "txid": "edb43ae05828408b76d0103c346bf8335c894f1330270a10f1648132f0cdfccd", + "weight": 449 + }, + { + "txid": "dbefb80edda3b3a3e5f5390a9ecff40c709c40a7a886c1e7d1c075efd7d75bf6", + "weight": 562 + }, + { + "txid": "a0bd6bfa9989d70f32baa3f527126daeadb00e086941217825926c7c1a762ef4", + "weight": 825 + }, + { + "txid": "1863d06623919580e57997d6cf96c94bf6e8afaa9eba556d201afa8a7b275da8", + "weight": 565 + }, + { + "txid": "af223c605901fa3dada16d8a4bc9c304ab73a314bf951f6d3f2f1942c4b743ba", + "weight": 564 + }, + { + "txid": "0c4dc2e3c57b9f23cd3dccaa9eb8a3c2a5bdc85c07107407c8702985e6accc7d", + "weight": 832 + }, + { + "txid": "bd5308ac018f25d64ccaebf295e5ef020782e7eac9877e99e9f22e6dd05d7d03", + "weight": 754 + }, + { + "txid": "951865d40f855e3aa81ead7d51c9dbb404889306943a22235b75b6ff5f6c3e08", + "weight": 609 + }, + { + "txid": "ce6a0537e3aafd155bf6a0c25e685f6951e53456de0c812ee05706cc694fef09", + "weight": 565 + }, + { + "txid": "814907f4c14dcd45b0c8fe274cca8b4df5a786b7e6994157401e3a6f9ee63e2e", + "weight": 1561 + }, + { + "txid": "86f71f6c70cea6ce0cc39b730eb94e2c9bede6d187720292f1c4e9d836da3824", + "weight": 1061 + }, + { + "txid": "ea9531e488abc23b391be99f39a0c6952923513a28e9af30b33982b897c0bb46", + "weight": 3189 + }, + { + "txid": "ca9afa00f0e44f7ca545567abacfebd9413c19a597871823348514b1a823ff52", + "weight": 1929 + }, + { + "txid": "70b079844c39f53a6ce56817185ede2fdcb3813713b6b5e2adc286b33f9c2ae3", + "weight": 2689 + }, + { + "txid": "3305220589eb96e009e2f8610ee58aa7d61d206bc12eb86820933e047be43e72", + "weight": 2553 + }, + { + "txid": "79ac658939bf1ef38ef8ce2df7b4a8115721713c534b199d52bcc746b1c5156b", + "weight": 4797 + }, + { + "txid": "208e2ced4cfe72224726f52f6f728033a0acfbfa233bae2c7709d362ad85278b", + "weight": 561 + }, + { + "txid": "ef1d1698876e0bd45ec67b899f22dca0b9956135fab574f2484252d1a47eb999", + "weight": 561 + }, + { + "txid": "7fc4ef2563b3686da4cbe66b1232cb95df75f69a6a429f109a6f1022d6eb90a9", + "weight": 561 + }, + { + "txid": "eb3ddaa68fa598d44c0c2a694eb2542e212671d8647059417d9d92aa30b92fb3", + "weight": 565 + }, + { + "txid": "5d9746f7ca4a5fcaa6ecdbc5e304c333c07f6e0a9601ad332716abbaf9c17ae9", + "weight": 561 + }, + { + "txid": "6b06397f01a07deb73a66909e3502a54459d1d793bd878f6f5ca7ffad0884af2", + "weight": 437 + }, + { + "txid": "bcc8da5025e64125366a8a992b94a0654e6240e5663386c34b337a15dcbb4df9", + "weight": 561 + }, + { + "txid": "cfea838c58f9d6bece8336cdce6e20dceb41a489631871ae8a731f56fe4e4afe", + "weight": 2701 + }, + { + "txid": "1f69a917aa1d1cffd1bff10ce13666758953e4886fe993df6897edc8201e1ec5", + "weight": 573 + }, + { + "txid": "8178f5b7d4ef483c866efdf5959bee3313b0789f442022a70a1a375e6ffb7c60", + "weight": 569 + }, + { + "txid": "16e266a3cfda86d3c4589e57f079c3d19b942254914580c4944cc92f2fdcf20c", + "weight": 1386 + }, + { + "txid": "63e05ded5fa51c3e676421deeab15e3f14876eefcf38597c33dd8c0f53ee82e4", + "weight": 441 + }, + { + "txid": "74e09d84ff7d7fbf5882ea479c1f133bd600d195dfaf88dff98fc8bfde69ec41", + "weight": 485 + }, + { + "txid": "7e8101b17b1b39393e86698af14eedeffa3b96e87992ae7f345eb6451e96f1b5", + "weight": 1533 + }, + { + "txid": "028188e0e2cd74f06b508478091fc7bc75f849bcc28f99afa3be84ce1b6cf267", + "weight": 18230 + }, + { + "txid": "9aca3affcac35a8f27c64dd5c1f78fc6efa38a1bb4ed26cd213c0d2ebe6df663", + "weight": 441 + }, + { + "txid": "67a139d7c9d608774c99b25e61fd37d91f67868fcb55e8faf1659656f47f0870", + "weight": 565 + }, + { + "txid": "7fa86025471d83e0bd0da3d403101fe4f6c2f801eb8fea775c0c27985c2480b3", + "weight": 449 + }, + { + "txid": "f4de7a5d4bcbab8d7c5d036d59b1c145fbefcf704a808fb8fde81d75f691d8f6", + "weight": 438 + }, + { + "txid": "a136ea276cb17effa73849787a2399d359d14649948e541c263502b83850ff68", + "weight": 581 + }, + { + "txid": "4f84a3f2b9ddeb36effd5d2fbac97b087c0b0305478b8670538bdb12b95aa048", + "weight": 118168 + }, + { + "txid": "14a690b07280dcdc9903cef8ab1397bab8478b2c1d4ca06877b319f3636406c8", + "weight": 118168 + }, + { + "txid": "e9e951f669eacc7ca9f80f1fae2ca2fb9137cfb018eccafb0e5f5f681998ee00", + "weight": 118172 + }, + { + "txid": "2908c858937960982551e981fde7cc04a583a6b9a42fb865e62f3be9945ec13e", + "weight": 118172 + }, + { + "txid": "535ac87912d217a30b55fc04d3e0527009fe90497b00c27e2b3234414e49a999", + "weight": 118172 + }, + { + "txid": "d4bd4e244613daa96f184465c272712e75c81fa2c32445f09d62380680f4a977", + "weight": 118176 + }, + { + "txid": "8c14443936301380c47a63262e2ba7168248fbd18851a0f641d95b6a6545bed9", + "weight": 118176 + }, + { + "txid": "fad10f7eb2931ee475fe2b42ec03f2da3d0b05b5e37d490b71e5febbb52fd502", + "weight": 118180 + }, + { + "txid": "50b437a6ff1cfc05576526716e7d72617abf97d8fd99d9f0212c843ed498aa48", + "weight": 118180 + }, + { + "txid": "961cbc54c3fad07ec347be7f9682f3e918e4fd1a7d4f354b7a69a339b539a04d", + "weight": 118180 + }, + { + "txid": "4c156f0988e10f5245bc11e5d3e27cf176870fb57dbb87bec36bfdf925419c91", + "weight": 118180 + }, + { + "txid": "a74a3b38a2aa12a1247ac9e94113058d409ce220216f76f1bc2a2bb48295afd6", + "weight": 118180 + }, + { + "txid": "d0c7bc320842bf23d7216efe4cae9f62f384a5eaffa8ea89c2518980b6e22c3d", + "weight": 68032 + }, + { + "txid": "92af532ba7db25c35eb2a27056027440a0d384e41c91cbc3df4f28a1519afc56", + "weight": 118188 + }, + { + "txid": "8150c08044183ddc32dcdbb0b3020d284b634a5df4a809f0647875f4e180fbec", + "weight": 118192 + }, + { + "txid": "06087bc213762c92742289ab59fd4507e8063887797aaa0959d31d972b80a5ae", + "weight": 561 + }, + { + "txid": "82fad86c5895409dcb73260ace9c32769c2dd6e0eac92492e0af25bfd8cc56ef", + "weight": 561 + }, + { + "txid": "7d3d7d8fb98c4024227e0dc92f5ccadaa456a2ec1aeeebb6fa0ec25b68452c26", + "weight": 441 + }, + { + "txid": "ab6511769073d04020d6885b7d9e27e1723cb5d18c2b7c344263ddfa4e7fe288", + "weight": 4523 + }, + { + "txid": "1e271d9bddcfa3c08b46504185fc60c6ca8c812de82beaa234a13b86222d63f9", + "weight": 1535 + }, + { + "txid": "c29ba44471739775d1976f90954e87223265e34b152f7a4948bddbad3151116a", + "weight": 3196 + }, + { + "txid": "c452b2db282c5385f55e7d26fede2277218d745c0d71acf5812b375079a22a7e", + "weight": 756 + }, + { + "txid": "2b4123aef316d052039df7973841857ea6458079e1b13952d0e604afee94bf3e", + "weight": 887 + }, + { + "txid": "d6d4e9d55ea66660022a73d36b4d57eb4ef765bc96a8c022e6be16999c8ba9d7", + "weight": 769 + }, + { + "txid": "e78bb56e891d239da15f1282920057d2d33ff45aef8330090bdefd1c0a562d00", + "weight": 569 + }, + { + "txid": "c24722351f1f53f3ffb933c13324d23360e180d920624383693db4ed93cd8c01", + "weight": 569 + }, + { + "txid": "080589920bec25a72802e5c12fdd2e6935e0555e25301cd8a14087b0563fbf01", + "weight": 569 + }, + { + "txid": "505a663d8424a8b5784f09191cd4e86e69eefd8dfcf0512898af8e82eb68d301", + "weight": 616 + }, + { + "txid": "ef143b025a71d1379941aaee3092ec1c4b8001dd3f32a373adcc46c2dc102e02", + "weight": 569 + }, + { + "txid": "232466fbed3799508ba03258e89d973e8f5a811b4f6b7913f257cc575ffc3302", + "weight": 1382 + }, + { + "txid": "2694f7216c5675b207b30e50e9d2adf2b1ed5d9afc43a78ba0c23a7483995202", + "weight": 569 + }, + { + "txid": "3bc139a1c4cbd085c39aa000442e9b49ca67e2c954aaf04e746e5fecb6b17c02", + "weight": 739 + }, + { + "txid": "412859f19076d7072915f2897875104ff8783ae68372b5e24bbf958a82b6a702", + "weight": 876 + }, + { + "txid": "74e4f87a15f6f95a01bee5408259753fb7554fcc9aebd8ef1d408f29c5e04103", + "weight": 569 + }, + { + "txid": "2e4717b7eb3cf9c4675748f8b4743b1d6d70d7cb2718c7ddf4c38eb31e159f03", + "weight": 569 + }, + { + "txid": "d4e797520e0f17657e9b67658b146f85f61ac86c31af85c08539e72b546c2005", + "weight": 565 + }, + { + "txid": "3965aee69a57cb4139964be99b100a9a61024f42495c88941365bdc977ab5505", + "weight": 569 + }, + { + "txid": "67381f0fb2cc42e084684959549605e47e7b93d71549d8e6ab65a00b59856d05", + "weight": 569 + }, + { + "txid": "b8c88254ec6940c8e455c5b60e43b5ed430037e57a78835cca4837bebd709c05", + "weight": 569 + }, + { + "txid": "137c490d4cba59b3fdf7d8ea907c218d88b62e90e90283c3db2db268914cca05", + "weight": 569 + }, + { + "txid": "f0dd6ab293b4e0af07927c86da80ff6ca27cb723886b935ff0ecd15280add505", + "weight": 569 + }, + { + "txid": "065b781c1c487604ab8e2051d7bbf7465edc8bf9994b7892482910006a721006", + "weight": 569 + }, + { + "txid": "10fc2c49e7fa2a62c60d419a14f6c9ec7c06d128e739e1eec7d754476f668606", + "weight": 450 + }, + { + "txid": "25d64245394da7fbff7b11256b0c1ad52611d7c880c23db11a3007616ad4df06", + "weight": 569 + }, + { + "txid": "28d60a0bb8396b023a37a48c042b68b76893073701055abb2c09701c02a6ea06", + "weight": 569 + }, + { + "txid": "b55cd9d6823b8dcd2d8c9a38c1d1dcb46437cb645d13ef9d9d0ca4d01fd11607", + "weight": 569 + }, + { + "txid": "b16bae83f4c371cd1be6ba3dd3731ee8ab04a3785cc95307f470afb0ea216707", + "weight": 900 + }, + { + "txid": "0d96afa5facb67275da30196eaf0919f5012a1e0df20f4e83d586156f9cfa607", + "weight": 569 + }, + { + "txid": "347aa2e03da56e7f872d1a6d74df511bdfa49f5209f22feef0794a9faae35508", + "weight": 569 + }, + { + "txid": "2abbbd7c6aad80cb5849cd983f66b63e499342250187dede321a9a3ab2dcff08", + "weight": 646 + }, + { + "txid": "91dc485c96c9eabc71d9b37be2e4c4db16cb29b1855af1390fb97bbf09276809", + "weight": 733 + }, + { + "txid": "dc136d3682d5196d099c0b0f7c55623a0f0dfdd0001b55912f2e16b5776c100a", + "weight": 569 + }, + { + "txid": "e9ef494e4b78fd1cc2bc43f2a081bc3517343d1c9fda103357b13b8ec0149f0a", + "weight": 569 + }, + { + "txid": "e0a234bcda8f346a0c6c30fea3ae8962fe175c4e28614fca5f13839be266a40a", + "weight": 705 + }, + { + "txid": "45529cfdb0fba815f9d17b96963cdacdbd8357e0b66180e83a12c3cda14dcd0a", + "weight": 569 + }, + { + "txid": "584f47a82642b6cbc0cf25a2a8f025f781e1846bbf9f7298f80871279d7c690c", + "weight": 569 + }, + { + "txid": "56f8b7d9520c8f424d848827203b459338f5757e934f693e99fec0e450d3a80c", + "weight": 569 + }, + { + "txid": "0d1ac0c5d61a1b82e74017b88a3e5fe233943333a8a45ab430b9aaa75f35bc0d", + "weight": 569 + }, + { + "txid": "3f00ac3b326f7f141720f677f98145fc41d3faa896f00967c44bbd983011ff0d", + "weight": 569 + }, + { + "txid": "ade23d93c91d39d007a851d1ebac963c9b16f22aebb4cca30f69a8a437b4100e", + "weight": 569 + }, + { + "txid": "7374bee7d5561f68f72b8987e36e5f17ca98a945978a69830c172695f3d6f50e", + "weight": 569 + }, + { + "txid": "2159034f5df0179706b228dee1c8aea5f67004d094d143f6468ad26fbadb220f", + "weight": 569 + }, + { + "txid": "7443de77676510969832dcdf113d8cf380cef0032212b8a8126dcc7d34b4620f", + "weight": 569 + }, + { + "txid": "e44e2fe52b842b15b57f84c290e92abf5f81972f8a1f679d77d494ea89119910", + "weight": 569 + }, + { + "txid": "5e68ffbce815810f532e763ddc5b6e4fdf0bbfaba6c7df7216dae24354660711", + "weight": 569 + }, + { + "txid": "cd47b9976398bedfb413ecea2cc107e9037bab3fe36e380fa4cedf0234d70812", + "weight": 569 + }, + { + "txid": "674c819538da0c28c374652d4be1d9cb2c21604c1f9688b94723a1f081cf4e13", + "weight": 569 + }, + { + "txid": "bcbcc937f9f532e8fa989c789719c03098993269104232adacfccd60e98b7513", + "weight": 569 + }, + { + "txid": "12d3e8e0d548177f98379de47a774efb77f79b1bd96bd3aac7b7bacb2dc6af13", + "weight": 569 + }, + { + "txid": "f81dfaeee671214b4f79e214e75c08c4ce76d1737bc6f43f034dd2fd4ae5f113", + "weight": 569 + }, + { + "txid": "bdee7f00abcc98186792d520805e9c525cefa7fa5bc96a568d9d88189ea92714", + "weight": 569 + }, + { + "txid": "149f314646c03cfa804fc75f4a2745b66c22c5a1ac477763a7923e2de1543d15", + "weight": 694 + }, + { + "txid": "68f45b6aeabc90652c65025f369f7232960b93dc333874946505695f87ce4415", + "weight": 569 + }, + { + "txid": "def506b254aa9f22b0d03dcaecc74b07f6aae8ddadec71487e59448d96e5de15", + "weight": 569 + }, + { + "txid": "dbe93212aa432cef24e270f6305c95b6c5297eb4209e2733c7c4b80e5bbe6616", + "weight": 569 + }, + { + "txid": "4d039bdce762b7fdc299211f8afa31fb167336ada2b8c47f025ee62608ab0117", + "weight": 569 + } +] diff --git a/backend/src/__tests__/gbt/test-data/test-buffer.bin b/backend/src/__tests__/gbt/test-data/test-buffer.bin new file mode 100644 index 0000000000..3a1b5b7c3e Binary files /dev/null and b/backend/src/__tests__/gbt/test-data/test-buffer.bin differ diff --git a/backend/src/__tests__/gbt/test-data/test-data-ids.json b/backend/src/__tests__/gbt/test-data/test-data-ids.json new file mode 100644 index 0000000000..2ab6324732 --- /dev/null +++ b/backend/src/__tests__/gbt/test-data/test-data-ids.json @@ -0,0 +1 @@ +[[1696,"5a1be765d06123c15a04cba41f87a59c9413b3bbadf39567dfb50c4d30d5f2f4",28.90391459074733],[8357,"a96414ddc83aff03fb9fb92241f90be67e5bc2ab350aad169b848520547bedc8",9.917710196779964],[6576,"6d3bc01b0840a108a2b317393bf616369ff849a4680e159c82ee8f5ef3c6d0d4",9.317957166392093],[7696,"21a448379ede13d7013097d1a903f60f41258a1c8c6e9313d7943db0bb5890cd",9.917710196779964],[2742,"8dbd8dd873e9782371029f729fefa0963b6c02c2ed59d9d7c0ddaaa8f0162aee",9.647446457990116],[17042,"bf4468844942d765e9ab6951cc34aa0224768b7338fa22484226fb14cf6d2a51",32.79775280898876],[2770,"581e63aebf979a15770e0caff9f689f575f408b8a5111af5289ff7cd7640f8ed",9.917710196779964],[6574,"3d0d878975ce151b083cdae5199720b9155b614400cf8258b14049c1b138e2d4",9.317957166392093],[7632,"4719ab77b8c44b1c95c3831ef42d104fc652216a4366146a97ba000a387bffcd",9.917710196779964],[8650,"193b63f5e9e70d4144f3302a511e974f168b459f8c80161a5cb1c0d27f1f0dc7",9.917710196779964],[12459,"5455a2d21c9fb93902ae74eed94c0a290e1e2f0315b51dc4a7cc188dc2303dae",9.917710196779964],[8439,"f8c6e417daf30480f07549ed6d4719430d52ce509820d261bc289100c62165c8",9.917710196779964],[16298,"cbc21433e0fef18af62297ef6b61c37d5282d18fdb3942cbd169a0ff9c402b61",9.317957166392093],[7946,"93b3b0a08d066bac7c79ac60cd35de5f1cfb8ec6aa10bd970fb9010975fdebcb",9.917710196779964],[10464,"c8981faa002768ddf46c07ccaadee20f3dad341dd830047eed27a975d33757bb",9.917710196779964],[10035,"edc26c95cecd5cdc1fcf48a82dc19de98015cd6e4e908e0a4d3467c1d0c719be",9.917710196779964],[9804,"100549ae31722c8de28bfba31c293287feca1ad59b42afb7472e1d468fc09cbf",9.917710196779964],[10637,"11cd62000dc05428f3dd38c5d019ef577654ef2dbcf2178177c3dec29fa270ba",9.317957166392093],[5835,"901a3455a7fbdb192fd221ed34a736c8883b9e2faa3287dabd6ea5e6e6e01eda",9.917710196779964],[17029,"978e13aa4467431f8af1cc3ca6ce07ed432fe2f30b13a5e63c63714799446751",9.317957166392093],[18348,"497acd50be1e1dc1f003c0c01cac527e84a9c390875ce005d8fed8d005a7d234",9.317957166392093],[4989,"1dbc8bec016bae533013eacc8087dc701f79ddfa2476d69d3e1a6ecbf7bf40df",9.917710196779964],[13203,"f0b8d95dd8dd48e7adbd76b429498b40faaf621d78bfe09814ca0f825049d2a6",10.0355871886121],[6129,"82b9dd66f945f0e1d2ebed20ea89807ddb4ae7e127902a8200304213e71943d8",9.917710196779964],[11510,"03583eec4e2cea17399e673904edc9d482fffe3f434ed415eebfc568ee5575b4",9.917710196779964],[4382,"03d646fb6eac66e63416657b2dc20587c2637ef8fe26829be93d8290dc8b2de3",9.917710196779964],[3283,"7220022334be6c172d3b8dcfa7881475ab9e90abd474d73ba4ae90e0a83482ea",9.917710196779964],[11451,"7cc9f889c46bbe44def7b833fb1f661ee7463f44c93735cb4d775986101bf0b4",9.917710196779964],[16783,"2fe4c35f2772c666f1561305ca4cd1068d8eff7a3f9e2383c5bddebe0cefbc56",9.317957166392093],[11705,"3592c18fda04778742ed1c7b7b829e58ac454f646e431dcb7fd2df808c6144b3",9.647446457990116],[4534,"c04a7a93aaabf6305380057b40367b86204b645d4382484614dddeb31f4224e2",9.917710196779964],[14944,"645ad19ea191a7e72285e0595fcfc1f28dfd0e8a53d1b2aabc52d92f1256ec7f",9.317957166392093],[16769,"733a313c2fa4349fcc98b000a78c7c154a5e75a8264d89f47209b3a6e5040c57",9.317957166392093],[19217,"84e53200936d939161da3cea308bea31608e333a3a1bf66f53dfe0817c7f1418",9.317957166392093],[2450,"84267832d71531bc7f378c810445eb68268b5c87804195b866413783edf633f0",10],[7760,"7eade46c6659d55c0224b93b56dae9ae7b8da231909bc7c534172295b75211cd",27.099630996309962],[4507,"04346fefbd322e45f6434e8a4b80171ff0ec2eb5943159b9c2ea257c52eb50e2",9.917710196779964],[18801,"0a4794a56ed0b9c830af4b704c7fdbde2ac3176e811ae6f19508781c0cefdd26",9.317957166392093],[11238,"eb76907f85fb8aa2830ce376413c3806729af10e0dbb390875c89434f2eb71b6",9.917710196779964],[8913,"93c1c5a167a41125494560a2eb53608dca3eae7815e3b24f5cbdae8dd68d5fc5",9.917710196779964],[9320,"6fa3217231ca8f253d086d3b78f67d5e1525eec3df07b3181dee2aec5a60c1c2",9.917710196779964],[19832,"aa68b830f79f58f68697e81a4d4f4164df8dd39792145fa606e5a9c90cc47901",9.317957166392093],[1502,"5de4013dd008d6909f4f15d7b89b42128175e1b1399bbd5cb11d3489608a1af6",9.317957166392093],[4700,"2c48f4f1d642ec069ee0b9106d5f0f0c9c4f0637db1cee27350dc458f8e7fee0",10.052724077328646],[4424,"d17a47ad9f356a5e8ae852773ab442db27d26c3f0bad8eacc594188e458eebe2",17.96672828096118],[10087,"2d1e1c4f9217b73b639231694dadc41946f8aa44e0a1b2b9120342f391f7ccbd",9.917710196779964],[1967,"5532115cc3ad2c6d36d408e2348601fa8a6dc351e417c586e2e0b9907a693af3",9.317957166392093],[9884,"58d60016dcd6b2fbea6d40c9d5c472c09d39e0affce7b0c8b95465544c7209bf",9.317957166392093],[7778,"5a06d5471bee5ffccccb47324d14d982c0ee71c23cccfa48ffcd00fdc455f4cc",9.917710196779964],[15532,"c5a2d4db397c5cfd1f18a55bf12e8e362df9c3844dd80b57e9c3ff5abdf74b73",9.317957166392093],[14355,"fabaf38ce71a044256f7cd97414d5be3f4531df50f9a465c724f22488705468c",14.26256077795786],[14608,"3865b5a581e1dfcec0c37e427d15b79a51dfc28574829805da7f823bd501f286",9.317957166392093],[1350,"45b003853f0d2daf3ad6e5d5387fbd2cc9104509a68bc0ad85f3a996f56412f7",9.917710196779964],[14361,"24009fb011862a1be0be6213f790b0122e889d88a39b9064ff18d438224c378c",9.317957166392093],[6457,"6f08853ffed9d1b240904bd3bb6207e36de5364aad50998ffc14ee793879d6d5",9.317957166392093],[19708,"10fc2c49e7fa2a62c60d419a14f6c9ec7c06d128e739e1eec7d754476f668606",10.044444444444444],[9847,"88f3449e066f855129c1fffc4bbdc8715f9a6c3148087798bac8c54a028b4ebf",9.917710196779964],[9895,"23de2e3bf775ac8bb5954ece3339b97ba0f87183ca1126100ae976e8747ff5be",9.917710196779964],[19467,"1d9d5b40047c84bb1af0112d3d71cacfc70847e0402a6daee6eee7ae5a917d0f",9.647446457990116],[14807,"b15894a2b66d283070fb4ca3385640c0129a055a1de735c99f7f9ef6af029e82",9.647446457990116],[3012,"a4d9c081d6d584a5159f270086d2b80a2a784df0453bb17c28b892b8a8cd34ec",9.917710196779964],[10195,"b223deebf0bea254977cf1b6142446cf865e4523f9c417b238539c14a39807bd",9.917710196779964],[16312,"ec7fde6ddb72162d09d399aec9dbb9a377b07887ab1454f0ab974bbd2ee1c660",9.317957166392093],[6256,"210dbe9d310f984a616c721b398b35029239aa8d81511fa576d8f4f457cf5dd7",9.917710196779964],[17825,"366fc2b8f37234b81dff575f8b8012c2bcaabf457a681a094a243b7077edc940",9.317957166392093],[4142,"f70dc7cb73e3c5ada63b551b67bda7b95cd5e438b85aa265cb2b962ba657c7e4",9.317957166392093],[8447,"0b5b240cfe0373b85c0ae92ed245e52badf3f8f06ce1281fa5ecb1b481da56c8",9.657015590200446],[18690,"08f25459c190e399f5ecaa5c4eeca494242100120289d5813177d9e72c4dad2a",9.497326203208557],[313,"26bf331823fe282982ab1d92bc900a97a7ec21eebe78ced6cd59372fbf2ceafd",9.917710196779964],[1129,"d690716f8f4eb1d140ff2dd69f9ffe09d32505c8bf8e98ebdeec3394cf466af8",9.917710196779964],[12471,"3de00c43cf427ff272d89de1d1a3cb5358b03ad4e86adf1399ea1a3c981828ae",9.917710196779964],[14183,"caeff3b9700657efd9c014cd84b54f553edf1a49df7d70e5d7f9eca2ca69c990",9.317957166392093],[9458,"0117e90f11c4cf5c3b6715d988793842a9f328ce2b4a3feaed73e41ca364f9c1",9.917710196779964],[4776,"0b1f35f7ee98e7ea837232b1803ce1df6a93f1861280449992363552575689e0",9.917710196779964],[12766,"5e81ec884d4900e3b838c6d834299151fedbe20e69a2063f111a1e35bca320ac",9.647446457990116],[10782,"936d282ff1e76d7a167d4e7d9ac20bfdd53b1860f713163473167fa2df116bb9",10.052724077328646],[3851,"01f3889a0359f9a881652c31a7d4c5d9c7687c004d5688f4ec9d84837fe2b5e6",9.917710196779964],[5197,"b0928c70caf11e505c53e36609be95f24ea4bf21a158bc0845ac5e14bd8cfedd",9.317957166392093],[15756,"5bbe0ed54d74c760ddf18b771f406af7971310475e472c70d5b6f196c737446e",18.003565062388592],[9519,"8f3293a184b2e7a854a1cbd948ee41b553b48def44641399bc3127ede74093c1",9.917710196779964],[11369,"562419a73d38540948eb5fddd3af4d7638a1090742e9e68f5c67b0ad3d8f92b5",9.917710196779964],[11039,"853fe323a04aaa842419c0272326a3684e46d683f7d26c57484353736aa9cab7",9.917710196779964],[14154,"999a1b372daa11a5e82a68f58cfe519236b5566081c3b55c0a7dbfe976db5a91",38.171171171171174],[5323,"8937d72feaf536f9a642b53cb8bb59335c3d6ce890b8a061b3f8db01b52547dd",9.917710196779964],[19652,"e132afffcf4bb2f0005bf6be03a014f11867e0134112020ab3a70581b7a70e08",15.003322259136212],[1180,"c4c1376495afefa0cbe53d74cda8f4b4ec61c2535a75570af61759bcb42821f8",9.917710196779964],[9136,"b230a2ef73948121d2d0530db79aa1249b1c9b83964d58a88d62d7322eace2c3",9.917710196779964],[17146,"2e5b95ab97f312715bbd0403cf3cf811545aee1b6940be9438bc97f6b67a244f",9.317957166392093],[3132,"2700bd3869fef7d0c4a7a625f7e5f6b76474816497337d28a032417edd9277eb",9.917710196779964],[8537,"38924bd6ddd5d6f5e01bc621122e61e379140a121fc62195e1db521b15fbcbc7",9.917710196779964],[3814,"694ebc693dbbf13d56bb61a349bb25cb9bcd120d2abd8d105010bf0b4d69e3e6",10.030959752321982],[14785,"d7620390c8ec1e5d09b982a8f84e3f6357323c8c0b3a435e17e22a2c1ef52d83",9.317957166392093],[16321,"a1a56247c0fc4e2ee730f9f261cca0e3fa6259f47c358f6156a9de841af6a060",9.317957166392093],[16179,"5addf2919438ed18b226f6af59cbef0c7e1ce8512d0c75c0b5610335d2046964",9.317957166392093],[19372,"b92d1eed8e06cc60cb804742d8d48ee9e8fc0d79fb662f5d9adfb81abb22eb12",9.647446457990116],[6981,"a3def81b6532a419bb87ad51d11f024e9f27f4c340c75a638c3554f24cc41cd2",9.917710196779964],[19140,"70c1e06935ebe0ff02350445412e6ba4c5e0ca9b29a5f38d83f992756637de1a",9.317957166392093],[18859,"17cfe351b404d852b882fc21c60e2f93b912241c084602df375c2ab04b21c524",9.317957166392093],[13284,"a395855d1dd6908ecbff00d74ea3deb35c9feaf50db61eb3de1ad753e8d2f1a4",23.90711175616836],[17661,"2eec7c3f066e466e7e425ad3fb9cd9ebfc8080f5e41307bb44ef808ee6cbe943",9.317957166392093],[4612,"ed5feb0f2d26adbaa3b4b5dcdf51ec728d0bbfc6e3f2b186164eca4e94228ce1",9.317957166392093],[13926,"e11f79744e92577ed4f9468671df49fc6a0939be2a99052ad1fc869721b86c96",9.317957166392093],[12405,"f2db8a3272f0dad19a08095f5639eae02d1887a81a46087d6f5e064c051694ae",9.917710196779964],[2076,"991b83f19416b2032d5738aa9990d528c66023d052299cfd8f8f3eb5919e65f2",9.917710196779964],[14644,"64ac62dc18819e20bd35710a97a06b4886b058de83ef9e176e2ee7cb070b0986",9.647446457990116],[14535,"13a08b2c4df67d90df1ab4a41caf90252e2f3c2b40b0d5b4090dcb4df6ca8788",9.317957166392093],[4655,"ca8d40c8ee18af1604687684013bedda7d158e92920db1bae4d4907752ab42e1",9.317957166392093],[2042,"70ab5c2a05accd55667c8bbd9cb2599a2ac8705d1405b98b5ccac481318fb1f2",9.917710196779964],[9664,"77dbf6d69230c051e1ad17857ed8991fd850d6ec60955a478b31116944149bc0",9.917710196779964],[13789,"6103a3521b2fe479a8f5dbacf28fec19806ed9f15cd90e05bffdd3a3e8bd9899",9.317957166392093],[2084,"d09fb2edb8863cd641143f1237d16948c5ddb385d37e90c190162cd4271257f2",27.066666666666666],[16491,"dd69d577c4fb2b20e72bea0cec6d4fd3f39a50b1915ca622aaa9d65718e7665d",11.530249110320284],[1579,"8c77d9da167b21613670007ac682ee92a1323d06ba8c5140e3302436bedea8f5",9.917710196779964],[8372,"f6e71398b612fd9093d9e66d7ef0660099dc3486415af88ad32dfd80e948cfc8",9.917710196779964],[9494,"eed6077e039e29f04a5c676a6abb982e308bc7857aed15f46c61886609d3b5c1",9.917710196779964],[17285,"b4125e04f90186417533a8efec8ec3873946c32a2cc38edd9a7cb80b632a7d4c",9.317957166392093],[17501,"746ea8344601d64289eb2b3f56768d43d9be2afb6249f1c0ced73101d8d58447",9.317957166392093],[5690,"658db390ccabef205c1f574dd5c3480aa5a0708f164e6d5763175b182a6c19db",9.917710196779964],[12420,"a8ef3a3823be798188126f12a6af34ab107c9c23ade62ebe244ac91a411b78ae",9.917710196779964],[8683,"c189712da133491cc9df111613fe1b7854afc144e77ebb8756d21cd4a30fc8c6",9.317957166392093],[8502,"35bec115e2a92daeb0ae24a8ee4378d4ba5e31853816fee277633a76a3ed02c8",9.317957166392093],[12150,"6dde5d20653c27377bc8b566dccb5b3bc71363968d2458d82668ba848b5e5cb0",9.917710196779964],[14500,"fcd2953c86bc15325ffcb060eadee2ed4d18e61cc7c2764aa20841ed0c094489",9.317957166392093],[17120,"0a5fda8360771d1065c9c95fcda3dd4c1505309d2caaf5bc72ae502ac821954f",9.317957166392093],[2354,"d6bf2c6af08e9f62a09747212f9deaa27dce6266887ce9a77095ae8c452bb9f0",9.917710196779964],[15841,"715a19d55c34c90c9a0be11d837cff833cc471fc26c013a1236e0e1a004b806c",20.11627906976744],[1980,"52fd25735c0fe58e629406d815a410cecaea7dc364a47072663beb7a688122f3",27.317073170731707],[16413,"f90d0de1c0d3c7864fc2e7d3fbb63d5d238e64bdf5a3ed39dedeb2811e3adc5e",28.09964412811388],[3724,"f9cd1e2a7c9d000b42335fea85e1b1284bd3492176e83856647dd5c1a7d96de7",9.917710196779964],[14848,"ecaf52da240c45ab544703404c7cc14b41f078c42800e9e027dd24a46f41fb81",9.317957166392093],[8041,"ce0286deac8b1a7c50e86a16332b3d07a9e9d5b0ddec3afd0da01fbf85bb4bcb",9.917710196779964],[14252,"866eced0e6c725b302286c7914475b3a49d7b65671d42e59182abce2100cf48e",9.317957166392093],[3103,"47b489a1e2cdccfdbd5976ca4469bb90cf05441d39868b7e94155403211ba2eb",9.917710196779964],[1123,"2ef56081a189f627f96b5c1d7596ecf65541f2b8f036011631a699d7bf0072f8",9.917710196779964],[5773,"0f5471eaca5c249a714cd461d456652bf2d282719f82fe406554526a9c129cda",9.317957166392093],[2762,"cbece356d04a88511d21e043c810ea4ee5a5d5086ea85f772c20feed4b7108ee",9.917710196779964],[9517,"4de57caffbaba1ac70d03c9aac2b96a226d10801fed1c5e74661385a4fa996c1",9.917710196779964],[1303,"e4a4381a81b72701743cfb384f4e3d93612ab3a1dda6172d30fc54635e0b5cf7",9.917710196779964],[4745,"d068ecb050f959997b08c5ebc5bf282d81ec229f2f62e7725c67aefc22eaaae0",9.917710196779964],[17124,"c4598ddea13b6017859f42e45cf38e65b80378f498286e963b9917476a51764f",9.317957166392093],[9425,"fa1f28930b9d70d3187566571ab92aac7a8fe466ccbf007d4a055af3f6402dc2",9.917710196779964],[17962,"718d53dbeb51ed1b6fcd6e06b05d35174c096a26d4f21646d3c0193d2441e13d",9.317957166392093],[8554,"a9868456ddbf5ae7a08937b02d34496d0652373570db8d36c1ea4d657e35b1c7",9.917710196779964],[14575,"e1107c7c65ec97bf037f0a26b60e283aba8b84e710325d6c19254781ee6b8b87",9.317957166392093],[17177,"5820e6c486fd072c051a6a4854cadf966005c00054fad6ce7422b1c191ac4b4e",9.317957166392093],[11335,"47d185b9245698bca0c233c1bff4761bb860f6c92e15233b46cce2b7eca4b9b5",9.917710196779964],[9240,"049191b7156735aec76e6c33e645c20ac0772f7d8529e1015394b32a4ce22cc3",9.917710196779964],[8446,"fdd5eb37ebda21f902d410e0986bba5c60f07c9697a7735dced241bfd50e58c8",9.317957166392093],[3335,"9ee6a9b707bc11544149a5d6d2b6b89fce96da9d299de4b54f21242435931aea",9.317957166392093],[16052,"d2eb0e1429b90e4704d2c840b3acbef187fa569a09a5ef79f5a34eed503c5e67",10.051282051282051],[14230,"1906fc47e96ab2cc726e7117407aa8da258b7c04ffe27e60990c6887db25758f",9.317957166392093],[1814,"89b7940d8be51b6fb3e6a59eb6b2d4320c1a661bc2ceff068cea7b62d17725f4",10.052724077328646],[10921,"d2b68775a50a0aca8d43f0cd4413f6da8eba7f3f57cd325eae6f83fc5c368eb8",9.917710196779964],[18328,"3bc6ae307d6e0d64592e0060c2d15f6d73dae183120831153f3cd07a9f174c35",9.317957166392093],[14833,"25fd54c3ba4ef2fd4e07f99ee304845e91bea55ffedaf9f649263c4e75303d82",9.317957166392093],[16670,"d7775cb4f8d0e57f05e044f9c008765bdb84b646aea54f78cecddb0ca8984c59",9.317957166392093],[10335,"353b86d2c0702472baa679c853b066631736a8cf479fe2cedf4c030f0a421dbc",9.917710196779964],[9063,"0de24cd7349cc93fdf0c61de539ba40c3acf0fbbed50615cbfd19a8a219362c4",9.917710196779964],[19357,"6467c4a2b16a4db53960801cd27abf3a051a0c90d955d5498198399f93026713",17.53846153846154],[5421,"d9d25f822afcd6d24a45db7ee687ecf8ac642765e849e9055143ed005568addc",9.917710196779964],[8230,"6818c09f907e1bf2a78401cab966e2af7ba0809a5087e88ba9e1ac5d449ebdc9",9.317957166392093],[12089,"c21365ab9b449040d42a0c77ed62f2139bfc4aed24bbf3e581a93046830bceb0",9.917710196779964],[563,"60f72e02c802ff95ca9cc000ff60ceefb22181bcc73a74d36c2aec41a1992ffc",9.917710196779964],[12212,"8fd98e795fe907f42f30c886e1a2b37261e9a049f4c509939f4a76d199f002b0",9.917710196779964],[9135,"761ba23b967bcac6104255deafbd26531976d91525de0c1741a289f7d941e3c3",9.917710196779964],[13662,"0a548400f41f612a1e4edc9f6e0001b3161715436de19dc9f483a59679ebf89b",25.88643190205109],[4086,"5627e701e91f350c056d030883c9375161053243354be7c282bcf07088b728e5",19.259580621836587],[98,"3eccf0dd2bbbc3581eac1cf99d652bcc3ceaaf51fb4f271e61ed3a8f0b5464ff",9.917710196779964],[13900,"6f35f6fe6ce0dd1b9bf71221e13b9dd0b3fc53cfef8f3c01e015d54191ee0897",9.317957166392093],[10187,"82645264545b9a51fb54203f45297821ff9e88cb9d66b43a43bf540789881bbd",9.917710196779964],[11975,"b13365372e9412ba82893683c5e3ee85e0d7ef588b8aba83243e22adbe4678b1",9.917710196779964],[17940,"8db2e3ad5bc866a696ba3111120180503ab976ec8dd34e9115ef0776201e703e",9.317957166392093],[4819,"f29a6b5eb1b0fdecc8e2b9d5852783ee03fd36cbcc352750ce5b7950747d4fe0",9.917710196779964],[19475,"66944caa1d4cd8a241afeb3ececfe1378183dff81bba402fac1d5e4b3080460f",9.317957166392093],[10042,"9370c7359da68572ec881d3e8c1e6fe19f4e0a0e5819f66dea2554f999c115be",9.917710196779964],[11096,"8e655229babda57f51a0e56d79c466b3c360f9d4598fff0b4381c5ed86c045b7",9.917710196779964],[17499,"e98ac78ae7e93b625ee30bf7d73dd9106d921c264426a8d045594c342dbc9447",82.29255319148936],[7764,"ad48185d76f98e314fb608fb6ca6d6133ac6f3c87931d09bed4822ddb68a0dcd",9.917710196779964],[16591,"2e3ed67ae1c898b7c5b578ce55741e58386f6f09b56dd3880dc3348145d31d5b",9.317957166392093],[10689,"c0bec8c36dd0b666a034043e10f6b348a37731efea4eede92f9f3494c09813ba",9.317957166392093],[7169,"b152a1c417d1b309ed10d2c750dddad24cdad31208dd4833a79e9fcccec1e3d0",9.917710196779964],[2912,"70e0533dc0c6502ef29849fb6e4bbc494a1905c07efdefb2283502a3537bfeec",9.917710196779964],[11520,"183df26d4b8ebaa1841762e8eda24bd9faf3a609d8c368fe5e0c3cd61c6264b4",9.917710196779964],[5330,"0183d1584aaa4dbb916983c5f62da6e0fef99ecddeaabf905508d9c3b4ff3cdd",9.647446457990116],[3305,"04b358a7980e777a6ab52fe3417ab63133c7eb302144dcaf139cc017d7a558ea",9.917710196779964],[6062,"b64661dd520dd77e501e0ae4ab610db6e54d28f29818e5a77f81dbc09fffadd8",9.917710196779964],[6030,"979b119ad5f749c039ce16c04ea6d5747e5334e9df09bdc459b946eb58b6dbd8",9.917710196779964],[580,"b2eee5611d87fe30fe1db30ce04c0aac3c6fb33ea596576b9b1f2e2448e40afc",9.917710196779964],[9271,"c0ce5a721739b50dfe6352dc26dadb12a440fef8c57819a99c7f95ea6d1108c3",9.917710196779964],[15599,"e8329d14befe457124a55c1dfe778e09aeb5267dff67eb2b5589941162076871",28.097560975609756],[2006,"5adf3f3408ad5f7dbad013fdfa6dd8cef9eb7ce5f7bdb64f92a3cbbdfb0ffef2",9.917710196779964],[11873,"500454843976b06fda9bf42b948700b021e229133600bdbadb492462c3a33fb2",9.917710196779964],[3311,"50113b1fe27fe682740af77c92f88420e9655a162d74d3b19fc8654a15b34bea",9.317957166392093],[9048,"576256cf933d895be4e8769448514d039bf03f634b8661fbe6c6dc647e4f76c4",24.557894736842105],[17519,"4d9d8e9803c852254627959abe7bcd7d712edf74d22597bf0e197c45c9782b47",9.317957166392093],[4119,"4b68ecc1c288b6efded964c7031d43158c4bdc349366517d48754ea5b781efe4",9.917710196779964],[662,"fb0bd7f3b766c6d1b5ddeb433cf35f70d4c970236a41f557b8b58466358f80fb",9.917710196779964],[8459,"dc7f10297dfcfb31e1d3bccbec8c3ffabf9a42e185505207a2df9c4cf2e043c8",9.917710196779964],[16959,"210764342fc671ce7b483318c728d070b1758f93fa42f15006ead3dd9a78fd52",9.317957166392093],[3744,"c99b6e24daae049d882d63fd4fdfe78a802e68581509f048eda332b104e947e7",9.917710196779964],[14934,"704066eddd5282e10ad162f91a97c55fae38e1f7bd2a38ff091a49fa7de11f80",9.317957166392093],[15316,"f97019ba42a15b8839d4ccdf174148ae261dcba920fdb264841d3ac25ca10478",14.375545851528384],[18378,"8d79cf560f12c77d36a915be8d3574054b1435288036e11122a19fced7af1534",9.317957166392093],[7409,"1829c7338605d81d24c49d19d1b2196fa44d56e008bf3b0ab3411c14ce7957cf",9.917710196779964],[5602,"3eba29f722517f9c1444546ff89a25703da74c1daceb541b9808aefef52f9fdb",9.917710196779964],[5939,"0b6ce927869fc452148777b2a78f463802d5f4279d0033e863864e03bab674d9",9.317957166392093],[13597,"7bd575956343f6f87c9683cab646b298d48867bbf4a6a2344cf319fe3716849d",9.317957166392093],[5731,"2937c14c8a83002f7cb6dc81057b3325d5baa898974c18cfe0fddc1c9880e1da",9.917710196779964],[14921,"d70f163e0812b9782d6bad7dead3355a46d2f5679de0ba8e96df5a10c6a48880",9.317957166392093],[3425,"0d3e988612dc765c4e90295cd963e6f8f165c1fd020c309c999c5dc6e2c37fe9",9.917710196779964],[17322,"ebf38157abc810941a1fd5aa943d83e4fb320fb38a026d8b40922a17d422754b",9.317957166392093],[18229,"5c0d5f7b15f8b455b67f53891709a21ecdb741e0474fa35ed32b18a163b35c37",50.01961553550412],[13359,"d6dcba54b9f070ce4df7fc46a607080bc771c5e1ac3a5429f49dbd01195744a3",9.317957166392093],[8407,"527110a85cb5c35336585ebe956d06c44cf105bcd0bcafe3431eac3e9f6b91c8",9.917710196779964],[12869,"79365695053e57373de40601b412dc137d1951ad4c85ffb61f34af34419771ab",9.917710196779964],[13447,"f4db851b96045455ebd8da2ed20e51d3258cd2824702c5a62659131403e617a1",9.317957166392093],[1978,"f65ceebddcd4cd71876cc90190913de5d038ebf0489104e75f20ac6e02b523f3",9.917710196779964],[4652,"3b557246310176dca2c255efe609d4b0dc28a31f7c0c6a0ecd406721451349e1",9.317957166392093],[2064,"858b09993688ea7da448ee5b8ab52ae4dde312edf177f5419c24d51943ed75f2",9.917710196779964],[5445,"f7c56b3c23111db1765e8baa49330dea0ef3e77ccc3616ab6b25e823b70781dc",9.917710196779964],[13849,"6dccbb687498a01316d207f76e6455e28ee4f27b2734ccd5007491b81add6e98",9.317957166392093],[6500,"8bb6b822f3bbae4bc29974a77b22db675ed714833a1bf4210186fafb1ace76d5",9.917710196779964],[19633,"0d5b8efaf5adb33944ffbee1d92070048f2df5d715dfc5cd3e8835ef886c5d08",16.97508896797153],[15208,"e2b15b5ab08d6bf7730432b91247894193e9d99d12c9e1949a7c8535f465577a",9.317957166392093],[5273,"b38171590931276e186da96d83d78e87e1fdfb92a71cb4ddff3c1b253faf90dd",9.317957166392093],[500,"013b01039c6dbce47d4fdf51903050322de453ff65622f0077bc8c389241acfc",9.917710196779964],[15559,"8967de171efd32c5917a532ef0060fea019187f80bfcf903eb3a1a1168c19372",9.317957166392093],[6606,"badd8aa8c729a37d2e7802f4f8dd607bf34eb7c0c8ca91ba8cfccdaff8e49cd4",9.917710196779964],[526,"6d033b5c1f4586373afac965c90c91202da8359a7daea1f4c0e1d15a36317efc",26.09252669039146],[2280,"dc89ea735a2152fa1a12f6e5a5a8e2de752334a83eac962e1a50b3a45b101bf1",9.917710196779964],[19442,"c2f376f09586ba8ed43831aa9c12c3ed039db4c309799895b3d5d13cfb500510",9.647446457990116],[15484,"a9c99958ba37eec84c82f8b8fac5ab1ab90d4c1191d52b7949232ad509cf7374",9.647446457990116],[3214,"17be8d6ec876eec233cc94165d40a3197063ce7dca5c2985f8beece65669f7ea",9.317957166392093],[3789,"2b01ee40bd7da90246b10a4869a0487ebe4f72e48069d37997a1f9efc22d05e7",9.917710196779964],[741,"6c627e8f4171041b8f1b80accbf3b039a27ca5e8a4278f9a3d44c6fb47d0f6fa",9.317957166392093],[3160,"387f0e461484752b97854d74c23ee5f0d2b8b5e294452c1c0897d3678a114feb",9.917710196779964],[5744,"b2bc6bbcedf6a9e1f5f627582a039bc8ed49526a20111c1097518f18b227d0da",9.917710196779964],[7892,"d4a731b2e88fd80761330167bed35d14250157e4ea0de31489ba0d7699904fcc",9.317957166392093],[9118,"a91773e9ab376ebc3ffb137d7d513c046a471897ebffca82ed530833fdda08c4",9.917710196779964],[19444,"e2a184b5990939d1960dc365311e32da5d1a78b894a09bc24ddda88840a2f90f",25.296310384176493],[271,"35106c2ca3ce3c3c2d729cc40adbc2874cf6f3f02a02e1691d88ec16de6022fe",9.917710196779964],[12599,"e9c514eb25addb654b7bf8d369f789419995ebd71d85f6c4a2cf4287528447ad",9.317957166392093],[3680,"d550f67822274b809089366538da60715d7a9fa2d3d3f03b54c9456740dcbce7",9.917710196779964],[7083,"369f06aad6c78216834276394eabc9b8b1ca826b22ee37b225e1ee49957171d1",9.917710196779964],[18046,"d707ebe3ab2656f6bf4d4e1db63d7661272354595f7688ddc4b90c60ebb0623c",9.317957166392093],[4411,"93b0a942a6adef9cdf9c5b7d3db482deed9f87e747ce014756186dd6ba7602e3",9.917710196779964],[3671,"35a7adf238a018198ab8c4da3d4161555cd0f81cb83450d51f28c8ab8baacae7",9.917710196779964],[9890,"217df805071c7b852792e8f9f82584516b4ed0b94e70edccaf3d169db1edfcbe",14.50943396226415],[8602,"cf720e28488813e20fb1b8ac80ec62243c4ed599c85dcfe949383bff428d6dc7",9.917710196779964],[6535,"01d00fe90e63bac9cc884fc58ebacdd3dc0a6cbca193e6dc324d408e529828d5",9.317957166392093],[16148,"e84097b9b57df70edb2639dad6763d61c0e2f52ace4c0b7bc9db42ac1da21465",9.342789598108746],[17904,"c8e03a71ce4ee4f3b415459a7bc5136a277200e76a296b2fb49a10d1b74f243f",9.317957166392093],[6218,"2c2e11aecb575ddd933ce7480cf7e99b8599777ba967ca1cf59c08086b039fd7",9.917710196779964],[1300,"1b4d9f27007d5c1e6cdc0ef2077c151246120c0776d7c9aca01a77c6c14860f7",9.917710196779964],[11136,"9ea36978f14a1e6e2c8e6e7961e753f61ef1f714f5cf6ecd96115b417a4c0eb7",9.917710196779964],[8787,"27351fc5b87db6fa2b0c6b28bd105426e0ac8ac18320d1bff2f8b53f7c1b26c6",9.917710196779964],[17754,"0cd233839219436af2b15c2201ac5c4ec2ff49471b0334f6a3abe6dec0522842",9.317957166392093],[15075,"bf658ce7e8f3b4c92c92f2cf9a30e61b04eea5ca551bfe6191abba7a0e63207d",9.647446457990116],[5236,"117d3f3a9730909f5626c1cc38f7a40df8cc37f9b81cfa6fc4afbecaa55bc4dd",9.317957166392093],[16778,"7d423e7e38760d907357678921348eec8a05982882a2abb9802106eeaf61e356",9.317957166392093],[10715,"82329b94538fc8a7ab73b5ce8fee41e40c336dd641c3c98988a6e51b338aecb9",9.317957166392093],[1463,"d68242bda218ed39f6bb66a9445b3b0dfdfd68089cf1f6d9f8a1208de9cc6cf6",25.956989247311828],[7286,"6eab19d1944d4c6ff2ada1519b2dc0e342872436286c0f82e93c637ecd7527d0",19.0727969348659],[732,"a88bbcd225e77e9937b503ecae54b0c50ea1bc12b6ca2ce5476405747a0203fb",9.917710196779964],[1306,"bdef670b12881984f369b47fd1184d771ad0a1117a34574474b06fcc8ea758f7",9.917710196779964],[17789,"01b96dd38c16ac85e083324f65fc088f992fd90c4a3f37e021eb315fdac88841",10.052724077328646],[9138,"be23348fc5079e929574a94e351e04bdaf8d103809b562ee65a345adc229e1c3",9.917710196779964],[2329,"42e519ead126aca07811a0b25e35e9c46393eba2b46cacbd12ea23458f04dbf0",14.95187165775401],[6915,"045145f290acafdd48e4aa6f43e4bca526121273e4c79d604464e909b1ab7cd2",9.917710196779964],[14745,"8d3e7ce9eee735c6d0d1fc032345a85eb6c2ecfcbf53f93b90b0e78ddfb1f783",9.317957166392093],[10490,"0f28309f07932d40ca3d7be81eb65a1ca96c91a86382c576dcc125b1861937bb",9.917710196779964],[8698,"9d71c4f330a17474361e6d74282c5cbe6cb495e1011777babc479207b7ecb7c6",9.317957166392093],[5159,"dc8417be85c27ab3afe5c9dbc8e35de7951d0b5fc0711ce162209e7373933ade",9.917710196779964],[13328,"cb5597c1907b0fc6d32197e6ac59ee318f9e8926b96a4f1f88219c532b1d19a4",9.317957166392093],[772,"14af83f1b284363da1b641b20bb95ffcc07433bbf8cfb94d1f6db5c1d453b9fa",9.917710196779964],[4337,"42f2fcb6e0605a42b0f73991071d1c8580733ec59833a5fdb7975ce1870d84e3",9.317957166392093],[2190,"466c0077f78206ff0ec21ccb191d45b094878dba696628632c5e8f43f6c49df1",9.917710196779964],[8607,"4b31ce607dd15a1d301e7d9d6b7a9eea5fa3013e07753939b47e3f3fca8f61c7",9.317957166392093],[5401,"12756011b014dd08ff23da408186bcb336139e7a906e08a88032d732ae6fcedc",9.917710196779964],[9931,"644da34ff8f3547a2f37f11469aff90e26b717533eed440ce42d72aeb20dc4be",9.917710196779964],[9632,"9068c305ecb6d007bcbd41b9e2da4999ee52db70b87978db5bc58b25adbfd7c0",9.317957166392093],[17481,"77588255f580e5a5cd7c16aefeb5edb63077e6cff47ef113a1575d6f9b690e48",9.317957166392093],[5333,"274884686e2608052e4c682c55b6ccaf973dc5e66345f115eb8a9d5356893add",42.05309734513274],[7046,"2f2bcd918c1a023ab1fb11f18e22114a036d681c832b0b2770b6c3f5053bb1d1",9.917710196779964],[10709,"37995672f397cf8b97e818584a7e81fee36ab8728ec9de6e6c82cbf4fe6ef7b9",9.917710196779964],[980,"159a10f029f00cb9b4da6557b8478581b1c1d99ea8e00cc236f46cff4f5651f9",9.317957166392093],[9844,"894ccabecfdb255ca833039be5295ba7870c59d4b09b44fcf9b8d0cf3c6b53bf",40.71301247771836],[4806,"3fdfca9ed57bd23776a39a83a3e83310a5ef8c8c99114d33ad9d8858539a5be0",9.917710196779964],[19647,"c459a3f766ac29180694e0d8b966d41825824528a467dfc002df2f8a663a2008",14.820097244732578],[18853,"e28cd06d7b2400ebd4a94d1f3d42dcdc0031eb02910754109056f7e9a7cafb24",24.296511627906977],[8117,"f2d3721fc00c08708375f117928f25659b4e6cb778942a1e03db3d05819ea3ca",9.317957166392093],[10424,"6f83d790c89742a3df55bca0476a951f19d23676647e718abe609abbdd39a7bb",9.917710196779964],[61,"d7c0cdf76639a402b3568988accbe85a24daca174be3a6dbab15cda6b5ff91ff",9.917710196779964],[8426,"d718969c6995107f8133e9f3ae70506d0af848934e15a3c317e6426d0c6377c8",9.917710196779964],[6293,"29b217cb9a89b3a13c4e422108bca27ad36b89989b15b2217030920a914916d7",9.917710196779964],[19356,"21350671981f4c9e20a0907c7a930b5bd95557b08263b5ba007f01cf8f1a6f13",9.647446457990116],[18173,"856fd65a42ca577e009806dd4080781c2be5e9945b74de41ea4113a0acd6d538",18.130434782608695],[4665,"443393894a2bb7f738f0d7b542d0c66c0c2a94b0db94a3339293e9df0d0837e1",9.917710196779964],[9175,"65128addeb555601c688c4dd7afa1164ca33bef0860c3c1e3c98ba47e37eabc3",9.917710196779964],[3821,"16177ce0c01febd53b10562767b265a4fb2f3693e4e2e53b368b17a0ae76dbe6",9.317957166392093],[6076,"bb7a0b297fe793ffcdabaf9e566c650ddc6bb36dc309f66c787441e94eb18fd8",9.917710196779964],[6405,"7f8bc070f78605a856928519979f4b361fea481bb0aad5149deb059520014ad6",9.917710196779964],[2021,"4331d8a0ee1fbef1f1a88045cc095302e5fd2fffc6f9e0fc806222b08fcad0f2",9.917710196779964],[13011,"e3fb38e5cf85284025505ebb851bc7454adbd8ab680a6731a6365ecfc37481aa",10.052724077328646],[17720,"fbe7cd2cd829f6dbc7da8cddb793f3793530a9db5c3409989b5f764ddba4c842",9.317957166392093],[5362,"c1806b6a7a393b9d9924b958928e36bbcbf60ded01ef6712dcf7cd2237e412dd",9.317957166392093],[4815,"db83efcdb38d7c93a4dcd587c1ceb8229039fc2d0b845679ba4e0584b00754e0",9.317957166392093],[11529,"8816f390a70f07673451f6a9dce3f75532b818884844142c42fb5ca3827c58b4",165.6108597285068],[19511,"83eed36344c2d754fe59e3ed5443fcde9d5585e6106359df68376e36cfc4f10d",9.317957166392093],[11264,"e2b24774e186e3eae94b38f3d24b8ad60da3d40e7f4edbc4975f50a8800546b6",9.917710196779964],[1364,"2e8574876f6647820ed2345ea29c6c400131bdcfb6b8526b4891106f1354faf6",9.917710196779964],[9455,"4e882c4d4dd459d13f922f8d4c814892cf881d6d9b678645fbe840d079b4fdc1",9.317957166392093],[5491,"98e49f6cfec575ac81acc98f77afdd0ddfe40dc58d28c9bf2b57dcf54ed844dc",9.917710196779964],[6772,"3195f70dfe10219c0e88b5c89cae1ce67a80c8eb5cb81230b00e0fe5118978d3",9.917710196779964],[9283,"9f8978e4dc755854fbff3bd0d3af06505c2022144f832253d732dc840cf4ebc2",9.917710196779964],[15279,"92bb643880bc356736571aafe7834d911dd088a0be40259c23ec48ecfbd2ca78",9.317957166392093],[3580,"6a138fc0b2071dd92a81baae6d16577c9e040c6f9e92b409be24bbaf29b36fe8",9.317957166392093],[10350,"82b38134195185fd8f37ea3dc5d83a59833b72bbaa4dbb12bd5dc9c3a9850abc",9.917710196779964],[18122,"08828cca76a0eeec163f6af637d2a75d50582317387188ef5b6ad4084627693a",9.317957166392093],[16550,"b01a126c1d5124916bc2bc83aca397d47bd00b9ecd3a51c184fa4ca2a2ba025c",9.317957166392093],[16129,"3e3217bfcc13c5df524bec370076ed5468d8940e368f8e75918d93d28bb06d65",9.317957166392093],[14055,"2c76c4e78b2403b0dc44c0533223650493249694ebdfa2a4c03bcdb80d2e9193",9.647446457990116],[7223,"98e1dd9c2ae843338f0857bcee0a97c260e2f1e8919388e04cccfbb58ea681d0",9.917710196779964],[12183,"d292ca5c0477f26fb671c5d520e7781814fa00034ea1c1d0edac9b93015928b0",9.917710196779964],[1483,"f3a948608f89a30c38c79f6896c70f6f1f8d0cbf3808fa1e203eaf7f59883bf6",9.317957166392093],[17181,"53eefdfe4ed9f775def155b0b61bec02095563d8c785bbf56182b4a4f304344e",9.647446457990116],[8408,"baccd6fb02be17d057d6b46bdcd1145890f1bb95fe686c8731ddfee7ba6891c8",9.917710196779964],[11246,"3aace3ba59120fd5e914020147dee9470a562486d101f3668d8350efec8b5eb6",9.917710196779964],[1893,"9e161c58b85e2ecbdda02a7af0d9430b041025b655115084bdc10b7a3733a4f3",9.917710196779964],[18066,"1629460205092125c89be1b89756b5b2d1d6175c712f9e8a78626db69812d23b",9.317957166392093],[2286,"47834d18a6f7df4339fd5078060a012720e29f0f2e03e3fa41ade96d0c2510f1",9.917710196779964],[14523,"0f941d50223b47273bb3f3b07d5330d77fee7a4956615789523d0de9a950b288",9.647446457990116],[2549,"f0c233a5f181833094572066227eea6c91187283d7d3e0867c235985b4418bef",9.317957166392093],[9075,"8c39c65e0b144b49e6a3f74d81f0f0bc4ff352ce869ee0675453d66c967e4ec4",9.317957166392093],[2771,"e4917d8b1bf1c59a45b475187c82bd14d9798d46696c79935d2acdc43281f7ed",9.917710196779964],[18909,"b729e9b8ee44fa11a60454a2fffcff7e88eb830380db70a00cbd8399abf90c23",9.697426239799121],[17206,"07fa4dc644b614a87978eecd667c05ea49b52c6802d154ae3283947f24ada34d",9.317957166392093],[12304,"a4bff77c14a573d0b00f44f16da0a78a0f20c723052ca8c5804ea58a5ea532af",9.917710196779964],[17920,"f7803dfc1bb079609498cd09040d3bafef354cff2964b6166dae0376a5c4df3e",9.317957166392093],[7006,"6bc7f9922a4aa50635a1bdaf86b90408997b779f9fdc4a9bbd1bd8cef1e3f5d1",9.317957166392093],[5428,"8e662d92ce040f8b7fd738d3da9b4c9128c70c0b1d3bece21697d16814619edc",9.917710196779964],[15810,"4bd02c1f0a6837d9e1d10c2cbc99b17ab5c0ac0ec199bb9e1a6c4560b274316d",9.317957166392093],[17864,"6b7ad11926fbf7bbb22dacf7fe77d480664d561a1028d329c24c862b5492e03f",9.317957166392093],[19026,"3194a3310d8445663c7aaec6ae48ae4426106788cf068d83f30c1ca67c38b21f",9.317957166392093],[6980,"73aa4bb06c43c938166d792ddf742cbbbd00e73f12a5c802c77decfdf2951dd2",9.917710196779964],[7527,"3eb6170d0168b2d5fd102ceba55f5d06eac49309a94edacb02233b2dda689bce",36.08275862068965],[13138,"1de3c364b8fffda18d83c59dfd3414fc1cc047cc53d61a6c1975850de26d36a8",9.610983981693364],[4666,"8a925ab1d9939ba9931d8f265c4f61efbc4208949a2490c6991354b1620334e1",9.317957166392093],[6433,"df7fb2aee82cd6faf14e48913a90494a6173e84a0d32441323a486031fc70ad6",9.917710196779964],[2834,"899f23e695cc2d0df56630dc1c73874e6a88ec408fea7cbfbbddfc7e2afa70ed",9.917710196779964],[1140,"a0d7ebca7cdcd4fdd279d3089f16ce623a2ffca53cbd25ea848179e368975df8",9.917710196779964],[12754,"ca734ccb2b40ec255a918f6bba36f122891f0de888ac8189a1809435aa7c36ac",9.917710196779964],[14222,"31a89e1c52536fc3b2f0abff0863ef525a06cfba8e879f4b1291ab2a50679f8f",9.317957166392093],[3190,"10b01741a014646cd7bac2b3297df22ac89e848ec9f381e11ca9d7225ec417eb",9.917710196779964],[18558,"95affc8496474885d00a5c2c474bc0151e77ab2c57763c6ced0cee903b6c3e30",9.647446457990116],[19727,"195ce15bb0d4bc35ae35ed79a55357aaa863ca1493f88c498b709af939b0d305",9.317957166392093],[15016,"66f4e63992bf182537b8352ee466defcb7454dd564ab0a867d5a82ca675d0d7e",9.338112305854242],[15963,"53e9f06b78203b9d62fdf5497aec45a6ef6a8e9f01dbd1079744c33452658b69",9.317957166392093],[1706,"35fe8da8615fe84306007126dc9296326d07a42b3fa5f9dc89aaf0819c46e3f4",9.917710196779964],[5031,"0e60fa09766d5de97188aabc528110d5e17538c5170285081a7f9461abb8fcde",9.917710196779964],[9798,"0ce8467402974c764b2e295b31379cbaa1765ba8da52e50fc103fcb63d54a6bf",9.917710196779964],[17345,"6474e9717e7110148975e3c42ce570f8573b587efeb9ba49e2abb1ccc7e4f54a",9.317957166392093],[9128,"70abfe169390d396766a755b4e5e71105e33b2ab9a734b8ec8cb46f0ff8ef7c3",9.917710196779964],[19435,"bcb178bc621219d10e37b8fc4d79285cb5298035df2e014c21e88d79169c4910",9.450184501845019],[2231,"49d823d445d079a28be389214c63ae7e59610237f94bba16b84ce930052a55f1",9.917710196779964],[7944,"28df68fbd08140a5b4a25c4fd0db825b493f2859f5af303f49931f68fa5ceecb",9.317957166392093],[12332,"1f893860f06d1d5ca4be5cb048ab9530710ca53e7b5fc00113dc7a6ad74c05af",9.917710196779964],[19661,"8dcf63c6c626f873799b3f27f7f1ad15d8917efb45008972e158b9c39337c207",9.317957166392093],[5146,"a6efbfccd4de01d1a7cd151ec76bc8169fbe1b8bf5e2eea42b74db3ef88f52de",9.917710196779964],[2858,"ba407691ae6134419afd637d4c03a752b8acd8a3d0d1a8ff762efadbbe0d58ed",9.917710196779964],[18111,"2debf53c26333bb9a3b2de91af52135b0513de0e2dbfeb1d35c60666f67ea23a",9.317957166392093],[13587,"c6ae35250caf7d1a6bbcdf3d1e1be03ba7c4c02acc823ad666b0950d50c3c59d",9.647446457990116],[6325,"e94d11f0f0dabbcfe15930080179ca18542b1388473cdcad4ee8b2f8d38ccfd6",49.64383561643836],[12303,"68e4456145061482b5f9cefd3209ac7c6093c72197f10dcf367ddd2257b032af",9.917710196779964],[18614,"366832a88857f440b1a140862608e131645100ea17470621b2b2ef9e9c0b4b2e",9.317957166392093],[8871,"40f6a215a1a8f0606998502f7d2a9072891462edb704ecbb102844c8c7289fc5",9.917710196779964],[17956,"e7c75be5a399ee858e44e2a5fe974b8def4aadff560b0bae9bb42429cc3e043e",9.647446457990116],[742,"9316c2d175e4d3ea9c034f3d21c04ae8e7d522f542b7b0c2238d8a78be28f5fa",9.917710196779964],[16813,"0af19258063af2dd5b401c6f2c69eef3c59c23a97a23190701b1ad4aad39f455",9.317957166392093],[8882,"f06e725430fb034911056149a0ab12a124832de0a1182ea3e88dec9ceecb8dc5",9.317957166392093],[16688,"c216777b22d7ef8f96502097eaee31e19add7bef05eb4af1774b8ca9e8aed658",9.317957166392093],[4275,"16a795f75739098048f075acf1b7b718626d5ec9a7fad34ffd65b2c7591debe3",9.917710196779964],[13210,"7fd5134e66d741e879ba5d813fac64b4f44c902c14d5aa51615871c3f3fdb8a6",19.2],[305,"2379dd99ad4d52614b1075be9606264929278015f2a17c507e0b6ca73c7bf0fd",9.917710196779964],[8399,"d99a03d72cac6ee93f1a9e7527ac19aa242d0877a9f61a3af2100c3ef62398c8",9.317957166392093],[5033,"62e8ac343a1509c0f54cef115d331bb78fb920153af66a521cbad50f7c6cf9de",9.917710196779964],[9076,"e2e44662a526b76f2b379bf2ff85132c1d8e287b34f9ae45e442e9a3f11e4ec4",9.917710196779964],[1953,"d440e39afa0c8007dfebef8a5e1549550c68461b25aaac177bdaf92834ea55f3",9.317957166392093],[18142,"ed199f8d3b093be19a16b813c26df5a56a976bfc684f629bddc43fe0eba6e239",9.317957166392093],[109,"3f9f8ea2070851c6c6a7286518f03435414b21a6adb128b445ea823875d054ff",9.317957166392093],[7324,"8106d317970f5eb9c83f0f9b384ad365dd5fb8170fa990a0b5e998d75026e8cf",9.917710196779964],[1390,"46941182ab864c74f300f3834575ae562a23a495804b7c3e928b6c3dd515d6f6",9.917710196779964],[327,"8c829af46c0ec390a92a3f7beb1423505ab8f7e8e94074ab77ad677df36fd8fd",9.917710196779964],[412,"0620e7ef10887237271167709154701c61ec18cc3b78dd30d369d0bc9bb748fd",9.917710196779964],[10960,"15731f447991589c7f5cb1cffbfc3284632d8fdcc1c761f213b322be587649b8",9.317957166392093],[18018,"3b6eb80d4c4e58ed068c99ab82b294f1a06816a962f8a91a283237bda50ae43c",27.87443946188341],[4357,"420a8c97347233e0f1d2fa1cff2e5fff7896db5bb73fa3cae6f13c83b30a5ce3",9.317957166392093],[2747,"bea646f5eaf6b33c21d51bed60c68e3875a93a3951c3262c52b1d6cff0c523ee",9.317957166392093],[17770,"4b6873f8d86cd4af33389db521ad377aa90df60c1f16e0fa06dbb4fdc5e1e341",9.317957166392093],[7858,"693667215eef88f7a1d55fdb836672bdb3563c0817f4b3d7ef3d721845fa7acc",9.917710196779964],[2320,"35120e2fb776288ca2e3c90df803a49ccb39144d2e8a62144df2df431a27ebf0",30.425655976676385],[10333,"13aa7dd8d5355af2ffd2dd0d6f49c4d70e3f7f9e37b81265c94ac476b0191ebc",9.317957166392093],[3144,"e2591be0a3b6436fac769eb54f8f7d624093f97a9e0218366f77dca175fc68eb",9.917710196779964],[7837,"59f1f2b8820df61929e94d78a2f7ab6071c9259892d4b55d87d7821f131190cc",9.917710196779964],[6429,"128e7a8ad39b31ef26efe822a0caa7a483b22907471df2f5cde7480f35f412d6",9.917710196779964],[2969,"8c3b5b6013018308e659c9e27c0c887e3b1d89afbc4e3b8ca9397d10af4281ec",9.917710196779964],[1490,"17005dc27a6bf86a9e078653c6898deaa94e9f321d9b50905f2b4f66bde42ff6",9.317957166392093],[11177,"3340632aea7614584f41b39b49d7163a8d013e73a270d2e7839ea42b6743d3b6",9.917710196779964],[9569,"f5dee624ccc36459fa66ecbc9e9ae62fe8b53a6912e22ae52acb6d0ea80d31c1",9.917710196779964],[11902,"d54acccb903866d8bd88f04a453df5ba81c5f32768ab201997d6635d804f06b2",9.917710196779964],[2097,"238b63ac415686e0b7f2d98844ef10bebeb1a488bcb747c9fcaff6183e7544f2",9.917710196779964],[16894,"e9267d362df835fc04d6d4892c55a79335e6d93cb0312926045b744230a05054",17.005347593582886],[4778,"3760269578bb1d3e0fe100d7c50a4dbc106a8c4bf7632ad8dcee480f1aaa86e0",9.917710196779964],[9848,"b0b66f998a2afe53ff51848f3c7bec6a40237f8af8b0877a8b10b3f08f764ebf",9.317957166392093],[6492,"6a179993e1bd04da4d7c00fb4b8298b3887ed220aef29f64cd8c317119fa8bd5",9.917710196779964],[8034,"d7d97d8d861c3975516c962ae16a3a40f2846bc27988892b529f76d4a1235acb",9.917710196779964],[15305,"5ea06c6adc8a9dde846e39b109bcf9281d486b427551d198d8aca076e9814578",9.317957166392093],[11922,"37611d79763099c36fb289a0b1b87a0f625f0e4e23d1c61663853378f680deb1",9.917710196779964],[5396,"cfbc62d7739c59fd1c438dadbb9b2e8988142200995780e5096e84c8a6f0d8dc",9.317957166392093],[7392,"2b47d9e77cc936d3b9f0aa81989ae363fad9736d36703a7b6439d2c685fd77cf",9.917710196779964],[3697,"0279133ad88701a009d3c3598935a4bcc81c62c9e74d84499565b7fb428c9ae7",9.917710196779964],[665,"0f6bacc9aede9feb1573c41103ba3033b3fb7661ddbf5f8ad68f25d1a2f579fb",9.917710196779964],[6658,"21b0d0c629aaa57af764e9ef542b2c3275b1abaa8851466aceb5e092e06742d4",9.317957166392093],[10865,"ee98e9c7a187010a3cb90880a3e8b0c3659ee197eda522e17d37ff597252ddb8",9.317957166392093],[3820,"d6229476d685193c656d207ca25fcd8e673256acccabba306c7ecd5ee05cdce6",9.917710196779964],[13916,"fe115400b5dc60312109973e11a877d444030b3a9c2d486eaf7ad602bb6fab96",9.317957166392093],[16626,"db78e84e081b0fe88e86fe0aeb05072e89c6211ed51d1e67a51f5d1f5d55485a",9.317957166392093],[15792,"40c8c38f948aa3a678f3ce36d598913f9131229b1ba3873b7e91442c8d13806d",9.317957166392093],[14504,"eb98a016cfd4d398ae81d52610791a5ca0b0557a806bb7d5d8364f4414a50689",9.317957166392093],[9120,"3e99b03f7ba537fc090be34190ce95450153c5cd01ead20dfb8b4c50582905c4",9.917710196779964],[4596,"bc7ec05911c579ea2084ea98c27db8d4dc80b73cebba85b004fba88a1413a3e1",9.917710196779964],[13072,"4fe370172a4762c73be899a9e3c5ea5007707f0222dd8ff1f7429fca126223aa",9.317957166392093],[9882,"1f26eeb435dff0f482c59d74e8a942c2d83bfbc2a6b1417b4a69e7890c0a0ebf",10.023640661938535],[14150,"212608021d34b4bc3b22406113f402c6ade49afb55ee665344fb505a3d7b7d91",9.317957166392093],[17185,"10f9cdc1ff3b38ccef83cf26fa5d92f0f527c4f94be00281db9b1b76f009204e",9.317957166392093],[8940,"769b5a660b54b5a93c9097d97417c1ad6f9645110761892aaa4587a0f2b33ec5",9.917710196779964],[4602,"fd88eda812870dbb02c68d2a19642b0e18a80cd4cd1b7ac3dbab217131679ce1",9.317957166392093],[16899,"f1e12e037ab5425ccb9359bffca89d227d54f0166a2c05bf1f9f95d9a3343b54",9.647446457990116],[18250,"635cdcb24598cc603ce588bea1478a4dbdea1609141c79a4b9245152f5c10037",9.647446457990116],[15369,"c1bd71d3142267191106ac842617bbc1839e337eef00664753996ef6fc7df076",10.052724077328646],[3381,"b0a347fd93bfa217f98763d639e6c0d8252cfa63ce4fd8c8c0240961189fd2e9",9.917710196779964],[10743,"494b5441f0740d2ee9f2d5809bc83b678062693028dd9af951105531622bbab9",9.917710196779964],[7886,"97651b2c394e8035cc63e31e9c04b15f131bd7ace57463cf508e25831c255ecc",9.917710196779964],[8903,"28716ef38330e29acef475c6c697a1b9d7a393191dfb820294c9ddbdeb6c71c5",9.917710196779964],[2314,"c1d1cdeb86c44ebdcae33cd66a4a2a1f371ed617b0f425f11ea0c3fc67e0f1f0",9.917710196779964],[11489,"49bf07518235f59fa92214050a526a7a507aa6a95647ee0ed156da8d4ce093b4",9.917710196779964],[10140,"43ff1f61dda2db4cbd8a2d72afbd9980b517bd30c26e83250e9bcfd78e1471bd",9.917710196779964],[2077,"9b25a5d266fb717d2621114aeb2157da465919ab69ce434a6933838b488d64f2",9.917710196779964],[19516,"b67df9fa96c680d3db148d705c45ac183b2f3a65538e6a4332429d3b6e31df0d",9.317957166392093],[6509,"7ef86c82c02a680ba5fb95e96f10e65cde2754dac4cfb5215d2f971128ae5ed5",9.917710196779964],[1599,"6881754e80f2dc99932cab2b98269fb9ee7fc3e7c542d74d4618a1ce6ad990f5",9.317957166392093],[11501,"134b668fb2f5b2b375ccefa25bc2505b84dc565454900f7d251b4580f7cb80b4",9.917710196779964],[557,"d2144684e6a8ee3e03c160412245c48e8b9f863bace7d4c84fffdfe3d7c63cfc",9.647446457990116],[8997,"f7cdfc8abb3f7e241dd222b637a6e66e247301e081cc7da94ea75fd0ad92cdc4",9.317957166392093],[18522,"334ce680413c78b68025362f8c116dbbaec78b30d9ed2a088d1bd4a45fa00431",9.317957166392093],[10399,"04cb4e8d4ffe8ed286a8a81c98f4bdb1ac4ffe7d6a2781c14eb1158dcb5dcdbb",9.317957166392093],[12934,"d565ebfc92e3c27860f87083aff3d9a60371781c5aa61ff8cc914a9d255c02ab",9.917710196779964],[13291,"be091b565d8fe0da7dac7ea90919e684daae0eda3b76576636e7ba78bacacaa4",9.317957166392093],[3199,"39b0cc230eb0fa8c6b705c1d6c669926049774ca49bca821b2a17688223e0feb",9.917710196779964],[820,"55a1d5073b07729b707eedb87c998c26e033eda75d88081b64f388191c0f68fa",9.917710196779964],[5379,"d62256139e6d95f7f011585dcadcd3724765f8a0dfe0195832f01bd9bf35f6dc",9.317957166392093],[3383,"4577188b8f0971b91f4d7c51f35694ed762141c54d014e79a9f7cc2c21ffd0e9",9.917710196779964],[2688,"d4dd6f63ca4d385e35230711c57c7236e5d7f7b5857b432240e232e6784d90ee",9.917710196779964],[16675,"4d6f5f45c10f7a8ea05ce10f42a9bbb7181ddedbadb90183da0f25e8f9d73459",9.317957166392093],[13638,"bfdc485035df02f398a60e7664f8a9d74ec48e4b41b1af1bd616979a3ca78c9c",15.001717229536348],[5626,"8aa604c411fa5167fc0e9701e1c70ff22a24b0d2294cc80d967aa7da89c484db",9.917710196779964],[14659,"99b403732b1cbe8e46f7556a0ff5d274a8fd26e21f198b6dc38569cb2f55ba85",9.317957166392093],[2488,"fffeca2b89656722d58d804813f55d00470e67cd33a2c8af4501b66e3377ecef",9.917710196779964],[18579,"438266d7f514b00871ded0ef105fa174061eeab0d0ff47fb7e97290ce37c642f",10.052724077328646],[4433,"c9def7181fc6ef36b27f33cce6e8538118c9406af812c0e7120d1fc2321fdde2",9.917710196779964],[8960,"af6cc1133a7e62ad9d39edd1adb76e8e75ddc18aee345abc7208f02ea2d70ec5",9.917710196779964],[1714,"35af63c434a4be040119e0cf0c8092913ad9d94fd649fa2fd97e44dcfcf3d4f4",9.917710196779964],[17059,"58acf18ff4777a1b31c7dce489a1b69715a248e1f4e9a19db2ecf7e8ce6de950",9.647446457990116],[5087,"941eee3647d90069b06a220fa751cd38582f641c72cf8795f65d7b0fef75a6de",9.917710196779964],[14923,"9bc702d45e6c45704981c34b3d2d3e4563a7f6b2c8bc4256871b8757d4957d80",9.317957166392093],[17996,"838c195b060da13af57c8f2150060295b4d34ca0e8009dc24b746a7be73c4c3d",9.317957166392093],[2641,"5cde4a2e114705ddd68ae97b00bb5a95d2b50bdb0f73d4a351391efcb009eaee",9.917710196779964],[3170,"94ed346bccdf17027c9ea35ddbda87eef4f252a71329ba1ba0aaebcfac5436eb",9.917710196779964],[1335,"1ae85cf744295f2bba3a0833cb1183323609061a7a36decb15bd28a4f72d2bf7",9.317957166392093],[2683,"59395666a57fe6921d34836a072bcfda35c46b33b72eafa760c4954e6e6295ee",9.317957166392093],[8436,"3449509d8a2d7f4ce738fce1c01a102bd22e8d9b0cbd95d9b7209deb391d6ac8",9.917710196779964],[16961,"3b9e26d4733269a60a6785f1a858c0e9e97c1e9b1c867b47a23623acb2aaec52",18.152974504249293],[3489,"80bedf44f19749bfb155821a3c2afe7f52f40606b10ffb92c727a8f241c618e9",9.917710196779964],[7680,"578f085c525d13bf015135239f84a0db427d40527e8c49d54d65016ffefbb3cd",9.317957166392093],[11428,"26e12be4792d315242970efa15d99199b9d223fb98b75e3b89a1fc92866c20b5",9.917710196779964],[5899,"d1e3b01d4553e0bc64b6ace79f413f6925b72b1906152ab73cc775bc903eb3d9",9.917710196779964],[18212,"912c75bd035323c6fc4da8ef59c3f2484a89fc30bce76fcab2b92cd5b57ec637",9.317957166392093],[3608,"87f523e417bad6d151a962a70291311fb6d742c42d19daf98f7a357baaa32be8",16.198230088495574],[6962,"597506092d93cef72be441394e29316d8bc3bb4e3cd56dca02e03642d6b733d2",9.917710196779964],[19683,"2bd9295131b3353dbcfbd3275bedd8b5962d82c9d8e45b2445294a6891724807",9.317957166392093],[16919,"5b02bfac52992ba1624c19c7d0af870b527d42f703579aa70df1fa6c3905c053",85.7085201793722],[19288,"b176210993d06632b6a93e2b65bb926bff18abbd4266584bfe650475d7103115",9.647446457990116],[18014,"8b964fd7f8d0f3e5ef15be530328669b4194f4918ffc0d08d954db4cf6d2f33c",9.317957166392093],[7435,"2af43234ce3b7ecfa7df54ab531e7d8117cc1e8c36dcada88ce9c6843c9f27cf",9.317957166392093],[851,"6d69d3331d52009a1d0df13aa347a3e3f6ea763e9dde171cf083bf285e3b3bfa",9.917710196779964],[8827,"b066821e7e129e74b1c2d6e7d85b3898fd1e2295fd84f7bfea7a73ea5dceedc5",9.917710196779964],[13245,"6ac76dffecb68b5b568dd8e2d06b590dc640a4494d4093de54d648964934f4a5",9.317957166392093],[15918,"d0a71ba1ae4ec2a3aa604c4dd4e3007a3f3e96a7a68ce6968ebe4cf9bfbdb76a",9.317957166392093],[17676,"715ad607b387984bfaae2fee27f04b4406a4a24378ca09bba8cbb9558c7da743",9.317957166392093],[17889,"c316f43cddd22976cac22aaa40d2d8e3cbba8ad3216e87d2975053f78e167b3f",9.317957166392093],[8802,"659dfe4ef5c61f1b79a230db0d27e292139df1b8ab8a477ff71ae71af8100fc6",9.317957166392093],[8746,"f03e47b791b10ecee19e7b856da1bd75ac873bd0e3a7092257d892d2561e69c6",9.917710196779964],[15335,"a46bd598ba457e8a6a266ad87e03fef0ccbfb967f11a63efc6f9972be4fca877",22.214285714285715],[18782,"85c8224ba2df5d181bee71d2ddf3b8666d083bc91419b7d4811fd0fa975b9f27",9.317957166392093],[18762,"cda42cb7306cc4e47f061e6998ee1e12d702c2af7998f77f8590de8006682b28",9.647446457990116],[2464,"793b3351b14c2f500c2bb7dff63357c53d88288df33e4af7c9b34238446817f0",9.917710196779964],[12480,"10fc72da3a247a5bb60f47d37a7fb8ca29ad339cce0591af222f3508e5870eae",9.917710196779964],[11969,"0fbe9b390d4dff946c8b7077d7511fa2c5e50c7d1c12bf8c1bed673aaa0884b1",9.917710196779964],[15079,"457471a7392a890b7513c7054a57ed79b4c93d1616d41a7304833ade0fa7167d",9.317957166392093],[8599,"c59f69eb8ae3b23629e635658777f5f2198eabf9a30c72e8cf94e211f84a73c7",9.917710196779964],[4970,"050d87543a0a46540b719eb3b5d8b63b512f2a0e1ac7a31656af0cbced1965df",9.917710196779964],[11535,"77116002a89cac76f1da3a356b60aac3e64b6127754afe5bcf6eedf541b94eb4",9.317957166392093],[9552,"4b3419a30f3bfa0b0de25e860d692c8cd263d60c00d52c58128f7b61ebdf5ec1",9.917710196779964],[16105,"b0a7aa7ada394923fe5a8f6cb0be037649a336a9ba81df0c73978c42748c0266",9.317957166392093],[16833,"3dfa02748a709e0ea4163a9edc5a3a50dc06cf56636944504b9162e522c0a555",18.11263318112633],[6529,"5a0ae08d355b62e5424115e115f877ff88839b78269c0fbdd3bca71e88ee3bd5",9.917710196779964],[3108,"eb9e393070945b7caec0f0d25cf7d6a255a87d04d043976e36a665b7e9c69beb",9.917710196779964],[12019,"e7858269da4b7622d540be14a7764286d982a7de06be7380ab3f33426ea737b1",9.317957166392093],[1169,"07c920d2c28a27c146b8203b34403837f3f2851c1f978fba17bea4e3bcc62af8",9.917710196779964],[7369,"7b33eb1ce195ff3d9b4d1d01c7a6786aafc0670842754c11f84de52feebd92cf",9.317957166392093],[3366,"c0f11376d950dfaaffd15f85fcd6c55d8b7ab352eda62f662a212ce24056f3e9",9.917710196779964],[11490,"0fbfc5e2cd4cfd295929cd9dfa4e0ac0effcd0a2f159d1267b1ceb1e51d993b4",9.317957166392093],[7904,"0da03a402bdae1127627f54751a9c747b8d0c5955992179419ef6b70dcb333cc",9.917710196779964],[6327,"22cadd143a14f2b749bcb2687ac677a2cc0906a714e541580529a6c8f05dcad6",9.917710196779964],[3137,"1378c7f9b39e4a900ef180e4be33f31a7ebd0fb52544c8aac53bca9b289071eb",9.917710196779964],[6149,"0dedac984c362e1a68164701e28297b47b8b88a3b86f93f108a54a76a57225d8",9.917710196779964],[12917,"6e3bc390f9812b7d78fd3a5b0e220ce51efb1c6751a54bbfddf22034b58f36ab",9.317957166392093],[1085,"91528dc635d96b2966b6dc6475e203e3c67d610b722df0e16da1a9fd24c2aaf8",9.917710196779964],[12376,"8aa70f47d32f626c922e4325f0ad01cd420d5ebb22b4b3bf3584402a2e77cbae",9.317957166392093],[10398,"389e80b3f23988258d9ab129ca45dcc214bce3e62ab6698473eb0b617462cfbb",9.917710196779964],[5142,"74f08305a93855737d171e593ed7d7c9b486120315d8a306154fa3f013de58de",10],[7584,"068af34fbe2226ad5579ece5ee06b6c2379d0549349ace9ed2b5f3e6066246ce",9.917710196779964],[15830,"5a4b244cd191105d5c72aa043583e0c7d83579ed79dcaa1a40fa994551b9c46c",9.317957166392093],[11049,"713f77b0784053ba2b55f3111e5de3ae9b05c26f0a13c91418725b21e4edb6b7",9.917710196779964],[6080,"b853932f50310d9ecbc554ffd78c286fc7db9bc09c3ca06a2aea7e5c11fd84d8",9.647446457990116],[7573,"b2f931f72ab52ed57006c0b816376464742f7420f789ec827f59778c590f59ce",9.317957166392093],[13703,"a2fd84f51e5e6f6821c2404141e6378aec8db9bacf909e6238c46c8872b0449b",30],[4468,"607ec05999fefc79de6cf77818baace059c47dbab755210049af8e7948d79ce2",9.917710196779964],[10351,"22b98be4e11d6f3334e6ed6b9b5c7b026ba751f60bd8ee23346ea98df93909bc",9.917710196779964],[18006,"7f7c12719146e4ccbe36a8e276852579765f1e7fbb92f67b95b14580e0d0183d",16.954627949183305],[10135,"bf1637435bbb2a6ae51143d7fd44b602884c60d9bf6babce36df0007548577bd",23.190532544378698],[9264,"87b612c6e06aab697fc0eefec00d7df95203dfcf63df9a1d6b3d0a7e803e0fc3",9.917710196779964],[16616,"4e0fc921545b9109c8fb95149d67fa9bb763d055daa4522323c5ea963bde885a",9.317957166392093],[9522,"e6ac3674ec364b150f759c77f0ec3743038efeff4b8d72ade4010b22f6f58bc1",9.917710196779964],[7089,"bf888d97e35f2ea3f0d1649f7a72803f32e034b643d6a208b4d790925ad66ad1",9.917710196779964],[4895,"cabb341c491880ba3c5b0701ab585c8f0580500214ab8c937c22e40206d2e0df",9.917710196779964],[19392,"26c2b30f2ba50ebd06b2c4e807cbc97b2957139cc42ee91246cadb65d64d0f12",9.317957166392093],[16920,"bc2d06c8213e1f5a7e2ecc8f85a617c7f71c190225b1ea12e91065301debbb53",9.317957166392093],[5203,"e5cefe80768957db34c6c010b8e380f210101ea7a871a7dcb0217cbdd10cfadd",9.917710196779964],[3745,"a5aa2b61ffaa14526d357c1cd8f7afaa56bd765f1f6a03d1ff3446c7a4bd47e7",9.317957166392093],[4435,"322dac3b8b70fc3f4461db3f17fef5a24ff206c46d253dca7e5e6ffe9bebdae2",9.647446457990116],[2647,"6ff5e9f81d1cb6e5cfbe4668f12df71c3866f752e151e1c73e6f4346e9d1daee",9.917710196779964],[18728,"80ea0ecbabcb88ef96b0ca28f6575d0313b5be175a8b5fa44ee8b18c235b6729",9.317957166392093],[16218,"f2adb3d5bd225f2c7768a1154c7e8687d457515526111001f87d82b0e8006c63",9.317957166392093],[17240,"558cc999d0b0a8916dbb9aeabb853150a3ee4a6c9e695da8e3f2fa7ee7f7174d",9.647446457990116],[11578,"6f8357a6b892c7c0d06a1bef8216c93848cde407c45ba0250ac86a3c550304b4",9.917710196779964],[6600,"2ce491b682bebbcd79bcfc06e810c1d09d2b27919f064887d197bcc81a99a5d4",9.317957166392093],[16094,"0aa907ab94359b7a8bace6c3df41cf7e38c7196c04901c7287170c460b8b5966",9.883677298311445],[3096,"41cf436729f0ccf8e3f74f41c45180d146a2d03281c5d9131a084356a8d0aaeb",9.917710196779964],[977,"32e26220faaacddc8f58441d824f27216ffdc11b93906037aad11060cda958f9",9.317957166392093],[16884,"5edac6127d768390b459e33c15b8417010ec417d93077b3e0c84e306e56c8954",27.86761229314421],[9127,"48131d81f90a1536b330baf358cd7304bd7f6b177c7d43961b571e40b041fac3",9.317957166392093],[1782,"7b2d98697244f01878d95f2a920a2f325d5dfc10dcfc3abb2e72b728455159f4",9.317957166392093],[13473,"e656b195ea2f2a8545c80a859af6e61036b990fb22d7235a555268aa38d595a0",10.052724077328646],[8305,"170ab6ce166ca1fa36e30f30adb7aa94831bda186d9d5d54c76bb5fe1cc34bc9",9.917710196779964],[6849,"56316538ca9ea5868459236ddd0ffff04a2972d3dc27f0051d7417b1e3f9fbd2",9.317957166392093],[2365,"ac24c32bf37fb52145f8316c48c259838820349fdc9756c6aa1d4628e5f0abf0",9.917710196779964],[9608,"b6d7469c48a1dabc2d43b00824e583d7c55b38c1e430bb0c033179a2a9b900c1",9.917710196779964],[16193,"e855f9fbeb7475af32f3a4814ea50e6b2787ba2a1d7b679fe33b36c1ec352264",9.317957166392093],[2587,"81bd620f875330e7f55bd8a5cf62650fb7d2de3c68befc6d785ebc9c45343cef",25.83927839278393],[14242,"15d2e88138923783f9f5fcd57aa1e7f7c6d321d9e19e8e3faf500b4c86f0268f",9.317957166392093],[18161,"253c2098efd30045a07bfec8831a07543975fe539a66b157e0aadf9e1eb41739",9.317957166392093],[2892,"b4d8206ac572ceac5b587a5172f75b075dbe4ba7e7cbcda124c8c794a9ce2eed",9.317957166392093],[16776,"866a595f2bfedf00225fcfe8979847932655d387548b8775db08afb1d963f156",9.317957166392093],[12197,"06f30cf2b42afb7475b5698df2ce7af89710147e66edf7c82112692a13b912b0",9.917710196779964],[2178,"af62f6417db231678264d65de17b50d6022b4690019e8ef3ea27e164bc08b6f1",9.917710196779964],[28,"bc7b1db04ffc8b95a5d05df32f4b118306ed5a5d14e727fe79ecc144f61bdeff",9.317957166392093],[16745,"4214fd189678a112890c7bcccca2a2cd172ab326f5d1d9ded65f0d63f11a8a57",9.317957166392093],[12225,"e0595deea20551130e9baac1ab4cb16fb3ae3e41605dbf75a00e67db6426e3af",9.917710196779964],[17267,"8e416847e0bc24ae33a46fc044cd7081ae422b5c234ca81bce2a3ca8ea49d34c",22.583586626139816],[6102,"63821156ea016ef2b1f1fb6a626cb468048135dca80e710e34ba4490f7e867d8",9.917710196779964],[4508,"8e2417067d1656b3ff0a2292e9b3bd4404e7905ab27fa70e57d60f12231c4ee2",9.917710196779964],[2403,"ed35b3c5bf8b7540c6d9914ef3302400a19a0f4f283fd2c8aec785a019c476f0",26.062350119904078],[16486,"ae854ac909a7c6dafb358f38f495d31381190d03b0414625c75ff6385a22855d",9.317957166392093],[9064,"e0ceb94af46c6da4daa8a88a338a1e9fcad4e193de7a517ad156cbef16a05fc4",9.317957166392093],[5907,"5694f618baf57a8d7ad3f7e3f80459fe6c5a79c2d63e24a7b5ebd00e58a7a5d9",9.917710196779964],[18893,"201fe51d01b5d451413da8d1dcc1ae9575cbced203e579f87112ec6a3017b023",10.052724077328646],[7824,"7542671e49ec5e89689a19c4d2211293e39e769df1ca84a9816bf98b92599ccc",9.317957166392093],[12996,"cb326d24ea5a256bd086dda2bc97f474c95d04048fb8f34fb5aab837de909baa",9.917710196779964],[17721,"afb44dadca5fb047e6de37b746f600257ab7e424a2bbd6703109d8d43436c742",9.317957166392093],[5601,"4cd216e20b07057de74f7a11becd780e5bc11d7988afd93e5cb38fd1c1fa9fdb",9.317957166392093],[12868,"774b568a328653796aefccef4241e83e544f8877ffb5520fea67d388641675ab",9.917710196779964],[18141,"862de439f9c6b4649c5541ac1b80e72b0a28e046bffc764b71246dba8799e639",25],[3385,"dac50d7d6b1290fdb8675b554a0533bb10219cdba2d8f61e7e58ecf27c6ecfe9",9.317957166392093],[17121,"fb100024a63b8e596b5f3a4e661d5a6127afc624192a1931e7ace3245721924f",9.317957166392093],[10965,"e889d9d125201287ec145bea6942195b3fac7bf2e8fd6764988c8ceb73a13cb8",9.647446457990116],[1700,"5c2b0b6492245298e552fabbe885c687833cef8ac7a5c380e43da6859d64ecf4",9.917710196779964],[1998,"eaefde4846fc3278eef7080c82446193200cdf5c05613998577dbf1ce23e0bf3",9.917710196779964],[17529,"ffa6e6ec8e325f8ec0c6ac75ba8f3ced9053782f53a175306b3825b47f1eed46",38.98954703832753],[14482,"5c43fd1654b05c144a110b6440cb5fcc37ee315f6090cc0a00f6b92853c49889",9.317957166392093],[17034,"1cded2219f35a87991858c4560c959e0ddc5a4223f539ece7bf2537122824b51",9.317957166392093],[7918,"76fbaba502a7c8258509979c48ff54800c16264990cfdd68fbf34cdec0a61ccc",9.917710196779964],[17106,"266f5e205b0ad421e0bad4712d1522299e4a5e3612b26ca6e0cd5e36c06fd54f",9.317957166392093],[6098,"c22d4d718d7e1190773da6f21473600ea5b733f3293817ebd5999557c8246cd8",9.917710196779964],[7536,"7f8007d50eec6bd000a79e82c999a77885bf5518b999d27e102faccd06da95ce",9.317957166392093],[10153,"ca1b771e2e898cd99675ecd65fd10ba22f74e15c6d551796f20c8c5721cb61bd",9.917710196779964],[13251,"0f867006cf1b691da83e1b3b3ad649dd2b38de4a3eaa14e58c718081253bc7a5",9.317957166392093],[7738,"3bbd7b97be7f1369e28be16d569209b1364c5461c8cab840bc8f53a5396c3ecd",9.917710196779964],[18680,"a822c0f82d2cf1c5a58fa7b0462682394ce1f68bedfb48679f74fecb60712e2b",9.647446457990116],[9595,"e60fdfc60ff929aec9cd49060fe1ac34bdc3202310500932001001d8a32709c1",9.317957166392093],[14816,"7412bd12eeaf65964cec3544721e27645727afed4932cdde8e7b18be1a667682",9.317957166392093],[16587,"b0a2f834478ca5e60f696aad82e51f194f513f89ef03fecc5ea7d0e637584d5b",9.317957166392093],[3804,"f264c797291ad1c97f3b322e167a92b88995a496cbc5bf1dd2785dd871f4f0e6",10.00593471810089],[15848,"2a7fc3c394524725bf9abe5c9779f7108a46a87bd6d176756165cd0feecb436c",9.317957166392093],[8946,"75a69417d0716fd3db3d66cd12775d2a218081a0adc27b84f04f0fc521eb21c5",9.917710196779964],[6253,"1802bda079dbdaf6af885ab9d5c3e3536ba0361bdf1772dfb3b777e29b0464d7",9.917710196779964],[1906,"9a88ee67b52a8ce958a804f1734c5f356e82b42486aafbd9c7045f05692899f3",9.917710196779964],[9736,"7a2c19014d86254e3abcfcc4a4797670860535a3d9f615344220ab9a537a12c0",9.917710196779964],[13247,"f39f7aa1d60317251c55f8dbbfc5557d048819fa0f97e8092cb17e8fdcf4e3a5",9.317957166392093],[1424,"db9bf3a391a5c43ca93cdd36d6c2d7dbdc82be81ee9a72efa4c2820a6800b2f6",9.917710196779964],[676,"cd12cb0f4f13aec45859880788d143be31fbf8e6b8dcfbc2f3e79f94ae7365fb",9.917710196779964],[8676,"050fd21c30fbd026cbd9cdfecb801f64ad94f07c85d5ba96454bf1d0f6d5d7c6",9.917710196779964],[18741,"5f30894ff737a398cfadb2febe139e5d67f5984c9c89dc41277e64137e5af728",9.317957166392093],[14887,"529e0e4f3e09e32ad8cbd55ff14135ff9f549861b7bd6ab99d42778ecde60481",10.052724077328646],[6961,"bb4fae3812c390a5830af06832ed1c840a97505f7255df08dd413499563635d2",9.917710196779964],[19764,"054bc7efee83d79c527da23da8b7f86ed93011395cd9d2551b5d39dc8edeea03",9.946524064171124],[14360,"d73b0472c36ca0f1db1d9c461398817b3f5e07dd5bbb74efbd485adb23f9398c",9.317957166392093],[12973,"429615dd89ccf76c9a48a6582e1fa1c0999d3cc596f36bd6b39d1d465ab1beaa",9.361256544502618],[4095,"c05e1ca5238f653aab3c15d1390b306a38a319800eacf424d5254a5a637717e5",9.917710196779964],[13098,"f5de608b3561ba79ffeba32442f979b03599e81ae4dca63571d8ea3c7e0558a9",9.317957166392093],[7771,"c460eb768db906a70fac830d3238f9295ce31739060fde8d7f5fe75af1ee00cd",9.917710196779964],[16767,"0b83572a3e06e887a30a9e0d51375132924950d461ad4ec8230390a5fdd61057",9.317957166392093],[2391,"193442b2eda612e36185ba47fe7eee8ac606f9ddf0726f81a690ac6ece7486f0",9.317957166392093],[6991,"7a7e0e48801f741b4207eb9026d5fec6a648f36e18ff48d9182b5e31addf0bd2",10.022779043280183],[7400,"32af005eb1e58cf0ef1c51081f8022f7c75be7a70785c43d45784d67bf5c6dcf",9.917710196779964],[6843,"e5843f724a8432a7ee4dbf2b2e68bb07ceab5a5f0e76a28bb727ebd37aba00d3",9.917710196779964],[19154,"48d7221fc0defe14c25a1aa79681d8a99323e4697a165ceebbff0594cdc6641a",9.317957166392093],[16186,"f8959b0a6ab36d7f647e4d2abdb5bc9afd9f45022529d0d71d0d1106872c3f64",25],[13679,"bfb8cb2a2933e2a49585b4d43db9cd3d11bbfbc7044b34845d481e3bca17b29b",9.317957166392093],[9510,"04769e62f5b426ca30248b4db5bc1951407532b8ea44880fe937c203ed30a2c1",9.917710196779964],[4408,"917ad2e9cff518d71133dec94b70d04632d7348bb86a115d942d839ea1b406e3",9.917710196779964],[2151,"ec7837c553621ba2baad016bf3dde27ffa5cc29c9791eed821996a8d77e0e4f1",26.019370460048425],[5831,"c31e02c6487ea8d41e3ce52f48068ac9fccd6e66c43d65904b30c3088c1227da",9.917710196779964],[4031,"913d7915ecaa629c0e300c7f5e8b67a325d438e97ed9e5fe6f1d4b0f59a28de5",9.917710196779964],[7102,"27a36a4d835a9231527e00780fb66082dea5bb2c8253702877a03bd9febc53d1",10.051282051282051],[7086,"cd5d5f6cb7fc320307cb6f6b83e26da9980cba039734a2b0b71c37d7ecf56ed1",15.040431266846362],[11748,"08b5426bac5039287a72bc078d9d99de3a8708ecdbab5080089c2fa0a0b804b3",9.917710196779964],[5318,"18a596b300afaae8f3f0ace8d4dea001dec295d7127e32252c12c8e2e5bb4bdd",9.317957166392093],[6780,"7821f289492acf432078e9ede64dad1b10b8d010abe2b6d662c86225637c67d3",9.917710196779964],[6523,"352c02b4c1b4df76d8b3beb1bf45ea3eef27b1aec45ea7b3a6df1f6bc65642d5",9.317957166392093],[8783,"8f915f94921d0d9e12d97510f95fabd610a2597e7917f0266dd5fe7d8d592cc6",9.917710196779964],[15629,"f5d00f57c7fd5a537f704bf8edf58f3cbc58160f975034397061aac9882bbc70",9.647446457990116],[7759,"0c444db6f2b23a6b40086ce7b80f4230721a1e99300ba8db4500fdd766af12cd",9.317957166392093],[11308,"a95f6399349cc1fbcbfccd9cd26a61d440fe5074b83aa46fce7b0d2a6d49f7b5",9.917710196779964],[12297,"c0fcf6d442892c65747abd3af83c1116555ea823e936642e0b5633af75a43aaf",9.917710196779964],[15272,"039051cf54b4916b85fbd68f6f2379eb259746181c94b40576d6760013a8f378",9.317957166392093],[11536,"8b871b63200bd2bb086b6913b6d0b157fa3ec46097c549be46122c4b72354eb4",9.317957166392093],[11275,"3be1e204a8a9019232cea6968f923ca41198b4dc33c8467bcbcf15e5e78e35b6",27.900178253119428],[1585,"35cd0cb186123de357ea4af874e1db8e5f6c2cd39de5bb30551050ccf2c49df5",9.917710196779964],[5231,"12f33044f4239340e966b043f4ba5b237c40f2e093fa1851faa9abbec365cddd",9.917710196779964],[14753,"e86e1fcc4a560bc84da3bd1790033ff8eafa15f37e636c1aff440a32e6e7d883",9.317957166392093],[19598,"5467e3f9a31410c4b5899b571072c2eef8d9101a9f8b2e14524c64c614cd1c0a",9.317957166392093],[8993,"80d818b7c3a583155b9a212cc1072b41b1bdddfd46ebb3fbfb542b9614dcd0c4",9.917710196779964],[921,"97f9bc245541de08a324ff427f4fc81c50ee5f192f1412fea2d0b4ca437cadf9",9.917710196779964],[17164,"143ef44ebf126d98de8e72f4eccc7bea8a49c75113f645222e7a61bc62d2a24e",9.317957166392093],[729,"da0258bc69039c5a0f0c7be308ef7295ab02427c1a1dedac4e5c9221bf1a06fb",9.917710196779964],[5867,"7bd8fac427ec2701a8800f1aaab10bd99ffadd3e3434557cc3470359b85fdfd9",9.917710196779964],[5023,"da89877117be8118d2569342019277003357bcd8d8a7b424906d98d95c1509df",9.317957166392093],[12446,"4fd37b3dc84b5344598ba7996108b93ae5e790baece7dca193ffba77d8324cae",9.317957166392093],[18551,"a1d49ca9d3671bb79af19d2693999430dbf0dafad8417fb142b21145fecd6c30",9.317957166392093],[13699,"cafa8bbaa1b3042f562a4d9aaa8889bfcfdfa9c0ae989935d54ab07f45054e9b",9.317957166392093],[7260,"de90862cafe3299b50af4a86f02e8eeeadf2d3d953b0012e546ede81d18646d0",10.052724077328646],[2949,"42fb3052075ee6a0af2433a102cad5a041c5157badf783d1a041db64f162afec",29.224489795918366],[7411,"24a2942ee89c3d4cc73cba6255def3aac0004dcded167badec85f1f86a7650cf",9.917710196779964],[15281,"2f3d320e252110a4b398de21f0758e92a18f9868a25cd61394aa12b1582ec878",30.20044543429844],[17171,"13de2c5095a09344d103f47ad5a7b900cc3fac4603d3029074cbee3f8362694e",9.317957166392093],[3773,"380b70fb108cfe2ff2665bebcddbb00e3b704316a4518e489cf8996fa8d022e7",9.917710196779964],[9259,"47c8c6917b08064ccdfc65a8517210a8e14f91ecf87f6746639e016fed4c15c3",9.917710196779964],[10760,"2e2666c72a65cc4f70c91ce65e62cc4278878c795b86175a73680169143497b9",10.052724077328646],[2624,"50c9e3e57e24eeef73d05b2825fa058912bed3744e9f2bc2bf2e5f8193c908ef",9.317957166392093],[5630,"b45346c8d8e4d81b3d5bce8bb4ff25e80880bc543d19998c5158e693bf1573db",25.202156334231805],[14062,"3468ae8f0d7a0d1e28c5ecf97810443e763089cf96d9f90a43e2b00d3c3d6193",20.021201413427562],[8118,"8ab8aa7f38c8db0539bf66ea85d5333ac03837b3675834e016313983ba6aa0ca",9.317957166392093],[6557,"bec14ed925d839d5d5e076f64ea201dd82d8d04105d8525a279b9127ca77fbd4",9.317957166392093],[1254,"09726b6e3ccb5f5521a9bdc0db47fc3cf5273413cdf165629e592a88549ca3f7",9.317957166392093],[4104,"fd18839ac8353b7716f65e6efd5ef568b17a215125750604d0313725034d0ee5",9.317957166392093],[14667,"24316611ab2d9a8bc8a236292934f2f781d87b29e21e962c79c88d4d4ec48f85",9.317957166392093],[15796,"b7e13a34f5fa9df92c552c6c9a047c5ebeb63c9fa77ae0bdae67012bef62726d",9.317957166392093],[13998,"affd40a1366777538f6bbbbc9cab634141c25b217ee94e722568b1ef809ffc94",9.317957166392093],[9226,"5f3d1a3d94edeb127ea8e65e3972cb9ff3c620a54d3a01b0596f50ce526951c3",9.317957166392093],[12900,"79f17dadaf86f5b6e4fd63c3580651f2d8155e4a277e5e88eb69f337439b4eab",9.917710196779964],[702,"f0b5fdadf70109a892a9f15136a5b4391809979dd7365e0ec285e6d0ca1d3efb",9.917710196779964],[6363,"9bdfb679c26d72a056d71dc234e0ac3f687c056343515bbf6099b856e43a96d6",9.917710196779964],[19728,"137c490d4cba59b3fdf7d8ea907c218d88b62e90e90283c3db2db268914cca05",10.052724077328646],[11591,"77524a6e4f02017f7c40441ab1cac41d758d654883ecfbaf259c5e141722f5b3",9.917710196779964],[9994,"f1fb88e1550c5013419374df61930a5f9d37c32eaf3fde97c68dfd0544cc5ebe",36.102175969725636],[19000,"15e34fa3cf23ad8f8582c80b548e92969cc373c6dc60f160f55dad9434978720",9.647446457990116],[3493,"f475c0a43ab10774c4e071e5f41b601315037d8485e800bafa433d00d4e407e9",9.917710196779964],[801,"6c703e2096fd8e03a9503cef086c2e699724ddc400c1ae5beac94453211588fa",9.917710196779964],[2027,"51baa0d9ec223cee8bc46005d3ca3d94d50684fe55f16059d2ece1e3bacfc8f2",9.317957166392093],[13228,"184c81a6b09831442b834f1433a75fd96d108704b994f18dcc0aeb2d335556a6",9.317957166392093],[18889,"bfb70884b0cd7b2a10ce3005adb4a70841c93860c6e5d9b7acad1dcf7dafc823",9.497326203208557],[6232,"7ff59c7c0ed1b0897d6c0a8d32dc469960ddb7ac8b501c570a146d0bceeb88d7",9.317957166392093],[9587,"46b19d94935b03cce13bb77546cb4efcff3ed55f5b452811b193041b81b110c1",9.317957166392093],[172,"7ec2bd7756c26398d36eebff5f26e33a40c9adedf6a5bcb9e7d00d74ec1dd7fe",9.647446457990116],[4454,"9fa5f803d0649b97a4707d4f8d61d7ebef2c6ea827dfd80e763708d9ec4db7e2",9.917710196779964],[18316,"ab4b638a9cdee10cc94e26858068f52a23366323e0d0786b19e3512a15288935",9.317957166392093],[10503,"90dedf59568ee1270a1b126c8707d23d10894e4bc940e1b5b2a243ecaea628bb",9.917710196779964],[5302,"bf265247cc2fd7567823591130dfd2ae1bc44e2d439de0494de9bf26005463dd",9.917710196779964],[7699,"2482e8dd41c559be985a43dd7139861f0ceca2fc9ad9e754ba2f6d85e86d8dcd",9.917710196779964],[17348,"a7252f4c258c19e53e22d93a460c4015e6f7d2d7a3200a23556907d15207e04a",9.317957166392093],[5347,"4b9ca84f2df15e2d2894c8cbc034286242caf2a54bcc5bd7f6a9e9b356012add",9.317957166392093],[7725,"00d32fe21ecd8f71bf84fa90174ae53ee8c057a43aecea0a4aae8694c29256cd",17.110530441599163],[1759,"41bfb85866b2361e71a84831bd81732b7d6e4e677c3966ebb127e55f3f438af4",9.917710196779964],[5909,"9ba455267bd0b07fc9717d15c45046668694ab0912040a876b46accd28979dd9",9.917710196779964],[259,"a152997af44e4b1270587ed1e4666d13d4c123d0a0a4f476bf9bba1edfc235fe",9.917710196779964],[6501,"4a806996292b66d6426b733d96f123075d053b3aa188b1e53f17b85e200b73d5",9.317957166392093],[17126,"9832abbd9d534d2a4ca9fd18a20eb6cb9f1d9568edfe6d4a3960686a0c9c754f",29.13975903614458],[12776,"7f32abc2a01a775cd8c95ae43804dcbe5f9a3efa3cee0b2614054158c0ec11ac",9.917710196779964],[17628,"5009ab92363541e849446ab6972dc18defa845994b8235b911689f960532a544",9.647446457990116],[1801,"baa9986e6b6d9874b5322b55214d18b1da9b2746380702cd6991323cfed33df4",9.917710196779964],[4186,"63e05ded5fa51c3e676421deeab15e3f14876eefcf38597c33dd8c0f53ee82e4",11.328798185941043],[12044,"945bda1893e4fbf41f0c46fafe3bbfc7ac75c89d857ca906339834ed748406b1",9.647446457990116],[12285,"ca632f5aeab926d1fb91e85e0f80f43bed3b255180ceab5478c276c2d2e35caf",9.317957166392093],[9971,"a0ce3c4e60f6a2a6b3a671666c75fd439a052906de3e36a4fe50ab5286067ebe",9.317957166392093],[6354,"fe6f5759584f7ca3a755a3e2a03641cec24ee39989d259208f27a7f2168ba8d6",9.317957166392093],[18532,"d3d24f5aff3029cd795d4e7a75efe22d0216a45bf714243c7b48dd03bfead430",9.317957166392093],[13301,"836b1dde3a299c7c4fd1d131763e55df6b5050adc376dabbb45c31a0aa8486a4",9.317957166392093],[11045,"27e8c0f8a5518d4f4cd27cc374eb5c8258d99c030e0e52f4bcbfbd312500bbb7",9.917710196779964],[19500,"aa9878de7cb971319c3a2cedf2a23dedd1bce2cb3f02b69498ed6c5cb638500e",9.317957166392093],[19200,"eb46f7b43aacaa45ed88d9c41bd440b65f34ad32e219f0feea0641a2304e8f18",9.647446457990116],[7302,"2cd182000acf28d0d45f275ee96ca398423fd2cf6932fbc7b034197bf36810d0",9.917710196779964],[5037,"e6e71637d0ef4ba56dbc061a20068db8ea9ba233b51165528d5ea9843248f5de",10.023640661938535],[16676,"ad55b8b077a751d52ef04ee9af912143e5e1ca5dbc690740c53594f147033359",53.188612099644125],[4427,"7a08e16e837a792678340c2f7c8e351783dbad140d0629f3449d1ceac9dce8e2",9.917710196779964],[9363,"f4704b5834e870a52b6bca6e882aa1b0c5c8c1d1282c6931319620b2d3157dc2",9.917710196779964],[7973,"1b57923f9429eacd3963f0d22f5d6e3cdd23d942508b965f60a5b1e674c2b4cb",9.317957166392093],[2782,"b4be3b6c87b309bda432d43c9ee011b7e1e3a1647189c77b55c35a99e988dfed",9.917710196779964],[10948,"44a71edade53429dd827b4b9a33a5eb023cd9fc0e19cc7e2b5ce8c83854862b8",9.917710196779964],[9636,"8dde5d142ac263e106fd859053a3ed69cfe3c3a2a8f055bce1c8d52a23fccec0",9.917710196779964],[17374,"1e95399eeeea54b65d58dbe254ed8d0badd17dc3d5e53b80026e940458dd574a",9.317957166392093],[8002,"0c403ab7fbf613bb458f4cb18cd7aa58820a6cf844f0fc64b5508b39c74d84cb",9.917710196779964],[90,"91443a801c2806d0a8a1ddabc9850ec44723ce37e7bc81ce53f236dc99ff6bff",9.917710196779964],[4941,"a7bfecc7a527b8ef52ff34fd6ffece9924b1c0fcb4e5118e7961f63a7c8192df",9.317957166392093],[19381,"3651bc7445be445cd9b32090665d9b5e926a1a228346025a38052ec6e66e8f12",9.317957166392093],[2521,"40444b39c5348d416acd9fb795c67325f5788957fbadd2268052cdd67395abef",9.917710196779964],[9915,"ac330cb95aa9251060303fc0627d9f424997dcef58fedb9163ad4028598fe0be",9.917710196779964],[8540,"c899af1ceab92e6f1ff49db274cfb6344d62ceb17fbb53abfbabf88bcfdec8c7",9.317957166392093],[10840,"0aefa1dac0751c445cf28c3ad161391cd69705b6d9de608cd789c10bc0440cb9",9.317957166392093],[11052,"7ddf2bfe75c743cd4eb1867dfa89a2227274ddec842fdd3a233894c3d232a8b7",9.917710196779964],[5680,"8e8038c170ddd971a40502d653e5b7a74e996078803e348ab559639740dc29db",9.917710196779964],[479,"29dcf2a595081b3dd654fbea3befdf27354cddbd9c87ed156769f70567afcbfc",9.917710196779964],[3316,"4f231d0eddc63290fdb3c725f7ee82d7437562cb6947e2fcf79594cf211140ea",9.317957166392093],[4334,"00cc9968988bbd69ec07afe7caf448cc1f2d000175c3cd94d27d873c37ec8be3",9.917710196779964],[11984,"8ec7c895c363343f1ffdbd7489188b029e644dca5a586cc27c1e7ae59b1e6db1",9.317957166392093],[17465,"4b69deb8b3f5caa8006c1d86d95398c43c6ba34e7da8821fd363cfd813e27f48",9.317957166392093],[8896,"259ed5cdd48934926afedb80cc3de248a57ed703a6079439f2d64c55a4dc75c5",9.317957166392093],[7033,"47103e4b2915750e426dc30fac260c17af367ec9470bbc0782e1f48e5021ccd1",9.917710196779964],[16249,"13113c7637cb6825ecb918a61dd286d360255b36f7488a67e1561a4190e75e62",9.317957166392093],[11587,"b34934b0743b7cbbbe08d7a6df968add2b6b6b52d58e667f8f10d2e37677f7b3",9.917710196779964],[10223,"8aca4ab368790a08f33962d446e164db061056a65de11067738865c64528d1bc",9.917710196779964],[8211,"102e4262e56d4b9827e3585e9191f7faa4346c4994cefc4f0cb897edd6c1e7c9",9.917710196779964],[11961,"54b62845b289a965eda0e14cb031184ee1fe19167d499e7c6a937e8a98e797b1",9.917710196779964],[5497,"6bbc488dbb78ccdeadd6c8fe3be9f3d67ca484e9a359fdb6b525aea4a9aa3cdc",9.917710196779964],[3005,"1f436a5b45f8f03c69dbbe46df03ad469ddd3c6823515b7367de70dec1cd40ec",9.317957166392093],[14244,"ef5d261c3f93e1f42d475cfdd06a35edd646490dbdbb3e32d941c83b8c10228f",9.317957166392093],[15730,"b2d26fc853a4d1161b504db31f4ce33c8ba797f8a21842acf4dcaee2bd1eea6e",9.647446457990116],[5883,"1289e98f902a11fa07320c65ecb697ffb5b646f55f9226473642d4ed5f4cc8d9",9.317957166392093],[2100,"fb8f471c91cdc515ca11ca135736eeb64b15662ef41b564ce9d76951d43543f2",9.917710196779964],[3061,"1e5fca0e93507bfdca6589595af104ad63b355f3fa70fed74c61fa7d4de7e6eb",9.917710196779964],[9143,"ab0d8951460b10fcf0066fff38cb9a791d0917d1a7a05f6f4e4b514dfe3fd9c3",9.317957166392093],[17700,"6ca303126ac9195aef58d62e533166f6b2365619dd56a2b3d426defd2b732843",9.317957166392093],[6073,"ba904a4a1b66a800e7518a0ddaa707e570ef66f9f89a1f90d6c188cf49b798d8",9.917710196779964],[8094,"830d6cfe13b74e3a412ef92176a1737b7339c19089c7e02e92e25a143610d1ca",9.917710196779964],[3642,"cf0de18ea1561e60aad8d58cb97f3fa16a2e5465ee874b7f2354739e254effe7",9.917710196779964],[10747,"9a441e58ddc82ab587be4896d3e96e243de35d829aa4cc3a1880176a2f63b3b9",9.917710196779964],[6418,"fb9dd5fb2c8cdc9b024b97dafabf9289b6e879aa236f4b8464022ef27e932dd6",9.917710196779964],[16092,"e1abb02cb39f96ea550bd89793ec3caadc3009f3da9dc71c2febc5f57c726366",9.647446457990116],[7559,"8f1a7d3dd0624708315a0b6e5de744072b0393e50cca146a0d37b182918174ce",9.317957166392093],[18847,"2e4decc7dbbc8c3674625679562f8d9cefb634c991a0b3470b17b8ce7cf71f25",10.052724077328646],[10513,"f39892e8fe6a102838712a5dd6b7830b9b57339a710e1be6cd2ff390a43319bb",9.317957166392093],[7048,"e2a23b0c2379b0757a280c1e2a4fa41c88adf89eb971a3dce6678e917b90b0d1",9.917710196779964],[7489,"ac1fbdec0ceea9fb99cd2a90efbfaf7affe0d17d50f33b91e8b5eeb5ed07ccce",9.917710196779964],[17960,"072276d92d8c4ff63b7a29f26023aa575d5171d9ecbd7ed90e74721df74ff03d",9.317957166392093],[15439,"133879f2efa16dd1390dabb1fb6446112e4e5bf46c64de258daddcf9c7e16575",9.317957166392093],[11818,"1a0cea5d5574e4d688a509c7a21fa24dcb642e6e82a507b62223c4434b1997b2",9.917710196779964],[3085,"f1c1bdc329a5a1957254748832cd4d658b1f09dab3615fc67db528d12154beeb",9.917710196779964],[2191,"23435d50553d70428a8169fb0e2cbe98a2a2f5fa0c514af5f454ef97d47a9df1",9.647446457990116],[1443,"8e0edddcf2ee462c97f2ddc7f8da497a15d290483d4d8c4e19e00ef5137d89f6",9.917710196779964],[8342,"91173c84f3aa6dc91d65deef8ae8bee25548597a0b1cdf5d8727815220ca0dc9",9.317957166392093],[4743,"9936df691cb2b8f8f1cc2066b266ed6c1513e6527ca1f3c10e85cfe3176dafe0",26.173719376391983],[5418,"b90cc4176a5de5a5c29c5845a2683b15399ac4ccfa5787d6573f9ef4c79db1dc",34],[13512,"8e64e37b5c72f8848b9ff68edd8a168d4fa8790aa74844d2b44f961e8f1e839f",9.317957166392093],[16781,"0b0389ef797f31dd4541234d24c225b186d23c8b25af9076daf94fa86304c156",9.317957166392093],[2035,"174c6dd459e6eb5a6f7b1f3da88f64ea575565cb0b240639d0c380261f1fbef2",9.917710196779964],[10058,"7c631a4951021fcfe026f09ec0e8fc4ef0d97bafbf5d10bcff2fb5e4aba300be",9.917710196779964],[10237,"773dffd9895af28c8aecd9825eb23573ed370af7b723a1dc439f61379397c3bc",9.317957166392093],[6583,"a612e637ff1b7f70b759cbb3ccbab31cd42b8cd56ca81d196d285c9a15eac5d4",9.917710196779964],[15994,"0755e432ac568e008d57c3729c684fd7d027979e5d3af7323b26c7fe0fdb9868",9.647446457990116],[17094,"db4a1cc566a99b1e83a297f36d2de94a03f9ee231289dce68f9c476b71b00850",9.317957166392093],[16665,"83cd63c83f5c16ff73419e0d950f549ba461e560728865e5e5565268dfa06059",9.317957166392093],[12028,"fa62462b1e6ad0a7c3ced4efc25398cb83712143c715e3afbf3788156d0a1eb1",9.917710196779964],[2252,"948d54f1b71420162967b0beac14e4ac8d5bae5bae50fd5820e8472058003bf1",9.917710196779964],[4208,"7f44792c0fb4ed22554ae35a035aec8e890fd652531324d5ad1d7665b9375fe4",9.317957166392093],[11426,"74c4accb596edc11a5eaebf39d82d9eb9e457605c1db92015691f507716525b5",9.917710196779964],[13636,"d2a39eaa5c80fd69e80dc0d1f822ac06bd225d47c3a510fa32af5969343d979c",9.317957166392093],[11429,"6fd7f3991247d004d28ea9d608d4da81e6dab3fcfe21fb8d5bbd2f349cb41eb5",9.317957166392093],[16207,"8af53dac9bc0d3539e6aace3d4b6d89c0e68efd8265dfe96f97d47b83047b063",9.317957166392093],[3483,"646001aaded04511415420fcb3da4fc13443cdb419baa7e8729599c98dcc26e9",9.317957166392093],[19574,"037abb3a7e465c9b5a40ae0396b2f2889a6f9a398b0e028a4881f55a9b0b620b",9.647446457990116],[113,"7fda1eb53bb3a5e2dcb2ecfdf0ef43f2cdda41c700de92e1dced9daa086e4dff",9.917710196779964],[12107,"4d003eec89d1d51703cfdd81e50adb9a7fa212663eb0163cef720bc61facacb0",9.917710196779964],[12580,"10d736511b8bb0d0a05b794593ca32b81b4e3bf7a9430aafecd0a8f6afb666ad",9.917710196779964],[7907,"1713fdc237b0bc1a6b7ef228e4ca4181e7daa238314b090e863362e8777830cc",9.317957166392093],[10175,"a0385dced5ce2c8d9c24ca2a5e7ee815d0d04f7f67653fc1aedb2bb8bc9c37bd",9.917710196779964],[16952,"ccad8e3278cb3c380d7fe68ff6905097e05c7498cb96e1aebe621ee7b7371b53",9.317957166392093],[1498,"d3964f5cc448ac039e6bc5989197f529d845fc62058aba966a5886f30e1423f6",9.917710196779964],[14748,"c7663a0801a90ed28614f1b8e421f01e46c253230ee81fb9d134ff0db435f083",9.317957166392093],[9288,"2cec43da6f027714323f4501c2c4bfdfd66d7653de3983360083222c131ce3c2",9.917710196779964],[14761,"b134d81212cd86cb88bc5bf32b6bc09c654b2451621b8be5c7fd3937a419bc83",9.317957166392093],[6395,"6914a32ccec5fd431421451b442b0b5b2b12f0f18fb19ade019438cc63d05ed6",9.917710196779964],[15433,"86e40d3e21b3778b2d5653bd843a436a70d534c78fe32719051f02dfb2e07575",9.317957166392093],[6618,"77547f489012ade0fdd13f24b840f7dba547397badca9c8e32112be766cb83d4",9.317957166392093],[8007,"7c2a4b2cfd6b1e0962e0afaece11e260796228f4a184b8448a14b14346bc79cb",9.917710196779964],[8351,"0a0c40646fa383417ade6b17b870781f27869ca40e6f4462622fd68ea9c1fdc8",9.317957166392093],[15912,"ba6960c8e263a0e02be6718651b8f076564f193b9f090325eda48b5465eac56a",100.53475935828877],[19401,"1fc057ac947fddadc80e9df8464c318b637b859e6cef6d2298c05bbf3bfa7711",9.317957166392093],[11137,"26d77be51b26204f65bceef9a96b326f6f07a08be07685dae4d34586b7a50cb7",9.917710196779964],[4366,"f4470e0817bc78b045c793be36db21f38535b2f9627fae5ada82f11a5b1e4ee3",9.917710196779964],[7061,"98c0122da42d671c38941509c4cdb277e2887521aa92ea4432d1869c52b298d1",9.317957166392093],[18605,"ca803bf0933486dfd313dc082196e2c63aec1dd2e12d009ddfc999cca6448b2e",9.317957166392093],[15383,"9091f11aee97dd3a2ebbd4c6e5e79d6c26017a449d039cd013ad0478b239b476",10.052724077328646],[5699,"74c9174bfc1d7d0a12838f36dccc826331f9c93b1d10ef5b084014e91ee10bdb",9.917710196779964],[8544,"ad1e0e448bb3bd8c6b43018a1f0cf7b544eb4119562f1e9d654ecec69539c4c7",9.917710196779964],[10059,"3ed2e5144f651cca046f4fdc859b413dffbcd9bb0a3d9c8b518b9647a5f4fdbd",9.917710196779964],[16261,"8052bd77f44e6149c4d504f47854187f048db5b6023630fb61950a34b30d2762",9.647446457990116],[4810,"136ce87727c1e296e736615c25feabd78d47f28c20dee96ee35108874acb58e0",9.917710196779964],[906,"ad57fae07628f915981cacedec9cae911aff95aca33e4619b7fa490ecf85ccf9",9.317957166392093],[4919,"fccae47e6e3412a750f66ab4fe639cedc17deed5f0b49477ba13e2acc07bbcdf",9.917710196779964],[3340,"8584136c77c194ff5094086172723c5f724217d70f2a60c7811b84edb7e40dea",9.917710196779964],[16528,"163eec7845554ae110d85d74ea942048b8937b57fd2b78a8ab7d55fda224865c",9.317957166392093],[13016,"0bedc866fa366671beaf11d959ef6514b561352af3187d127b3adc5b75f67baa",9.917710196779964],[1362,"0ec714750f5d2178dfaa7f95c4434499a2ebd8e203b92514d909fe984eb6faf6",32.76712328767123],[10003,"4b929426751c7e7769b59b8fa73dfeca5b4d82daf067d58e196b94a0df9250be",9.917710196779964],[18405,"33e4e3777d36062b3a28bc08ed65e9181425d0336b19703776a8d615e36d5233",9.317957166392093],[6955,"f1ff06192ca17f30162f7ac95e81c70232a7f4f9ca455360de87d7c3042b3ed2",9.917710196779964],[13641,"91b17a51b4e548a78dfdc44d4e58de527ae400e8da74a37f55ce19a98624719c",9.317957166392093],[17142,"a4dc35143dda4db4f8431b299e4d9a467cddbbf0faf1636248da088acc1c444f",25.359430604982208],[8373,"f5e63e6adc58af92bdd9996b2621c8c295b20b2809894300c4487f0f6dcccec8",9.317957166392093],[16327,"ccde28bd01b80a5b90ac849071bd92bc805b74b63b02cdc53f9e6a021e757560",9.317957166392093],[12670,"9e5e94121c3eb8d6bddfdb35527ddc26c4b0bb5c6d4b392bf0eeb287c9c0c9ac",9.917710196779964],[15300,"4cfc2e817ceaa1b667681ae742431b6c7c7e57ece849bc5d626056153f556e78",9.317957166392093],[9067,"07b57fb33ad2978141bf0ab7047dce0e046563ca238c02cca48d476f18ef5bc4",9.317957166392093],[9443,"3cf55751c1ecffc30d2c86b91343a8403cc630f2053f8f39fdce8ae1111212c2",9.917710196779964],[16521,"20a472cc542f8747bfe51ec138f9edb0dd597c2d24e545bbe5bebfa68bfaa15c",9.317957166392093],[16586,"46e84e4b420ebc47aaa7cf021603c496cbeef81051be3dfd3249b40ac6a2535b",9.317957166392093],[7989,"3436416fde24510f9091131a26ef5499007dbc233964132e87d8b961107297cb",19.796387520525453],[16015,"9ba4e553287601e68061dc2ddf734c05d6321b3056ad11b8a6173922be762068",9.317957166392093],[1422,"32d68ecc418e1a152b4c80b8870c493eb03dafdfe15d72a8d54e3c00be15b4f6",9.917710196779964],[244,"cd18c54343b0369a3a4a807108f9c0126893cf71087eef7faf432f42890559fe",9.917710196779964],[10576,"67a8749ad1e7f2d4048201978d4cac9fcd47db295276db674f080edb7790c2ba",9.917710196779964],[1044,"06fd2042d900475c162dc3a9ef2d954632f972a8def8a4fb70738920632001f9",9.76595744680851],[18899,"81a9b0e36a3860299414a4ce6e6fbbea7bdc78811fa371a4bd24dd7005458d23",9.317957166392093],[18011,"b4432877acc94beeb5d54541f0edd79c8c1f56c352a644b00b627d0d3753023d",9.317957166392093],[1099,"081b7d101d11d8b7d7b12a60f9f63a959b470a263cb39418d947606ab35194f8",9.917710196779964],[19095,"0526c4e2163977964d0064dbfc13e52d6664123fa0ff14bc866fdc7ef1e6ec1c",9.317957166392093],[7078,"a763565459e128bfacab7291037768d22d49e424f893bd0c69dce4a062c378d1",9.317957166392093],[11437,"25f762272acf77a90a3963613d5a8e37a54246e047625e7ab67f5597eda30bb5",9.917710196779964],[2504,"26ffe0a60ed99138a3e580fbc1f990134f35c2e675eefd42529fa76cbf34cfef",9.917710196779964],[12631,"bef69a8c8450ded700bcdee20140c6e50dcf3079c857a176ae9d3b9152e713ad",9.317957166392093],[12320,"952b8bfa2f144049434dde659b96fb0cfca51be042a606de3564361809e714af",9.917710196779964],[4217,"808911acec64821c668bd0b8168f070c1fa5e2adcf87e8cc02abe50b7cff58e4",9.917710196779964],[9503,"04e046751bb94bf05ec7c81898cc4addf65fc9cff0dcf8acdd764062cc91aec1",9.917710196779964],[16553,"40d4a8e258bc936fae302556f52dc547c40f2e112ed756a09b5bfb466c75f85b",15.91637630662021],[14560,"d0c590db0864345fe2663e01efac88e8036731f973ecf6c135f71a21563add87",10.052724077328646],[17023,"fe05272af4e18dc9f1873216d566dd9e370d569e0178d12aa4529109f20b7451",9.317957166392093],[5002,"9d00464845bc226d4f91410690419dd7dfddb7cc11c85273a149c1f23bdd26df",9.917710196779964],[13461,"7d5405ae6f615dfb5dc90055cfd3fe97aa4087a287aaf875e0872d30c748cba0",9.317957166392093],[12392,"915949d55c5c7a3c70e0092afae4d457a643e53933b02d3f2185edec2ba7a8ae",9.917710196779964],[13030,"04ec8d78fb2a5faf1b023277694c81415187f06e88426be758f8e3f8e4cc65aa",9.917710196779964],[11258,"5d013a54af5d94d11c9316d644f2409e7eddbb2211542850052067fa04104eb6",9.917710196779964],[16414,"46610c981de65ac232f71eba60fa5fbaa3923435d35928ccc43619c3d3abd55e",9.317957166392093],[1072,"f20860dcc21f816762e690b92b501b0fd40f6b565f3f8d888c6e4df6bc32c2f8",9.917710196779964],[9976,"dc4671b97645be046e35097c59a75368f9017f743b71a0d121273a8ccb0676be",9.917710196779964],[1623,"a89abacd7d4616c87ee06d627751aacae8942795eb378e22957ee68a302570f5",9.917710196779964],[5607,"f744b672237dbb1571f31142d453754cd6fa741a3bfd03af8b23156602099ddb",9.917710196779964],[18039,"21e29e93a4d7856da9099cc6f1b3f845157410503c42f3ff3b153e3645f3843c",9.317957166392093],[10024,"af37b9f94efc4b939c35ac17afe921a23afd08a5c6c3dfb7fff93fd47b3230be",9.917710196779964],[13204,"1c6c6998011c89bbb2b3600803efceb61cd1c9cd968449ef52e3119f66ffcea6",9.317957166392093],[11728,"c6f4a7c9872670f1618b0c973e6ecc6f61104985102dd7c53b878221a8241db3",9.917710196779964],[128,"5e6fef413825ceb9a3069198ab85f7ee332f3c71fd343286fc8a7c5cc95421ff",9.917710196779964],[18098,"f24b51d91503132af9a5e1b6330bc654269062916e26e6344fcff4006a38063b",10.052724077328646],[3867,"bf98f88fa303f688d4deaa3d4f3d7f9a43e34ac28cce7f174606dc42241f90e6",9.917710196779964],[10501,"50436d5575eb98fd010de24e91a425a98d06c8222c6a0f6a5d1093e429d12abb",29.112403100775193],[10356,"118fd711b25bc69b74a3a2bcaaa35ee5b6e26514c7f49b29f2298561106e04bc",10.030959752321982],[7751,"946bda54a994d553441f078f6c5be681315793ff06c48c7e313479a91fc221cd",9.317957166392093],[6119,"78b42de3b50e1bdd997461c631a208efb6d73aeebb68c61e4630fbe9e0b74fd8",9.917710196779964],[689,"4b67f69f90bdab13b5ce7616cf621d9a78940d1b0dad24492decfd79a90554fb",9.917710196779964],[1702,"4ef5c7dc4993ff3ee313448344ee317ee1ce99e8853fa90f31f98acf962cebf4",9.917710196779964],[14364,"36632c1c4ff8a6f7c3f2e0cbb40735a2acce82e75b828a3e1e06919b272d298c",9.317957166392093],[13326,"b9df5d727d49e3e69b238647ee0268e90b069fe1858aee2bd65bebd950a720a4",9.317957166392093],[3581,"92db447ff7496eb3c4a7bb9ea704b31017c55062788a694f06ff1b3c9ec56ee8",9.917710196779964],[3935,"23223a9f4c18f71789dda12363f453eff08e5f0744af9b5746a348c5fe811ee6",9.317957166392093],[14428,"be3fda4bda48f4d7fdd116ab68da44851e80aa781ba6bd451c85d8ce5ddeb58a",10.00836820083682],[18534,"d7b3a653854270eec7574c614d45c54cc5aa8e1d1ed9fd5efe978d4a866ccd30",9.317957166392093],[9312,"ae0d1a14453df80a875b5c34f4c16f745d5fdaed4f77ce9d9fca374fe722c8c2",9.917710196779964],[7376,"1c0bc922fd8c75d6d462d6bf016b5c53c56064c5c320449f57d57485f5e68ecf",9.647446457990116],[8552,"bddb19311802d1d9b1fa6c02c3ecab2b2e2fa0718f8c950a775f94099ca1b4c7",9.317957166392093],[16932,"b6587671f5bc46365f03262be4cdcfb850776e9b49d8a22a6bdec7daa1457553",9.317957166392093],[16461,"6be3ca33481acc9864feafd982630c91fb7f86dc6a77c431dd955ad04fcbfe5d",9.317957166392093],[7812,"52977e01ab1ef5fa636c6151d3867dd07a3b9e2fab8eb98da74325a2ff65b0cc",9.917710196779964],[19718,"8b64d0f14f0a3f2b704ebcdbe34cd96e682a4df65b93cebea14cb6fbb6ac1c06",9.647446457990116],[1817,"cd298c4922afec6dc564ca1cfab53e5941b09c6dafd03448c5629a47dcca21f4",9.917710196779964],[18799,"293114da8744d455bb4a7420f84b59d0e121ab9e5a0d38e507a97e00ec6ae826",9.317957166392093],[16808,"ef6a5dc9f79d2f6e73991a7ad96bb94db2fe2ecfe364ed194ac4db13f28d0e56",9.317957166392093],[1766,"2e4c0ea3a3e0760d8c5f9f9a534175fca75590a7388c1c80fcec7b2517967cf4",9.917710196779964],[12764,"795f3f943ede06823166cdea073e6812f8711b65589a8dc37a112fc2581721ac",17.073014018691588],[11953,"a57e4faa1041c682ff8f17457162706ace57dac0b7bfc6e3c1a40f9c4218a3b1",9.917710196779964],[2526,"c72331266a77ee1b9dcb8b625c43be28c5e42b7339e7c898c1e7f3605836a4ef",9.917710196779964],[8039,"ab065b322f564f8f043ceb0388b781587da7304b552f918263aea29230104fcb",9.917710196779964],[5498,"db11ee56278b6ffa5e03e2bfd987b043aeb6cc29f67f48b94de516ba8c6d3adc",9.917710196779964],[3070,"adab097d40cad84cb473abc3b567d04dab0163796a124d1f2a0b670d504bdbeb",9.917710196779964],[17166,"03fb6d5e0b91fbc8ff0f6db1c8ed38bb4376f1bed049d970b7b692d73522964e",9.317957166392093],[6766,"d9761eaae7a171dae4abf36b9958f0bd6eece4c1e27a957ec0c4e935d8aa81d3",9.317957166392093],[19451,"b71d6b32eb1c37bdb4120b75b2b85ea88904b47047537108fa7cf66f726ce10f",9.317957166392093],[18732,"285a1ec43f40512be34836e1a33f2d29abcb9367a9754443944b804d2d744d29",10.052724077328646],[14600,"fc4ef2b83602f2b645e1d7aa39f1fdfd0ac083e1a61966815df6a90de8131a87",9.317957166392093],[5420,"54cf0f1186a9881aa241fc90d6c877a2518bc867d263d33e12c8c1161530afdc",9.917710196779964],[15456,"68632309fb5f33cb2d879df9d80f64b31b8fdbbe4639f5874ff0133dda070c75",9.317957166392093],[11415,"6277c79b422c2198032be3dd455356ad69af6bc3afd55bb934280e91144d40b5",9.317957166392093],[12032,"23502ce7b4960585cfa1bf7aab35a5e561810c4a612496d660dbbdbdb2a516b1",9.917710196779964],[5908,"40a486344ffdd2fca82872918f1cc3a36663b870ddbfcfe705034f9c5f6fa1d9",9.917710196779964],[15444,"e9463f105811201ee2d76e010625cbe3016b26cc45da13cd83047a89705e4375",9.317957166392093],[9542,"14eece1b751ac1fc6dde1aada6c93e443409677b0157b8df4ce953d0a3db70c1",9.317957166392093],[19813,"232466fbed3799508ba03258e89d973e8f5a811b4f6b7913f257cc575ffc3302",10.014471780028943],[10898,"34b6c12d00eba5e9773357d661710a8fc983a0de6f941946cbcc5aa7dbdcafb8",9.917710196779964],[7076,"93ad9c7595804d6c5e81994637f1939622c4ce21c4b1e8b121e26ba75af07cd1",19.17640779290099],[13590,"726d6629f1e1435928ee963866c5f5cd3f8d90716c8e1bb53697a8064698b19d",9.317957166392093],[19113,"4d940908c5a9303acfd8dae5057bff8ed2c4c7058b17d397694d6db93c04d21b",9.317957166392093],[9224,"55ee5cc5d9e18e4c1f6c759cb1e8b05f4f541c7b5e5fca270ef3c5407aca52c3",9.917710196779964],[953,"88e317c03068c54bc1f393f5e40ef0b8fd9f47121d4bf7d13fbb1438ce067bf9",15],[2735,"c7b60264c87903cd6797cd3bdf9aae394ce1f93d222f85520159358a072433ee",9.317957166392093],[3957,"5430df5ba9cbb03e341d665c83d98d888b42625e5ca9f6f51bc7d8dba83df8e5",9.917710196779964],[18119,"71ab4941581850b2614c9b3f8e4581986c4995e24cc6f1cc7bf0ee05cc60703a",141.45234493192135],[18262,"17b53013b074f86d096be911f90cb80b0bdd76ba4d70c757b803c8357961c236",10.052724077328646],[8653,"751e4efd0b315c68252307c4d359f81626e36de86fd149d505467c60ec0704c7",9.917710196779964],[4428,"58f3606453de3dfcf2be4d9450707ec5b45041ed88bba2c17f160b4a8d61e8e2",9.917710196779964],[17413,"286c6e00f4aba2915dbd1e10c16491c0ad649a0158dfedc0b3da29d468cf8f49",9.647446457990116],[8379,"8b1b5a3a2dbfaa060fa52e9140673b394649e5c17f52a710a7a306852028c9c8",9.917710196779964],[16409,"ca223190b00ee85c35e7f76245919ffbf65ab7939f8e93313797e7bc71f4f15e",9.317957166392093],[11661,"7fa86025471d83e0bd0da3d403101fe4f6c2f801eb8fea775c0c27985c2480b3",11.073496659242762],[2704,"d834b0d9fb62579c5cd7db152f650c2c8830bd9eff7f2dec33462671f79d72ee",9.917710196779964],[7131,"f545790048e348c15b0210659ec624816535ee5e1ed116df44ab4806f38f1dd1",9.917710196779964],[838,"4cc7f970590b416343fa21c6557f9442d95c9c5c97a16b9bf1d035d2780c4efa",9.917710196779964],[5346,"2272b1b77ddf77352d3b4744a06d823b1c073f84d7fb7d5aac4bea78ad7a2add",9.917710196779964],[3344,"9a9358a1f721ee716a2a786428872013cc91ef153238d87fe5981f2e28f308ea",9.317957166392093],[7747,"ef8128785986ad018875e77fd8a64b958cc2ca8ec343f44dfb8704ee2e222acd",9.917710196779964],[328,"e7bd8df053f84e24050636179fdce6b1d6e57ffb7f41a5a8191cf91c97f3d7fd",9.917710196779964],[1689,"c8e42af00827f4ce64f81fb8e12b4b07d3b771fa8742bf8c94713b75b84a01f5",9.917710196779964],[8411,"70599ea61782f96042b0304e1dbf395566ec0739fc3fa26f72b52a1b5f0e8bc8",9.917710196779964],[19025,"6f179dcc38ff474b0596aa6859e432931e4787948692f32c82de5b557e30b51f",10.052724077328646],[7678,"8d45e27a5fa31168da64ab37a6389b5986d14c36331ffd9ec2729234b794b8cd",9.917710196779964],[18181,"c762c041b1838c3d4fdd749760b26af1dcb9abde40501f1dc7ce8b18ff5fa738",9.317957166392093],[16392,"c22efe516375d3a8f201f13a938ba25d09b9765528f204ca21cf8a1095722f5f",9.317957166392093],[312,"bd61171b0c549dd51604da1c90a519fd21b1691df350705820919414ce59ebfd",9.917710196779964],[16946,"337789ad39dd590148ee1fd3d2051c58e7810a4d18169ed9b12a72a802fb3353",9.317957166392093],[8726,"8e1ddae62ed3f657849bad8211da31e27951f0e8767b356b871288a40ac487c6",9.917710196779964],[8803,"f2cd0702db1f2e85e587a173294f9ef273d8fe35f442ede4b3e57fe68ed70ec6",9.917710196779964],[5496,"a15fe4d9df236a93d763dc9cd001330c0986ca8a53fc55a5bbdf5204b11941dc",9.317957166392093],[4986,"34a9e87484fb2382288fc17fd0dffd0a2bf7ee0b363c1544226e35ef511a44df",9.917710196779964],[9821,"010cb188b6ce56848eaab996d3104ebdee1775b57eb81790d71313ed177a7fbf",9.917710196779964],[14442,"a17b4a3bdef965d76ec11da38a9b21edb48dc53ad2f1f6963d2ff1456a2a638a",9.317957166392093],[15718,"f5beec9381baf07d8eca7091737cfd83dd38acc9a98d80f1745266950fc01f6f",26],[6893,"4b836abd745543422d8fb3f7c3db1723e2e1abe5a672f747026e5d1979a1a9d2",9.317957166392093],[9753,"76f217c8d3b484773e2aaaf9227f59e4630c6e93cf1b16b3f069ee86fe6dfabf",9.917710196779964],[7342,"c5072422cdc971c75a1d1de1dfbd97731b8868516d6f01e31d93f2d5959bc0cf",9.917710196779964],[13434,"0cf5b853a481d7ea3e7ac87a88613aa2799b427cb5fcc316400a4ad7267db2a1",9.317957166392093],[13153,"686545c0d5dadfd9622a1419aa56ae852b4e0932a317b7b8e122daab1620eea7",9.317957166392093],[14502,"0c5d7816c5d4588746b34431ccb9bc05e306d577a4d61935fa57b8f30fb63689",9.317957166392093],[11262,"73d67059121835f671e24912a5d595b5f2b91150cd63b0907719fa500cba46b6",9.917710196779964],[16888,"e738d2e779e85db927d8b9d845ce892e8a531980e13349f02d2213a269378054",15.003322259136212],[18562,"a7819421821bd11a2a7545c6f4707a9e1115247305c867d3907d58aa8b562a30",9.317957166392093],[15397,"f8d87430812e23a2d7fdc5429258688313824dba74752761e93134c62c556176",19.09090909090909],[3127,"bf782472d67a8b7bf6ddc29796e9c943a89f5e50d6c79034488c388996b77eeb",9.917710196779964],[15364,"c058d194b28f1164c7c49c79b28117b3c979e0e2ecba6fa1330b9d582db20677",9.32788068318499],[6419,"77bae7776c0f8408864cb96476169dd3e55c3fee0b177b7ce9181c7583be2cd6",9.917710196779964],[13374,"14402edb2963242a1da0edba1d0a2a81cf8aad307672051c1bd1279f08eff5a2",9.317957166392093],[9533,"b8f8056ab41bd018ae8765083add96b9d070e2bbc77c7ba048d309e0aee779c1",9.317957166392093],[15003,"dc919eee644188bd537dd950b015e9b905b429532de032a8c8b677a6962a4c7e",9.317957166392093],[6371,"e87a7e0285da529e9d5591eb9d75cca25938ff96588ff6031763e7e0f9d787d6",9.917710196779964],[3777,"13ee7a864a01f7ee20bf1c52fc1d8f94cd360d5838d56b1a6df58f3c4cc91be7",9.917710196779964],[14993,"93c2248505afa3ba86c0f7f755b475bdcbbbeb6a1a526f90f89112f95a7eaa7e",9.673151750972762],[9220,"2d2d0179894370495cb1a58f74403f4253dd9d0c7fe14686c47de132af6157c3",9.317957166392093],[2734,"8ae09ec557c0731ed9791d80f775fb8e69cc77abfd2ce5a04f6f9fa2a96534ee",9.917710196779964],[2248,"39841399b6b757cbd88cb750177ebd07f58c5c534c5910a2114371a696ac41f1",9.917710196779964],[4403,"c118dac00c4bab43584ce0367c07ff128d9c46bae55f58ec14af432d91510ee3",9.917710196779964],[7936,"b7f88fdd42fb090e298d1370ab276fcfaf937154bbde6013f75bdcdb26c8f5cb",9.317957166392093],[10471,"cdc310e8228af3e851226c34d83d327ecae8cdb9c63be50d9c7d7f3875f54ebb",9.917710196779964],[5783,"5d6e363bbc22b92ac80dad458cb78d0012da9eec3a87b254fdfb91db7b3a8bda",9.917710196779964],[5412,"03de0291f3700bbe85110013f697c2084a64866ec65fa4a9691d76ae3a60bedc",9.317957166392093],[14860,"adbea8a9fd546b5d4830cb25390c8d200ee998af2f79c88ba962f72ef2dd9081",9.317957166392093],[1000,"ae9ae935b8f5d9c601f07c12d10f0628aa7596b9b59720165084882443823df9",9.917710196779964],[11497,"0dceb256f9364157c2319f6ae91e165f800756c09251cf281b93cf3d07218bb4",9.917710196779964],[14897,"2d622df033f2fcd46260b406d982d9a6de8500b09664570aed2c5de0e1b1ee80",9.317957166392093],[17568,"996f3d56dc35dd5225c5c4cac6c2f2b6e7f88f7c23328b22f4b6581468c0ee45",9.317957166392093],[3411,"eccb9eae83e6420b7a30fa11a4cfb2553f95eb70d1da745b8abbd56197bc97e9",9.917710196779964],[15429,"fb0f9b24fa8d4597db966501d59beeb65b5869307f9f8ba9583bc13bfe9da275",9.317957166392093],[2710,"f35570ade3a2973787aadf3fa5b6a9a305b72057052ef740623e252bbdca64ee",9.917710196779964],[13059,"1b00a460bb86c2ad0185e3eee497975f297ba9e9ecc6dab68a5c9a5a941c3baa",9.917710196779964],[13736,"955439b40b10deba292fad5e3be7c27e1c2d2a7995579b89c013d672e594c79a",9.317957166392093],[17026,"0ab77ee5c954500675a5f3425ab1234b952f9125da80ca8098781d8bb1dd6c51",25.84102808186578],[9282,"25af83843fb48305f8c0f814762152faa5f0c71129b33a9275b6bb205c90edc2",9.317957166392093],[900,"1be4393e3912263c966da30e1491d22651a53bb5126c940f8f953e11679fd7f9",9.917710196779964],[508,"f98b40e94018f388533063785c0a57eca7fcb140b30c492863bd63b726169ffc",9.917710196779964],[8863,"a70a0ee74c538e9a5f09f29d5d8fa6f2a91734b8d40884ce1f8586c91bddaac5",9.917710196779964],[10616,"113dfd431e93d2e2a0ae51836d899b632daf06d7d7db921507b30d7ba21094ba",9.917710196779964],[793,"eee6382d52b7eed7c79294fd97f5b794ddf95f8718266eb8723713401b7992fa",9.917710196779964],[15025,"033dea61e58ecf70ef6c0765c270918f35e18b90622954edb4ba0eedd51eea7d",9.317957166392093],[13741,"b7796025cd12a8124ad38ae145ce05748416c05d745d1150f419d27044df9d9a",35.17149220489978],[11472,"977f14cb4827820b9a982c63a5ecde7f3295e9e7d98d964812673f385c58b8b4",9.917710196779964],[17935,"33172fdc2fb4dfd1fe8be3d437b8765f75ec650ce2db4be8585f84976580913e",20.201793721973093],[17552,"c6b30ee5823664ef1020240932156109a673f428c39c0203b8e1eb591ca86d46",26.17364657814096],[1897,"e30b8e4a1ab0c1ad1fdd4ce2cdb97ab2777e3566f60f8274d4ad043f96caa2f3",9.917710196779964],[9550,"988d53f5e9b9f1190c29a6f006ebb0105be0b6eb004b07562243f2f8b8a963c1",9.317957166392093],[2375,"99971f30cebd3cafc27ba68903203c0583fba9ce865696a80b1219caeb299ff0",9.317957166392093],[15233,"fca937a04b70fa21e2b8a601eff83902f7ba4ca75e0e3ff19c2a14d535eec979",10.052724077328646],[18469,"2693e0ca56d1d20a65a37510c9534495c3646f8fb5620c0d4422d3c77ba43e32",9.317957166392093],[12611,"d961d3b4a1c927a837cd53b276db5522df16cd8fd3ffb18cd576e7b9fcdd2ead",9.917710196779964],[4615,"f12cfa0aa7d549860c884f9122cdf2b90b1d0e6f9fc505f9e4c4d96ccf7e81e1",9.917710196779964],[17104,"969a07813427d5f46cb6faf5b510aa60d8a7861a514e2864408eb40fb4a3df4f",9.317957166392093],[3934,"2962974fe251a981ac49f86d714fc7262d4ced81c3fb49659ad1f446f9fa27e6",9.917710196779964],[14362,"ab6c06ede39dede5ddc2e48a9bf1df111c9b34988f63fc032edb24c6d0ed318c",9.317957166392093],[12397,"5f1b5bfeb5e4bb6c8b335953af0359d774c3949abebbb2141df84d08ba1aa1ae",29.50530035335689],[10588,"63d628c484db64704b2c28bdb5823f3e02c48d0be269be12bc1ddea6a347b2ba",9.917710196779964],[10939,"c5a6846faa288eb4d8904022631b61cb782e7d0cec2f9816a3b18e57d39e74b8",9.917710196779964],[4653,"ba5018d79f8a90265f23e81cdb5db85162c1562f57c2c7acb3ce62acced848e1",9.917710196779964],[7458,"4f1b334eb32a082ba05256c95c256cc9b1237e91da93136fb4af1282a46907cf",28],[7938,"7fa68e60e423bfb6addc0c76bf77215a9a4c779a5940cfd16435c51c6417f3cb",9.917710196779964],[18531,"e2338d504aad856bd6aa98a6660cb29ad38eeaaebad20e1528eb2f75cf29de30",9.317957166392093],[7656,"7b3f9aca302310ed046b68c33dc928fe17c24d6bf46b092a20390e471ca1dacd",9.917710196779964],[997,"f73b22ee94420d95099fc96a9d473e5a791d76eafab38c1d065ba166781542f9",9.917710196779964],[2010,"3c1b5f205db252b614d831091daed0b41045f62dfbba83316ba9a6ca10d5f5f2",9.917710196779964],[17066,"8c753615f1e38fed52ea48ce94579f2b82e28a108ee4efaeb287105e04cec850",9.317957166392093],[9038,"462ea26da6ae48a0a1050188490ad49e659051bcb8fdf437886c57e7e7b687c4",9.917710196779964],[6732,"69283bcc0798385576983bc22ecc291bf38368261ce6301ce571042b7c91bad3",39.12786885245902],[6925,"0e398a827c8ae0d35457d298bfc2962a703b368cc5d15981ed1d3879aa6a74d2",15.003322259136212],[15759,"f66f86e5df4629703cbaef351be870fca3e394978e7d0279a93efdc486e8386e",9.317957166392093],[13454,"3783c6ca0d9e06d4f07eb207b3bf062a51915ca46aab86aec8bc094a6669ffa0",9.317957166392093],[3405,"1774470f832ad001fb42bccb43a70ec96c97590c62233b5b6d9894804933ace9",9.917710196779964],[11830,"0c111d17e27f8b5df5cfb51cbaecc10ec751406150cddbe08515ce9c5a2687b2",10.052724077328646],[1001,"2a23fc636c10cb623a651d4b6e56088123d3d46caaade633846b3c50814339f9",9.917710196779964],[16544,"d797cccf85cb30a739d06eacc87dddf604af282054439ad6838af880d47d275c",9.317957166392093],[19780,"26989941d32e2ae0a8b345fe2f52c0560594571fba1739b927ece1d409007c03",32.387083462292374],[6331,"9b771e1ec897ef449bebf67279e880ee7506b3301ff25b3f8e4aa49bf0bec7d6",9.917710196779964],[16403,"c183734212288aa66c41968f41696ad87d800f090c2b5b3b1dc02c80cec00d5f",9.317957166392093],[12241,"8d35cb5ac63f0ba78a07a589a4abe2848a60b049d4e8a9917a8cb0029cbcbbaf",9.917710196779964],[10702,"05a6bdbeb8481774cfaa77976a6e3a55c06e6c57d90c19e1a97089787951fcb9",9.317957166392093],[6063,"6070b47b782eb413d21ce70b11eccf8ec79c242ba150544d31b9d9e0b940acd8",9.917710196779964],[6508,"ff896a9404d069778ae853acc696a33a07b2d523b5ad3592d48e3cd8982961d5",9.917710196779964],[11530,"e9f222fb14e5e695cb7ebc9ba70d08e58580aa76137c4035450af5e672eb57b4",9.917710196779964],[6740,"b2d45ce569c2792afc26cf4112b0fa104b90614f36c8fec3fc3b1472b031a9d3",9.317957166392093],[11966,"1491e48bdf12beced48356fddc8e85bbe02b445a71f4ffc3c9a5d29e515287b1",9.917710196779964],[11189,"dab8ed6ba38743f2680295c8cb23f3213230265b2dc093c97b8e26a77e77bcb6",9.917710196779964],[14085,"4a7982e52aeb30c4f51e443ebf34ba3e3b7bc66779badcdcdf64f5776f75f592",9.317957166392093],[10900,"b6331efac5b8d82837f58b604f761a2e7a5c4b16231b065c01b42d98708cacb8",19.00467174821736],[8333,"8564d9cef72fab72d61fdde94774b620a5619a1f74155e8d01708ce371241ac9",9.317957166392093],[12430,"29504031e3c35fc0d123c0d4b5a16f6feefe81dcec0e68c6867c884d4b4762ae",9.917710196779964],[11588,"1e273cd3f22dbf35b8dd39f3145b55978ad07066c2c2c56422a751fc6b6af7b3",9.917710196779964],[10984,"1de9cacb07cc1faf3657a398661c616efceb05e47364dd1efad02d15f89618b8",9.317957166392093],[1493,"199b10f98e32ac7d73af3f0b804ffc76364c6b9eb043f3687a28c0f5caca2df6",9.917710196779964],[12851,"c3bc2a86194224c63706cc362842c252f15ffdc1bf75d13c7daa35f1d3a890ab",9.917710196779964],[11026,"961acc8e47564257fb6ad73b1a4b3323b26fd2553fae7b869761fccd895edbb7",9.917710196779964],[7978,"a7405a4e38a411cdd8fb88b21b1271f52691ed04db88cc8afae4ea700e0faecb",9.317957166392093],[12374,"68ac218084f7f00c150c151d79873cadc93fa876a510a162789dcead26c5cdae",9.317957166392093],[19701,"d248dbcb056ae678f204d52980a1a638f7b4a1ea33de3a38a856bae9e644cb06",9.317957166392093],[9262,"406bb01ad8ec462d456b234f643613ca6f8e13ea05abd3c0c4938338225f10c3",31.664921465968586],[14609,"7b807c32e2378b5f9fba32f8d85ed2a6d0995b2a45804a7482d1d3f0891ef186",9.317957166392093],[16460,"d50261036e20833fce3a53a1ce29cccb3f139e6084509da8e57bd510167c025e",28.187082405345212],[874,"4400d664f97b04ea2e07ea551deaf7bb9e5b7eff7ed6a1c95b79b95b398610fa",9.317957166392093],[7660,"86a6609e1cfbaddedcca2dbe80b3bc7039abff4ec6e615a5e3e08aa101cbd7cd",9.917710196779964],[10805,"75bde504ee20a125811fb83f7eec87551fd6a0214433054bdfdd1901595143b9",9.917710196779964],[224,"c77e54b18ccb08510b07c67d0b30a7f8772eedfef6d7112243c3da64fe0c7bfe",9.917710196779964],[12936,"01c5138e34ae854d6615ca4aa483c76797824d89432efc31ecc60e494bf901ab",9.917710196779964],[14067,"fcc5e774405f1ab65a0d0e25a655b5ef20161893b2502ce8b4b26bedffc64d93",9.317957166392093],[13713,"a18e9182124c4993a3e7c5df795f5f737c577eaa7b62389a66feab4586aa1c9b",9.317957166392093],[5365,"f28bde0fd565d4d1c18f8a174795c02a34b42f7776048dd61fab9d3839fd0cdd",10.052724077328646],[18218,"254bdf0202413b450572a96fe5532a15e78135b629084c4437bcfa99a136af37",9.317957166392093],[15351,"9fc03491002bd6be58063df5e8afc764805b42e71a12ce2bb6eb904455355a77",9.317957166392093],[15702,"3dc0d6429d49fcf7f5a5bdb3636927c79290ccb652e4427ac2723cf32c03746f",15.124260355029586],[19247,"7a4cb1d011219c1ae2cf2ece108a1653df92dbe5f6b8057a350a105ed02df816",9.317957166392093],[13215,"a66f999b8f08e2b8728487ea4bee095835a44d5bbcfce211befbaabd12c391a6",19.19373297002725],[8969,"61441ee40fb6db739a142a974d4e8035f7b086255037030c3ebcdbb8f61406c5",9.917710196779964],[13006,"d397e4b38ac160e0b06412f754267a025eef5d100ae730fcc2c107677df789aa",9.917710196779964],[10445,"627672a1e045d98c2a12a2b060af7f1da7ab8a289c2f1acaf0b0ac376a2971bb",9.917710196779964],[4421,"6267cabc9a0f5d6b95996ca6407ba0e90ef84338dcdec0fe72e29af0dc1ff3e2",9.917710196779964],[10230,"2f02d710be5d34c11d0d6605af0343fa43d2c769dc8e2525b5ef0883d566c9bc",9.317957166392093],[11295,"f1e130e9d92333b14cb86d1c8fd8dc660beecfdf25746587a60b1ddebc2813b6",9.317957166392093],[11270,"ac1d38ce6eac95e22be427f9754153da741a3bc216e4a6cea41cc9e5f60439b6",9.917710196779964],[9830,"bbaa8a92c4b829944da27c3d0e41a3119e67b8abb67b678e87649acca6646bbf",9.917710196779964],[16442,"6810f42348a625e66e19f4ac5f2a7085035add16f3731cea3f61b6f47b48545e",9.317957166392093],[10257,"164f0783f797f70b02d0b4d3b1aa6047f8236bcbdd7beb529eb10f0588eea6bc",9.917710196779964],[15808,"adb42ea9936d65bd3058ae3c962d4d08740f3b31791edcada5d38a65d0c2376d",9.721518987341772],[16417,"bf0d8f736f63bc2df14d1962278c47515cc6fd8f67ebd2769b14b1329ecebe5e",9.317957166392093],[9188,"f91d4c5655e2ec0f49a7f7631b6e3d9aea4152413f4899c029b6f1b3823794c3",9.917710196779964],[2984,"1a055158e7d3b394206311c8e29e106b19a131921fa035564303c8e5b2cc63ec",9.917710196779964],[14262,"c0eb926e5bfc49fa6229425487c9af9e70b05373924fb5345828710c882aa88e",9.317957166392093],[2335,"24163570ac95a05ff3939e1106a56fc909bb6ced28938e7aad0ac70d51abd3f0",9.917710196779964],[15625,"e58490268ff11330dc8a5054c0bfc7039e86c4afd53b30c50b9f1b211060d470",9.317957166392093],[7715,"3a19dbcc92b0ea97b29840d759056eda824bf75c4ea443f04cb4835607de6dcd",9.917710196779964],[899,"f693edb7fa2483a9d7238a940a921dd341e8e6241c9d970bb610bea4a300dff9",9.917710196779964],[6762,"b8a79eb6d97150db9ccd3f4865f3e2479443d251f5a59750c4075b04745583d3",9.917710196779964],[5481,"fdac5d7aaa0eec7150821739cda4a0263136f59ef6c1dc0bbf942a67c5ed4fdc",9.647446457990116],[9570,"1c4b142e9e43dc713708e01af9ce01ec6edaa759a0bc6b90fab4fe76dffb2fc1",9.317957166392093],[18994,"22412a5f25cc03bd8c7697f711d8198c392a6f129ac1f6f865ddcb17652bc020",9.317957166392093],[18482,"3063ec8b79d3ea93baa01bccdf3e15903e9a64b852c60296e4e4d7532c1cdf31",9.317957166392093],[7866,"ab6d19c8dd55aa78fc3ae43f0b56aea4c8ee1f29d7148d29cac6bf96d2a275cc",9.317957166392093],[16604,"160cd076fbcec10ae041d0818f84e44e6222825c97ccc7eae0a6bb2c8100c75a",9.317957166392093],[4078,"e49a1d5738afdadaa2f90588b542313c0587dd689c0d6433cc1a723e191335e5",9.917710196779964],[2531,"a660b45be877bee22927f0055b0b97e1cd0562f49560a7fe21b3660ee5a19cef",9.317957166392093],[13460,"ac27acc3cc07811cb4740c3e95c73aa1dc3a638e187558a6e8d31c87a72ecda0",9.317957166392093],[2779,"f208df8936e1ab50b1684d77b47ac51db5b684065121bec1efa572eb8dc6eaed",9.317957166392093],[16572,"a78cf9c0926d37f69decbce3ad8c0598784f89d108ab6259277135651dbab35b",15.052631578947368],[2575,"8d0c5ed969a20fa8a45c166b5e7bd98c55af07806111a5eeff81062350b95aef",9.317957166392093],[342,"fa7d4f35a67bb3c11e3f48f5d8eb3c7608d4d95e7e27846a516ccae029cbc1fd",9.917710196779964],[11925,"3ffb2895a8c5a70dcf2148f829daa6929ae7585e5f598318a7066c751188ddb1",9.917710196779964],[9827,"8edb9bc4ee34499fd4db6c8a1c0ac27eff9ebf209bc4783e459efc23ecf276bf",9.917710196779964],[16190,"080a6647d0bea8bdffecc9d8e1be40f586934505eefe7a0b55a8392d2c172964",9.317957166392093],[11194,"adee3dd53159af3c5bc272f3b33b55a1139816d42ed5eaf6781100609c03b5b6",9.917710196779964],[12033,"a22a6294f59bdc35f64fa951aa0da70ad2bc2655059a95b348a751515ed615b1",9.917710196779964],[10925,"3e68dae65927d78167acf4473ec8958f04864aec00d74a42e1c588000e3088b8",9.317957166392093],[8209,"5a1bf379f1407ba52b68ff6cb0e56c9ce900e74363dcb0970218dfac59bcebc9",9.917710196779964],[528,"4e330a0f1bef79295bb1818a146c9d6db7e5aa3185a768245f414915757b7dfc",10.052724077328646],[16333,"ba79622afa0350ed80ec2df7606d9440afa1e3a8b0a22c78c96580d8d1616160",9.317957166392093],[1035,"061698190b5241309e0fe8c0b3da82e506dbf4d07bedfa983b56c3788dac0df9",9.917710196779964],[16600,"26e849d147291f0e6b66dfc9138ef11628e17b8a80ca7c0f1934bad4f2bcdb5a",19.100775193798448],[3262,"1129fd135a66483febcd153e13f2618501484e64396305d2579571d1edcd9bea",9.317957166392093],[5160,"7c704459d5e83fcbfa96341385ea1d47aca2dd65eebe6085093137639fad38de",9.917710196779964],[13039,"84d5c205fc127b3b913d9d6c3bc1e426fd8b08f6a02e8892278fb72af07c53aa",9.917710196779964],[18457,"65d18c1724ddd8b208a51c99b6cb58e43b753b3d27a8155f266eea4256ba6d32",9.317957166392093],[12054,"acba13f4868535e6c4408de5bec9b596c03b0f5dd21c77d223e0a6bdbf9df5b0",9.917710196779964],[18035,"254226bec26d7b0bfe0d5652cf62ddc51340aa15a2c58ad6333948244663ac3c",9.317957166392093],[6442,"8bac918deb41c05810a4da8843e4e3280767ff39c3f8db53c5de214e357cf3d5",9.917710196779964],[11516,"c558cd4ba06709bb2e2414625615586a25ca03edfd7f3060ee8d03aec2396bb4",9.917710196779964],[14861,"6bf2aa972a55f12778030865c6f3f76113d8f954b0e9b2af403936e28cab8e81",9.647446457990116],[3550,"d1f3adba493d24eff11a7363e1534471706f44c06525efed6d63395346b89de8",9.917710196779964],[7976,"a5fcaddb64a7ba7cd1f26d6483024659afcb545b658ac764f6c3ab6218ceaecb",9.917710196779964],[18533,"4e48e5320c92270d3f8c1b6b3960591b8caea0c6633b0afa8b9b54119a57d230",9.317957166392093],[18109,"44b3a5d4dd40dcd4d98105e8801a92e286612479e7e194802693460159e7b83a",9.317957166392093],[5704,"4d75e94e3edc71228a18cc49ebf4d8923ae6bd13c6430b7a7df8aae2a2cf05db",9.917710196779964],[3947,"fdf70297fb88b34f4e89d47c4c03abd3706e53a84c3b1d21f4d6fac05e8503e6",9.917710196779964],[7056,"a40cfd4454585fbaecda5c673d88ad883f4e45cd5cd85620fff4b171479a9ed1",9.917710196779964],[6831,"85904b2702b89954635e78cb2ab30a82d9ed678f4aad3bb02c3d9b3bc9b10dd3",9.917710196779964],[1806,"f62397a31a104bd3565ca19eb2aec7d116d37dca95ea3aeac2160632e3d02ef4",9.917710196779964],[9891,"66fcacdf6f0ff464df4f9ea598bb4460c253a3484bda69b8fca13798b94bfcbe",9.317957166392093],[4229,"9095867fd22fb0e33dde19392e4bc5dacf16e496119150670b953a41cbf735e4",9.917710196779964],[10437,"82ec5fc4fa0c91d1d066dbf498311126d9b4e4eea1df9f9a5f8311bf227d8cbb",9.317957166392093],[17296,"586bfe153a4e18f5d76145bdb065bbc0bbb3b976ea87ae2ca308e67a8b173f4c",9.317957166392093],[18037,"5151e48dfb612b3a29508904a096e8bbe3d133dc2e675c4e12d9d521e0aa993c",9.317957166392093],[13682,"187c494d995fd9f8b44c4d5ea946116d1f1476434ae1be3c4cec453e0b9c989b",9.317957166392093],[4460,"c251a86d9dd2d5af571ff989cc8fc4d71957fdaa1d199ac0519ee4ee9843a9e2",9.317957166392093],[7481,"386b256299b95cea1e6ac836de3724f182d07a4d72daa658c9cc72289e7dd2ce",9.317957166392093],[7250,"27aa493ace3139e206f91f18cf1dee38c867d72ec2219779192f83cf7a325fd0",18.05729877216917],[2806,"c34704316c7123898a7c376d5c973211f8de03bb94ab36474187c1c27919a9ed",9.917710196779964],[17603,"f89ca168c095244556e12f359cf4606584b6e72deaac51d1d71c556d3e410045",10.052724077328646],[6223,"04446862ab4c85f930c1d48462148db9e778003638c65e4ad8f24c390f609ad7",9.917710196779964],[1969,"acf0c958d8cd7d7b6e4699b30314d063d8605c1912873bd2f56e480ba73137f3",9.917710196779964],[19747,"b646ab3453343936d30acc2122f9ede890fd3dd099c92b9cf4cef0f08dc7ec04",9.317957166392093],[6034,"261a90b0b636474b1d39d65e05e4154820464ef39c2a2fef87b6efbe3311d8d8",9.917710196779964],[14076,"3647a0e552a011da9368aedd13629ae1552710e6a2815c98aca18d651fa21e93",9.317957166392093],[16496,"22bbbfeceb0a41381cd6da0f518b3142b0fac7f37391ab8ff6c5c9e6354f4f5d",9.317957166392093],[12425,"579c20670706b739302607076e22cd0898500d1a0fecc65d2f5b2c3bc56769ae",9.917710196779964],[16664,"a10f555131d68dea9041f5e5a11af9072b36a3c6a5e1b730f47343f231877459",9.647446457990116],[15822,"15be6a643e5a96b72bd86e77d25ad9e4ea7677fd8c2357ca9a9e6f507ce7f36c",9.317957166392093],[16672,"f83eaf6d7979a27b5c5993e9e39020d7228aa04c228274a41fe4edaf3e5a4259",9.317957166392093],[9674,"e3806cf85e0a2a92659da638cd7ac78d6627ca104fc0980ec9db4ae4609d90c0",9.917710196779964],[8027,"ee8e7a0bc67373b6daafbad6c299461b24f4908962f251dd1f6e37595b1761cb",9.917710196779964],[13127,"4a59b792aad9dbbf1e7cf94dae111df92fecfc1bd3a504a7b1908569e19773a8",28.101083032490976],[11087,"e065e2483a99b9de7a3e3565f5fd33a17a4f3deac9683f0cc44c12e3a99a53b7",9.917710196779964],[6079,"5d2c01daef06b9238bdd2996c1e22c5b0f869558919f5aca341611775d7786d8",19.160655737704918],[11804,"eaef687d6b0b9c600b771600b7e844cba85326d2f89046d7808f777e1d41adb2",9.917710196779964],[13655,"5ca7f6fcc0fdb56c5693af4c3f002b5376533472b4353a6839c13e8ee6001f9c",9.317957166392093],[13813,"4097a0f755cb4f36c1282fd92af437dd8e7e8539fff2cfe102a3aac254802999",9.317957166392093],[12775,"cbf8d074eb9eae69ab6b56415b0a70c6655640533d0915e6054daa98ed8614ac",9.917710196779964],[15974,"e6934b85793c91ac026f15dc2b12ea1f7c655c1e7ae6dc893a7f97d619d43869",9.317957166392093],[2878,"3b05e02c7fbfeda5b16d59f825e8cf98659380601c0889c3e414d3747dc040ed",9.917710196779964],[7541,"03b5c060cd33081eb6db71b5569c1311a8a4ae14c2436ea3a18ce5a883f990ce",9.917710196779964],[19605,"0ea3af93d36f1569e6cb44a848e9009b4c41d838d99360f9296df57d4f81e409",9.317957166392093],[5869,"ace144b9b4eaa37d5152ca9f2892d4daf6051cf7ad62e4bee68263959b6bddd9",9.917710196779964],[9943,"eb80b0a18ee87275b483f757ec55015e03c312c56c99c54accbd1dc6c37aacbe",9.317957166392093],[15082,"2df3987e51a78a8437d2e12c453fcac33e59278ea5a289d98a740606f5adfd7c",9.317957166392093],[13654,"e3dbe332a8407b00d24bc6015420cb1deec299bf043c66edf66ade26feef209c",9.317957166392093],[5024,"793f669babec5cae286597906824707e4598cca0d7c2832800123058a8a008df",9.317957166392093],[1892,"b2e9f4ba4878310d404cbbe76cf72e69e516961ce865eeb0a3111ed8f55fa4f3",9.917710196779964],[14832,"a616526c98bf802cbd9c2156b6328302c65cdded3a9fd9bd09dabd000beb3f82",9.317957166392093],[12885,"bbaa2f2d2954874bd404f67f44f8bda44b4c08c5b46d645c7bdfabd7d9235eab",9.917710196779964],[2610,"c9e117d57aab070e90e8a67ff63f9ae65cbfe17eb322e3a0dd3920d4003a1aef",9.917710196779964],[4463,"e8a578501f41befc225bf523f004b0593a1769a87e3dfe6b296da4b03031a6e2",9.317957166392093],[4320,"8f72393a622f00f6ded258c1b744f22f9c45459281fd9331b179f05f9889a0e3",9.317957166392093],[18855,"5f0682bd713d0a5829ace058bd43d01a601713dd527c5eec09a9572e7b3ed624",9.647446457990116],[1955,"da9c03adaab3e1bf56005fdea2cd5b51c33651613f085bfaffcb2dcddaf953f3",9.917710196779964],[5449,"3312e8656fcfb8d4dd32f843a78e014bdab99cfc2ffa4a7e0e5997b6cfb97bdc",9.317957166392093],[12200,"089f6447aba1d32922b00cc5af55e6b589ad79f3ac025f8c2df42db3f99311b0",9.917710196779964],[9068,"5f84bfb64948d0f05937b91413fc4e06ec0abd3fd41a024a1aaabc854e375ac4",9.917710196779964],[17798,"bbfc4783c5b9a620daed774bffa23ccac3db8af936f686f1530b1979916f5341",10.052724077328646],[15990,"c2bd110c1cf140a7190f4accc7459c2f93c83a6eb1f663d6e047722c92a1aa68",40],[13532,"72ed57dcd3cd69a4aca30311f1667110a645c269c4dca56b94be3fe38965269f",9.317957166392093],[9080,"09972dff9cadfe3c75010d563b26fc69d8c1cb0b2ac6c8d961590d28a20545c4",9.917710196779964],[9538,"5586d2f4b908d86f045d452cc55c85020f33c2d631ea70be73e6109b315b74c1",9.647446457990116],[8121,"cbbc5ad9b41fc17eebb2f45faadad353ce3b8b7eec97be4423cd6127a4669eca",9.917710196779964],[16634,"935e092be559c869dd8ca0bb84fc85a90d6e12be7cda91b984d5d27dd9761f5a",28.12785388127854],[19159,"350a21181ad85a2bf9159606c431d3d876628382cab19dae5895a9590a092c1a",9.647446457990116],[4762,"43536319e9dc7d6c11df244688a666e38db9a891c77b2c59b8653ce0e02d8fe0",9.317957166392093],[761,"420415c54e6d398b3222012af56a86d06903480a8dffa1eb3f4e6fd93cdccefa",9.917710196779964],[19040,"a53ddfd4ff982b68d2b2dba17fe4cab86929a01c2a49b5b3583030de843c451f",9.317957166392093],[5047,"85e028ccef049f0c1223862ccff3cc5276ade9aa77165ed29e27489dc3ace6de",9.917710196779964],[6027,"e8d1bb082d986f69baf4b3edc0c4fb9240c59bfb53e84620b7c604e8413ee0d8",9.917710196779964],[2579,"4860bf922906788fe860031ff36a51b7cdd0d82c30e5d7043cdc0268aa9551ef",9.917710196779964],[8763,"63aba44f07df8fa2beb59e19cd8703ecf752c1bb0dda24e762e925e7036d44c6",28.19221967963387],[11313,"ab317c7e0833f3b28e7e0769a8e109efbc00d6ad0a7cead539494070affbe9b5",9.917710196779964],[1090,"a59d8a3b2712ca814eb3484c17dfcc857a549bd76be389c6bb9219c3d39d9ff8",9.317957166392093],[334,"c692cd64b6b38d7c46ed09839d11bb104189bbada78210acfa77e5366b27cffd",9.917710196779964],[16822,"c50202648b7101f3380265445c86c7963db58eb5f60796dcc7678b68dde2cf55",9.317957166392093],[3515,"0ece9c293d73b92e1d18c449334dfcdf23ae7489907779b42bfab43e1ab8dfe8",9.917710196779964],[348,"cd1c94c86ac0c298eb81c67669820b8dc19589a8f7b79c116b213f120ac9bafd",9.317957166392093],[9819,"4fc61c49d2a1030ed1f83780679439156fbb24884bfc2c2d5e18f4b9815b82bf",9.917710196779964],[12792,"e32bd232d3ecc09cebec418e74d02d4d8209ab6949121ddbefce539defaaf5ab",9.917710196779964],[4182,"924b483112ccc409bee842ba3384855be405b18dd6a871026dd775974fcb87e4",9.917710196779964],[5260,"6dbd622db24262711ebaad5ba44841080bdd256834cf1950b08d58cb28389add",9.317957166392093],[8578,"379160292026bcfe89b44c15c507bfe06d630365aa2535538b5c4dba809e92c7",9.917710196779964],[788,"c03b99c22358f933f074f85048c12290dedf64205a0dccba9c8f8b2bb83097fa",10.052724077328646],[16974,"cacaacdfc73940860e40e170a47e345780c504f9868d896d89695bbba08a9752",9.647446457990116],[18848,"30cbecaf0de3d23d436865cdcfcbe0f6d4fafaa625ccb95bb8528eb8fa691e25",15.073170731707316],[8066,"1a4561ba96400f653ae89a4b6e365b0d7a162562fcbc5e1685189968914efeca",9.917710196779964],[1837,"d17bd3a7744cc4bce5ddda53143023c90d5ed6e908f0136cc58d246f336906f4",9.38125],[15562,"af8ad037924b74527bdc01919e140b6a0a3f5da7ebf98bcb0611391f07d57d72",9.317957166392093],[644,"e47d9bc837dd1968ccddc0748cc2341cd945ef0cc363b504bad250ad2fe09efb",9.917710196779964],[16446,"d97ccc4231705b9e78e3d8978449da2cde2553cc05e62eaae6c2c55db96f475e",9.317957166392093],[8584,"65b43446193ac83f24a5d4b21d6bdcf3fc82d4ed0a3d7b5363df43e7873d87c7",9.917710196779964],[13135,"003c3488b9eddeebfaedbc555f9664e767788c4c578543103b0eced2a2af3fa8",9.317957166392093],[16080,"f525d94c2778476696f5d4eb9e2a0704995df37ceb53dd598fe2f35773cfb166",9.317957166392093],[11629,"14e53e1bea7aac2d83fa2896bc8c35a4f26b93e3dd2921b5c17549633971b8b3",9.917710196779964],[18465,"a55668cfc06a2111595ddb6f21737e97a51df6648283db724912dc3534914e32",9.317957166392093],[10454,"1794838f6352c727bc07ff781efed359db531788cc4c992fb8a9c3be1c2f66bb",9.917710196779964],[14505,"1571dd34bd29a5c40a51ddb9ede0bd29f7abdd99f9d5ec61e9d3d0ce43c5f988",9.317957166392093],[19518,"2dddc212828963e32cf622b50388419f9639f777d4b0e06188016dee416fd70d",9.317957166392093],[15711,"8cf1745503da717d6ed794736698d8d14b5ea7733853a3001a35193215a93c6f",9.317957166392093],[11645,"d281deb2c22694cf627e849b85024bdcfe36e1bca8d5724595eee4bcc8b7a3b3",9.317957166392093],[8798,"b569bb739c4f4d3f5e536e56ccbaa7a2ab4ae7230ffc2a1c9a0d59fb67b614c6",9.917710196779964],[15171,"901d82c3544f8df0f8bf4968df05916963b97e56dd1ae4184b9e80649b02167b",10.052724077328646],[1828,"b6244f290bf31f812e79c03b65e0eec2cf94f12adb9e578bf41c04cd1e8511f4",9.317957166392093],[9062,"4634cd9324f31ed1440d086bbee7bb26cf0b99b2bbb086e8496bdf7c071467c4",9.917710196779964],[1344,"e0fb861be02cc0e49c7552cc87890ebd126f234b3acafd1e726cb761a8611ef7",9.917710196779964],[12023,"b24f1205e87036da98edcf465887e1705c594b8db0ea59a1899006a88df12cb1",9.917710196779964],[11236,"75c1c73127337d8f9e138084b687c312c57719ab4c33e237361b9743449173b6",9.917710196779964],[4378,"7d7b4ce4e84e948dab1b79ffc2e5a023b34def25758d49be479f3dd8e18935e3",9.917710196779964],[1557,"7acafa2721096db1de2bab10ad228c4a2ad93aa967633323ca9344d5892bc6f5",9.917710196779964],[14661,"492abbc38e9b22df7743a84e95cb66cc54e9e038ccded78b2ed84eca9042af85",10.052724077328646],[1084,"68b52b61ab1c1defe9f5bc0c1db578e12333b50333b5b21b1229ea1c9beeaaf8",9.917710196779964],[17358,"a9bf69f72785f430b824a9aefd11678e24d7b51a70da9ccfc5a318e68740bf4a",10.052724077328646],[13140,"e2e58bfa50b2063c48eb8e4fda5a577a2df41703f00ba546d33ae8ed401b2da8",9.647446457990116],[6117,"d74751f45cc081c0c08fdb9df74b292a6544c09c1d8b0b1199f877c3eeda52d8",9.424083769633508],[2965,"533c03f0444398a958ee642c9b91581f6d666dce8260cb51abfb57f59d6388ec",9.917710196779964],[9923,"d560d2f4a6f1337a4e9128c938db7b2eb4bcbf05a5f7a02dbcd82832aa28d2be",9.344947735191637],[2843,"734329a2a3e33811d332eaa2be7030622eb74413fea0cd86db46aec4a33664ed",9.917710196779964],[3932,"a9468a2026ff0145e6668177ea1431d556e2387fbccfeca4a3021c25178a28e6",9.317957166392093],[14059,"14296d3ce34c191627fa229c75969a86f90842afc2df2f5729985279c8f67593",9.317957166392093],[3203,"d4b58a89ca4d91bc434ef6da1c194bee8958fab05195dc1ffb3f69655df406eb",9.917710196779964],[16474,"00e298a88d10e8f53969eb17a30c6bbda054e788fec34d7b3e626801e891d45d",10.052724077328646],[1011,"dff906f4a578f89d5ab6859c22ba3d9ab69d5c0a57805d07f6cecbbbce7b24f9",9.917710196779964],[10226,"216bd875529cfeee20f153f7afc7c9085c481a78abad435dbc680db3c729cebc",9.917710196779964],[12455,"33a0e7e23d174ac613fe0ac9cb88d1bbd4ffb7f75ef5e5bbe3215568663840ae",9.317957166392093],[5820,"de5645dbe15433b1d49db90d1672a714dbea63f562fa5c5d6dc670169f1941da",9.317957166392093],[4727,"9c2fecf441ba09fc6539a5742ddc7f25de5035d64c7e71af69bb5e53e42bd9e0",9.917710196779964],[7213,"89d68d9be710ec772436de875be499fa17bbb1b7207f692cd95a3968325c9fd0",9.917710196779964],[3480,"893c97332d6ee7d9b2e71ea7d5fb34b58250ab435ef904dd91559e8870632ee9",9.917710196779964],[17401,"729496df3e1b3ab85c8c89fd6c4608b3f5c68f292f8a3a8a87b0f08390f4c049",9.317957166392093],[17797,"d275e34cc1395146c4306a2b1148e0ce30474d496ce6ad7c4527b80c71be5441",10.03181049069374],[3679,"0a3bbe2551b1d7bb5ae41efb35a49528a590c2fb4eea74e80e07902b608bbfe7",10.028818443804035],[10338,"ea72b5e9f3aed9fa4b6a3951ad5da58954c6787a6c707cbd61ec526b6f1018bc",9.917710196779964],[9800,"fc69fd672c049c85530896ff12419c0c43718eb0dbfb36c1af9744ab86cea4bf",39.20855614973262],[15160,"512e253276d976a5946be500a6ee5f4898477c3bb08f65ad1e029468f5144b7b",9.317957166392093],[7093,"1faa348f8c178d07b38b9edeb303afd0428f024fc4144ab89dd54ae2a7fb5ed1",9.917710196779964],[3186,"d5a61d725e43164007a857dcd591fd58a19f09f039d2e1534274710b178f1deb",9.917710196779964],[5517,"7a6f029b53065141784c64991ba4f209eb0e0615ce5259eb96df6ae856df21dc",9.917710196779964],[16110,"ac1776d41508804215c56796e6f3feea6e327319c4c9e263d3304b8ee55bcb65",9.647446457990116],[6075,"3223e7f76a9a53dac3ed82c965c07323870293e2b3c502229379eaa92a1692d8",9.917710196779964],[19829,"c24722351f1f53f3ffb933c13324d23360e180d920624383693db4ed93cd8c01",10.052724077328646],[4622,"525c8e1c7034950c9d6e9090189faaafa59689b9d356c28246623e352f2379e1",9.917710196779964],[13341,"2facc9ec5a0139ffe02c6f11332b5c29b274fd44cb30ced5b8852eee63f1c0a3",9.647446457990116],[668,"f86eeb785d5150a8f789bffe4c8475a74f6fd8f95b6d5da01be94cbb3c9471fb",9.917710196779964],[10385,"0ce8d385e45c9a9b9134f23e0bc2096f7ba2301464e22aa9e230071d07c2e3bb",9.917710196779964],[1168,"093e0b8b591c93f71194f8391ba713ec92244803a5f5b6a9f4e28fdd0cef2af8",9.917710196779964],[12771,"0b949087cde8031d41cd372cf24316fe02307422f5b57b33f94c0496196d1cac",9.917710196779964],[5438,"bb08f0de38810996e986770caf0fe0dec42a7a13cea73decc5330a2847038adc",9.917710196779964],[13918,"6cdeabd982136b5d3e818f6e6d1b7cb1839e74245748e050f0e25a4d3f608c96",15.91459074733096],[10884,"62339b679c946af31f9103c3713dc0bf8f6709e3c0355a9757a98ec557f2beb8",9.917710196779964],[15823,"480161d7d7b752f74e5c2c8c3ac1fbea545832fa33a72f971912b515369af16c",10.052724077328646],[14686,"f2ada60c3253983e3a236b53d123495c9b8f2f72f406b8405a09e5f8baf42285",9.647446457990116],[2805,"d755ad79589ef22418b0103d2a7884197f0e5bb946112ed7ca6b22c50532aaed",9.917710196779964],[4137,"9f544d67126c7ccc3687a0ca883cdf92fb7826de5466f11f2e4bf32a1d40d0e4",9.917710196779964],[8580,"dd46533f9a4a2f17792520d9e26ba4ffe18d2df4417d5346f2a99d1b285292c7",9.917710196779964],[5121,"95deb73affe8e2cb90e1ec986c939d65095cf563f184c4ef057507a5201377de",9.317957166392093],[18564,"c5d368f33adafea14ac401da80ec4ff2ab9a9816e8ba8abb46a12f3fe7382130",18.07758620689655],[3082,"06a36547960ecbfe6d650c8fe1a646a84d0f3dcea368b05bafb78feda4c6c2eb",9.917710196779964],[16339,"6697bf05d9736e11d50dd1211ee6ed595cc64df8bad9ebfbca79ee5fb9b23e60",55.19163763066202],[16268,"deeaacc4d4dd94d41dad5eb4591b24b1b7c048b9b4fd0cea1bf3552db3b2da61",23.872746553552492],[10301,"8359e4a9f5f1a226b0a533d56911191ec945ea57707f9900eb627f28c18f5ebc",9.917710196779964],[38,"fde85b479fc01d76001e27f1662c69e0d22f97dbcf41fd0bdedd01be2407c5ff",19.03869653767821],[14819,"c9097ea287a5ba85455dfc88c9e80791c4ea652ce8db692de2fcd091f5326982",9.317957166392093],[19501,"003db652b417c5fe8a9c1565257d2c8120f8f0e9f56e3a254adcc9aede3c490e",9.317957166392093],[6694,"eb8c4174c8f83e50ba3f2810eb384e83b64bada7296848844db5f6e1d5effed3",9.317957166392093],[11826,"6f4e014578d85318d5b62ce1fe1d2b6305efae1daab2fbc13bab2ae22cc78bb2",9.917710196779964],[11249,"e6e986c9bd62a742696dad932f2da9d582fedd76f74d7cc7186cfaedf3fc59b6",9.317957166392093],[10144,"b34c03219fc8acef045405c1ad0b657c8f7747a7c5d758d4b3965905389c6abd",9.317957166392093],[9936,"abecc5862adf454476361455c56746a52c02937c00776b66a4541895a521bfbe",9.917710196779964],[723,"7848db7a90909714de68937df168f7093eadd08e8c5d70c80ece66b6999f0dfb",9.917710196779964],[3592,"796f85b76161dd7f3246183b5a8b086723cc9e54a9427b47c5472412cffc5be8",9.917710196779964],[7818,"e477ce1b289db7b27ced508db9a7f6632658444d0c60930e7cdd771d825ca5cc",14],[4692,"9b0d3be87a08ea4891119b2dd460014d572c5a1f488ca4607c7cff108c4b0de1",9.917710196779964],[15095,"ae9d0f8bff600feccc33aad55305ef6c4ffd741ada4e11126584ce2a11f2be7c",9.317957166392093],[10550,"6134185ad3abc36e3ffc9c065cd15e3ce815e9854245c59329e85f407be4edba",9.317957166392093],[3360,"25953546676692adc99371d0888556bd5feee810d652ae692dfb733e09caf9e9",9.317957166392093],[18333,"422219a59263a303cc063708bdf6fdd9fc1d4cc289f718164aaf762195653635",9.317957166392093],[11596,"87fe670fec97b7134dd68d0de41fca631baafa83ce6039fd90b686e51e0febb3",9.917710196779964],[3163,"fe6e86f8ece8446754eaee2180d42ca27246bd19361f71704b6df993f3244beb",9.917710196779964],[955,"285622ab6d272db731e5bb4f08bf3ff25d631c862e7e4540ff30912f281179f9",9.917710196779964],[19483,"3d9a15e56b32b2734b6968ac4a18dd9e06b88a0c716bcd5279f1a2be58acf60e",9.317957166392093],[1949,"d8a5f2717d9e84418182fc415633b798b02edc31a10ecc7c9182832470cc58f3",9.917710196779964],[17087,"b2c083651799bad1aec45ddb4cf9cb7369701804026ed163e28fd8f6ea4a2050",9.317957166392093],[18646,"b905b321270f871161e038cfa9af09e56f51829258492329e6984900c5d7ca2c",9.317957166392093],[9049,"7384446c60530220685c0b00b4f8498be7016ea2406e36f131695605de8e74c4",9.647446457990116],[4396,"e95a2a688a3596e02aa83c183703e7754b8ba3a202d83cf081dc8ea90b491ae3",9.917710196779964],[3535,"4096df5c3b7adf5f910e83b66561e2165078c5dfa71070ed1cf571a611c6bae8",9.397642257991386],[520,"009d07401e75da36e21a3f61e665a608a07049c27f47f79ed44724083f8689fc",9.917710196779964],[19292,"d8c14537eae540b2eb2c992f1798fc49bd5dabca55ac8ccf3f696dd68a220d15",9.317957166392093],[5571,"0c3d4fe7c4892b17ba0e4a0ccb2ce1f82b956ce4f4195c547061b7e806e7ccdb",9.317957166392093],[10998,"c168a269207e440fb56d75edef625aacbdcdd79647b89efde7ec12625b5bffb7",9.647446457990116],[7316,"10f583d343df1272d9e68ff2bb43b8354c27363a396c26365fdba29e459df7cf",9.317957166392093],[6300,"4f74b2d6054dea9da86a25a4e252749bda65a77b794bf4b1db6a037b58dc06d7",9.917710196779964],[14800,"df8d43cb7d3d7645983dde57c5e93b160dfa2945695cb0133215f36055a4e582",9.317957166392093],[3010,"dd06fd8700e59b690f02632a69cde295602b3686d076b19c21b7a13440403aec",9.317957166392093],[1266,"756ba6b3fb66013af43fccf875959a0ceecd2ea0e7b99ba3e827b051735390f7",9.917710196779964],[4449,"7fe9e1bfc9bf935460b9067397e0f4f2f786e48f0f5dcf62954566329f59c2e2",9.317957166392093],[7932,"ab6b89391b69659e185afcbc407423838d34b48bfeac0480d2d2e4754ff403cc",9.917710196779964],[8813,"92e479f84974f5f17ecfe28c62279e65f2ce1b6264c857541c7912af32ce04c6",9.917710196779964],[650,"a3698b8fdac06414f76da337fcbda7359c7c9b500d2db8f2c1da11275b7094fb",9.424083769633508],[2128,"66bc00af4f1803bf4f18a71cb903f0635e4e1000096793e858eca46be1250cf2",9.917710196779964],[17516,"4603b471f3df2adc098c6a1443eaecec656154b6f49fc667f42fbe4d59942e47",9.317957166392093],[15438,"bbbf217c51e048ddd1587f29ee786b30cc0aa693b6d9677378ca5d96c2a36c75",9.317957166392093],[7396,"36979f9e4064e196b5eed93f54f9b21c5e6412a9967cd649f14d2a7bf62672cf",9.917710196779964],[15413,"cbfb8928f3812d8a42353329fa429b2a0dba680d39349f59383dead6f2550376",9.317957166392093],[2937,"ddce6e54fcc6cdbc0e3c8eb72d3e7f842572c6087c29466ef2b8a9608434c8ec",9.917710196779964],[6373,"aba0b1396334202589cbaf3380d5c77e5e97f791dc24ec36a4e62333422079d6",10.011587485515642],[10072,"4e8b963e3a87eee9d22f20fb4f07a761259c796117f1a67406e7019b9d18e5bd",9.917710196779964],[4367,"566fa9c35ee9eede03cc97c526420583827c8c4e2caafc5d7263cf3e8ade4de3",9.917710196779964],[16580,"0ea5f6479f6c73a4b1a72105255a7e9797cab37ca999cc09d536d7b22882715b",9.317957166392093],[7271,"94056b0cb2cfd2d8a772c3b62a6ed26a62f36410ded2580858196fe8563132d0",9.917710196779964],[1429,"e03144e88ee9495c04f8e00dae87e047ab59a4b000ee6221246928cac075a7f6",9.317957166392093],[8586,"beaf11fd264c6cafb8da7040385c2ca75c5d14c9f9971a5eac91107c073285c7",9.917710196779964],[13879,"802523785a3c236acc09d3665501765872e7a962b421795789bc1e44885bad97",9.317957166392093],[10561,"00ccde5b3ae3676a25ef75b7bc301d769c16f5079cf0bdc88d3dda26c597d9ba",9.317957166392093],[2548,"f868513567e557ba921fc383153fac485c98ef3f01535f86e519adca36748bef",9.917710196779964],[1057,"a6eee25aaaadb4bdddad459daff6f0f3a405aea94321216a2901dd4709dfdef8",9.917710196779964],[14328,"d0a64a8a7d69c585e1584b4fba1fd72bc634097667c812c54a63308a01efd38c",9.472566371681417],[16927,"e3d29a76507bf658acc729e89aab67ad50e2b089ac8bc65b4e4849d0c5f6a653",9.317957166392093],[10532,"8a3774103b8ecdb1582256834c2c76618db444f4e5b54ec0b5d6ba877c11fcba",9.917710196779964],[5696,"698603634af5a8e970e2241329123bfe0f60d204c5e7f994fb0972e04f8915db",9.917710196779964],[15209,"797b5eb6a6e0a161a86c39efcfd251d486e7c1b57ee62c11c199924ebfef567a",9.317957166392093],[15251,"a9f66ea490dc7ce970f29f8f587a5fc3932d16c314dd1f13aa58ff8c53126c79",9.317957166392093],[18693,"62ec1f4bac07c66c33d405818fa4137e96edff4bf37b2fac8f82e23c49bd9c2a",9.647446457990116],[7627,"e5d9bf8663c9c8ec3dedfa17581408eed417f44fdfc2c4c29293fdeb585b0ece",9.917710196779964],[14233,"3648a3987ac48f05caf59c5fbdbb544251a185da41ef9a05bcff8d8e8fe0638f",9.317957166392093],[19019,"34cc000b92d169b80a789d34329661990901c7f55de5f5c70def0532ded0db1f",9.317957166392093],[13584,"d8ee11b501235740e08739aae550c53821ac29cbcfaf4565838b8ff8b3a8cb9d",9.317957166392093],[10980,"fbab001b7c1ae59abfd70f665fb0f0bb4eec11c1c6385b1930b8bdce46da2bb8",9.317957166392093],[4773,"62d4b56392ae0a58cf5d5f421e8cf120a960b06314810bf84119cc64e9348ae0",9.917710196779964],[1657,"4404b7f96bc9b930759ed234cdc0c1a29e3e226c425fb5e19445cfafb7f837f5",9.917710196779964],[13248,"c47a928be606ddd23d7fe1ad76d8aa0019b98de289eee1fda77fa0f15e1de3a5",9.317957166392093],[1105,"2d8bc0a64f122f90198ccf54cf567286066deac02f357d1a073e07671cff87f8",9.317957166392093],[8335,"419a076bb15046d5d7374a67260701e6ad1fed0eec0df14ff69eedf8b2b419c9",9.917710196779964],[1654,"c1f09271769de7a2df1a3fd30888313d058f227401768e3e6487bcd239413bf5",9.917710196779964],[18364,"0cd5501c5efb8cc00415f1e734fa89bcfb85a5db6ddcb946da279c7e26d55934",19.20142602495544],[17158,"48bc49501be5ffa47408297d9a45ff73c50112c71f0cbf05bf57848fc250dc4e",9.317957166392093],[14790,"2982d6cfed391292c8b6c4917c5d17b2ef67c941106f6e7552c48e454a811e83",15.943362831858407],[19049,"fe9951809362d86a12e3c1d8af25ed629826f3678fe3aae20c77693afe6fcf1e",9.317957166392093],[2052,"8a281c2bebd4866676da1df77c2ec92f946c53b7fb98547724c1607669a199f2",9.317957166392093],[6054,"b049ddfd581830a3d2d1ba6f7b672f48d71f0f09bd73a9fa9e0a629f396fbed8",68.17198335644937],[17803,"440007462921d0ddd1b36661ba29243028bbc157e854b212beb080862a073541",9.317957166392093],[4265,"4dfcff83309ab61b8d4725938806d12727f2b3edde28a955adcb98fe0c2c04e4",9.917710196779964],[12908,"fd3468208f3b5a94a9e9ff5ed45dc444bd8362b0be6a139838b95690899342ab",9.917710196779964],[16037,"ede0f922e6a29f79ec0ab089c7ca4a1390127d56d0d2bfe819b4d11ddaeda667",53.97276853252647],[8405,"84bdbe67bbc2b823caf09305fdb58337d9f26095709ac65c3f911fd8321994c8",9.917710196779964],[4835,"a362979f927f2622552e68a9c338a6793334fc2ecb14d78955612874e1aa36e0",9.917710196779964],[17108,"ac3c3ea692bca0642e1a8dfaff127fdcd3437c68a35773900d766f731e4fd34f",9.317957166392093],[10268,"29016c397a911999e6d7246feba8a4386810ad6a9adde0701a1ba9feeaef9bbc",9.917710196779964],[2081,"cc6b25919b92a926724a262cd6131c076ccd198d205869add78d128d917d5bf2",9.917710196779964],[9490,"1f9108191e179ee4c8b9418273fe5121b2aec0d5922585e6a99c7eba153dbcc1",9.647446457990116],[1835,"dc84e2a6088306e8401e4ffc38c6f337a05714d83978bc6428acef12106308f4",9.317957166392093],[641,"f76f83452ebba55e231111b023be9eddd7d8e6f7b7255efcc5054e7ea140a0fb",9.917710196779964],[10924,"207d382c288b62f04ee8ec1d816573c49b244d93714a93f634e8db6545d789b8",9.317957166392093],[11714,"37e85263d0830f8a922a4f983c66915e29ee9c878b910466640a86a68a0739b3",9.917710196779964],[518,"c3b96664d6e2274006ac7b478f4500bd4285c180dec9d390fa8a4f0543fb92fc",9.917710196779964],[16077,"5de82efaefb876526792cd392ba10ad01205057ac4c994e73675842b24bfb866",9.317957166392093],[9252,"e6f901b08196da0dbc04d3326112c3d5eeb1bbef0b1b35208d1e26e97df31fc3",9.917710196779964],[18572,"d25711aac899e223c1abca5158f7f4c52ac978d0e10ff421750955ad7dccc22f",10.052724077328646],[11963,"4ce90bf0fcc1f202140020028a249245e4f9d9db8f7f2b765024d740e89e91b1",39.2070796460177],[13480,"438d92847cc15b9c6ac5abaa9bb2ab307f7cc77e61e617327228f048702a4ca0",9.317957166392093],[14612,"645fb248826b5b0bd24cb3be87a9c16b69c4b602a8b177648d3b187f2cbed886",9.317957166392093],[2409,"8ec4e12cedf5847495b0768fc8f7b0639f2d0634add62ce2eb2983987e2969f0",9.917710196779964],[8403,"d01c3f2c403270e5ddbae672006234468f5a6b7ddcc233703da8ca1c605296c8",9.917710196779964],[9680,"087886a8b24f9f0177b04a4300a4c68a8655e21f8d42a6dec8cf41bcee1a85c0",9.317957166392093],[6173,"c55e5c77f81a2bf9b4de4778635fba20643fc061bc913147ee9e07a4bed5f6d7",9.917710196779964],[7434,"506301afca0f044ec0b2a5881172f922a924a7de77732bcebab6a8b293c829cf",9.917710196779964],[11797,"76bdeca9501e24c71e6bef28cb81acde8daf9c904af5b1c9f34b1bf57439bfb2",9.317957166392093],[9623,"6913ef9d89c12ca43a09aafac827dffe8e9b366483f6c776a111ea4e3d4de3c0",9.317957166392093],[9758,"afa7878802d9048ac2b2cdb5b2416c5610080a74c0f0a550a099076a8030f6bf",9.647446457990116],[5393,"332cbf0c2ac28d8ed5e5ca04fe3416b2324c49d074c205793dc75cba3324dddc",9.917710196779964],[7167,"48444f717223116ade65151610e1bdfb1b0e8f4ae436c82201c2e0160399e9d0",9.917710196779964],[14718,"cc4c5eaf3ea0982e1f8cd01b690427fafe912c72916a7fb40997027f51cf8f84",9.317957166392093],[857,"6ba87925da1427e8ac92d5311cb3ef058b37d9bddf256ddd4d366b187f0f2cfa",9.917710196779964],[9372,"6bcabdf7e0d5666c6f83c095abefe6df8100adba20e4516588c6e297a20368c2",9.917710196779964],[9942,"d0d144c25aff4b89b4e2a1402d6e8d38604f51c95bf57517eeb2793b09c8aebe",9.917710196779964],[16160,"d20a7c520ad5290afbcf297011fcccb7a4e4b68c9e5a9d34243e2a640704cb64",37.08409090909091],[14657,"210c1739ad081604c4e5d9a073825c4c09da2c215b94816bce065abaa863c985",26.13612565445026],[15795,"b08ee0fb896ec4cc01bd405f41e5d9dca1bb79c7d65a81ac946b59806f90786d",9.317957166392093],[9625,"0ad3a6e69df4386bfe2a5e897f5d4a18e6d3514281e9c3881b4436f7c6dee1c0",9.917710196779964],[5897,"4e932c2f3e3334f568d31a2e3d2fa7a1ae317cf5ce4495662cae9bda7dc8b9d9",9.917710196779964],[9769,"caaa245169e5540b199d57ecd4a6e84b889cb66c7e9f8903e57e42fb6146dabf",9.917710196779964],[5216,"e5a791cb71c4b02e616a44d4bdb60c328b5a15ccb5d5b34932f6ca2ad333dfdd",9.917710196779964],[10739,"6a4c5cac26c93311dd5bb026484029185e3f4998209e44d9612cfd5dfc31beb9",9.917710196779964],[6567,"6190b5c5fccb371f8dd805c04001007403eec1553b4fd17ea62f5e95bbc1ecd4",9.917710196779964],[14723,"b6aaddc9d4129973753e0d5f788d796a843d8ac7fcc3944458e4fcf8778f7c84",35.047879616963066],[5161,"7b55a4a84b3d455f8c398d732522c6e038bd0aba10d7aa47456f0541c07235de",9.917710196779964],[11658,"d0861dfc6d07fb846e59768d0f68d2039fa7928ec429d36bb8a52c0da3a388b3",9.317957166392093],[12124,"57b496230d570c68cac3e4401d6a9607585208555d1ec42b56a45f9adc4186b0",9.917710196779964],[11221,"441d1cc6a72d49090845c971a53c9ce704907c5b3c7a325d05500390f64495b6",9.917710196779964],[14870,"51371207204188f4d13ebc144587fdba22d9fc8f30c7938f9dfec62d90c06081",10.052724077328646],[10970,"673f91b0ea7c3eb12719a3b18b06d64c1afb39ff896ba64f0ab53bb9b92837b8",9.917710196779964],[2370,"493646cf74999ace37ad0d90af980d24ac141139cdd3f3b1c93506a10e82a3f0",9.917710196779964],[15000,"172840d7eb36485fa65b6aa7bb1b5cde3fe678eecd8ed8846a996ece06d4797e",9.767590618336888],[67,"add93b63288f9c5acb5b9ad76e7275d3501d4170bfc627a951ee34b5e00b8cff",9.917710196779964],[5525,"b9b4604b2266c0d90f1e34871f797a4a189d0320d3ebc7dcd42d0123aef314dc",9.917710196779964],[18947,"66a9c525cdbad14cda00a027c1d9176b0b46bb7874edf039b3bf831a60273722",9.647446457990116],[12689,"6d88d02cdbab23df4a23a7814ac860f49ff0f49d3636798e5f7c5475a591a6ac",9.917710196779964],[6103,"779daa0b50a09a28b40235b233e2b57ccff34e902453a149858c8a96788467d8",9.917710196779964],[4188,"eeacfdc24f5d8ca59087c6a2e6be357c514debda320387a046f0e90c60437ce4",9.917710196779964],[15163,"d33d495ea1f4649d3f650ed5d969d47af6a68ca9569ac60b81cfacbe8f70377b",9.317957166392093],[7846,"096f8f4e6420a7f3a8a22f888f3f1c0ed30e24f16a1d910c9e71a4ee031786cc",9.917710196779964],[3721,"4472ee9e56062a401d0dfff5c593864a5a00ec73b0b1468eddce57198b0473e7",9.317957166392093],[11065,"3a5ce1cb16d888cacc0e8b6521b817872cdbab8b283230086c1bf882cd2392b7",9.917710196779964],[19187,"44683846dd3d1e3ef7a2f6f153ba953c7f65ea4771a35040066cbc3540061b19",9.317957166392093],[3776,"3cff17538111c374cec84ed6500ea04e144bd9657e056e370c7be6bd22f61de7",9.917710196779964],[18027,"1522e75f9cc5dcff302abed35cd5d77f91d1e0a74df7ad1c7e50db1e638ebb3c",9.317957166392093],[11941,"10874377dc7699a182d726eb5827e30b1193599d432099a7ee69ff4efbcab5b1",9.917710196779964],[10923,"a9c5be386fbc52741dc8646a6461da9f73ebff812edb8e84c149e95e11f78ab8",9.917710196779964],[12759,"4f5beaf7472c7fa8e52d161f7bbde9da81cf65d25cd64c3bc4c9ed6f7af02bac",9.317957166392093],[13471,"bccc9c3dcd8ab7c2581c1a09c4a577367616548b762c4a3122c29e1149e298a0",9.317957166392093],[7139,"feeb3363d619e3ba2f33b8ca386f024460b7db6f63f71afeff0938e954f916d1",9.917710196779964],[1442,"21c33178db358d43eb2c1bc7c47653deab0ab8f9e978ee79250b9f47f1758ff6",9.917710196779964],[1940,"4a57f25e6bd0aa489a0b8edf2ce70888760f6238435055ed8d4b10c1d3976df3",9.917710196779964],[17533,"33e3ff205f6ee35c3f6f28e984d6e5934fdcf4d1bced8e4efa666a04c934e246",34.88770053475936],[9452,"bac7ba1ebe86ee5550992b1e9d0511832effea2c23e74c417fa58f2a1ebf01c2",9.917710196779964],[11735,"57452fc13655048f58ac996d316ff6f1b38c1a659daa4b1d2b2e2410245815b3",9.917710196779964],[13154,"7c1ae4fba0bbfe2df7c343bbdfe5ff10436b50d7a3711754fc84ad325ceceaa7",9.317957166392093],[16264,"7da28566482bc48465f3e2ed14b648f6bee9dd97562881b3c469aa1436480762",9.317957166392093],[344,"cf384089effa1912ee8563cee47aff0b9eec12194057adc377fd289f072bc1fd",9.317957166392093],[12582,"635275f90209b337c314cac637c9755a7bd1c56cf37f0a4a04f73a66995563ad",9.917710196779964],[12990,"86b56b9ea2098fc8790d7183dfbd2296e464329500268703479e6bae1121aeaa",9.917710196779964],[7072,"78b647d0c75b5840dc41eda29c6834f52ccf47a608b6ee5dfd66b368b7df80d1",9.917710196779964],[13559,"5af4d5974a79534f7f273e0ce651f0f35f9c366776aebda41b877d901e1b829e",9.317957166392093],[16441,"4b5949760c9ae383dffe88c92d2fad777355c7f0f5a47e5cb7cd34375917565e",9.317957166392093],[4623,"fc77aa99e4f616ed5942c39db2415786f7bce166bd70f82e233af7bc9e1078e1",9.917710196779964],[1811,"8f93ae440dbf7a9117df7301f68d8d392995cb07cfb663ee4f8844f933742af4",9.917710196779964],[1611,"ac3a5fb5f2b62dedc9f6132ea2e265a310949c70a66218e9857c0f5b113c81f5",9.917710196779964],[2388,"779a6c5f23743f8785440bf2c3370da308d17e14ae2ee67a51651dbda83a87f0",9.917710196779964],[898,"2466668ef9fdd4c73ad8ddd1b7754d9971131fe6879d60a31f6cd466a45cebf9",9.917710196779964],[6649,"c4cb4cc27b95d02c7fab5c5023e902bb2769d2fa084db575a08d754c01da54d4",40.13437849944009],[5208,"bb475301c07a5d67f2f59575c64b55c0cc91274dc25f5de435384c423942f0dd",9.917710196779964],[12457,"4e569eb056c82c937036dc3b2dec549b89c6fbecf9cb3bfe39fa42b6acad3eae",9.917710196779964],[2305,"f6f7de7b75c0a5d7728a85831558b3c88a68183c41ae64399925b7709415fff0",9.917710196779964],[12878,"87c30e38e68991e12caa4d985db59e04228843b353973a43e7720461748368ab",9.917710196779964],[19464,"6a25808f823989bc76335dfdeddafe98e89b54cc4a7a81b333ce7a97e97b8a0f",9.317957166392093],[2389,"367c516566008da737bdc3bd0da998a57da499cf51cf2e9c6cb7408e12fe86f0",9.917710196779964],[4409,"0fb84f005f9b9feb03d7d69e06a4d974fc51082e29efe79dc21db216193e05e3",9.917710196779964],[5353,"ee84398182d94207da48cea5b83d78f4af40fc03417cfd6edc71a123f26223dd",9.317957166392093],[8392,"b815bf5755c71492c535174a1392432d257a5e8f25cef3a493cffa888590a5c8",9.917710196779964],[2886,"9ed36bda0b93b0c1505763fe42fc807cec29316ba9ef35e63bb08ebf20eb36ed",9.917710196779964],[18583,"d24f9969916b2ef6142d57a4b0e8e0dd3ee0c2da04e48af226692958a622522f",20.096618357487923],[7348,"cd8e85fa49295338986ffc873871f0639a1e1404d5ef90e09b2cc296e4a5b7cf",9.917710196779964],[18280,"eb8f3c5f1da73d9e91a44c36ff8bb05a6e70b351fbc65d2d2a46279c884c4136",9.317957166392093],[2195,"b664ab5e52018326de618e9a8f89872e025c5cf79b6e1781359f1d0ab32692f1",9.917710196779964],[14485,"5e1ad287e6cf9d6b30ea0314438710b8e84f1ff66b037813f703830fd9508789",9.317957166392093],[2515,"ae6a43d784236642b95e6e528bddc7680950ecd0aee25c36d06a9c9f19acb4ef",9.917710196779964],[12067,"e64cdf6381ddc651d34a51290d08af711849241c4f62b317e1e4a70daf51e3b0",9.917710196779964],[17834,"1514167e535f9e8f0d49b0db02f346c1dce4aa2af53ef1c2ab2e36ee2b299840",9.317957166392093],[17704,"b0023c15563d2b16b28b8a5c9ef4e6ff59e85f8e13e42373feaf8e5b462c2243",9.317957166392093],[2150,"0d0a7acfe9995e34e90903aaf56e33961413df3276572df9985cf27a8af6e7f1",9.917710196779964],[1838,"65df3bac04f8b52c6d9d8740ad959302bf2e673a1e47613ff25b7e48843302f4",9.317957166392093],[13604,"981e2f6aee1a779d41c6e6283ec37ac812438ea97416ec8b9a205c4c0172569d",9.317957166392093],[2882,"1bb5f1beb681d6764f1fa1cec0b63335b905e43fcbf3fb90a70fb52446b13ced",9.317957166392093],[18160,"15f003a3f49b72d5197cdf9062705b583ac412ab78594ba87eae6c70f3eb1839",9.317957166392093],[13748,"f8a9c0075ea27e2c728e2c0bb9030677bf3a67d1108c7aac88027bc9578f7a9a",9.317957166392093],[5308,"6f84509e979997aba1fbafdf217ec4e9cf300c29aa177bcbc92037014f7f57dd",9.917710196779964],[5670,"37e2cf07599824a1005f229190e16713ad5a4f1ef57bf5f2e20b73bcbc6535db",9.917710196779964],[11870,"9e386c4410efd53cd95469c6af63416a2c135de0de948d8fc27722b3c83e41b2",9.917710196779964],[1598,"d224ca2e58d16f087c139eed82c48e0d1ab0df5eb4caa032e9269f68c06991f5",55.40636042402827],[15930,"ad0b318add472159bf619114d15ea6f89bb85fa2bc717441090dd9b19bf0856a",9.317957166392093],[3572,"9e137743f84981bf141bcf8ff83739f45d4682eb0a0dd9f693777b8a141a79e8",9.917710196779964],[11268,"62da65759d14567879c0d60cdbac6d6c783673a85a1947ba004f297fa5823cb6",9.917710196779964],[12414,"aa15de95e8520ce8c19d29bab4f8914ead8a9f1885e78abc5ca8ea8c107783ae",9.917710196779964],[19465,"cad5782b72d51036bebb5521fc25d9b35a696c2cb1f664dc993b18d9ab25850f",20.08888888888889],[15306,"9eb3cbd5b959d420b8b844fb5e486a958ff7a286fb00b2b2acd2735dbb5b4578",9.317957166392093],[13498,"a7eb2b4ea7bb93792375247e28b844903dc4bed958317c10c364aa2984eed79f",9.317957166392093],[1808,"436f10be87190f81a1efc46a50772db6ed92b6040017a459498cd9ad77552ef4",9.917710196779964],[5927,"311ec0ebf0c2455e79ab49fa697dac9e7e30dbfeddd24d1418844daf190186d9",9.317957166392093],[15165,"9207ecd34fdb1c46484f4d92d11629c0bd9f9a5705f9a2533ee65954a434297b",9.317957166392093],[15591,"f32a0a23f6585c07d1f957a6eae2683a606d2500980bc2db0f92cef449e18271",9.317957166392093],[13893,"2f4adcf5a5a66f9ab697d22f81fbed195abb7bceda1995359dba4d7a9cfa2a97",9.317957166392093],[7864,"d376fa5b784506a07be9870f4ebb2e7d96c109a89258233e005569e85c6d76cc",9.917710196779964],[11926,"9bfeb8769f0adb8d4438603c0d9e833fe191252c2b408deb13b2c876773adab1",9.917710196779964],[12546,"da3f570ebac1e214a68a792d0d73f3039a6c11b2dcc0de07f4a93733b259a5ad",9.917710196779964],[6921,"9f6ff795d687a59443681f2cb09d8c304a2137940d665c9958169a2a8f2a77d2",9.917710196779964],[10890,"1f4ef175a84cdef1faffa7445fd68e2cb9fe6c1e4ad4d2aaa90fb4784025b8b8",9.317957166392093],[1589,"a825fe42fe967da21e58fb28edbb470c385ab80c6181165bd3c5ea26f31199f5",9.317957166392093],[13001,"62fe3d412c3f09024c7159d3b27d98592048820da2a838da0fd988007e2a97aa",9.917710196779964],[3371,"c6e364e8eefef80848d98b445042c3b59fc3327120534f69ecf685144fc7e7e9",10.052724077328646],[12533,"585ffe17b1c67588cebc80f40106320d1200ea1b723715352e6a47122b25b5ad",9.917710196779964],[18318,"0caf98b567e37bc1593cc43cf3f7f4adb0fe42d8d12a3c586060ee4ad99e8435",9.317957166392093],[6647,"98e43a63dc370f2ee1842282512f76525ea3fdb614e5df7ab26ceb1f1fcd57d4",9.917710196779964],[110,"86384b5d5cc33f7bfa39e608054b1a801e7f409651856d41abf0ff837dca54ff",9.917710196779964],[13007,"f03872daef97d05381eeaa9d5d7486695215920d37ac653f1e7d327e34de89aa",9.317957166392093],[2627,"0098fc8b4c66f86ed5812f5b6703c17efb49e8b90399575a9599d11c51ec06ef",9.917710196779964],[1242,"4b666c59a755621d95fd251f0b35436e954c8cb76d86e1a14a23e16a7a32c0f7",9.917710196779964],[13700,"1db5058a44329201175adc387dfb5b0e305823588d0ba3e88e9a0b689183479b",9.317957166392093],[10031,"b4fa00ad91e9071a0cf6469d787c99347848122e881782d4bb66ebdb9d3d22be",9.917710196779964],[19768,"9230de1e49a0239818780354b33f93980d62d0d42a552d7c93b7666f43d0b703",9.317957166392093],[12816,"94535acd9dbc1419fa087d918e01b1eb1593f8b042ec2f3ad62d2c156153d8ab",9.317957166392093],[9546,"3600fe0fe32830620f32c123e0092b2a66bd5ebab7e05bb5095a3fd72f3769c1",9.917710196779964],[813,"109ccdd41289a3624d1f86bb7b95153c959eff831a69cc5d7cb9d487ae9072fa",9.917710196779964],[18787,"34775cda09e514b0406266483a95f62239484a23567242dc1846575976e57527",202.0523560209424],[10905,"67c3df0039c46ab1f013dec290204f7bd2050184a814f9ee972b8085c70fa5b8",25.031096563011456],[19003,"28a557e0e95019420d977b981e6597430962a5725b318fc2a587e04065477720",9.317957166392093],[15873,"572e47fbbe7ab600c52fa71db2c999c8fbcde64df12cc8ad9de9e7ac189d8a6b",9.317957166392093],[10357,"c943639b59432f726141dd9912ba6beb76033552c7231d84f596318738e303bc",9.917710196779964],[5163,"fdfdb9a939c7b02c477272d40ec1e01f222cccf15f826bf7644430023b9331de",9.917710196779964],[13678,"132607f8bcd5e6b67e5579f7966a5ef3efe1a726093eb0f5c41f92ff5dffb89b",9.317957166392093],[606,"001d3569344a7a88fbf1a5d6ffb95c96c09813c791ed29ccf748a1dc9703e7fb",9.917710196779964],[16555,"9832c0694b1a910066e49d8433c52b2853868aab307b619b0c5844ed5150f55b",36.807291666666664],[8853,"0fafa78c22fa6a1e0549e9fa168f316795246ae6df4e72c8faeed5af48a8c3c5",9.317957166392093],[2323,"15d24fe4f129fb5620c105b9c24dfeb00490c9a116677df75eaeb1c35067e8f0",9.917710196779964],[4902,"e25bffbc9b054d7803242185066dc797a0fde6be200f3d69d62fccf729d1dddf",28.14867256637168],[6146,"60c11f785dd7ecee8c3c8b6948843d0718c972e2b2cd2157d94f4ad09baf29d8",9.917710196779964],[9716,"1152905785a53354ae756428c49987f697f6c727be873803c4997635f0be3dc0",9.317957166392093],[6979,"33d3475ff00d8fb3aefe66fab6954a260ab64697f93455b0950ea920ebc11fd2",9.917710196779964],[9529,"46e45b2d9d37696fc3e98f8e67cfc710bb480c8434965658a666807a479080c1",9.917710196779964],[9439,"c4ece4b57dca2293d3404a7ca26da849335148a5d59dc854d76ffa2d8f9215c2",9.917710196779964],[19128,"e728123d0744fc90fbfe525d7b6b324e8d21529b0803770a1f9825664633391b",9.317957166392093],[10284,"3782794a74b261b4f8fd3edcf949c33a0326633fa283a8b2180703784cfb7bbc",9.917710196779964],[2585,"35b5775438501c60328a14502d1c445c2b1813358ce7ffb7e398b8a0d4e343ef",9.917710196779964],[1337,"092789fdf1a98ce76d4ee55a6ea068d8b7c45f05963548c5a48c94aa27f028f7",14.249110320284698],[18967,"54c05305ca56fd3d3694c304fe1076f5f420c5f0b7fd13155babe4546da19f21",9.317957166392093],[3140,"5d417fb9347741304fb974e9b4579185a4ba44cf5a890052f3d7086dea6c6eeb",9.917710196779964],[10430,"be3f157b77e6ff42433496819ca14f260b939fa480e4d949156ead15ffa99bbb",9.917710196779964],[804,"eddfe87c0a6966dd9287a8baba17b1be578c8d403eaa045f2d035bef41a586fa",9.917710196779964],[4933,"caf48a7e70ecdc333581225ee15c9694abf95e677782c8161e03a1dee20f9edf",9.317957166392093],[9645,"1963a29e204f7f5d95f51d3ad476114baad88ebc8f9c99eb47c9a2a46ccebcc0",9.917710196779964],[1922,"6a7770a06f2e91802efe8f353daeb3de09460ef37fb089628c8a6db6469f88f3",9.917710196779964],[2085,"8296c4865f62193d86cc03f8a914b3f67c3cbfc23a346303bb2c6a30883153f2",9.917710196779964],[6231,"6a7a523c30911ab4701fa1d08b1530e18250ee7a59063a946ef905b8003b89d7",9.317957166392093],[19155,"8c73498fbe701e48a4ca7131d85aaff0671f0cf89303bce97d8c8acddba45f1a",26.062052505966587],[5243,"a5e5c937000c279677fe6503fa68d112894acc7ffbda646c2944abce4c13badd",9.317957166392093],[232,"1437e699db48424cf9ea0d039e2d195e8d11525f0bfe5bfbc6761f7c4f6a71fe",9.917710196779964],[2623,"d3d78fe219f5e2a48650917f9aadf6847d762ae0f43f48944273cb148aab09ef",9.317957166392093],[19853,"5a122727d13eca20e88c65d6349647d31c4bc2750ecfbcc974b9842292e9bc00",9.317957166392093],[19081,"1521d83302d9c9437fd23e9108e4bb342e3220803656f2062daf00ea8208901d",9.317957166392093],[7155,"8e6e484359db85c37c0bf82ab23f4030375a3ca12d90b9ef44060e930d4dfad0",9.317957166392093],[11736,"cb24951b2014b2a7598a48e04362020e3197c50c20ea310211cd3e41a95415b3",9.317957166392093],[14037,"4095d05821133905663967fd43981805be6948ee121952219ae94d410cf3db93",9.317957166392093],[963,"c5ce90a395d5003f44bbecb37ebebd8085c5dfa39853ec29cc405dedf4416af9",9.917710196779964],[7961,"dabd1e53665207b5478f0e35eea0e016fc3e9d88cc8ee37538bee21720ffd8cb",9.317957166392093],[306,"03bc3c6ec4d5c9cbf9e1097776ab5e7e1660f3742b940fc4795c00a1cea4effd",9.917710196779964],[13811,"e91b00566ab17a18331cfe3908c17a4e6ff237b8c2ecf9e70dd0347517002e99",9.317957166392093],[15889,"d58b2caade8bd8560beeccaebd6aebd86a504c15a3f584cc15145e098ae7386b",9.997888067581837],[8248,"59d5449f00e4ff7b052fdc49f235f83f0622cf25394e5ca57cec29af2847a8c9",9.917710196779964],[11619,"d19c6d23c9256f54429757e253a0b184f676c7d58054be107627532fdfa4c8b3",9.917710196779964],[6897,"45a2b9b142f0b9ca8cbe545b1b42fda556c118be66cbb5301530f35fe853a3d2",9.917710196779964],[18103,"3ef2da1f1d869938d866e5d10e1b4fece5746299fc1e1346354e6c2f3879d53a",9.317957166392093],[9091,"946c6be3551988a9303a50b637dbe095c116bac01624b161fe2f3406cabd38c4",9.647446457990116],[11511,"a7e852753ee56f7cc1955652111fd63e47b2e7f8f3d3d5a2bedbfdbfc9fd71b4",9.317957166392093],[12037,"c22aba1fb381bdb2167338e2e475132392983ba8f618b60fbb68c0ea15c40db1",9.647446457990116],[2640,"0a8372aac6de561a881865db448de9aa8756e226e106f2ccee8c8048296aecee",9.917710196779964],[8933,"fb337abb01533ab839d900b782959f258bd14b7b224922747453833ac3fb4bc5",9.917710196779964],[9801,"397c6e84523039fd84070a51e5696f44ffbc524637b12bf50b5da499c1daa2bf",9.917710196779964],[18426,"0a6fb1e09fc934ff19c3256f20aabdf92106153b411d35d1b864b4cbbba21133",9.317957166392093],[19830,"1644ebe71c6c074d5390b35d85ef8afff30ed7bcb9cc312053dd5d3f84d38001",9.317957166392093],[18812,"0aa24dfc46748096e13a742bd01005de98cdf21e67a6288ff0f05e390da35526",35.831932773109244],[76,"b3903e4e7b5866c0785c69773853df9c18a6265acb544c080e7e5f0263947fff",9.917710196779964],[6403,"3de442e323043282a429a1900c73bf9f74152d2cd64a8fef7bb18959a58d51d6",9.917710196779964],[1160,"48e45dd1377eb9be4ba1971b7f807493b1159f2d83d1a46cfe597524e6ac3bf8",9.317957166392093],[12708,"b7a1db2681db17f649031cd862009cd451c2135c72a76443921b50e613a48cac",9.917710196779964],[2685,"0111ee761269cf73d29fa286fc89b5d673fd25921a865c01e16e1143d8df93ee",9.917710196779964],[10654,"f5e1f9dc8d7d76e4fab4baa191f02388ac126fc83cfc84798aafac9362a057ba",9.917710196779964],[12989,"af1241ef463389b746827589a1e540f2f3012196c0073524ba9be47f48c5aeaa",9.917710196779964],[8325,"4958edf9e5b3c7c50ce4bb1cdc708742a383289af1328f55a9afced3c77f25c9",9.917710196779964],[408,"fcceed17971fab40d6f9fba353ca770684223c5ef67213d954f21679d5684bfd",9.917710196779964],[18390,"9b33a3da671496a2ac2f0795eac21dbf6996883f6b0f829be6273a9afd079f33",10.040705563093622],[9313,"3d86f12fb8dec026c4d02ecb58ffdad44e538dab14b5587489f36d9022ccc6c2",9.917710196779964],[12074,"ea97d6422e8c6116e64ef82a9fa6f0d3ca42a1d1a589a53513d0d72ab330d8b0",9.917710196779964],[7753,"57603ee4364b40958db1c0a58c59f339cd6b795a41f3e738e52a5f93a2b51ecd",9.917710196779964],[14122,"97f5f459d3b8b36f41e0be3b7fec4fe29bb0536d53e37e600d04dae55af00d92",9.317957166392093],[12832,"926e886206c70674122cc0bbbe841bec338a509deacf3cbf1839abc35b66baab",14.188948306595366],[19628,"08697f060f7ce5f2f5a21d31285e832bcde799580f4506a4e474585d81717d08",9.647446457990116],[17085,"f43bb1a2b751dad59affbfae37235e828db2f80da4631e287f4c823903c82350",9.317957166392093],[11438,"7cc639174fce1534b98ba9e26ac46cc87125506f24d2fdf6c60a20cfb6f706b5",28.046511627906977],[14245,"05bafa768b3d48c65b806512450d65bed51053ffe0dd813a952f9dedf507168f",9.317957166392093],[17952,"535163ca4d23b8b4dce1cbb8872583dc678558b9f995ea399d0de106fa80303e",9.317957166392093],[2885,"3a73a0c7c3922f2fc7813cdfa3b83e3310821afc2f8fcf88254550ec592c38ed",9.317957166392093],[16329,"6fe67446e125575b0bb45dc40607670c6aeb931d63acc5cd83b8cf697cce6860",9.317957166392093],[15377,"c440168bc555fa4dcb372edc1ef6633a849f01cfd00d2c2cb60fcfd1e5eedb76",9.317957166392093],[19258,"d6645684dcc3333a46b3e943e16f1e1a3facd0ccde3794628e43d2fff3826616",40.76292335115865],[9140,"2d2b5af8f45db6e18770b4190469c9c17e9efa9a284d3007f3e9db7cdd79dfc3",9.917710196779964],[7315,"5ee3c747089575582803c027788642d81373fd47b1f07708629e098fcd0cfbcf",9.317957166392093],[16471,"cb185e47d6b9909638fb7a4cc7962eba9dc41a74f49eadc4230d75696afde05d",9.317957166392093],[15139,"5fbea6554c4eea866a2ce041c5ea0c99fab803e1be973fddd7aea08b4dafc07b",37.63106796116505],[5769,"9aab8a8be844a533bf26b125707f5d2a3e2cbccead000179e0b3265f20eba8da",9.917710196779964],[11364,"f782b4fba533d6d18c13612f35c140b0576907d2ee2fd9c293f34859dd849ab5",9.317957166392093],[4842,"ebdf740fa59432f3c3cd00cc466a3a61f3759030b7de4eaaf481a0a1ac922de0",9.917710196779964],[6047,"2aecd9d4597f88a46972781f86681a10433b8fe39c769b2add049bddca26c8d8",9.917710196779964],[4299,"9b8b7306927c1e83c9d14ccb85997f4f54e3ff55bbaffe3c8f324d483b7cc6e3",9.917710196779964],[18385,"6decacec836525ce0a35e6dadfdefe9d3f8850bb6c7a75b3490d03699bc9cf33",9.317957166392093],[13503,"a13a1a51ceecff084c8ce3a4345fcbe006f9a5c9da7fd4d528f01894d9e2be9f",9.317957166392093],[5470,"384845060756c64a43ea9c481c65b2e1663c9d294bb4801222fcd8d7cfc164dc",9.317957166392093],[18620,"d0178d20d1bb358c597ee8e180863a8ea120e11431ce05b18f6d144b3ffa262e",9.317957166392093],[13810,"1025d2b14e277fe5aa2fe1ec7499d41b97e20db25ff060654e5bdaf807413199",9.647446457990116],[1560,"1aa0db5d07c5749f3025305d31d9bd200397e065df8ee8d047e114f6d460c1f5",9.917710196779964],[19276,"dd7b3fc0dd24d5eb75fa792d2f3c81a4d780ab001c1bc2d56f9f86209ca5be15",9.317957166392093],[18076,"3dbb24cf5648b8b22476f5fdd4da8392e13308d8a8269085224562d1f3ab963b",9.795475113122173],[5409,"42546cdbb29f528cc937bc5cc9936a6fc167363e1caf91306fe8e1d4c9bebfdc",9.317957166392093],[14374,"661bce64f91aaa5396b4d52689705524417f1ed6655a042768a14def333fe28b",9.317957166392093],[8238,"d73b522ed197ce653d0e18b1ed42410368d62fc922f9004b81dadb82d2c6b6c9",9.917710196779964],[5717,"a6b634c244c91c8388389ae55bcfcf55192af7225dccece33fa515fc8a5ff4da",9.917710196779964],[14786,"2d463b23e1eb0ce5400f9de36082f6451ecc867f7006ff9f098f827f3ac72b83",9.317957166392093],[13233,"6aed56758b490f413922431db7420533568d323942b2968c8be472ea347244a6",10.052724077328646],[235,"e86f8cb6a0079235e9e980d6c8ec0cb46d7debbd280c4b833c5866c54adb6bfe",9.917710196779964],[8635,"8c333d1f324c1db080919850dfa54a83f7ea89d76ae0e53c51306a182f8c32c7",9.317957166392093],[18169,"7d465660c6dce953ff76a0517d5228ea1a00c9d2357e4c26fc3c4da053b8f838",10.052724077328646],[6133,"a369b67cf93358937a3648ae32d808ede45452d48ad5676a94417aec29e53dd8",9.917710196779964],[1016,"9e67f83dcb99b13e27b49ae9b85363f981738cd1c20e519617c206d0bea61ff9",26.893280632411066],[12556,"363ea3d6a48821f913a3076c7795eaeb6135ab8d705cbf8236a01f252be598ad",9.317957166392093],[4085,"f1d6a75ef3f69420a9441eaf34f2977f0c7f92c088315a4478da5941264e2ae5",9.917710196779964],[9162,"8fdd4e85f5a3a95a2dfdac09703278f80c57122eb55b5328845edde75128bfc3",9.917710196779964],[1406,"6049c1ca43a2e961215805a3b5f0ed465f0512b65236c7fe2db5d9ffbddcc8f6",9.917710196779964],[12399,"67768e67f18447074e1ab5e81b358691be7185f01012b32d22435f6195069bae",9.917710196779964],[7787,"4c08c24335a31fd5c403f354bee5ad82c64e951263efea257898d9dc0c99e6cc",9.317957166392093],[12202,"27a7a01341855155fa708683f5d5712cabf094dfbdd4751f0eb780e6d78b10b0",9.917710196779964],[8884,"717a524c495607cd7d862bada8b02178cf1428fbd0924b4b42c247b229f68cc5",9.917710196779964],[3605,"1c00a1583df38a9d81232122c63b3c05902d17dd87ecdd629dc76419cfbc2ee8",9.917710196779964],[2930,"74fe7d44c7ac79544254621adaae67fe1df3bc2f643a3df982e46d12e03dd7ec",9.917710196779964],[18517,"dc2316d786cdee57689fab6ccb5bd7a83e4edde6c78ef8aadcd0fca4c9181931",9.317957166392093],[8376,"c68c5b914831f000863c63087502ce0b72bb83cd6a8499cfe2a53c506e18cdc8",9.917710196779964],[13499,"b60cbf99a4046be532fb76b5cf5f3a366c5be7192cf497157be2d5538423d19f",9.317957166392093],[3711,"8962c25248d36b99d632e7b8e0eb2d2f621b205d01b879ac133918ec47d086e7",9.917710196779964],[16687,"119618f020e528c2349bc7f7f9600b47255b24ffceb0462e170659d8f5fedd58",30.133333333333333],[15052,"0a24c6fdc35ee85e77639cb5fbb36f4de19f6593969d9ff9d4f513e17e37797d",9.317957166392093],[17415,"3a7ca338ce2feaf219df17e1864336a65aa85ab8cf2e87afb0e905844fc96e49",9.317957166392093],[1923,"fc223d0cfebc036b9cf64b34427bfab9fc604cd7cb8c63c2d518214062c387f3",9.317957166392093],[13564,"8e63233b02470da33c45a138006a801ede6dbb03662840545ea993afb9276d9e",19.213029315960913],[3219,"4afaf3ef1fd9644af48ad8379a700a933aead263827a618bc54f35eee165f0ea",9.917710196779964],[4830,"834b27ccb71a5f2e773e744754eed78b4477c2e8d2b80f8c10c07413386e3de0",9.917710196779964],[602,"06e17c2c6d5d5905756cb1bf23d51d8cb9eb7acc76929978a465a5d5eec0eafb",9.917710196779964],[5947,"6a97043bbd96ab7013fc3714c66d63648e8368d4405ac9485fb1799550cd6cd9",9.647446457990116],[14957,"a12db2beb58a01a2d27b4d28206d86d489f28b51985776b06fed25fda7768d7f",9.317957166392093],[14586,"108b1ed4c90dc2b3b215a47ce7f9b855bb5f3b85b89899133f7a7a1fab7f6d87",9.317957166392093],[10862,"a36c354697c1999661fa3f9fc8314dba3de240e8320cb38130ee0229e614e1b8",9.917710196779964],[19786,"74e4f87a15f6f95a01bee5408259753fb7554fcc9aebd8ef1d408f29c5e04103",10.052724077328646],[19754,"d2edb31a01d603669bc16da177d64aaad3f7096f58b4589d7e9720cb39078c04",9.317957166392093],[15687,"0fefa980228aacbdd7872909dd89d70e339d99e7d45621c178896c6c9e32b16f",9.317957166392093],[4637,"3c360c88bc67130faf17e33aebdc7f0107eac75c7ededf4bec38b7c3f45166e1",9.317957166392093],[5334,"87d729bdc90455bb2b093ecab66f7ec48b7cbb12ed0fcea4ba5bd2a54b1438dd",9.917710196779964],[1326,"b8196bfe9b6ef60f77f99bc2d00a3bdc1040dc04cd6af5d14d62da17192440f7",9.917710196779964],[13442,"9da6e393b2f982788b3671a8e081bd0aa4767221656eddf1fd55ca84a35348a1",9.317957166392093],[9743,"061d90188f8aee6bf2ead260aa3040ca5a2b27a6f1679dc809b7e842512908c0",9.917710196779964],[14117,"07edb4d8725fa0c1690d865edb925404c51b41b3ff840ab4711aad27ad223492",9.317957166392093],[13884,"f9a24e35365683f9b5b99630673a608bc7cca52516c39b9e3bce56a2681d5897",28.12785388127854],[5722,"51390ebb90532c926aa4ac54dec84e871a7a8ab57c1baf5ed41732605355e7da",9.317957166392093],[11792,"28867f11f730cf1f304cc97cf01a1182da5d6c5fd64fc134b6b39beb7104c6b2",9.647446457990116],[4735,"a41e8a5c56bbc5748b3b9f1e9b752b72cd907f82dee8b8847fa8149fed56c2e0",9.917710196779964],[14478,"960ef1f5970a2cec12333302c2d0e0900122466c52993779aa21533e69f9ab89",9.317957166392093],[15430,"54d0fb92449c166d7c6e5c98b2c7499d1cfcdea72cff0f8268f3e59c73f49e75",9.317957166392093],[29,"1fd9c92091cbd61550089d19cb6ee432fb6fc6c6ab3654074c6b1249ffbdddff",9.917710196779964],[6141,"bb97ef51eaf6c7af91f3b6bb8a50fdc4cd1c8fc70feb191f800b1445488237d8",9.917710196779964],[10363,"e00b6eb017d58e9ffc89c5c979e99376791e447ed756a8c3930e1c98a5f6f9bb",9.317957166392093],[13137,"13f175cca0dda885e4be98500d28fb25423b55d1548f37ad6e778e8e1e4439a8",9.317957166392093],[18021,"499a053e122ffea7ce1d151f19d7db41353f895eddda79ada196c25b2c38dc3c",9.317957166392093],[15727,"3cd50cf99818fe7a65252394c712be2357f1733f7f865f72abbebc2b6b33f76e",9.317957166392093],[318,"c4aec5db113092c8d1ed373ab4e7cb0df26975246a8d0c45f424a61de82fe7fd",9.917710196779964],[7594,"d4d2dbfc7efeec542ed90152b0ecfa6df64d24e7ffc1c7473668c32d7d1e37ce",9.317957166392093],[9805,"c401350052ae571d54b9395f3c615a85471aa798d7817d1d58c3eb4e51c497bf",9.317957166392093],[15450,"d4b1a23f981f99040750aece9220736b7957faaba8e6cb362451c47f44252275",9.317957166392093],[17330,"5d61d188e74741ff6a98206d7cc8172c44b7fb451423ce367feebdf80a6b404b",9.317957166392093],[13160,"c1bc4a6e0da6f79982a20350df5d82d17d11ac2afc463e208e5986bd0a37d0a7",9.317957166392093],[7807,"56a2e5ac6a22aa795d2552305e9ecf1abf32a2ad65a6c010519e78a69a56becc",9.917710196779964],[16700,"7325439986486fbfa2c50f78c97d67e33250e8be5a26e696a97d1afc41927758",9.317957166392093],[5065,"ad613dc2fe5febc4c91e77e25d3ca5e1feb925a42b1ba0395d16ed8b1adcbcde",9.917710196779964],[13661,"24864157853046347919d41ca2725490e52f3344ba9a0f15b626c979ebf2099c",10.052356020942408],[18897,"e9cae5d4e0746e06684404666806195639b9e7347ee75819e092bb50f5969223",17.0744669218152],[16505,"e1c995bb4b5e826d0f00bac1082885e21fd7a961ddbf1cd6ec2d04bbf0fc235d",9.317957166392093],[15613,"4044117dd657717a17e8123082855912b32b759ddbe93481a95ac62c7eb21b71",9.317957166392093],[14029,"7537a5f8d3d55ab8bf35b63d4e4df185ccdcfa91b79a28f5c324915444762394",9.317957166392093],[19428,"55bcbedd77c788d6b4545e7acbbaadba725a96a5ab8603273990b57cea2e8e10",9.317957166392093],[17255,"7c82d45800c2bfc967629fa72f6d0294e101e17417311688be84720deb1bf54c",9.317957166392093],[6344,"3f9a8f92c4af031f17c010d2d1150de79e136ba496e7a74b689759b90968b4d6",9.917710196779964],[3706,"4c483270b37ae1a5e19bf02680611cdf5eab8a92147a9107070cfad929818ee7",9.917710196779964],[10621,"5e92e89d35070c49b0e18d13f73d2cdee1ce0ce4d980db7d3eacbf4126238cba",9.647446457990116],[10601,"e6832de8ebae25f6b7e716de9589110e96b7663978d8f33ced2cf59701f3a3ba",9.917710196779964],[1260,"829a82e00c8f75c391fa4e2c4511589e6a4968c9a73d7f4a3cc45eade44299f7",9.917710196779964],[4577,"bb694666991fc17d9f8fd8022857262568c0b393bd18661730aada29c45ec4e1",9.317957166392093],[3637,"248d9536d51de3149e0e9b6c0e97bb22cff76e55ea775967195c43f8690806e8",9.917710196779964],[14342,"961bf0d9e9675fdeb27d274070fcd4fec1e09a343fd6a5fea0738fe4c1fd7d8c",9.317957166392093],[12574,"3dc1ff395ee4753aa45d9bcf149f4c8b838abe046336b8aca27be411e9186bad",9.917710196779964],[19206,"f3da3721d8c3acb11df21cdba198e2c051564c45b873c164f23d073bc8637a18",28.14867256637168],[10543,"78e3b9823db4b14d8abefd51d6e52f2bb74114ab0afd5c58a18a20e87f76f2ba",9.917710196779964],[19137,"be8ea38be04954dc0070ab8a3a312d698c2ff8121e01120f4bebf26d0590ee1a",9.317957166392093],[7823,"f42fb957d596f63a144dd3b4e771380c1d53ff73a8a3edf267b5d03bbf9c9ccc",9.917710196779964],[7610,"2d1e0ba537daa7225f61a00c165970237973df5a43a8262f95062d9d289b27ce",9.317957166392093],[421,"d2b0b09956fb1a5f1d38bc651332f9840e35c00b685b1f952c55de3067ef3cfd",9.917710196779964],[18615,"9f367f885857ce1ac2520af4be6c4d9af8135b74f643747f08b2d9b0863f3f2e",9.317957166392093],[1409,"ed7d4f369dfed5cba242f8d0452f7601343b295d545b3f9f33a6ba319ca5c4f6",9.317957166392093],[6036,"222459a2b31c5dc9eba2563f84d8a9da1dd3b4b12729c707e1f0844ceb4bd4d8",9.917710196779964],[18513,"2fe32bb040a12fd14b76a07f26aab6891d3d94f457bd47893ef3fce908953031",9.317957166392093],[13715,"41e8c00424d09787057117ad9f6bcb278b485fa01479f063c94dee1571cb0e9b",9.647446457990116],[18986,"17f8b0d98a137a38aa0ab88ebd302979aa8bd2567b621b5ca202f19a76ea0421",9.317957166392093],[15252,"182261fa9c02083cbf07af6dd7d923b42dcf82fc76341afdc78ff15557146279",9.317957166392093],[8037,"b573ffb9822b39d26e0c97740e46fa99557eb9968e7084bac2c2f73dea8651cb",9.317957166392093],[10725,"d38ad98d2d823b0cba161751817ac4b996357fd7721bbff31787bf39598fd2b9",9.317957166392093],[11835,"f133cbf9b499a79df4ef2ccd8f402f514595ed1497536de9a8e71f5eb66d81b2",9.917710196779964],[15676,"c711bd9b75d0e643aec2dd40a433214d451146375ca944d2343263ee7e06ea6f",9.317957166392093],[3921,"a3fbba94cdebcebfae26e5875f78c471677695abd63303e6ae99b9e462f834e6",9.917710196779964],[7893,"d9c498c680e45e8fbc6214f2e1fc47d22578882b787058c93f9d58b1a0fb4ecc",9.917710196779964],[7583,"815f50ddad78098c8393524d9633308d2e265d9959597cc992e60695957747ce",9.917710196779964],[11646,"ed263892a0edca8b5f6d56dd3d3995bc50cce38f62d894bf451e04000c64a2b3",9.917710196779964],[19290,"7129f0b706d4f93b879cb6b826610e1d5b3686e8de3e8f452bf40ef8dbf71415",9.317957166392093],[12679,"75949d4219159af08ef252a4cfb927399d4498506b9077eeb47cdf5c8954bbac",9.917710196779964],[6368,"ab3925d81eb7147ae5c26a24947b1296374e24f6c46a45642c808fb879f68ad6",9.917710196779964],[4400,"48a6bb64e0f19ae5d5c16c247cdf657af7bd5832284843858916921bd24814e3",9.317957166392093],[9876,"77159f36874c7dd9d9ff30c992bae952e707e5b06e5d3e84d394ae3a135318bf",9.317957166392093],[16875,"76b27abc7a78df3b55eb01b9250d49d8a5c2c9836f87aa7aac9e1f3c6d32bd54",9.317957166392093],[2271,"d1dd6576dcc493b7cb75c85f83c737b335cdcdf38f1f625fe7ba9fb72c2025f1",9.917710196779964],[11413,"779fb186cd074d1c3090dc9d985354a2891eaefbe346d463db3a5b542c0649b5",9.917710196779964],[1941,"7cefd4b3970d0209f848c2ef62420781fb5d998df9d648f4849456aa1a776df3",9.917710196779964],[9199,"52722110c77ee9265c0dfe14d4ff4b4edbf1933e46e096bc785485adf7b172c3",9.917710196779964],[2362,"edaaafb422f0a20407941bc3e2d83cb4b5fb6002bbbff5b2674dd48ee878b1f0",9.917710196779964],[6613,"4b2e022b03f1335fd0b70cbf6df5add5c7c28be3616857ee5536cac6fe3a8ed4",9.647446457990116],[839,"ecbc6dda079d58f35890a6cdef170fbfa5295a65ef9dcadd4e517494a0204cfa",9.917710196779964],[1866,"830e336b6b6d53ef33fbcf1d2cd536147e5df82dd8c4006beb29e38c508ed3f3",9.317957166392093],[8052,"dd83af12d5fdaf4d0aedb7d2f37ef5dc5f470289900c322fa0e0c595fa7a26cb",9.917710196779964],[5609,"d90e7dceeea86fd5c1a644a1a181dff56ed9e3289c50b5f1ba5de0a5802e9cdb",9.917710196779964],[19099,"b8c9f9b177702e9d99b407ac61b3db25339cd4c3de65f81e924d404b862bd81c",9.317957166392093],[8790,"4d7880ec3becb9b457f5a40cb73695b04479aaf7c1225a1b720595830a8122c6",9.917710196779964],[1381,"45690cdc2ff85a8e25b35c8fa8e69563ca327b59d074430100156eacd5e7dff6",9.917710196779964],[17280,"989965022f4b805b923099527092e452d5ac95b708ce99f4ec88a88b1620964c",9.317957166392093],[19363,"d41df26495840cc259dc402c5574404b6f8e842b86de8bc85cefae40c9f04313",9.353846153846154],[10459,"13795a1c6838b2499001990b8d6ba4cea2eaba95034060d2c04e1312a3bb60bb",9.317957166392093],[14845,"063483fe37bb952824f15fcff851bdf241a5e778de6a15581a57f987583f0482",9.317957166392093],[19419,"82275be95487453c07f9d2c35948d1f0132a1cd9f4e8c3a2cf4ac6174c75d710",40.38961038961039],[11278,"8687ca930aa2bc6f5cfe0132eb912768d7d1a9e3b87abcb40993940b79f22eb6",9.917710196779964],[5342,"43e866dcf0a8a0ce151ec07f54647112f7a5059d1cacf638cf2425c17f5330dd",9.917710196779964],[4015,"d986cd83ee7d00bb63014957d0116230d4cd85512215d7a2724ff9723401a6e5",9.917710196779964],[19642,"f8715307865943161ff9d1b0153c9ff016bb852ddb4ea8f35938f98939f63008",9.832572298325722],[10206,"c365fa56535b4632ae3719150be05c9274a0a7df52c391f5dfabb9d1dc7defbc",9.917710196779964],[3461,"7c392facde7c4f2ab073c0d4c1b8836fde342ba33d117d1f67dd6f5b97d24ee9",9.917710196779964],[2513,"c81c1d70ef3089ed293012bbe9add19c8d00b84cca1a5eb6f369dd36918fbcef",9.317957166392093],[3329,"8e7a11402c020bf796ac075a6ab587083996cc846db2a4268097c7d057632fea",9.317957166392093],[17558,"93352df9498836e7f434d375cdddb752c02f9bd2dea2889a9f45d9b58e935c46",9.317957166392093],[16133,"c26264f284b7c3a188ff0914fd4e03f6462d3c3f50c0183ed184f4467b066065",9.317957166392093],[378,"de08f1d57049db90c4e8af42fa32bd78e764873ef62ed83e6445a34d493381fd",9.317957166392093],[10,"00458a5b693f471f1eec4fb15f3dd459acd3f3dc08efe7dcf6232abdda39f1ff",9.917710196779964],[9305,"bc0f95e6fe8b91ee466f3005d84cbd0bfdd449768d862123b2ff6473435ccec2",9.317957166392093],[17731,"6b1ebbf7194afb29b1afdf25356dc60a03075ec4c2a452175f0763d4f142a042",9.317957166392093],[10696,"d0afbcf055928b317e1adc9abc9a02f81fbacb25f028f2de6de68fe2ed7c09ba",9.917710196779964],[3187,"524df4065dbc7ae9db939a20ab1a530a3f18f900c71c1109035b7fefe7211deb",9.917710196779964],[5756,"828e7644d54c40412a37a846e7be6a4f19438241a1f0cc2adb33732c648dbdda",9.917710196779964],[1264,"b8afa8a1756cc6ec59b1fdcab7369a2827ddaf8c32dce1cde9bc34dcb25b93f7",9.917710196779964],[13175,"e648c5ef2da0303bc60bb6287497c70c578e3e8e5ee692fe580fb2cd65bc75a7",9.317957166392093],[18653,"84c0204b2bda2a75bd97e03d47c754ef65fdde60c584004d3e2750334ed87e2c",28.146596858638745],[18507,"c0fcb2378e1c58dfa1fe01b1f870285d07690f1893206fc72f65aadcc5fc4a31",9.317957166392093],[12222,"f14db22432edbf42a40a3864bbcdec85c08f93dedf9f5a12c328938e4fc3eaaf",9.917710196779964],[17681,"472ed68af50bf1927d536d96533fb033bdf99e6716d5b3ab7705eeafbf5d8143",17.04221251819505],[18898,"5d33b18ac23d17bc02b04053980c8a52482fa246981fd431c2f72068c2449023",9.317957166392093],[6135,"fd19693b19640c329ec2866b045f2aaf1cc34747bee335af1be88a60b44a3dd8",9.917710196779964],[4458,"beee9224b86f2910b453b5dd3113c350834c5d899c1b93dd69e3d54c19fda9e2",9.917710196779964],[8974,"73c469250046257ed7fa5098f0646c1f13374c436bc21bb05c60435918e7fbc4",9.917710196779964],[13257,"d4437fe490cb40b2c49956b8ace203c1cc065c8256ebdc8d52587e411b4788a5",9.317957166392093],[14588,"6d6e21329a512153af8834fe82a6b658759892e78b9042c0bd8302d7182b5f87",9.317957166392093],[19434,"aa086d4dbca77ca6d3f3c6fd9cf0bd5ebfc9af77aa99c9a3aed61484a8f15e10",17.005347593582886],[11453,"a06106aaf9ec855b3745baf5fb242e1eed2231841aa8141f8540f99cf0aceab4",9.917710196779964],[2079,"7465cbb0d27ee9624db0103540f70679a85b71b01f5e6c9e455a1c197c335ff2",9.317957166392093],[10017,"54f8518abe26d6a52cb63b4d9426eed58b314a6f83ac3cd9880a7afa537c39be",9.917710196779964],[4722,"33dd91cd13d995c7de22ce1ee86e6bfb86e811b8bd6e4d2ccc7b6164673de8e0",9.317957166392093],[7238,"3d530db52d5b29b1d26c1cb549fd786f55da12ace09cbc5cd53783d784ed72d0",9.917710196779964],[12755,"d61f4349eb48215e38d0b20cc4b48b89b4a6c06de6c1b814663797bcabf834ac",9.917710196779964],[2785,"50c57ec53e491d24cacb50127e6ad69832e658a956b3136fcd7ab506290dd9ed",192.30769230769232],[4563,"db78fb0fd9b86bfae863c67850e16526357b1d069c059857c4624687a0a5e6e1",9.317957166392093],[7466,"ba29799432addc30ea8d3df74692df4a8cdb01c644cb320e5d365645cc89f2ce",9.917710196779964],[5084,"ead32ee21149e8a8e90ba7cf053570380ba9cd1b45f3233e8380c46d64a7a9de",9.317957166392093],[17228,"97ac6b145b5830cff652054351f731e28c4c2db62899e9246ddf307570f15a4d",9.317957166392093],[2032,"69d89695daf5dd891eab9c8dec20f62ba884f4cc89205dbda0d017a3a1f5c0f2",9.917710196779964],[18856,"d91d9f2132621020dc118bcaa598c978735be6de27395de4923c7bda2e2fd424",9.317957166392093],[6626,"e7dcd8e3b18dd63b25ca008b829c05762c9de42c2532bc60bdffd57727387cd4",9.317957166392093],[7801,"fec9c3f12f00dc90c056e4293f0f6f11f7680949016f5b56206faff73f6bcacc",9.917710196779964],[10339,"80ccebceb722028662709fc33bea8a69c3f0aee1c8f1f7252181322bb06515bc",9.917710196779964],[4,"93282b44e9f6075a5129afa1b15adc11df5d57420de59d2c2af59c7280d2fbff",9.917710196779964],[2003,"eb71879f5506b77b047d7a109d23923c722bcbd4eedc27774fc7b9321e6d03f3",9.317957166392093],[16205,"632826b9db47168a0ee764a6a62d1a88c49cdfb29d8b2d70c7816a564607d463",9.647446457990116],[854,"7854398bdd0347b35d12bfcbb6572f00eec8c8d79d01f110fe1cdffc29ac31fa",9.917710196779964],[12963,"901556d2532ddb9e5caab4389492fc00507a025e70f9f0fda1e7a8c6ed83caaa",9.917710196779964],[13346,"3712b6798000cdbc723d0e5195e2621e3e35d955a5729918e88b1e3cc04597a3",9.317957166392093],[4865,"818d42883df38680ff4656d971268fe004d6ee6594a4342dde481328ae8f07e0",9.317957166392093],[3770,"ac92f7cb8c5798ba46954e9e816acd5a1fcd9c9554ba38b9097de598986426e7",9.917710196779964],[15216,"c59c9ce2fc3bbba9a780cf7cb804d58f1d86f2e3f3407745df6f4b1dc4682b7a",22.83553875236295],[6856,"68518cc2b04630e76f45e15f93d626209bf2cde08bea8790c6e254ee1cadf3d2",9.917710196779964],[9655,"eb559d237e40cddb24c8bd24f1a92a5d8db94d54f7152f50e2f069510c9dadc0",9.917710196779964],[15214,"3406846cac38536337f51af78e1ca01147a6ad310c6d8b55cadce8b0b542357a",9.317957166392093],[19063,"f04683f93e7e70fac29554d621cad9a4861f1343c6ee58f031365bdb0b9b311e",9.647446457990116],[844,"bf3c399945ee406b82ad082f97d98138ecde908a51b2345c83f300b1999b44fa",9.917710196779964],[13179,"04fd3ec9f64d42f5d24e6ca12a176f1f80922e28cd216156098f55be560667a7",9.647446457990116],[825,"9e0e979c2fb9e610d9f57db051d6606c04c2d32574ede8da88d6514aca985dfa",9.317957166392093],[18749,"e4bb97282b36454469821fd21ada24e6eb06fe501f281dd9caca4d257313a528",9.647446457990116],[13617,"5ebdfe9f4c02296e11384e4face195b6b5ed2b9e704daf82851e8c84efce019d",9.317957166392093],[14401,"811ea2f98782523a36d2f8b4bfc67013c0bdec7f760f1813b1549404ddbe388b",9.317957166392093],[16739,"911d045eadc7e7dedcd44c30ba779f887e62b4f9d7ca11f3abaef0d7696d9957",10.052724077328646],[17675,"7f953f7a6871e2b8dd2c2f23f04b82589b830c00d2b40f0634c9397e52c2a843",9.317957166392093],[17218,"b9ad201cb0728c5cf9de01c855d1472ed603d40fb5e9080df4f0cb3d1fc88c4d",9.317957166392093],[12807,"4b18f84b69ea4eccdfa077263521440e33bf36d2229558bb569b678c4288e1ab",9.317957166392093],[10000,"60552c9422e00fc2a3200ab84b5eab4ab4d3b3d9b143f3594ca29d6da4c853be",9.917710196779964],[15400,"1484ca74798b56a67c3eb4274f3aaafa21539a8bee5c9ea8f0601c67544d4a76",10.052724077328646],[1933,"940f73ad6402696c5f11238d882d8b3fc845769312572440dd827181e9c775f3",9.917710196779964],[2296,"a65730adce961da41b4b75d42301e2c79fd879af75d71bb34cb8b7603c7208f1",9.917710196779964],[12753,"2bb0db88a65afb42da16d2269351f1c009b4743f0b78f0d1d0255cd9fe9d37ac",9.317957166392093],[13317,"28d79c1acd3aff3fa8657ff2a411b9cefe40924f7a5bb67036c2b2341bff48a4",9.317957166392093],[3709,"b03f3f307658963a4e8ea36a7b0c4792ff86a45406d8aaf26ec46a01343788e7",9.917710196779964],[5167,"e72070c5d8f8918eda7f90ba17487a54289080340d860cfdfc1578ba7b512bde",9.917710196779964],[19757,"ae54d0e33b648fe9ce0a4a6e82299eab68d16079adda623bf8f02d7f61634b04",27.144385026737968],[4498,"8d2b54f73e969120300f8a03c6d47512d31425b85f877f23f63f8841d9126ce2",9.917710196779964],[6377,"cf4877affacfee4e03e9eba3a0831604c332c1a83298a33aab0e21dd68ce74d6",9.917710196779964],[523,"732f4dd719019cdf9c56d210ae321f2e7313f92d02fb7a4c2dfd2682d7b780fc",9.317957166392093],[9370,"bd2d7aedf69ea1cd289065be6929c780f2d0a3b1cfb92cb6527464e61ac868c2",9.917710196779964],[4260,"af822c43353e9a511dc947103660ff7fab364fe4870090e51da1c8ce2c0908e4",9.917710196779964],[15946,"429a36f321c4ac12f0afdf948cd26f07fefba966b011500ce294310aee11056a",17.027642276422764],[18401,"25b93d7f6da316e9456a5238ef73e100b6f7b627ccf08f010e104b249d576633",9.317957166392093],[6880,"1afb90cb7971f3807a94891b4e93e732718c712cfbbb2473247062e368e3bad2",9.917710196779964],[18609,"07882878d4373d95874d023e093813732a59e65a1bec07caf7ce38f5e67b5b2e",9.647446457990116],[16014,"f3d514d788affaa56474696f4f038bf76ed349bb0f4f4080476967c9dd642768",9.317957166392093],[15477,"e74ba621bcc7cdc1122c126d5edc364faa4eefe85150e876fbaf14413b688674",9.317957166392093],[450,"64dc4a7770d4fe33736d501bffaa402ea3a9be41a39f1ddb5654c56961e711fd",9.647446457990116],[17088,"6262ea2b329f45423b08892ea8e36a8538383f60b9081c9367fa41eff0e91f50",9.317957166392093],[3607,"ae70641e2f37c583904d76ca27c15accf07596c97817135889a3ebb758532ce8",9.917710196779964],[5742,"81fe94dab514bb89b8ee89b1a4e5938fd78f0bf5bd11be59c552859ac08ed1da",10.052724077328646],[17292,"8d8aff675f9f01e9f8c5e5879c948392601114e00f423e271a4948034f81604c",9.397642257991386],[17884,"c0b87e2f68e7b46876eff84ff769f764d8d914e6f04eb17fecbb52dfc45d933f",9.317957166392093],[1902,"f6c8448578726f2b9a55eefc5e166c9f9f6faec2c3d0c09ef2f6e780eb459bf3",9.917710196779964],[10583,"72a9df2cb91afaf2e47f8e9b2c9fa1f7a24ec6708f1378a3a4b5b6693733bbba",9.317957166392093],[10196,"a9000cd74d6af002b0c762747fe6285282c85681b2d1e0dc9523acc31a1807bd",9.917710196779964],[5091,"6666aab9f3321faffd2de436dc52a07995a693fb9d7f1a094041c7332fc0a2de",20.02911208151383],[10916,"192d98e2b2ffbe7a68e8b424ba2ca24050800faaf6496002129ba316449096b8",9.317957166392093],[10152,"530a1de13d7f836da45da977d416db0364ab3e386b2f17804b84b71abfbb62bd",9.917710196779964],[3686,"e652217b869d4a4750835bad1f1d1f711d12522a9298dcc450b5281402c7b2e7",9.917710196779964],[17452,"e9e0a52d368a85185012f75bb6eb09fa7644edff212f74944bd53fcfc66aa748",9.317957166392093],[14073,"8c4c40f3315b0b0458bba0d2b182b6ddc3a2237f6234376ac8daaa0caac32393",9.317957166392093],[6324,"a8ad3511f0ffe9a9d565ea8ebc1d0714365f0a1f98f3fd9b152bb6d89c6bd2d6",9.917710196779964],[19825,"080589920bec25a72802e5c12fdd2e6935e0555e25301cd8a14087b0563fbf01",10.052724077328646],[2809,"57fe7fc6e9ec23ee690e93081617bec89f51dfde548b74388a262fe65a409aed",9.317957166392093],[674,"7a2b20fc91c3114b151d9f0d9a3ba628fe18049a4ee8f6ab5c0efbbd74f966fb",9.917710196779964],[7403,"e00c0b45aa0b790f938723d7530fbb2ebaef2075d0cdf956c90e6c4a632667cf",9.917710196779964],[3256,"d75247d723beab2ba53d7089fd7e8728b81c82a1acb532aae3c1e20db5e4a2ea",9.917710196779964],[18601,"bb0827be7064d4b2d9175c70a559c57a416dba3549d439be23804abe3e21a92e",9.317957166392093],[18297,"e2f63aa61aa68b0bc4d9785f8ddce768cb845328c84d0bf1c687274fdf61df35",9.317957166392093],[6498,"f128deda456cdf06c39711bfe2cf02f5fc89d1794b6393ecc3487851a3d879d5",9.917710196779964],[4814,"0fe535d6bcfaf704448ddb2ffec596189e230c236ac8117e95b864fd3f3155e0",9.917710196779964],[12159,"000dd7b6ffa3893453ffc6b60ca01204ab3c9f800d0659db90ef243460bf4ab0",9.317957166392093],[18541,"bfa4ac2e00c7e5a4313a3e482a4255f350cfddcf02c07e22555326313d289630",9.647446457990116],[4844,"557acf7a3faca02a11998c239c3df8a1376aab86c5f938a93720bd42b0612ae0",9.917710196779964],[1521,"53632f4e9047ef123e253c4134ee37473efa3264444736b168f6a559296cf9f5",9.917710196779964],[7440,"0d850c7172a2eb682e1ff441a8beece294c73861904b65407b587b71137c24cf",9.317957166392093],[5020,"c799c84b6dcca40d2634e7a534165994fc0f3d257bb3f447a77adb80d9a40bdf",9.917710196779964],[16117,"e80ba4f4eec26f675f0063e19874f3819a3bd7732c9e5d870f928b9b73f4a265",9.317957166392093],[17706,"48d54f379d79e44a321bcc59c159b5aed1f83bc32e01ab5b5576eb8012c81c43",9.647446457990116],[5232,"fc4f95723986edfc56f3967413fb3bd9536a048d5e4ed5635fd174fb1714ccdd",9.917710196779964],[19855,"380ebde92db6dfe2ac4ff5b8a0b68d87294a1916e0f5929fafe7dbacdcda8f00",50.01562988433886],[11644,"43dcb7a4d73c60f479266c535ee21ac060ecfa89f5f2413bf388a3948d66a4b3",9.917710196779964],[19090,"07711e082602a1c7ac90a94acd69b0fa8d463b0be8c862cee949ec1b977a0e1d",9.317957166392093],[896,"05f55985b2cb7ea61c492ba266ff10cdd7ef00a4d858be6e162c78550675f2f9",9.917710196779964],[8754,"a57e564cce2bf5fb386eddf693dd8e67aebba3ef1b22a7148450135fc09954c6",9.317957166392093],[5175,"63c5946f1923fa49f0590b3e021c3fb0a8381d0710cd658e5374455ab36f1fde",9.917710196779964],[16171,"6cb9290e3ec82f9f6f4fb5dc22b9473a0170cc26d4e25e2ea4ed8e67cdac8764",9.317957166392093],[12473,"c3a23370ddf81624d0bc67532e06326a43ec858089d4fe0963bb1241bbd01fae",9.917710196779964],[17271,"efd03105cd0573ba0a8a2fa6dee328930184eed3631ccb0899a030b20e88bf4c",9.317957166392093],[8794,"f2c33473bf0b28a624cd1f21501e499d5742338199bc267e76e3f4ed739d18c6",10.052724077328646],[14451,"a751c02be232f90929355c59f1d8dccc783ab892dbeb4f2b12431edd8053318a",9.317957166392093],[4255,"5525228ea7be64cb5ac9f1c45f976adecc1dcef0cb786a1b1d9e3229d05018e4",9.917710196779964],[3152,"7ca59e68f11fcbded6e6e0b68f954867b9ff59e79f928f25d0f361538cc655eb",9.917710196779964],[16447,"bc1f7adfd1e19e62b182e4f8af4b0eacf0c69dd4ab5e72905c1a50895d3d475e",9.317957166392093],[13537,"cf4a4c4611d56a9c481ed2567afed91be50d86eb13bf9be1cccd2b9b288e0c9f",9.317957166392093],[19443,"32c1ce5bcd2b27f9461458d058f0a4069666bdc98995a9be6cec9184613e0510",9.317957166392093],[9934,"5568b46c8ef136661dfbc90e9de8bed2dfcc2860fad232e0c61411e785b4c2be",9.317957166392093],[159,"08f7080380143f1facc7e23b3771ea834e4dbc1a4fc3cc5ad1b9437c8eb1eefe",9.917710196779964],[2219,"7d1aaddf29af07e0107fc8d2ceec0cb5d11ab6fba0ade5857f3de7ee36d663f1",9.917710196779964],[8785,"e639997f4a70b240510547b924b69cb932b01790bf876042288f036a42b42ac6",9.917710196779964],[12693,"4da26f036af85a31747463a4f770c9048492abb942cbcd48ddb965136feea0ac",9.317957166392093],[19072,"4e0c3a21f8bf82ee2bd84eff74ed3f9b18b3efbecbc305ff11a49d8dc95fc51d",9.317957166392093],[13287,"2de3a4c6626542b5252dbf2bfcc4518fcb05c6322b1c539904d4a4e0649ad0a4",28.187082405345212],[12187,"00c14651fe4af09704b5d9c591de44b7de96672da13392b60b3bc5411b9926b0",9.917710196779964],[18809,"91641cf75446e4635ccdd38339c37f353d4ffb321672fdfd174c1613d85e6326",9.317957166392093],[10378,"a1877ebf33b75e379cda515c59bc51b07ef321998f17ebea7ccc9764305aefbb",9.917710196779964],[14051,"cc74e8b33de6e9397a410048032899b8e0591d6a1d1b912ae8545734df14b393",20.060422960725077],[2737,"2c28878d82008ec4a3ae0fd30a3d9b9c64ed589d421ca235251f4759eb4f30ee",9.317957166392093],[17216,"e126fe1fcfdfa00e7e44cc68854f72fafab58226e2abf17820c4551d4718904d",9.647446457990116],[5454,"077bb05f01d2520932c09ea809c5be99129d696d129e11f8726d4fc2bc4a76dc",9.917710196779964],[19379,"c0490e71e36f0ec709b620bb1d8dd3079f2e9dc34b402e06af1137188f479d12",9.317957166392093],[13517,"7be4d555dfe10d562eaec65acab721d51b1fc115988a98200416bba17f6f6d9f",9.317957166392093],[9004,"cef4ad4e8b898918dc0912244ea83c9716adaecb2f060f3067d298959490c5c4",9.917710196779964],[11502,"928cd4ad7883c7bed0b74c17dac4081c1785dfc7f2738c54d0c399a062a37fb4",9.917710196779964],[16518,"8adcd2b61facba6430f7b47c564c16caadc610a83bca2c0f7661bb191f64e25c",9.317957166392093],[1979,"850817d389df6491924956d5e161936024d1b63329b0fafc6b1cbec250b822f3",9.917710196779964],[7570,"368a6960158e4d2df39e3484c98377ea4ec25a06c536a1f1b7ee221d16fd5fce",9.917710196779964],[12712,"e551db0a5d12dae700c164cb9eaed7e1303a8cfd0fd1f3c797f86536e3e884ac",9.917710196779964],[17323,"80567310df37f722da04220988c5fb86b3e8e7aaf7171145bcd5fc6e02d7744b",27.86634844868735],[1555,"b001201bc879be70202f2d945ebf8e7cfbc84bcb253499cf042561bbed45caf5",9.917710196779964],[6499,"17771c16f0bdf9acd537944d2c11114f0dd4cfd3676afc4581e0754ab6bc77d5",9.317957166392093],[12261,"8ba3b2bfbf26c9c2ecd0a8721bb3426d6016425615f34ef43120e370b0b2a0af",9.917710196779964],[6844,"db43d7027dc855b8da9bcc5c25830f323daa08760938744c3a31df339fcfffd2",9.317957166392093],[11519,"3a9fb66ae88cebd4b053202fcda9d35bf5ce3356d44ec943accf86a3e2d664b4",9.317957166392093],[70,"77dce29133684ee610616f157afae246e7bec5242cb515fb83ed4766770f89ff",9.917710196779964],[3802,"08252dfb605df9274faab16d0bb0ab01106d0d70bab745a64d593d27a69ef3e6",9.549738219895287],[11380,"446f4925bf349333034a886a273bc1154554e5ac15057996b6fb257ffc8783b5",9.317957166392093],[14556,"63f940fb1b097e2fcf662d4d0d3c37377071b59398851e18fbcf502385c2ef87",10.052724077328646],[4245,"8b028d31def94c69fb5b2be1ec9ab9273c1d412590a685f994c77f90dac824e4",9.917710196779964],[18814,"a9cfc6d10cb4063eaf4b647fac1eb372cfaa0ffebae8477160956aa8dc4e3a26",66.92913385826772],[4827,"aeb43f8b42d94c4deb0a30601720d688d0f37017b9cbbd7c772aad32f0053fe0",9.917710196779964],[7019,"52c66c0ec73c47727eef7fad510e5d3032ed9247068d0d9a9fb151e03194ded1",9.917710196779964],[10907,"67d9c58397f046e4ade0bb99009c69905edf9ce3fc2507d8e9eba32cfacca0b8",9.917710196779964],[8901,"aa9cf031f529a77cc074bab83728dd54736f8c223595e5c3dcf1a7632ba973c5",9.917710196779964],[5507,"73816b60960ac3de29334a0a965be5987897469beef4cfa6798ef2e44ae12adc",9.917710196779964],[9702,"5072c0bb31ef017fa6157cf70b6996d2c968b7d667cd140416aa9a8580725dc0",9.917710196779964],[7183,"4800ac3e8a20ccaf288708abf2a45c0dbbbd9793cf7ffaa8086e8b8712cacdd0",9.917710196779964],[7830,"e42d347652547042d89e2afcf43f34ddf9f1f62defea32dc1f0f904481cd96cc",9.917710196779964],[12351,"859d06b2b4160f348798d1e17697cb96dded65d8836c42ae77dff758df84e6ae",9.317957166392093],[16702,"a728fa24ca91c152029dabfb990c375462fa683e6566a9c25df9be14735b7558",9.317957166392093],[16273,"9d659ceb49de60da975c23ce96909ff6fcbca5f90a663dc91492d13ec5e3bb61",9.317957166392093],[11897,"a338b5d0fd524fe5c760c2dd08df8b0a47969c82be1e9ac10ee1d9638a9d0fb2",9.917710196779964],[12980,"094f1c1c07427bad3945f17be1c6c55a74e6d2a6a5928b703de4ffbb3b49baaa",9.317957166392093],[10961,"811e2fdda79fcb9af158c377e649a7d703ac03d71b2c02d08f470b559a8746b8",9.317957166392093],[11640,"fc3e3af67e6bab8032895a2d59b12bca264f45e59503e1319520cb71bb8faab3",19.058823529411764],[6715,"a820832427116d4b0fad2679273a618db2f42c1e8fa4a49f7542de538218d6d3",9.917710196779964],[13904,"340a627d8c5c231f090306e4413a5a8c538feaf8aa8920f4ae11f27c8f70ef96",9.317957166392093],[11431,"94ae762048569aed6044626237e0e4c340b6a16565aa5c6de9f9a0099e201bb5",9.917710196779964],[5808,"d023353ae422171ab2cdca2a5cb9dd842eb71c996624867b02954079e0a755da",9.917710196779964],[4588,"7872ed6b16aab00f19b29dba3ccce772a8fb50b18da42f130e827dd1aeadaae1",9.917710196779964],[16182,"5cc6ad36a81b5dd184d7d56c57f09e5dedf181ec7ba9aa17b92462de7f1c5664",9.317957166392093],[11043,"4e031285ccc4b419346dad4f2264c0cf81012182a4767721491a24cb29a9c1b7",9.917710196779964],[11208,"0797fdbfc6cb4ee054a23b3258c4ec772c366b1366bfdbdc4d97b447028ea2b6",9.317957166392093],[8423,"ce22a82cee6075cc3a8d7468e80582234487f1f00e401746cb0cdeeec8c479c8",9.317957166392093],[2909,"0adbaa1c510274ef35e08fd877a9c93609b897f8d967137687bfefd85c8c0ced",9.917710196779964],[14307,"b9935385c4359dc2883d5b5846eaaa2a725949819614ec0101a09a8fc1e46f8d",16.71269487750557],[14493,"2b74cf84de871941cd551a035818d9bab749b4c5295e88b1f7965d3d8faf6989",9.317957166392093],[16617,"d3422ae1c988d6daaa07b741404af8d4d7ffa0489a2463b28855f3d2abb5825a",9.317957166392093],[6815,"26bf3651fc833af683b5aec84f5aa585928b84cb9585b3e0bf7974aae26530d3",9.917710196779964],[7201,"59202ee274222d210f22bd2251646f644c5487d5ac06a674d1970a1246a0b6d0",9.917710196779964],[8939,"e145c8e4df0e1c3a0aa215e818e98923e705854f15c8a78265e50b369fba3ec5",9.917710196779964],[4211,"04c0b287bf489f82f17b47f1f97da2381da79b46e5c5cd6e776c0497cdf35de4",9.917710196779964],[4544,"a070f094dbe965e133d9f51e9ad9096ba51c6bf37f3250debea08337419812e2",9.917710196779964],[16662,"c1fcd2a1f442be8b8a57dcb5c3b40aa798e722d4d9c404ede095b9e1e00b7559",9.317957166392093],[19431,"fce3e13441b4b4f31f190cb26ff714da75c31f40230e7e34ce0de277fe2d7810",9.317957166392093],[18592,"0e5fc35092211406d8cbab21c986914981d95e0107bf6fc83a19300b7c9e0c2f",26.04580921218223],[11419,"41c0c4651393c46533a4959f9e3fe0845ab25ca2a3b6d946ecd21198f3ca3ab5",9.917710196779964],[14115,"fd9d671c1f1878c5cfca4aebaa450a8208bafdae68bc18c903c84a043a673892",9.317957166392093],[2803,"7b9ceba90dfec5a9fd5cf70a0eee01901d191a01d3d145df568bb0af4c20afed",9.917710196779964],[14990,"164ccbb8304526f31c30958715c9642e652d446273367cbea240154425a2b27e",9.317957166392093],[10327,"fec9d7ceff4488427191708d87da009bf8a74e9c190bd8f42935678edb012abc",9.917710196779964],[10342,"206e302648b5578e79bb94c6c0367995aac1951d96a76e8bf37695baacf113bc",9.917710196779964],[4213,"b6b9c35fc2cac90d5691348a91c58154dcfe35d6b608aa708d69d0d036ba5be4",9.317957166392093],[10594,"7cca13e64d0f3b1a30b0a22c85e70490a56637d8586b2974d6d8e80f5169aaba",15.003322259136212],[13797,"59f16657311287c4f9b7a07442a61b15bf182bda94ea0439572c2a0c8d067d99",9.317957166392093],[17811,"70e3b1444a08550a76a311e98da2383054f6f24c3b5940cd879285cfea120a41",9.317957166392093],[17468,"f4899cc58da061ad0ae0ae24ca8a4459eedb020a5ad16d8ab4708811d6cf5048",9.317957166392093],[11435,"c41b4f3eba6a63c3d7514812afbee4ece9c5a5b882f4a627dc3a5622509f0eb5",9.917710196779964],[19324,"53d9c4e33f03071a91fa0f67e191e3d0fa7790c7ca4294d4f88aaa9df65f4814",9.317957166392093],[17867,"b51f744bfc2565b8e39634a9db4f5f939dff0022548245a9243d29bf0b19d23f",9.317957166392093],[14919,"7ce69e5e34a26df621c263a43cb3704adf29688fc8f10cef7322532546a88e80",9.317957166392093],[3274,"54d1c0c9783b2bde7ceea6e94073ed5d57cf6469eba0acea715f69b336018fea",9.917710196779964],[7304,"5ed5f0be133a55d45d2ea1db1a5c19f638364a84936abf54fcc254369c440ad0",9.917710196779964],[16464,"a0cdbbb38723fa2f58d41595b3d64482f4dba529b42952fc488183ecdcc8f95d",9.317957166392093],[5464,"0ad88e75a817aa78e6b55d8872d4208499d6afdbb83be5caae74e61e7bdc6adc",9.317957166392093],[3125,"754ab2b7b05eae9dd2dbba7297aa904f0689899725e58e67127687b989c182eb",25.961605584642236],[19282,"4266c5504c1c7c7d7108da8012198c7bd5bc646d6041c92b626f7b9649786315",38.99651567944251],[8162,"3b38d8bcfbd38c7362f172ea3487a6932a455ed70a4961114b608af389b341ca",9.917710196779964],[1382,"7342a29960f5f19e568078cd32a9e176805d980c1053511fe97053a2f764ddf6",9.917710196779964],[10287,"9129d5287ee1aca56b21b7c5939257c5fde088425bf380746d2160a183ae75bc",9.317957166392093],[7188,"2473ba2b0f94b8932ed35326566fefdd7ce2cba062270f7353645ceb2595c8d0",9.317957166392093],[15868,"8acfe3df27a265ba7aa49d212ba9187f984de8dc6f40abc64193114b587bbb6b",9.317957166392093],[8681,"621dcf2e7d486a9e18914875a24d73170bc8406d3b8c0ab2dd338b24cefccec6",9.917710196779964],[12645,"784f155012c926c070617cb4c613c39dace8307f4f41608fa9b10fded7a8f3ac",9.917710196779964],[17874,"867e7f424025be5ab8e8e46e3ef2e088196e6f949a22ca7099f5a2556df3bb3f",9.317957166392093],[12677,"aefa899503bde398471e975be377f05007c03979f31beef2a84bad71d685bdac",9.917710196779964],[2254,"b1fd8b0365fd97272c235c13105bbc59144c028112887363207c0e87c1313af1",9.917710196779964],[5578,"a04fc47517311bfe6a69fddbb5760a24f1f944900f5c4bb7ebe8bb95ed6bbcdb",9.917710196779964],[15202,"fc690b289c11f96ce50a56941d8bb896a165299b132a876907d2e3eb3141837a",9.317957166392093],[1385,"1c106136a637c632d95a08c2d3f4766940f0294d714620d27f37bb411c8bd9f6",9.917710196779964],[15816,"bfaa4e32d71a4eaaf4d62312a3fdef447fb18311b4d426908533be042e76106d",14.188948306595366],[19697,"28d60a0bb8396b023a37a48c042b68b76893073701055abb2c09701c02a6ea06",10.052724077328646],[13820,"e430d0264cd272c3ade640054a630babcad9320a66495cdee72d6e1be5c61a99",9.317957166392093],[17828,"643c9c2406303457e3bf031c84ab25c08cf271adb8d745384b21da0c9eaeb440",9.317957166392093],[10698,"9d2c0c792db25d2beaa4381a18e6d2311d750e474bdd320226dd009f63a203ba",9.917710196779964],[456,"f2b72d950993b9b4d754ae24fdabbdf340f72ff384371f09976121d5a795fdfc",9.917710196779964],[18908,"e85ed984240f188b591fa81a4e6f839606d4016abb41e1ba888514f36cc01c23",9.317957166392093],[16011,"39612c57bcc0686f7e878f484fc45359ad38da5c0a26e316c4626d08ccb13368",10.052724077328646],[9454,"2e9a64d7e7df5428cbeaa9f8841873bb1da2b010187d482d40195602af48fec1",9.917710196779964],[14134,"38eab0ef7af3f1be6e3f2096216792727cde5237cafa70901799ec45036cce91",9.317957166392093],[9657,"0230df4b425ea76cca339809f83d6363b8d88b38ba0724808db539a77f92a9c0",9.917710196779964],[1731,"1cf778cde50e5948ff523a4f8e3ded1778f20627f5fec77a2cbb605512a5b8f4",9.917710196779964],[17338,"392dd40403e37643700a734fcef2333256f67e227371d77c085144d8c6e0274b",9.317957166392093],[3534,"50b555d9c4406da1481da0195b36c9c3b1ce77d223e16ec85c47293a5ce3bce8",9.917710196779964],[12334,"9bdf40ab07df8f24b39c607e2a501f8c780563c4213b14ad20a1a5c21ac001af",9.917710196779964],[11701,"0bf988f50956e644d6caf29e3075e1f2f0010f4809d6db2198e8f6bc31c44fb3",9.917710196779964],[6565,"6d0677a9202984c92b27b3ebab82403e09ee6a09ae47455c64ed290e356bedd4",9.917710196779964],[13369,"3c1b0fd7c5a4fc419420d3438de848ba01c36c5cc8d85b3fcd61c8872ddc17a3",20.05763688760807],[9034,"953666ea34684c535fb35e617fdcd7bdda4f01194467734e9c9166e7b54f90c4",9.917710196779964],[2612,"d55f0b45b5d575796fba469e553d48aec8a8d637d5a2349834180b2b299f13ef",9.917710196779964],[16826,"1a293fd76eaee1bd73f35a5f1e37dc30cb05f45dc1a8705353ed13b79367bf55",9.317957166392093],[9323,"e720dc2e88ed64cceae428447b2abb3bdc30439e28a37405e24f4890561ebfc2",9.917710196779964],[5640,"58640b579df467b3d8525177d2b8c0352db18631bae07a164fe7e2a12d6863db",9.917710196779964],[10291,"45b7d47fe6d0370948752c3808ff52e1d737f2ca6ba29d1c138e9c33ce8470bc",9.317957166392093],[2963,"1593f871d590c45a58ba69bb0f242dcb0e603c55a0060b372452e7d7f0198aec",9.917710196779964],[11515,"be5e546c5539494d09de641242ae09a62d97adea3cceb964045a18e192676cb4",9.317957166392093],[8911,"cafbb71ef08181dceccc78ba498d4d5afd4e34bb1e3d983a1c3e25ca4e9662c5",9.917710196779964],[13380,"0190f2c392b14837ff81b8c1d9c5d2ae9f241a37e3cff73b7cc916822d5bc1a2",9.317957166392093],[2250,"9666fc947063c9e6a8ce816ca71b81470c7e54c50b6b6912ce22c24745c23cf1",9.917710196779964],[15514,"39a28adcb9c90bf58c01e62d2e865d6acc2cd6bffda5faba7fc746506556cf73",10.052724077328646],[16547,"092b279db7a19e78a4ca7003c33bd162fa418062d2edaab54b0e0242e069115c",9.317957166392093],[8856,"751d467e5d97dc881ec985eeb2f264eb737efbf56a03347cfd3ba7c98978bdc5",9.917710196779964],[9630,"7013776c7fbe5583778b21665546b550ae2295a64206831122c7f5f99478d9c0",9.917710196779964],[1220,"412c0d57a13b971e7778a1942d3ede18ff8df4be8f4e9dc7ece6e5c3741de1f7",9.917710196779964],[3796,"1931a9ffc8cb248d820dcbd5cf22b2b50b898203bf0d8fc39e95de000f8dfce6",9.917710196779964],[9362,"8e6d21a9604f336fa3b99c7eda4f1e6c31e91c337f1e711f815c619cc69f7dc2",9.917710196779964],[9792,"dec9860d1173d8931af91b55f0810f572074d13e9a65247cd3b7d225356dbabf",9.917710196779964],[5292,"d862e7cf52052c1ac60ed4f092fb1b48da84efb137c651dc1364c8ecd00d73dd",9.917710196779964],[4712,"e3ace376021ea1985e7101f5139e3b6c2ef0fd181b438594d68f8ddba923f3e0",9.317957166392093],[15928,"6e2284d3a60d0a1d98afd744447bbdd029cb7531f4789fb1096870e2eb518a6a",9.317957166392093],[303,"eb610a880e562bfd56ef7a299b55fce9054b6e4b283788de73652a2b36ecf0fd",9.917710196779964],[5784,"b66fec13b390970c4b8cc5438268575eb9daa74e760a50228da9188fc8c788da",9.317957166392093],[2767,"f1baaabcb9a9f3466afdf84e5155ff7ab408f1b5ee92282af89abe68c8dcf9ed",9.917710196779964],[17690,"8b4009e97f28c992d12a9711523f583a5f3a9a2f561a3c84aa9e27f9c61f6643",39.78082191780822],[17869,"927fb9648c5af5f1eb892741a6750128c1c427a6cfcb28ab1aae64efb637ce3f",9.317957166392093],[9341,"d8edccb726c006623d70c9fafc06bc82c0b43010179678800403e2faa21fa3c2",9.317957166392093],[6044,"33c9b6d1ded500a21f8eff8f6c65b6bb1401807bb70412749d6b2f1fb068cad8",9.317957166392093],[1805,"f2cbde64078ad8aa0273857cb8357757c791d99130c4170ebce0e6ae603432f4",9.917710196779964],[19281,"56db4076ecaf4afbc0a13a0b597f9690b51ad04d5444158011a96d6210a37115",9.317957166392093],[14709,"5ec440008106d0dad8949b39ecaab86ad76f6799d3deec4ea689bd5bf136bb84",9.317957166392093],[6485,"0e4c837f60e90880663e4727c50f7e9981639c4c4f14393cd7b36a5dbd4194d5",9.917710196779964],[4874,"0924a897cd368674548c3f6de18136f80060289c8952c784ae31103b028d01e0",9.917710196779964],[11017,"5d7ebf7986f7c0b991d515723634ec04d6a1f36a737316f954da7808a688e5b7",9.317957166392093],[5049,"95449599e87ca11ede5ec523b09c902e4663b679bbb89ec15471a807f9dbddde",9.917710196779964],[9401,"5275a55110aedd4e6959cda7113661d84a56079026664dfd924ab41429cc45c2",9.917710196779964],[4675,"23e527272deebb1cf272716d1d1400eabb4d2c602af5b06cafba6e57e9f125e1",9.917710196779964],[17464,"e5ab72f13820b97e4708162999a2b3b500af2e0c72a6c90d41266b80d7ca8a48",9.317957166392093],[7947,"aff0a2aebcac46ef51f0cdbdd4bcec75b0cb543aa162e2206395f8be6b51e2cb",9.917710196779964],[1200,"b02edaf59618db522cd3c1a77b3e29b1764571b5f9d450ccc97184eeb6e202f8",9.917710196779964],[209,"82ce47cc523e4ece9088c84107a35bd1cf10c353078bc40f5b49906183228ffe",9.917710196779964],[17954,"f07cfbef89e36859b78bd0c8e7d0156f3c0d9457d57989b7d3384c24932f2f3e",9.317957166392093],[3991,"24b15c52b12866ee76bc4e57eb1a2eebc202859407e16755c3c01df5b610c5e5",9.917710196779964],[19525,"dd973fd3efcc02f52cda74a21be6efd339f0fdcec175fb25b71693567d0ca70d",9.647446457990116],[9093,"68b7b82923059f40e3481597f7f75beadc79337add876f4c9ab7033868a334c4",9.917710196779964],[18057,"181a4e3e63476e2779f351c37fcf63076db6b1ed3c2d399283897028d3ca113c",39.78082191780822],[19402,"0ba1d145571754a9928b18ef77dc268c92ddbf22c0d5b892f7fee5f387e37711",9.317957166392093],[2343,"255dd89516c6c39c3f4a17c142e70ccbb067f57988add162f8e9f66d17f6c5f0",9.917710196779964],[16497,"69b5e38d0ccb674b00459c69e85b0eba9bd2e5c91ee43a5a0268fb48772c4d5d",9.647446457990116],[11479,"8b3880efd046a26148fea77aceb96d359059d1877ba803f0c773af0e51eaa8b4",9.917710196779964],[13199,"6c468b872406cdc738b8231682df1d503086cb0c217d64aeaea4fc7912c2eaa6",9.317957166392093],[15624,"6370c53aeba1f5cbc01ba7ad490874518bed561fba37b9000ad3175cddf4d570",9.317957166392093],[4254,"a46efc83058e7c36ef93436fdd42dcad6769b84ec3310ef968e77389e68219e4",9.317957166392093],[3386,"7cb424597ee2402a568e473abddbfac7ddee51b6a367723c4922b729f127cfe9",9.917710196779964],[659,"7105662c06a4d693f53bf52d2bdc96d6cd55407cb27b42b43b339415786786fb",9.917710196779964],[8501,"99b0e50e63d8502afae0d6c7f352c3b26033672b26d425937ceab1433e7804c8",9.917710196779964],[17641,"57977ac42c83964003141398a387735a472a0858dae0301a4244de28b62a5f44",10.02309468822171],[8542,"d4c473ee9d7adafd9add6adad99725b52b9089cd4f1fddc6640dc6e5ab25c6c7",9.917710196779964],[8987,"4079901eea1f29049aed9dc569c9caebf310b05ac471ea00b81d8ee37117d9c4",50.22156573116691],[8829,"f96ae2ac396ffaa0ba84e9163a8546172ce21730e3c3a32ada876992dc51ecc5",9.917710196779964],[19075,"e9a637ccfff7bda9899200ee3c748f7a4a0a0c3a9a75fac3894939647596c31d",9.317957166392093],[11361,"4312486fc328bf9f0ddcad071e845d9f08ee7661276533a29131385624c09bb5",9.317957166392093],[12968,"709c30ebe4a0459b81ccf0e7967636ecc0435f27f622eb4092131ea7657fc7aa",9.917710196779964],[6094,"34d4b87e8a725d51aac8fe9d363ebdd56e7fbdc068893c6612f1673a14d66fd8",9.317957166392093],[7628,"aaabf977d68a54e43bba0e886119866db8c04093de2cad000dbaf0afd9940dce",9.917710196779964],[10253,"f04de96515c5094aa2f7ebbafa1a615500337ed65822c305988eaadd3493adbc",9.917710196779964],[2007,"3a68ccbb4aabd7bd2fb4d5b36251f461051c22d34144be75da80a165e6dffbf2",9.917710196779964],[10987,"17f9489c45c310a489b67b70d13c84adc1388fdda6f3c1988bcc6a08eada12b8",9.317957166392093],[14169,"f2c7c3e7b38e229e64969ac50d520f93fce88c736675d0522fae6483f5471091",9.317957166392093],[14267,"a73ef972a48dfba1ad6c79e821eaeeb1df76481d29588d092383c135b2bd9a8e",9.317957166392093],[4928,"de18c03eecd02efa8e03e47de05f8e8393b7eff06b3d8fb722318335fc83aadf",9.917710196779964],[466,"2b5bc9f033fd262655201f09be47c22930a637bbddac2fd841357cd87851e0fc",25],[13155,"0df0b3a5e6ca08460d99371fd93cd6b55b16dae5f4eb42cddd5a18ea2d39dea7",9.317957166392093],[10527,"5c77984eba5ef6fee5d610f1cb0467833c51a1798c70e74bf28b3d0d921701bb",9.917710196779964],[15298,"d052563111c304c2bfea33d2bf2e80eef8058c3b8298fdd33e2734a1e73a8f78",9.317957166392093],[17881,"ab0de0f16172f1da4964e05dc7280257dac9d203b36ceefc7298fa4d0ce6a83f",9.317957166392093],[13466,"57cbcf4b4e428316504af8a5be35a5a0e5a502cb0fbdca671678ae40fb6ebba0",9.317957166392093],[7920,"fb1ccac64615d6ea6b427648bb2da672801b96a36805cc75caa349a54b0618cc",9.917710196779964],[10304,"9c5da31d2e9682a73cacb5abbd8064d40461b88ecd384be0ebdda718789155bc",9.917710196779964],[15156,"a55510ec38a02daade94751adc7d4067fcbea91e0732256c6b161fa182515a7b",9.317957166392093],[11898,"c0ea78d7ade4745cff4a5b7cb07d1adeeeed7546ea2cb053b02c2002ba5a0eb2",9.917710196779964],[2377,"d784b59cfb429f905c787ccf259817b4e0e2ba7bcf5339b3624d80001c009af0",9.917710196779964],[18917,"d42e172eb94629d2b95b6762da9439fe3fd062f11dd6283cd91e14efac71dd22",9.647446457990116],[5508,"a15dea67aa86fdeaa40c320d33c7bed0bb5e9502b22a19f2686c8a633d662adc",9.647446457990116],[13347,"2e75da4f87185c0ca74acf7db4f521c4495a85e09438a8b07c7f3592ce5490a3",9.317957166392093],[6012,"9c64bee51a59ed3b17c0d61570a3e1a7e73f94efc7a37d1cba547e7b63dcfed8",9.317957166392093],[8886,"6f64cae80c23e6ed15a6ec969ec51f6eeda7ba7674aa40db29c98255fbec88c5",9.917710196779964],[12327,"4c88480cfe8846b6abb65d8027dd25f202e3aeea7ea84af4a6674dde6b2d0daf",9.917710196779964],[3889,"28bff4d0dfe85157b4c55e47d79053701eea6b0ef36a30b1655a2bb5db7168e6",9.317957166392093],[3860,"50f29cd840a26ca11760ce0ef64054afe064d25580cabf09c172437dbd609ce6",16.05693950177936],[6615,"ae60f2c52682e6879770a05b64068388c694f0ff6cb3010c15edc450387589d4",9.647446457990116],[589,"9ba320f8bc45060733aa830cdfca077297685783a49c69aa1bc80b4c8ceff8fb",10.052724077328646],[2913,"4c2db998c9612c271f703136dd2800c0a306495cec57b4a0e1c265d36df8fcec",9.317957166392093],[3314,"214449f34454ce280e582512485989d9bc9b514808bf8e80529123d5c8d448ea",9.917710196779964],[16995,"be7bc5cf76cc051921e47d7814e4290ca0e323f444e2069c71861110633b2152",9.317957166392093],[17851,"bc937358d89a4727c987623a2f7f3d3eb2c793917f1ae284385ef7ec87073340",9.317957166392093],[5683,"67f8c7cb03270c14cd1d1236fafeea881d76eb0c1e3d2a6decb26016271d26db",9.917710196779964],[17862,"c245f13028b7132fbc880e494a82bd259e1af715c7c8933cca180d905b79f33f",9.317957166392093],[15966,"6d968e8568fca6c989ad874480034b112b2a54d1d640d484b01ac2e336cb7269",9.647446457990116],[12709,"dd619bb709a148fa0688d027ef128fcad9b51b87bc0b687ba79211fa0ad08bac",9.317957166392093],[18020,"fdce6486d5f9c8b0a7b52995dc796f63a6386d389372f253496a656a13cadd3c",9.317957166392093],[6943,"9fd3ad7d520074696e339d76a188fb5d6d545caf2416e1c1fad157e0a20756d2",9.917710196779964],[18836,"7fdcc53321e71a344c5d2b4151a8b565d4598523733a04cef94f9be42a7b8425",9.317957166392093],[9995,"21335c54dee183fe4d7b721d11e368efcc62a968b092f67172c3212942015ebe",9.317957166392093],[19417,"5e3f0ad1a548d01f20953902cff1ed0fda869055da93b781cfa3fe939c87e410",19.14044512663085],[5102,"1934507e45e0c5d07256594b4f68beefc8d070502ca2b647f91d71ee57af90de",9.917710196779964],[13601,"8bd2bd8b96b4b1b3ffc3e6925fe3b54639ef43e6ef0aa992fa7ecaa011c7679d",9.349282296650717],[6193,"f6066c71c5741d10feab52bf2158778afcabc66001f17d847a183a34f72ad4d7",9.917710196779964],[19109,"6a152f1f15af936207e2e46eda01164767d2a90e28817d4572588ada0a27e51b",9.317957166392093],[8234,"888ab935e3f8b99f4d1de6717d32d6f692dbdd5f9247ed4d26dac69d4e66bac9",9.917710196779964],[19809,"b3df9c417d85adb7bc58049436a2bc350496aa9d4e2663c42dec9c62ce345002",9.647446457990116],[12773,"341ead1a184f4f2c351ac0af4aea1552ec95326cd2e2a16d6af97d5535ee17ac",9.647446457990116],[923,"a19f935f8f1c0042d8a000d4b9ebd4f4ef4c79ffd14abc7cc9b5c1ee0f6eabf9",9.917710196779964],[6607,"1a3f655317a3ef4434c91b74758c20f9687ed12fa3c2885f50578da4ba5f9bd4",19.104712041884817],[11832,"ea5bbc097cbcbbfbffaf5f44f047c48627cfa8d82d7144ee5c543515e98c85b2",9.917710196779964],[14346,"3f614109bc24839fe27978123d2dd9f33c4180d1b03e16d56544ebe7deff688c",19.369781847562617],[13005,"a0002c20f1b4dc8df05cfdcf89bda23f9bbff6d44dd86adb34f3e502b6d590aa",18.130434782608695],[556,"4ffe1090e838222363ce55d508e24482e909b94e5cd5816981f54712ce013dfc",9.317957166392093],[5213,"443ed1cf19ba873da59aee26a91bb4a15095871ad2988ed02d5471019523e9dd",9.317957166392093],[3848,"a7bcaa15b6e1255403ccebcd8ea0502e53e6aaa4bdb482d60900d315e2e9bae6",9.917710196779964],[10473,"843de8aa887fde9499f27f673c8c8af64ea5394efd180755a7d86aa5000c4dbb",9.556547619047619],[17387,"efea3a5ae617b6e9bb3875e0c0a222baed80e7e57c018a41376e4ac1a53afe49",9.317957166392093],[9786,"9ee98ff4338ed745dcfb233d2465e865f524831589fbdfad13ff1aa1b4fbc0bf",9.747538048343777],[2906,"70212cde0e4029511e993a6782779b0a25e834a249c1391764463baf569d12ed",9.917710196779964],[15612,"ca392740224fc433e5360e857b33bb12f89c1345b3d7ec42cd82255742c11b71",9.317957166392093],[11099,"9feb2aae7405a5e933b202636aebbd2eae0ababb597fcf33f467bf1b984241b7",9.917710196779964],[3067,"10481e68232b86f19cf928de3b4a03d01b7123d2cfe1447f1b46bbd591e9e0eb",9.317957166392093],[16100,"e852666cb12299212de35a0c5645a3d3b035d162c053fdcf6601367dff8d2666",19.066666666666666],[16632,"26e7214b1e2e6c22e946b86babf1ea773dcfb99bdb918181faac000cda5c255a",25],[8437,"aeb1aba98aad26710984a51af4fb2c73e83f4a3eaba7a5763b14af5811b569c8",9.917710196779964],[5190,"cecfdf332b5ab6a33624d8fb9fb0648a4eb4ae1f6ab23424ea40015ade600bde",9.917710196779964],[9054,"0e2815ecbc59f629927e90c9121a745de07e235837d8e3a415cb37bdde046ec4",9.917710196779964],[7645,"079e2e77b9659c2a41f34ee5a72293f9b819186e1497eb71b98716166104ebcd",9.317957166392093],[10132,"960ff132b1c1ce9a23b33a27a0621cda01726aa2fe89dec41b799e9dc39f7ebd",9.917710196779964],[7860,"07adea752d0eefa3b11fe96f93a773eb8afb4118c4aa4faf0cb82a8a11687acc",9.317957166392093],[16081,"da2b041a0d4a74b4c70c4de058d9b4343311ed32a733f85fd5637a4a0b82b066",9.317957166392093],[13136,"71acec90dee1ddf6ba3e0092dec79589f97399b3ddfd14de3303df1c14873ca8",9.317957166392093],[13804,"2b35981a0f7594a839b961a8ce586bd8f43bc98bb2564dd2b2523a8687be4a99",9.317957166392093],[8909,"0461117ba173756b8feceea12817fc95ca9bdf59e51128e2ecd9eae94bcd64c5",9.917710196779964],[14557,"2372c86fd48798dd9c337f2a0c361cd890c727061d7d0775fa5d5fe5cac5ec87",9.317957166392093],[13643,"eb2e749f7486df03779304ca62bb356182703e94f43fa2fe8e3e050374e55b9c",9.317957166392093],[17975,"5af7446200291b90b33ac4661982e17f7d4f8c874191279b21b70176ec50b73d",9.317957166392093],[7049,"b6595342ca14a84cd5addc75cbbb0e0e365f2ae5b0a7a5e09b035ecb8012afd1",9.917710196779964],[9619,"ff73ae36b11e9c355c395811dac1f3538e086e63545ea975c8d5186fe353eac0",9.917710196779964],[15509,"0122a175c1623054ebc1ba8c9cc04210124ae867cd9707a2a51a1b7ad8d1ed73",15.072463768115941],[15187,"7ea6534fd121d92812944af01ede4914815249f8106de1c2f21e74e95e98c47a",10.028818443804035],[7984,"f681d9f982ef1e8f053ca0be4e885408933b5e4b3d899cffde1c7980be419dcb",9.917710196779964],[15473,"56d55800130210572f16026a528928372f9a0ed2d24e615080c7ea225abca474",9.317957166392093],[4283,"27b751d16aa464c4098ee9fc59b7af853ab78e078e2045c156806b29ae3de2e3",9.917710196779964],[13426,"fffeabcebc451e7ba08326a2faf0005905fbc8e9f180164f913089d52a49e2a1",25],[17257,"7c5ce0ce5467a7798e526e0779d0f760ae10d3f33f4e93f09b569e5458c5ee4c",9.317957166392093],[3987,"8b15ba68cebd518090067f9fc25dcb23d6345b6f7658d78ca7598ec84923c9e5",9.917710196779964],[17926,"48f5e3aebfcceb58d33ce43baddb8bc60a3961129d2370d435c2b0f539d6bb3e",22.11764705882353],[13202,"abdede0f98af0500763946e7ea04f0f655cd85de1a96daf24eb3a137dadddba6",9.317957166392093],[7467,"ac821468820cbf438ff7a582da7029ea997bc30fd3320951a50c5b0011b6f1ce",9.917710196779964],[13201,"a21afa9a46b7081f58e1865f7eb4b2dccc61156790c228931742912ce6b6e2a6",9.317957166392093],[1375,"275e886d65c742b333fb94b14178362a4101135dc0a7d2a3bda87e96bb73e6f6",9.317957166392093],[615,"21596703a651815c08110d189abadc74052e96d82c3fb7b39b1b8dbefa17d2fb",9.917710196779964],[12673,"61b4f798266626bf8fd2595c6fbda1b85e0d18ade657d1640c5725c5454dc5ac",9.917710196779964],[3800,"842e9200fc1d9d1484f1b100744802ff723a668a7e2416b3a1dd67f15ab6f6e6",9.317957166392093],[17625,"94746e2352b125b935f86c355f240f568422d5a7ecc5ef0f880b2d2e01d1b144",19.167822468793343],[135,"9719ae9b7d40b26dca18aa1013e816649d5f8fb58c9a48701faff2fc391716ff",9.917710196779964],[12716,"db1be4ebcc857fd8b3ea159eedd253ed1603629195e24b63d5bb101902427eac",9.317957166392093],[14835,"bba5447daf2f640cdfeb091b80cffc70258cf37d626a138411710af137903482",9.317957166392093],[9854,"d88fa79ff9ec95ad06362dc3e711a1fe38ce61afedfb7193126b0b4da5a947bf",9.917710196779964],[446,"548ba92f527fe2bbedc372f71520b4ff07f73b2e83acfea76fc8878375d015fd",9.917710196779964],[16452,"51b6ef5f6ca563bc5579956d4ddc25695bd1bf11eb9f8b2ff423a51839ca335e",10.052724077328646],[8503,"404efd07cd8b88757e4de47916310818a0f3ef57c4a5727be12c2c69a330ffc7",9.317957166392093],[4497,"3d1d3c239d6c1f1a010b819c17a06a49e27b93a7a28e5c4e199ae1fc99336ce2",9.317957166392093],[7098,"51c3e828079902001d9270b2ce332eb1733851f45667268ff908c64b7d645cd1",9.317957166392093],[12363,"791f56e7e652451f134c7bcd08eb23c223240b6326759938286d0e6c0648d6ae",9.917710196779964],[4599,"2b637fe096de4297c5f91768a8dd53b0bdda0ed00fa2434db9b81bed017ca0e1",9.917710196779964],[6291,"32fef3c142a8de38916172ebed7fcd8ccbcd7c08b0977c3e6e2c06e417841cd7",9.917710196779964],[7564,"62640737901d1ec56134d6f753dbc290be1a6e8cf65a9f62347bc5a08fbc68ce",9.917710196779964],[10435,"99fc55d42a2473de8a5849f0286be55d4a62f27c93d70f2e8c85d169826694bb",9.917710196779964],[6091,"bd2f1e5a1046afe1b8f304a7c3f2e6aada1d9e107b597ac74ecd3a62142571d8",9.917710196779964],[10323,"e3dfae6ea0b3ce0f74cc2fdd78102ebc2ce0c098777a41d6f63c17eb0cc130bc",9.917710196779964],[19301,"18c74ec534bd7a79135ea529a7131260146add8d6feb94a2221e079e5f63f014",9.317957166392093],[13781,"ef1d1698876e0bd45ec67b899f22dca0b9956135fab574f2484252d1a47eb999",12.064171122994653],[14472,"692c1daa0749b1b72b59424bde4ee1224486e241996e19103c28fbb81ff7cc89",16.142857142857142],[15299,"7ae96a5baafb73d4c2d984e6e6610befb07a9acc75ee073e70e3a11e97527478",9.317957166392093],[370,"8669d86bfe0096cd9d5a788625688c5137eb94b36f113e332d9cb0f9db809afd",9.917710196779964],[6264,"81e10a093c2695931a23477d11447e1b99fa175be11c7e076fa1755c414b4cd7",9.917710196779964],[7027,"2965d2aa4881b1d487962026c3298182faaa4101c821ade43c7cb5c980e9d7d1",9.317957166392093],[15370,"e8a0261ae8c7197990ee4fe7b1129e1245861de47ee7fa49202d3621abbbef76",9.317957166392093],[16790,"961c47df54eac1d685b6a96800cb7bc7d17593ee1d9642e982323af4e4de9356",9.317957166392093],[81,"37ba6d9af8f3034ab53bce277b75810014a383157cdaa471e2d2f181b91d78ff",9.917710196779964],[12324,"1c07a26744f1b7697c66cd7025e53f16ce111f8f67452ff9491ec8fcf1fc10af",9.317957166392093],[14046,"63230d8d49948a39a0c96b0292f083461312088f88ed64fc31429bcfdadad193",17.16883116883117],[17563,"fdc58cbd9abfe97c70b69f610de36e8422ea04b18840287b5368158b36ee3e46",34.83778966131907],[12224,"0de8ab02bb9d6bfb9696b3fa9d82bdbccc52b4d75ce6e2d72517eaefae58e8af",9.317957166392093],[11237,"a1e7bfe63b4f333a645e550383669a2eb15d6d361adc8eee1e2ec1ec403272b6",9.917710196779964],[12891,"8bf9e31fde7525373b8082c0959b5088e183f29e0e48d35cf299ae49c35b57ab",9.917710196779964],[3520,"ee581391ba88ff1791b046e770ace404c4d1ad9ff50e53a4e3c9abe1a587dae8",9.917710196779964],[4223,"c84d162149da785ed46610b738a4a8fe6bb88815baaf8ce4d42f98c9290050e4",9.317957166392093],[5892,"8c14443936301380c47a63262e2ba7168248fbd18851a0f641d95b6a6545bed9",10.033847820200378],[10080,"288694a66ee3e351f29e05487d83914493e8abd9f80a4607adf400c36a2cd5bd",9.917710196779964],[3825,"86afb91ea1613595527fbba7c00250be599d5673f3493e56e87bc5ccdbcad9e6",9.317957166392093],[9622,"0db4121e7f0f23762094667bfd6d418673bdd6b6ae3350b0d46590bdc2aee3c0",9.917710196779964],[7861,"5349e1a5879eaa39571e122eb8aff9db785f1e3f514347b6ce71f53f7ce979cc",9.317957166392093],[18462,"1ef8d54e4af7e9ddc77c5c300083c98e88ef5d18a4344715a513887fd2866032",9.317957166392093],[2732,"badb92698971d0012ca757b40f251a6b472de73557217022ac59258f46cc37ee",9.917710196779964],[5738,"d5f24e635f15b84762b28568ec86ab29bff8190d8f709cbdc6cb1cabed48d6da",9.917710196779964],[6109,"c043313e901c0494ffab0a6c61e527ed46221d454ff55d556f6037ed654861d8",9.917710196779964],[10942,"8d7f9786c3590ff4efe0004b031db805a7947417a7891b733b955237d7596cb8",9.917710196779964],[14427,"28e9a1ad0b301bcdadaf703dabbe673ecbb155af28c444978d08ec9c99aab78a",9.317957166392093],[9909,"fb40b09a9dce859dc643b833d287e2328499aee2d4cc1a49208a742f6105e3be",9.317957166392093],[5940,"3be824fe7dcf4aa081c8e0a57e4996c2a6ef1e2b8e7bbc94fc3326d489ed72d9",9.917710196779964],[10367,"cdb21a8589a2611fef55df9518b4c8a64ba575e5de6c03567d540f23da66f6bb",9.317957166392093],[11853,"d04545198a98db7e0fc1ce9da2141707625e87e2b98edd4a2593f5ae89e756b2",21.804878048780488],[11979,"4de42fb8472cedb4323c333b199c91a33a8a1ee8e8ae8a39ebc64821a01770b1",9.917710196779964],[18832,"d5a201d925c273c82298ec437aa6014e9a00fd20df71602a8f5a808a424ca525",25.668449197860962],[3153,"835110efdfec4a8f852ada9d026464cd2f2dda59fca50c0a0d8e53b7eac155eb",9.317957166392093],[19166,"3f3698bcf8a5935b12bc662fcb9908a9c1c4efa48e9a6f886d5b3a706d4ce519",32.87894736842105],[18703,"3aa12e183bcbef0563531473410bea04784a937340e976e8620ec008ca71332a",15.054282267792521],[7881,"307be205a2d7f244bfcd56d5d245230fa7a3e597717d8f2fc2054dae031f65cc",9.917710196779964],[9613,"40c57ffadf78ce6ff95f6edf9b2d807e918e9197936b10bca2835ee4d37af5c0",9.917710196779964],[14814,"ffaf41e87f1e514eca3c3840b44b8e9a15ea42fa2eaedb5f50f1525c27177f82",9.317957166392093],[14762,"c96e6a27c5d9293462ec4b5ecae0eed1904249fceaf95374110bc9781c3dba83",9.317957166392093],[10205,"dea50f9df1e753fff6b9a8f081e394251fe5921b6a7816b61c7dd894a7e1efbc",9.917710196779964],[15313,"8f975fb84c72b753fe21c8d0966099f8e6fa090d10363f436ca5ad61833f0f78",9.317957166392093],[8259,"d43b4ef04a2aed1b39b26fe603b94c644e229de3a50aa1eb41b628d106829ac9",9.317957166392093],[12246,"1498b8f2c35ee86565fc0879873e9036fd8f32ed8aa2178e2381a5f29876b9af",9.317957166392093],[3858,"b4cdb0b9d88ab76ee6dcf494753ba36f9d6e309e0f3fb8de5a7229678a2c9fe6",9.317957166392093],[208,"e1cb334f37d3794ded4005f9a66db254840d6377a37494261c9ec0216f638ffe",9.317957166392093],[6480,"92a86648dcde85966a2882f4ea3b630a44f39919a4c7fcee97d1ab58e5329ad5",9.917710196779964],[15267,"c25f9a9dc6e061d42a7dcfc01a178646a6999cf342f01b54f9aee2ac6d830c79",9.317957166392093],[7245,"e3c13c9bb96a834070b6c1094de15f7958c02b05bec5016532674b452b336bd0",9.917710196779964],[2363,"0ca2e82703de11ca3610edccf52f7f84a95f9b3bc381a7e1a159610b1d04aef0",9.917710196779964],[19799,"fc8134b10f021651bbdebf44832aeadf49cb2a399614548d69057f31413e7e02",9.317957166392093],[352,"8e5dd11fef631c3adbc0e17a599d13f0143d2c947e5cfbfe6751037dbeedb6fd",9.917710196779964],[6769,"1deb4447749abd04e3a9bdcca74f4b90baebd88b21b386e0c213e70fabfe79d3",9.917710196779964],[5003,"b5f938fd7f0b017d8f311301c1ce12e305e7e6999c731f28a29c0c775ba226df",23.003533568904594],[13183,"03905f3a052e760f22a5789b83ca5aa8dcab22448884c54934788b8a578b5aa7",9.317957166392093],[8648,"e6da996e8143aaf5d666715a518a681ea1024b869fa059d2e86abf2af56810c7",9.917710196779964],[1758,"00a0b97200a1b8dd4e09c00af846a98fdd2e1d283b8a9d6c078e9f03b6fe8af4",9.917710196779964],[181,"04dceab01fdf6e7c2a06741ae6432f72ad34afe21ba214ae664c67d029c6cafe",9.917710196779964],[16811,"4044bd5e16d6ecb4eb66f3a38f18740fc60a3f14a7ca35b7a07968423ab80756",9.317957166392093],[913,"f4eb060c1ea319074d08b721341efebc2c4cec0fbc93d7833a4db5b8bbfabbf9",9.317957166392093],[11598,"a699753e45d9effc070632f82f281a8c9c9658ac2eceb07db33604b3ae02e8b3",9.917710196779964],[7173,"d81b2df94447738012f58c0240d9036e324822700f74f8f3594f605a0ee8dcd0",9.317957166392093],[13323,"9616e4df4bbe7d73bdff5c50528de9a46807ce073346bdac8a778f0f307e2fa4",9.647446457990116],[9698,"0fda56ba27942e9940f91ece5984e3d1cb0c6b276c9ecb0d32384156f43f68c0",9.917710196779964],[1372,"8ec2e14f4d286741d6f1d7d6341c28f4ca677252dd122d48f0f35d3d8bc9eaf6",9.317957166392093],[4131,"8296c8c4e61d2de648efa2e9ae31b3d8dcb8508ce2a63d70b7cde77ea9d6dce4",9.917710196779964],[688,"da5198b6ea868cc895cf2babfde331a09cae7d7ac44df43a82abb1b0946154fb",17],[1088,"6df14a740cfc22e6515194c4f6bb5a93f88f69f112112fc944007e525fe2a6f8",9.317957166392093],[14102,"c991ab3c2292ba151f7ce12893e58617dd9039320556ae16686e3b7572298b92",9.317957166392093],[12558,"67b9d5eea042008097cf8a868bf046ae9529b8f8a2ca90e62469d326f75d98ad",9.917710196779964],[12068,"c918606ab9145c9d232b6482dc4ff0424746a9c93c76f52221c7f2964a7be2b0",33.52815013404826],[14429,"81bf837be7ac3025c8b9f1deca9fd26749d2b9a69f38315d3cf0dc1b9df9b38a",37.23076923076923],[17854,"df258dab4183afa3aa2957a3535e2035c3c8cb6595e9f4b5ad4ba6792c952640",9.317957166392093],[1995,"91f054cdaa49dafd9a4beca14507500fef3cfb5deaadafe8ad4d584445b00df3",9.317957166392093],[1762,"31c464118ba5e87198a9fb087c307645150c9abdc702a32ace332954e8a487f4",9.647446457990116],[11243,"c9aa8c6732aa7e5f3b024a4db59de63d1a563d56ccf9b15e8860f6a4e24165b6",9.917710196779964],[14020,"68297e8c80d58cd4a9147bf94a3277b2ab5d3eeb447d02bd2c75603de24b6694",9.317957166392093],[1026,"a1e61fcce6fd6012a66b8e888bae1b119821358479504326e44db632ca8715f9",9.917710196779964],[2536,"4b458492d6847d8e08067cc90a5a5aa421244360d6df1200cf4face0b46e95ef",9.317957166392093],[4822,"1e4d16e36f46fa782db6c180d3f386bb168ce29b11ba6b01b99d20d19ceb4be0",9.917710196779964],[18072,"1832e347a54f36da3e78e4f17763ce9be5e352d268675d114d5185f3f11ead3b",17.70605187319885],[1444,"0f1a277dc638dbcc4272c8b812e49f95cdf2b571faeee3dd058f7025bf6589f6",9.917710196779964],[17610,"e930482d8138069424d01a10523b01dffc295f2a23bdff881e7445160e17f344",9.317957166392093],[6278,"2af7a0327fd8bff915fe7645f601ed021780ef721bb9086d4a89b8a433bf3ad7",9.917710196779964],[4222,"4aa2d5491c090788b306d5fcb68b843653025067e77ca5028b9507deb78250e4",9.317957166392093],[13500,"fee8034c04e1e1d557296de7f168150b8c568f608de330a8dcbba4d61bb3cc9f",17.136363636363637],[4441,"450d36768cb5256e2f1e2c67039d2c2939666142587dfd891f35fa1d4040d0e2",9.317957166392093],[5282,"637afc29b0224fef8559d9084637bf3816d0e2e19402022f39d8016265a285dd",9.317957166392093],[330,"e778d44e7b8758e7950f1240a867f039c4653184014a092b9d6416f4397cd4fd",9.917710196779964],[4296,"ace65fdeea07eb9b2d687f60486acdcb7942c6449a8a18254ad2242ed719cee3",9.917710196779964],[14289,"5ff7e9ecbde78152698fcc223e683603288fafebc148ad87ad049f06b713ed8d",9.317957166392093],[13624,"71d7f0ce4f62ffef7bcb3b2fb6036a96f61bd6286c8a5365c394a7b7dfaed99c",9.317957166392093],[18723,"3ce2a2d25095b955ef93215ffb62c8d0ec73a6d048e5688786063774364b9229",9.647446457990116],[17095,"060a78a79193bbcdfed5267e6c390f4734df4d18a56e7653668be48585910850",9.317957166392093],[16771,"c701f83fe9b9b9d6febac3e9dde3f15de62b436875d683a56928eefecab90057",9.317957166392093],[543,"ca1fbecaf423404cd4931dc105c4cfe80c2f8b48f3d30b91c509911af52d56fc",9.917710196779964],[1288,"455f4e9ff4bc8e85d3076a87a5e4d9f9a7a645803cc97872d17c6ebd3c1670f7",9.917710196779964],[1776,"a459bcd0bf453dec056964a0d468ac6a461926cc94c56972c5a73963a14668f4",9.317957166392093],[3836,"2bac4541c6b592eeed4db71c12ae898044a415489910a5f1c8b5b5f4f7b8cde6",9.917710196779964],[10092,"10e9a617d559c3de5d20d0119c141ad2713705b7ceff8a31732fe770820bc5bd",9.917710196779964],[1983,"f748aa3b0c1bc1e9f8e3d35e96ed3e957af6a2d74ca3ba6d5593407d298820f3",9.917710196779964],[17536,"c4fec4208f9ab4c338b72bbfdb29ff8d7cb8b0860b46d763938f45bbfac9ca46",9.317957166392093],[14174,"addf424e1e7cb67e7756f47fdf02dea8e547532d6a636d3c95cc32dcebddf190",9.317957166392093],[9790,"c4b95e56b98d3b1be6fbb77372ef6e2f888b3a233671b28d0288040445fdbdbf",9.317957166392093],[7986,"44b27caf2f1c8663444f52a781cc5869c0800be99e588b5e41e871c4e5ab98cb",9.917710196779964],[14040,"e421567a9b458093e5c1a9eff81d50ddc599fc8da98f169bf438f43b74b2d793",9.317957166392093],[11981,"89251c5008cc697f01b2f3ac716d5118c4d43685bd8039eaf402751ac39d6db1",9.917710196779964],[1492,"5b4fe52e158c2d4d2fe740b542121d637bc1f592cc2b088e8d4763a596c82ef6",9.917710196779964],[750,"5b70bd713196a1cab0c1760397691d00a2ee3ce46d9c5a9a3c674b36a8a7e4fa",9.317957166392093],[984,"d5bfc5159da90603df5c8a5d591f9086365850bfccb92160c6cfb23189fd4df9",9.317957166392093],[9366,"1242ded9adea30522c64ec8e60c52eee7dfb6653600bbc0d03a56f4b589c73c2",9.917710196779964],[17844,"3b12661d7ca521b05c2653b6b997bc389a68ed1043460c32a846b5d6691f6140",9.317957166392093],[3908,"990b21539aa01ee7df52446331057caca6e55e7919e5a329a7913118ac7350e6",9.917710196779964],[8216,"9f108a69bedb18a5aee7fe3e51937a9c6964b18bae1b7c9303b65a236b9cdbc9",9.917710196779964],[6571,"88bf4c2cf14604d84640a94125d1e66c9f5be13127fefa03daad910c936ee6d4",9.559418700301618],[13218,"6a49d7b7e59ac39c3e8f0287fb73e611f9ef561c770b8cc0346900c5834286a6",10.052724077328646],[15062,"f75ccef5cafb2b84cce2979a1f2e50f91bf39330b1b804dddf0a7a94bdfe557d",27.85053380782918],[18374,"fd04529c4f5b83a1283858e980e4cc8e877d63b2a557f7f099a11927b2c73434",9.317957166392093],[2025,"7f583bd822c8b89c43396591fd77c37fe02e9755b8acdace84c19bbe1188c9f2",9.917710196779964],[18213,"8a39e6651e44645132e5344eba623ef803bd33107dbe5daad388fa641588c537",9.317957166392093],[13958,"f621f2ac6e45e7aeeb6242d9a1981bf8104812c2770d2082909e875f6aa5d495",9.317957166392093],[2041,"591c7344e212514682e09206fae6e8d22823903492f357b0d507a9e086b2b4f2",9.317957166392093],[14685,"3c7d721752654f71e697e67827522636feafb2e42caa8bcac775a260b85f2985",19.217777777777776],[17040,"6fd385ca6fdfcd0f47be473bc0375f1ff0673ad25feebc8c04fd5dc3905e2e51",10.052724077328646],[1276,"1b45b27f90729e0e9617ee993853a8599e6ac433e5177a710b2bca6035ac85f7",9.917710196779964],[2977,"58a9e2e9407f8837ec9594d85cedfaaecb038bdcefc099ec7511f3cb5da46dec",9.917710196779964],[9512,"1f8356ff386c77de1308ef8309ecbf1712b2393f09f5525603c06e71a78f9dc1",9.917710196779964],[3019,"34049251f78910d1c1cca612ff5df2957b2324df9facd4523f3e45e432df21ec",9.317957166392093],[7963,"d86a61dd5ddfb94e85b2fa9fff7c435b668a911e5893591555dc18d8dca6d1cb",9.917710196779964],[6547,"72da57ff6d9e260fde786e91f70cc354ae9c7935d6659a6a739e0b1b30820bd5",9.917710196779964],[2746,"26e21e090f77857f3bf1ea88739d070decda31fc2e5713099f82daf1e96025ee",9.917710196779964],[10595,"7ce17b4e0192efaeeaca4c07dc9ef65f7cdae8c1bc4ee47f2a8566dbac18a9ba",9.917710196779964],[15531,"b6efac0974d28cf2a193325dfbdd78faa60345cfdfc237d608ab7da11aaf5973",9.317957166392093],[13062,"414d85eea50966ddb39218f9bddb87bca65ce5b448ec474db57e94b9691337aa",9.917710196779964],[9912,"b403d1bfe7b81ba486e1a37101463b5ea1c573628335251633b90576db89e1be",9.317957166392093],[13524,"753af2fdf9b7e5857839fcdcba1b8bab553848019dc66fffa9a77a3fa5614c9f",9.647446457990116],[1025,"45bc5cf1e9c41f4c4f1c98cf67ba02aa1cb483c0fee4fcc631f73c78234b16f9",9.317957166392093],[5796,"cefc933bedae7b0d0edd6a3e54e9c9fc246a63e9d4c73984a798bceb16aa75da",9.917710196779964],[5570,"b2493a13cb5c1cb2b85b2ebf61a7e90145bd6cc0e51c43b1e4b2a53083ddcddb",9.917710196779964],[942,"ba396b14b26fa85df1b7e9aaf1822b03e5623bb3393d66d76287d3152a0e89f9",9.917710196779964],[18251,"5e51b84b8b32c11069a39b88fcf819412d9efc7e29a3e2861307c9f38914ff36",9.317957166392093],[6233,"b3749d9c9504a220b5cbaf3318b92495af95fb1b6c5e4f581e173c0ba22b88d7",9.917710196779964],[3741,"6cf4d137ae8101a53bf780fc2b35c88e9cd1a5c850f61ce9717472256e314de7",9.917710196779964],[7483,"e0c6b4af288a5e4487558ef4741a52c3115f9ba6be02d842e1a7a4a141d5cfce",9.917710196779964],[8582,"6bbcb74c6110f3a0cc92040565c4ea502f0906f67a85e3499aae5cc06cbd8dc7",9.317957166392093],[15910,"243ebd6ed9716855d0b6b6dcbddcb5585379db3dff01bfce19419a5103a7d36a",9.317957166392093],[11455,"50e0ee8f3cd7c393ea85ddf716942419728139062cd66eff1be038d1b183e4b4",9.917710196779964],[5448,"656b6c878944bd2ded5c4224eec932cd93d4802846bca5296697604d2a047ddc",9.917710196779964],[18317,"483efcc6af574bb6fb10c3fbcef0b6db55af7e06ecfcf44b4e29f925234b8835",9.317957166392093],[12118,"2be8cacf71ff2d3c92d2f62ca5470d3ed77e3e9ba84a0f1107c20571bf90a1b0",9.917710196779964],[6549,"d619525073edfe219cbbb8dddd5fe6af7755fd3da57e4e006aa570c72e3806d5",9.917710196779964],[315,"cff23d536a20dddc54f56fdf2393e016f5451a819f5d14e181583943bf42e8fd",9.317957166392093],[11446,"7dc3857493bde996666da15f4025f1001e82c5f7275580cb26b39d3e4b74f9b4",9.917710196779964],[828,"fdfb4841bb971de09af306178e8c2dd42a03c8ab64e9b5c24445a83a24df59fa",9.317957166392093],[17733,"3f2c1e1ea6f1b6b4ccb329f158b3be2aaa3b5587aff074a05744ff8f53098f42",9.317957166392093],[17395,"733381788573800192f28936f2cfea6b082a53b871d88d7929af99ba2a9fdd49",9.317957166392093],[4270,"0660cb0c9a5c449e1e05e1b1c77451d16058aaef48f6b679b943fbb5b5dbf4e3",9.917710196779964],[2442,"f019cb9f9487f30c6dca011dba932ed7a2697deac50dcebcf6cc1cf8354e37f0",9.317957166392093],[17131,"1fc2037fb1727f93d2b44d90426c7ee1a71c21c066854234d69f687af5cf614f",10.030959752321982],[15235,"bdde8b9b97bf7637ec7fbebc4da1d03a8e10891382756318fb4639016a3cc979",9.317957166392093],[18922,"2bddae3a943109759cefdc839da17b13daa8602663f155a22f65e51b9f10c122",9.317957166392093],[5665,"e72e8ef5b20c72ef44db946300f742a0e7173d4a643ba0fa69e0a6bfb54f3adb",9.917710196779964],[14318,"e5af1a99019d49cdb24253496eca4878863bd5d64c88d77dab43756b82273a8d",9.317957166392093],[15470,"68eb7e49e0462520f6bc19fee08102068343992e6a02f73d17b964bc2f91b674",36.94240837696335],[3585,"276143811404f67ecf10481916a9416a3ce273fb9058d226ca9b37b7445e66e8",9.917710196779964],[12199,"08df9c8d84854013277cb1c9bb71538fde68855d7a983c80c03489ff7ad611b0",9.687074829931973],[2395,"118f49826d927eecbd4257689761c36c17fef93b762351a9e3b50ef2949383f0",9.917710196779964],[7566,"69d33ac590be0f52457ba5e1c74de1ba0a86bc6b85a2b0f419dbb9eee11c67ce",9.917710196779964],[15589,"afc46bb48f774b256466a2f7e9e5145ed6d85f9ebbe5fe5837d9298edf798d71",9.317957166392093],[4837,"6af44800a539a9dfde4cd0d98badbe9e2f60dc84113d75dcbc58ee610f8533e0",9.317957166392093],[15839,"d86dc083262e53d0d7ffa0fd2fbab833fe5bf1506c9409c5900abffb5c0b916c",9.317957166392093],[10362,"449fe5fe251757c1d652685d43d1ead9205cdeac4cd11fdf2d01e34c61a5fdbb",9.917710196779964],[1083,"db7e3a3e87f900545500b0fee0497e134f1c5249908506d3e7d0dabed623acf8",9.917710196779964],[1601,"c8147df49d4b1476ad38bd9f1f9c6df4c8edf86fdc61a7535895c27c25f08af5",9.917710196779964],[12523,"a3dba27a17b4bfb9638091b228d5faee9f73237af7721f3f914e05814df2cdad",26.8631090487239],[10536,"c3f27fc964e1b18e7083112b43e8d456a7d8344f5fe13bd021e9b1329d68f8ba",9.917710196779964],[4401,"f538de5def35e688140b21394967602828892d0b8901007d9f75b93063e713e3",26.009070294784582],[18268,"3a1eeee0319771adb9d0723b6be97fa59f55f1e31b69cec4310b423004877e36",9.317957166392093],[13807,"865d9315bf006f272b8ceb8d643e5ad4edf3620e732e3ad41071f5c565a93e99",9.317957166392093],[18844,"e7921d379c06c9af7d043c6f984b81d64d291eb4bfe979707db9dd10b7122625",26.89439374185137],[8281,"c1e9b3b42efeb152e327e97c4fdf5150a6776445dd86df3d87ad07550d8977c9",9.917710196779964],[3945,"f91f5ea325eff8d86fc8fb58db490e0f9c59654a6c93cd6c066f1d07f33205e6",9.917710196779964],[12393,"8262ca3a1b942319718bb353cabec85ddc56ce8b1f5dc9b9def5c83a036ea8ae",9.917710196779964],[2866,"b16ce38f8b173762ed606ab24da47c89b9a20423a5ca99cc7039bf3d1a6450ed",9.917710196779964],[978,"f59714a20a707126427efa3eba8278bdc35bad9dce39d6f74c459ce008bb54f9",9.317957166392093],[4022,"4c9a47d17dc41ba77ddb1893ade2113873fc88f5e6436fa63ea304744ced9ee5",9.917710196779964],[2844,"6206485172669f6825ae4021acfe2250641efb7eeab166f3c3fc5df1a50b64ed",9.317957166392093],[4348,"ddee0c3536162f9e1a47bf2b8087018ca3e6e95449aa1b9db2255a919e0b6ce3",9.917710196779964],[12499,"2e1462af196c27cca29e7abf8887275cbaed701ed4f79b55f94041be6e33f7ad",9.917710196779964],[11485,"3f01f5855fcd11551d9ee05367520733a4f87c868d6fb7f463647c794ec69bb4",9.917710196779964],[8269,"c2d0b3ea2cb32c519e264906e94660275f950dd32cdfc65e07a3bf546f1b85c9",9.917710196779964],[18862,"1e192517d0d0e1f59d2bd76784b27b32da69048bfb1777b46a58a4d17e4ca324",9.647446457990116],[2324,"3479189f3c0dc9c375548f1c00644cc3b12313e7a3826f91ca3624a92e76e5f0",9.317957166392093],[3426,"c28fba095fcabaa036ed06f91e34fcfc0e0bb18243fa27fda0024c5b773b7fe9",9.317957166392093],[15257,"ec5b5088f1e0e10ef0f3eee9107c7348a1b4d9a9b8c6f74fe8be1ba5500e5179",9.317957166392093],[5148,"718834198b1f9e97f9978b049dde8af580c7e1018377429ae8b925281e884ede",9.317957166392093],[13647,"c93ebe80eee6c5149ca1a5ff552ebb14baabdc19ce87867953697c252d5d479c",10],[10491,"d2fb2751ba5eebb8c0aa0634dcdf345846dc908568ff3d20067b93b53e4936bb",9.917710196779964],[12396,"5d944e7da77fde9227db1ff21112c672903cdc7a30e39b8ad7c3f074d210a4ae",9.917710196779964],[13397,"eddbb78bc570e6ed4d17b3b31bdb0e707768fc57a39133792ec315c26cc155a2",9.647446457990116],[18979,"86489f0e93b466c741686a43104e1732b3d65024a13c503cf5ab86a5e1954821",9.647446457990116],[10793,"eee58ebdd779483ee8629db43e4dac1b2e3a952657bb4775132123e8d9c057b9",9.917710196779964],[1121,"9554409b494ef84215cb9c7c8e2c20d3b0818d4a7d86688049dbf4bd6c4e76f8",9.917710196779964],[14683,"c3d1b97e1e807e24b19e0af8b304977581b69cfecb910220f3192e8084843785",9.317957166392093],[14779,"4e3c01aa6683ec81d4d543848308d60bd20c2896f57a64e1c4a34662e89e5a83",9.317957166392093],[5530,"fa16b5f86acdba3f4fa48607d985854957932f10fa5b2bf574c818c65fd307dc",9.917710196779964],[15454,"e326e299d2333841d64b2cde4764701768604ed41afd5ec9280b5e56f0700e75",35.650623885918],[4088,"9e386c649e437fd919f235a7dc9065085b13d9265201d06d8a0d6bda0fd826e5",9.917710196779964],[9561,"bb9231168c81ed6983ce6fb1790f5dc292142e1096419e1f2f9dbb4dc2bb41c1",9.917710196779964],[11721,"0940959a3428e8796d947d3ecc34c626f7a276ea09c494adb15ba1cc2f7b2db3",9.917710196779964],[6040,"ada8e091484182f0de0dd956151aa72e90497510c06088aab0002305276fd1d8",9.917710196779964],[7446,"cdc065be86c3b2a12bfedd7b21cbf5722c131f7bfe0cd3300459d83ce62d1ccf",9.917710196779964],[17771,"d9d45b21d8e0a5df4c8a932bdc092d99e4987ec2767dfcbbf2f9561c6e56e341",9.317957166392093],[5577,"6ccc8811a9d607b04ee008431a3597e1ce4fb11c6c3ed6db7cd5ed9fff70bfdb",9.917710196779964],[476,"b71fd60ba2f971bcacc57171fbcb98a2864471b167c5ada8e95c2d8b8f7ecffc",9.917710196779964],[19108,"d91ea2c160e23d04414e3b571c8097f8fff66a312741f8e9e5ab289e6d00f91b",19.228318584070795],[17969,"ce53d641505b30319917b8d797165280f36f8ec2fc74d3ca9f1272593babc23d",9.317957166392093],[9572,"60008925baab753b84ac146c5aa99a2d7498dbfd6a76cbdba29ee65bd2b82cc1",9.917710196779964],[6486,"f3fc61325025028cd2a4ae52025cda48a8bcbdb28d82809f4096812063e693d5",9.917710196779964],[13095,"13db0c88910edc12c0a8ab53b520d06bd6e9281bae192f469e62bc802d5983a9",206.59102455546147],[18603,"4200c5fce9c644dd98249e51e5c76a3b2633d168b19d6de11a4d98f8b037952e",9.647446457990116],[13932,"68e100898cbb4e2ad3bed7ced13f0034b3f77f55704953a194340617e5ba5396",9.317957166392093],[5921,"2b4e461540afd79700ceb557a3619b73d1e786ac9093288b3431a3a7e2008cd9",9.917710196779964],[18312,"6e8c219390ef5a12ae6fb58503753c66f823a89e85cbcdd4ee3e152d76c9a135",9.317957166392093],[16357,"acaff58640a5605c9e76efa9f49985e094cb108cc777d6ff054357f780b9ef5f",9.647446457990116],[10757,"9e2cc06e122205f01bdddd156f9ce04bb3fabebf7dd36bde36e1e071f8afa0b9",9.917710196779964],[19649,"38249aef08ad0e10b17683ae58086c58efed2ba9277b05fd5c57f8b203c01d08",9.647446457990116],[17564,"ecfede44afb82fd9bdb716bf2daa0c8e9598dafcd7b162b972f3c078086b2446",9.317957166392093],[11597,"70a2c499463501603aee53058610a17bf32e2b4e6b5e4ea9560c6220c0b3eab3",9.825],[4661,"4b0d8462ec0396fbf2a80db666bad42d7abe9b143db4a6061245dd65b1423ae1",9.917710196779964],[17964,"a403750ac68bc14fe1909856adbb858a8f746caba6959c0d8c6452c36945da3d",9.317957166392093],[15815,"027d3310b49fd0450730dc58b2eeecdc93ede44c1b4a03af06914f76094c146d",9.317957166392093],[3327,"44b975566997f80528331169ee503191150239b4b688b3db42ed317ae8e332ea",9.917710196779964],[12493,"f7dcd1c8f1430c04529b607d5d8a4754264831e2d5aa6752ddc7699c538900ae",9.917710196779964],[10707,"844b89c8513660fe3b8b583dd3565ca70cf1e12bacde0511810dd7797308f8b9",9.317957166392093],[8755,"3dad9172c4ba341512f2a3cc4ef2c7ebd8a2ccdd1b9c2d77c34bcb65ec544fc6",9.917710196779964],[3250,"606ffd6270281c2ac45c729aefe6da7cb01d6b14d6bef21ab1bedf06ae25a8ea",9.917710196779964],[4094,"192e35703739224a590e294da6ff7d08a970895f47e7cce45c8062ff5ddf1ae5",9.917710196779964],[18341,"d62ec459b8568388495b96db284cca9f0220d7ac3343a89cbc7175521249f334",9.317957166392093],[12569,"9c2ea97e62fcc636a99197fcdea97bdbd28b9872baa85e0a9008bdb6b0317bad",9.917710196779964],[7736,"bf5515986221a301423f67bd01520011988877f83058e496fa6211a914e243cd",9.917710196779964],[11757,"a6f180627875a7f92f3dd5cdbdf102573544964f9aa92cce28c9bb723a96f3b2",9.917710196779964],[13477,"8ef27a2cf6903a3a5038041be5709f8717ccdd9ea1926695cc950697c2f867a0",9.317957166392093],[8627,"4b8af66c3ba610ad88f2f529bb0043625b1bf3c3dffc61486a90029e795442c7",9.917710196779964],[7413,"81616f1036ea688d189d5fd9f911c0e498b3068e7fe4d98dd84a1fb2d1bc4bcf",9.917710196779964],[17320,"be2cbe98e0faec5f96b233f75002a26959f552435ade406e5516b630113a804b",26.13903743315508],[14045,"2ff6978ca8f8f180e80c946502ddde9c3864a14618343302a2cf2c7c04fed193",9.317957166392093],[10417,"8f1b6c8398727b133f0c2227cb27aace5f4bed15268db5833ab56a4cd8a4b2bb",9.917710196779964],[10688,"24cf2b0f216f59374a0dd62b525a21e418e72825ecf4003304a88ed782961dba",9.317957166392093],[6646,"7996fe48aabf8324366ca5d6817afa56f07d183b5862411dc65e38dcfe3e58d4",9.917710196779964],[6183,"30bb4af194a3b8093c07a01c41bafee001ca68ba105815b62e1a1e0e8aa7ebd7",9.917710196779964],[7335,"0cbee9d9d41fc85f092cbfeb9dd4115d84a912d14fb4dd8a2a4fb477975bd5cf",9.317957166392093],[7121,"ebc31b634dc978ee696250900504b55242f5fce236dffd834d63986499be30d1",9.917710196779964],[16291,"d63e0d166c1557bd7346177749053f2ef48b51ab44090c35d9a46acb071d6161",9.317957166392093],[6123,"8b491481bbcb147f712a5f304ac351cc15ec57e492a5fcdd3bec9294a68f4ad8",9.917710196779964],[4252,"95df08cd04e96e0f77e589e2fe8c41965f07e652230bbb8bedf1e172ed8b1ce4",9.317957166392093],[15048,"737d4f28afc19414884a5b8b33e8cea59a8755b5ebbd8403128021dcc290977d",9.317957166392093],[7669,"8007790cd61684e6e259dad809ded9faabe4add59c0bf6f63059b2874a72cacd",9.917710196779964],[10104,"8816e6ea65d35be43659a9f482a30a20a4f43096c6967bcbfb3083fbc8acaabd",19.004566210045663],[10935,"fb625e507044789cf10d3be8e2663931cc032e68e352408399e8f37f284579b8",9.917710196779964],[13,"c113022287f5cf5c12a49ac5203144f8e0c6b83295dd4fd550a0d59741fbefff",9.317957166392093],[14899,"77315a65af0a50258aa5c89a89f5ad55a83f4fe159fc79b60f52c6fe9ed2e780",9.317957166392093],[8659,"cd7fa24f33e85e2a9df3edbcdc66a2e7b10cafe7c75f711a7787cb5d927df8c6",9.917710196779964],[14153,"1add42b14978e244324edb2bbf1cd5d922e43b3020f69a115d658f334d5b6491",9.647446457990116],[8081,"dc0a7ef27217ed4c8f47bd3550722138fc65de98f7221996b647c3322942e6ca",9.917710196779964],[3763,"c6789953f8b4381b2af2ed0660c1a0314e6cb4ee99acef786194fa8f185f2de7",9.917710196779964],[3632,"74395a4bf1d29fff9e8eba643076a02569f0ed8fb427a2f0d4616c7e92f50ae8",9.917710196779964],[8185,"eb64de77034cbd5f47e22bf8c43c8f436c4cfd29c109e69db6f428dbe65717ca",9.917710196779964],[6113,"94f237ea1197ec309d856adc19814cf4a18f5c11dbf6add4adf7116c367e5ad8",9.917710196779964],[4532,"7be9cac9b3e759f93e01c90d929981c4e163d004cfecc791d01a86f67c5226e2",9.917710196779964],[14495,"ae0b3df0b542093628e7246794090a15c1236450607d3dcdfdea9ecd851d5a89",9.317957166392093],[12503,"e35721b76fba5f549efb2ea76b3ef8231797468dad7f9fbeee3f6608252defad",9.317957166392093],[6358,"aebd88b9b9e926b3b18ef3938469c9c5008760f7cea9a9b81165249e69a6a3d6",9.917710196779964],[4040,"cef0a10636e054d896f698f929e9359bcec4b923baf3a4b0a48db4b571d67ee5",9.917710196779964],[19671,"bedb66c379d81d3c265a07cba7ed063af123b32c45ce51e0701ee372acf78c07",9.4279176201373],[19298,"0d41e31120d003a4fb172f06e65778beadd1dc8107f0532b39b1d4076279f814",9.317957166392093],[2359,"8e6b1730bdaaaec2e15ceda92f8824138469f95edb93c29811fd0ed4dbe3b2f0",9.917710196779964],[13684,"a07b91f87fc1038731d52433e34564694ed78870fc0062ef57825ddf8a45909b",9.317957166392093],[309,"dc09b1f4ed462ea9b2af1db8eae90d52909ae3a8b4101c2c0cc6e5e3b287edfd",22.21639344262295],[4038,"436fe71a4be243dd0e54cdfcf370ddb5c7ebecf7d410cc0487863e48922982e5",9.317957166392093],[13400,"6ba343fa0ee04b33a1456a263be0b83dcd9c20bdcf39f9dcc197299ec3e84ca2",9.317957166392093],[17273,"20817398c985cf27a5d531a2673e435d86ddfc907d6f7c7cbeee84306e7eb94c",19.066666666666666],[12056,"8204926dec24bf8d3c0580161de3c365e6a0b3f9a0ba850f40536ef29fccf1b0",9.917710196779964],[14151,"b010df49f09a88c9d190c86b7b70a7f0158346599ab35616aeaf6af36b8d6e91",9.317957166392093],[3811,"88c6a2f0c8528d24b014bf606f26b935098b6e515169b19e008a5125f0e9e6e6",9.917710196779964],[14276,"c2831ffa17fc983e865cb6b6700f119e37149c1c318c68cb91355e557369638e",9.317957166392093],[5441,"74044a237f64b4ec4e0d489a758dabe9f88a112ffec641e131f11e4e705887dc",9.917710196779964],[10233,"5e82152c82b23aff1b4c48ba2906f80d600febaf9596e2ad0f245263570cc7bc",9.917710196779964],[9762,"49d87bf1b7856c8a8a618c24b5b7e729e025d5eacc3ea9121e9b5b3a4ebfeabf",9.317957166392093],[6906,"32784a7b7ddbc6a9e24af8c73d1190b6107a6c674e1356106df205393fcb8dd2",9.917710196779964],[2687,"d9e254b90a242019f00dc9ef1c23900cf2ed9516c9ea0d5bf4e378a941cb91ee",9.317957166392093],[19604,"ce6a0537e3aafd155bf6a0c25e685f6951e53456de0c812ee05706cc694fef09",12.063716814159292],[16084,"a53791d8a5b498db299e938bd8f017c13004824d252b3257bc36d8b3a35ca066",9.317957166392093],[15549,"27517f5232a64178869c85d1e0c66b4710581153c80bdf17e35bda9a43f3d872",23.08712121212121],[12137,"4bb682310062f18caaf8a99987f46fa78b87532e51541cb8aba6cc1f0d9f6cb0",9.917710196779964],[5856,"63c96796c3ca62d3542482db108abb65177c2478532162eda33e495c4e14f6d9",9.917710196779964],[12823,"536fbcfdead127d7d6623c032a1b1c1bd3bc690f8525aa33cadd52de31afceab",10.052724077328646],[13573,"5b35426811f33997ac101685f6587558017106feb55399957da6dbdc61451a9e",9.317957166392093],[16824,"4553770879860c5f8b6e8884cb058b2b6323daf8f1504bee3413e3fcb412ca55",9.497326203208557],[19571,"6b5c7367071da53491a25a03c64983088ccc025718abf98f753429112a0ca50b",9.317957166392093],[18176,"152eda52e2ca6f177a62e003017f1b2950d75dde7d679e140b2db7e6b2d9ca38",9.317957166392093],[519,"14f5eb379b6ccb8396a3a5a08cb2b5a9ccb4338663f756afdffb894ac8d68cfc",9.917710196779964],[2463,"1f0063891ac89194bec2deb27f16d50cc3e86ec6936303c1e98236339e3a18f0",9.917710196779964],[18935,"a49d1624762dd064516ebb413ff56b46d598726710db95bf0b047d459ff77822",24.10958904109589],[16510,"4ca3c8e4691a07b8e2ddd22fe485a0a1c4ed2075924fd4c447b91b9c8197075d",9.317957166392093],[14351,"4e0399ecec34dd96154f6cbf77145475a0f5b7991468325b17697237712c558c",9.317957166392093],[19163,"267c140c61af4e0eb598db3417be54ba35a65d9da8cf19f9cc29c0ab6ce5021a",9.537836027934564],[12177,"30daf198fe8d0a2a109f24482f68328c0c37fa61fc4c683f8f5814292cf335b0",9.317957166392093],[7982,"31b152f99e316503f13e0d4a45a916f9743ef418c2fd55cd96fbe8e05b11a4cb",9.917710196779964],[7914,"a06f6be91e6e8cba9a52086cd5e850682ec8ab3d379e7a4aee935a4a698921cc",9.917710196779964],[7432,"93314d38a025771ad1ceb904ac9388c83456facc2823db918191e7bf05222ccf",9.917710196779964],[4100,"edce6e64a2da005f1541c5d590255aad38f62b8bda839ea4d6f62cafc31d11e5",9.647446457990116],[218,"0e880d1db269c6a971be3254ec61fb8d35656c08a02f3329c5f0c9f9467184fe",9.917710196779964],[6673,"7b3fffe7f82698ba13229b336d92f2c0eaf9db1b29e014dcd0bd6b8ea70c29d4",9.917710196779964],[10119,"f1224d4d7b213707df0d3b501d2d456db1d5f1a4bc3eedfb6fcec8a9d9d092bd",9.317957166392093],[16096,"25114327b3cd13f363d5526643663bbf3176a3436e27d3186fda05f2e64a3366",9.317957166392093],[13458,"85ae3e2778bf9b562caf318cced32fd4da5791eaa943dddd89725ef505bfe9a0",9.647446457990116],[14388,"daad078ea9be046e86f3076d0d6d9b99cc99504f2354e56c69693ef41fc3828b",9.317957166392093],[13788,"98856136042d6d874be40af53670b43740bf1e71a2f1bda81c893d2dd72c9a99",9.317957166392093],[11650,"2c98dccab62e51eb10870a459481ec6ad63e66695c16983ba49bf0c145309db3",9.917710196779964],[7452,"9020750b0ef7b5a319b6492c219be157fa336cbffc187c8c63db6789ec5510cf",9.917710196779964],[1810,"4548d23826a98f6231cecaf7b719840473671001e5be06c9ef705833ee332bf4",9.917710196779964],[5277,"b1b3713459c47c66cf58bd672c67f0cf4ec7eeeaed2e862bb93cb87057fc8add",9.917710196779964],[17911,"b63490bfbe00445526e4a2aaefc53393a74c31a48152187227d1d264388e0a3f",9.317957166392093],[7152,"c25b62de7f32fe181af31f6542810a6b49d11dd398e2487670c205b67c1201d1",9.317957166392093],[8967,"7e4e105aece4b6ccbcd52c23f3b1821d0ed9a9d22e282e50d9ddc82862a608c5",33.3968253968254],[10162,"81012be8476d57d44aefcf380e1eee6f9a351c6c025f326e4c7eb5e0abf057bd",34.77580071174377],[14526,"c600ae7496253d45e56bba0413590d4b69dc5cb700f3cb63cb4a4e1acc42aa88",31.690582959641254],[6544,"c2c270cd720b537a11937c1bbb93a18cf3b48e8ec2c3fe96868ca2b9e7cb0dd5",9.917710196779964],[9555,"6377d4df7ffb8e226c8a950b92635cddea9479c8f750b1ebbdfd39c9e2504fc1",9.917710196779964],[18638,"ba79aaf57643d6ddb2c8b86185548e3b32ab0b4e8d6a63890ff61bab63ed422d",9.317957166392093],[11271,"8a2b5a72d79be92dc5aaf2b0448f8055f0775fb15d6b92b5bd93030670fb38b6",9.317957166392093],[15362,"162d34e53a7ab5aa52c86a67b775645d53f850c855314260d51c0ecc94b21977",9.317957166392093],[15767,"ac46f6d38fcd94a4ce006c0eccb45c5f2b993e8926f8fcff22943b567527086e",9.317957166392093],[4900,"aebf6abe09854b190478dada7be441164dbb58d2434798f1c088ba733035dedf",9.917710196779964],[17658,"c06bea880bb85edef0a3ef07778d61ae9e71040448747ac97a54edb332f7f743",25],[7071,"7f23215fd5aa7d0daa78b1a4178d35215dff6bf4e96d738dbb0f77acd61182d1",9.917710196779964],[1224,"bbc5be700e55d6d35bc8227a918388f84ec37a3289cfc734b5fc28bd83d2daf7",9.317957166392093],[3397,"77ba7123667c29db058e0e1af6d7d8db5e662a8cad92ae9bca3c0e7f1497b1e9",9.917710196779964],[19039,"f51f601fa7bd60e4d396e93db092202485d8dfbb4bea7d471d072df70699491f",9.317957166392093],[13611,"b2994a76119cd5f929f8ac24dc200094dc63cbb1b570bdbafad18fec7562319d",39.19211822660098],[1361,"27c9dbbe22a2d90afd940b643f9f1ae6c47a61d13d29a2bb93eb7277c209fbf6",9.917710196779964],[16988,"82304db22f7e78c108a24faf2748c183806afaf1f098c8072e259cd177b64a52",9.647446457990116],[10440,"b9b568a7f9b3b09afbcd5f11e8a3ba0e991155d38e3b3a6fa988eaf4454881bb",9.917710196779964],[13816,"1f2e8f42b4765af29eb6846a005094ac5d527b4e6a740060e70a238a444e2499",9.55656108597285],[10913,"64b21cb05afa6aa5d9aba5b3b08765611557009a94cd85b83b6975be91339ab8",10.052724077328646],[7013,"0be1c27f787976f8a89b0218156eb1159678f146e60f47606c9f67963ccae9d1",9.917710196779964],[15036,"7724e5da8812932d4342ff32255c52c76456a4a13db6268eec8236ae58a0c17d",9.317957166392093],[16297,"968d9b760eb69774ab583a58d37e2754d132547e2d733e0e685ce798b9bb2e61",9.317957166392093],[13293,"4b8f788986cd8dbc7ae3298f583dbeb7769a0d6b7cba9dbcf78d1d70c5c5afa4",9.317957166392093],[7768,"af972fd284b47969ce5216cff938bd27e603725ce26009555cf99eb9ed1d07cd",9.917710196779964],[6609,"c51a78585f252fc8b188afd55cfcc0be68e1d7efbadcbb52f80f95bd300095d4",9.317957166392093],[9073,"08d7771698c5186f84ac92a9d5d0df73e29ff16e1b1e576e5caecae98ee14fc4",9.917710196779964],[5672,"0cd22e98bba7323aeaa5bb09551269eebd93c52c21bed270f5852240129f2edb",9.917710196779964],[8221,"d9045b7cb7d0737ca052af2cddd02f7c0939bcde98bec3e63f9442d922becdc9",9.647446457990116],[16646,"4f66d02254195f20011b68671d311b011a198df091d8031d162a65c2f813dc59",18.06896551724138],[4848,"0e3530983fadf841d6406e15817587c06b7a7ae50cd7b7e1f8a40616e65928e0",9.317957166392093],[7731,"820f64c3746800039462f0111542045a263288f15cedc9b24df6d654bdee47cd",9.917710196779964],[12216,"37510d50b7ba93540207259ac1073a8d7a142cd18ffb4a0c537cea93b07bfeaf",9.917710196779964],[4977,"ad697188b36a5d89ca79d5143a91e72ce7966259a5b83a2afa64d32edcd754df",9.317957166392093],[12228,"61ff68de933cb83e8cbf7bea0d55d6131269754618672d11397ce6eba645dfaf",9.917710196779964],[12743,"de98ef3530f6e8904a2ee36fde18b25cf1f77437a77ccce0ed22f2d952cf48ac",9.917710196779964],[833,"69ad4e7eab8483997067072c6764911ddee1df723a071881dbfb74a3fe2954fa",9.917710196779964],[14647,"136cd5ea82971eb4ba04a380a61fe5483a35ed6ee0724176814e509400a1e985",9.317957166392093],[9468,"68cff193b8057862c4e610aeec03f4d029d761176511832249109b9f0a8ee9c1",9.317957166392093],[6803,"ba7b9a1e7d07f6ec74f93b82bcd3fbe1a5f980a5448f854caaa709c994623cd3",9.917710196779964],[10130,"232b96618371918455835b3a764b2b676a9068704e6acdabd2c5dde7b94f7fbd",9.317957166392093],[7561,"b264794d61992466c97eb8644f10c84fa14e0ff9b5f26e3ca37cfbb902ed71ce",9.917710196779964],[7158,"75a7067dcd1fa78400f27551d69f431b840cad2446bab36640a63a9004d8f6d0",26.13903743315508],[15399,"55ebff41c9a7cd5c91ca86cb1b3c9ff429035dc850d9e5b6466fc737d7005876",10.052724077328646],[7166,"d8ceed13733dca67d9d55c96f95fbcb0c0351b58b862371cd9df053072aee9d0",25.38755980861244],[17588,"d24c8986622f8b1590ce0b0ab0dfbd60ddeb9fd836b89b9b8de79a8d5fad7245",9.317957166392093],[12235,"88756eb06ffac46ddb3d8c7d57198129261eabf6d5c517e2fb543276974fcaaf",9.917710196779964],[10322,"df5fbd153509cacd16a3946734ce4adb09b21f644fc38c7d5f00776adc1433bc",9.917710196779964],[13881,"46139f36a2c40b8c158e046ec52a4e6dec9712ff7621ebebaa680a9f71518a97",28.390243902439025],[10057,"88cde0532e2af03b72cb7a8454ccdd4da210daa8adc52c3a6bf1eab9cdbb00be",9.917710196779964],[2543,"939c8e7acc41fe2d682fd993f9d102887f7ec490e498499ce5a61818d6f98fef",9.917710196779964],[8826,"6139d44557b83589acf2e9910b98fb8ee2ada90dbad9f19d27bb15d08e5beec5",9.317957166392093],[7026,"39288bf6e7c90c85d2418bed2ede5f53e1da0868d093ee10ceeeb03b701edad1",10.052724077328646],[3402,"5a0deafed05a43d96666eda81eeeda315bc2787f1ba9494fe7850ca1fec0ace9",9.317957166392093],[5298,"996e2c78893d62092aee6b0875dc2bb2a85fcd35f1622f0a1ec0aed85aed68dd",9.917710196779964],[18398,"ce533f56d16d7538468eb1459f44d26fb81dd15efc14087f378f45517bf17333",9.317957166392093],[5164,"dbaa392f1cb27f4902d7218b62ab15ec7bbb93515b628ea3f65db061117a30de",9.917710196779964],[18484,"a85cdca72fcfab71aea622a3310867925e4769f0b904b24fb7ca909a1b38bf31",9.317957166392093],[6996,"00a84577e72e7e8a0799a443be674898be9ffe2c44eb6c7bc1235a99e4da07d2",30.79787234042553],[13468,"ad69a3ede96e81c66ed74aff858f53a3663f5278cde628f4868d5b94b7ddb0a0",9.317957166392093],[5385,"83af0b6759a733d844bcbf7cce0fb23a8d80c5ca96903a0e81deb77a32d3eadc",9.647446457990116],[2922,"edf36d23471f7ccd536233ddc25c90c04094c614b6ed945655077352b2d9eaec",9.317957166392093],[8618,"0bc89f1fc40d2351f83e110fce8450ea4e61903e8f3d9fafb23a52dedb224dc7",9.917710196779964],[15354,"0c4bf4267f8d4ed912202c05f2d56198be5e8dc27ea0aa0dab6edef9d40c4e77",9.317957166392093],[4474,"00e05df4af9ff2abec1370d150baa4f30a1edcc8b401b1eda875b8612a0791e2",9.917710196779964],[9157,"e2bb804f596a13059e74e550cfb7220bfca460b09bfb3a7f591de9f65f65c7c3",9.917710196779964],[19487,"b1656cf2cef025a8139622e1f10d5b0b51b683c082ebc25b90dbdf167fedd20e",35.893048128342244],[4595,"528c1697cb2ef4d1d0dda6cf9163d2bae922adb5a26378b6c1a11c3f8175a3e1",9.917710196779964],[7341,"8e42b9920661ec48c067fe7f9fc91a0fce3950bbcc3b5632694f9608afc2c2cf",9.917710196779964],[17461,"d5ed94ee8352b0beed31b1e9c0601ea2ed3170d3d2aa0b99c6e00b9d8f519348",9.317957166392093],[11112,"0ef3874ccc71a81832457413cea91a415ded2f04df4d9855b2dcc5366a2e31b7",9.317957166392093],[13671,"74cd04ccd7e4bc8fb07d2c5114e3f969c8c42a1b9a9f5685931f0b7b13d7d49b",9.317957166392093],[1919,"a4d8530789efb8bd391615192eb409da93639344cf27712f3daea135b7bd8ef3",19.080851063829787],[16892,"a2f451ef889340fe975e38e61049c4fa3807768d29a5a811ded399612cd66d54",20.491103202846976],[11965,"00b7f5fd65ecff90b549dc76e866164829bfc206095f69a9eb6427f9dd558eb1",9.917710196779964],[178,"12274bae5879737b6d913345ff5f7c5cbf70638574e60b6feba764a7688dcdfe",9.47085201793722],[5719,"e7cfc4281afc36de8349322c06a0189eb64028fa5681a789b3d008896052f2da",9.917710196779964],[5821,"df9cc46f5677ff0f730f4ba308c6a0e4eb70e1c928a9ec85920acdc927e23fda",9.317957166392093],[5321,"265a1dfb9888a36a4841724028db37c1aec597c2396cb8b8dbfa84c1fe1c4add",9.917710196779964],[14961,"99d6d7dfab6ced5f87ad6dc5f1bbc2e5fea604008aa807d46c24891064f96a7f",9.317957166392093],[4956,"e51fb1bf325d17f3a78243fdaa6e2086c6d274e28b2077740a1ccbf2838585df",9.917710196779964],[10769,"c1575af6f3fb14fb25a6666177dfbab925473cac27014859de473965bb3085b9",9.917710196779964],[12604,"6edf94f594fee5691f72709744d02ca344546d7987162ec693a6e5f2df3c3cad",9.917710196779964],[2230,"47ee5bf9c36edc5af702144f806d1624ceb2a06fb227ce819009e6ba83fd55f1",9.317957166392093],[12291,"e4b4122a0341afc8b57c35b7f3e91c4484fa44293f802b72904c74e1d9574caf",9.917710196779964],[15349,"ce6dce439eddef99ea6a0eb1f78ec9a1748af6997bc145ddf995c16b6ef65f77",9.317957166392093],[16463,"e88eaf4166f601c278e4c479eadd98ddd8c20e9ac7caa5d7f69454f8ee15fa5d",19.144861238182372],[9720,"4296f0d9337dd82a639997f7cc8c47afd5bacaf37d368194114fc0d1439d39c0",9.917710196779964],[10313,"4efe4f65d83ce8a502faf0461835b3bd7f7ac14d9ca9140aa45ba72cf4ce42bc",9.917710196779964],[8701,"f084ed818efe9c93ed2e5fdab86f60706a4828ba40f48a0a522afc89da6cb1c6",9.917710196779964],[1377,"124d3190096ac0d79fd0aa649f48be7102e1ddb6ac5e2095f8f776a743d1e4f6",9.317957166392093],[14614,"3f8112e5270870d902fe54080c2251aef8d8c78e64b1d72fc679baa5ab0fd086",40.63324538258575],[18739,"36b263b34ed2b03d69775ed6be571ee034656cc9e3f3e3c183b89e68474d0129",9.325283747886983],[7307,"2169be0c011b821321f27d4969a9122351c55bb89064c02e353a2750f69006d0",9.317957166392093],[4642,"071a4649d632bf07964fad559c5d74f86824e1f7b9e4aec4144475fc5b5c5ce1",9.917710196779964],[14086,"ec91668f693ff85c29c5db7c10b29992f8d174a51fe8c172fd8063832050f592",9.317957166392093],[658,"bb40967d99d6736e350936db5cb0e317bcf66b976edc6e7b71d08ad5e8cc86fb",9.317957166392093],[12468,"365581ae385fcfdee5b4dff3e03d4da299a4d8ba19fa647e41f745c5494333ae",9.917710196779964],[17508,"fcec1d0369219488cb04ad7d2bf90160988a12c82caf73d6f7c2f329c9ff4947",9.317957166392093],[7279,"88c7b5349e3d7f8afb4bee25c42898031d36b5bbdf63006125b360a4855c2bd0",9.317957166392093],[16061,"f53492e6113e22adcd04e30d16f828ac8811b0ab0dfd773eb04227e8c2fe2a67",9.317957166392093],[5294,"d62d1f2604e510b247fd24b82fa6233ce1d527a5dbdba8921b04bd6da41f72dd",9.917710196779964],[11812,"d175627d0914c54adf98f0f232e87ebd51c48f87705127ec70fb48f48dd6a2b2",9.917710196779964],[7145,"84f66daf86cd9502b028ebf84ae125f35fa08270762555f5bfbe754fb3c00ad1",9.917710196779964],[3578,"80acdbe54f0757755d78ca30eea22d17a4ddb1aad920fe510b0f5c5459db71e8",9.917710196779964],[8687,"87a2c6430cc931a7cb93ddeeaebb5118ab8b878eca73e131638eb35eea44c0c6",9.317957166392093],[7476,"c574e1cc83f559a2596b190abe91d3e53520af4017c4f5e60fba0f6846dddece",9.917710196779964],[9299,"567fe87129e4e7b53df698d99870831b7a35b90e539ddfc324de349dd297d6c2",9.317957166392093],[12548,"933812f05097772af576884be4c3b00a9afbd993c49251d2c3c087d65cc2a3ad",9.317957166392093],[2987,"4dd8d0339f10baa0351a90f2cc9759d7dc84637a105ad17d2b58922368e95cec",35.829181494661924],[7903,"91fc397cf5a43675896542142592ece3f15c60f2ac6982464d06869d75c933cc",9.917710196779964],[16226,"9b5a2394670e4091d2ad93c84a305958f2d50bc6755d78565b002ee743172763",9.549707602339181],[18595,"1b89060955b1ef497df54a831fa1c490e138371150410c4574fe30f18e67f22e",9.317957166392093],[16069,"b66bb5d85c39a369d87a9fb39c4ce9df5e9a9d6fae3e62ac00b433930c3edd66",9.317957166392093],[15797,"ada85ecacbd97a99821c0dc4c5182d458a7dd19f902ce02c388608354fc66d6d",9.317957166392093],[7670,"9e5b52d9195e29e150bb8780e081901c2a56727b624380fc70e06e5bcc04cacd",9.317957166392093],[584,"8a4a15732a655cda7c07da36478e36e4f6dd13906829539c848f0f57bc6605fc",9.917710196779964],[19558,"63ce52f499bd14bcbfc09fbb98b1f9cc6dd150b2cc9996b44b49645353fa5c0c",9.317957166392093],[12305,"bf5ed5242868dfdfa6e7d4f10b0657c1a86f25a46462e56cf91e91f93c1732af",9.917710196779964],[12317,"bf8788b6adb6ff7cdb1aa2a263a2a45fd1a78dcf9467827e1cf832b174d517af",9.317957166392093],[9562,"77000a1a803893358bf19e262fc1b46213b59b60d2984f73b9b9f6e39b203fc1",9.917710196779964],[3275,"94b42cdd822861c0dcb06e1bd174fc9d80821383d1df81425fd5c3ffee578cea",9.917710196779964],[13594,"211eb0ffe6a78f7b4697c49bafa223c415481249e73328fbc8680eb9d291a09d",25.831050228310502],[1717,"fab8d67d3aba48851a30b32547d2c4c1c2e868c1da5a89f81fdfd725a602d1f4",9.917710196779964],[6078,"e7b1cbfed796fbfa60615053dc149dc27c7d82fcaa8e173c479c89593c1b8bd8",39.20855614973262],[19590,"3645099f48efc2b85aca0a0a84971f905611a9b5e93bbb0309ce3ce35d3b930a",9.317957166392093],[292,"ce3de2712da1b775639131a0bcbcb796ae30f83c28e2ef37d42ddc4e1df001fe",9.917710196779964],[10215,"61c6ee6c1827a98d2bd84fc28314f8099e38c87b7b55956ff1bbf3a6016ae0bc",9.317957166392093],[8995,"ecbb5baa2d387b8d8f5a59936e415ede78137ba6c645fac4c716f568b033d0c4",28.12785388127854],[8709,"9159d6b6bc3836eb84db2aa54773d1ae60a8b2cc9730d8f45c6b3d5b67dfa1c6",14.031890660592255],[11837,"1c8049f7f5639524c4c863b0307ffac52079892e96891d999801170dfd2c7cb2",9.917710196779964],[15204,"1402bfec65ff3ad9d217a0d039d9e682ca6f01e346e7d17e2e01fecf365c6c7a",9.647446457990116],[972,"6b99d13e8caf1930e7fe8a69f9bf9195232706a09094560f794feb20074c5df9",9.917710196779964],[515,"7bea1dd7cd8a983d5a79deeb6cf0c3b155669a2edec0207d15d0f4be72a396fc",9.917710196779964],[1291,"b26aa27785ac284f9f6ed47659d31052f534c01a4b4f549c4e6d9c6b57796ef7",9.917710196779964],[16697,"c8d0a9051b9ce82862febf88d4b6598e0b86fdc8dd996d38b64c342a1bb28c58",9.317957166392093],[16602,"259683ace6cf8583d652bc78cd9de6780682f75cb5110e31951c4ece4ee1cb5a",9.6],[15236,"725da7f648da2650e964f2b989877b9c21c66b1e76aef84dccb3e1d8489cc079",9.317957166392093],[6025,"076ef2cf5cf6c026c4d75b66d1e3e0def1c557a899ebc7ecd928311ee483e6d8",9.338112305854242],[11144,"6e58a11770d2f8e5e72f6c7284a105c6a3e6c1517fb2ea1c91f8955fafc100b7",9.917710196779964],[18352,"44a482ae1bd8ecb996cbcf3af496793dab5c9fc13754dc94a1babc9c764eb234",28.187082405345212],[11035,"154f666dea534c810a115d51d54a3161844f1f58c08d362c8d882704850ed2b7",9.917710196779964],[3307,"7f3594978c1daa322d2302451945d4cab1fc9d46930d0495c6bb22da8d2e56ea",9.917710196779964],[16606,"1912b058e8a30dc876c557330ac0fcf70f0326b0411767e596897b54a8e6b65a",9.317957166392093],[1518,"c578f76c4ae4a261ad0171e49a18c9f171ddd645bff95784b899bc0c418afef5",9.317957166392093],[7323,"0a1df94225038f9fa84b4bd27bbcc6922a47b51090ad55b87960adfa8d9ae8cf",9.647446457990116],[15627,"1f78e4b161e9ac1d4de12ca9347577eddcc029f33ccc5dab7c2b9a3a0df0c370",9.317957166392093],[5572,"0d45f2b38c6d65e22c737c9402a665b7f98aa38a6496c60f8c45aacd8a61cbdb",10.052724077328646],[15609,"cee8125289adbc683b7f90bd1980439fbc8d30bb16ec728fa47fe814a3db4371",9.317957166392093],[1453,"92d26867a74d365379c43f91f691866248df63000e8099f982ebda73bd277cf6",10.040705563093622],[19521,"0d1ac0c5d61a1b82e74017b88a3e5fe233943333a8a45ab430b9aaa75f35bc0d",10.052724077328646],[5369,"ebb0bab7aaaf41ca6b3bdb7be2542f2ceb67c455438a07020084fe22e5a309dd",9.917710196779964],[9124,"9a43b4245e25d7bc7090c2e27b239c7adfd0cb9708db2b606e3b86d1b83efec3",9.917710196779964],[2616,"f98fc78b518c4aea49c1b50b75641eb8c225d6d0a76db897d4ef171d2f4e10ef",9.917710196779964],[7870,"a344ecbc86a9cc58e0247b62963f086d6266424638a90626f3601354164f70cc",9.317957166392093],[13529,"f51ae87e7fa832a07f1b452f02246ffbe3054760a0723e43647cf02f601a359f",10.013531799729364],[17752,"64c89892304e757f4c52e877bc2be1560de2bd2c06e24b91a5c853c18ac12e42",9.647446457990116],[18523,"38fccf05c7883591752e2046bc37a23488cac29637b5e439c6047c1b60060331",9.317957166392093],[16637,"2bb158b6dd2664baba1b5c09b290d68654254fa8c2b062638752ca58b26c185a",9.317957166392093],[16948,"ac8687a81f5ea4b22c4f742722cf10f573a56ea962fd7f9d9ec00051d94a2f53",9.317957166392093],[7591,"57e7cc8b513cb6a99ceb192488f39e5a4ba84e307c361b7596072bbf3d0f3dce",9.917710196779964],[17011,"ab79e9601c671effbb312002a3cf106fe874575dc8632d3901b817a27c31cb51",9.317957166392093],[17807,"450494a848dd1b14f8165ef93001d58e3fb85120b67d8f77895d10f816551841",9.317957166392093],[18446,"3c823f98d2b433d6832ff540699f3168900688cd86f47a65e7981a118c59b632",9.317957166392093],[2299,"5b6ec33d38b1b00fc62218872dfb08ab593e60ab14fe4fe5e0f7191e7f8905f1",28],[8797,"e1c19251cf8fb1a4d1aba7bf8671be6d19c373da18dec380d442cced906f16c6",9.917710196779964],[15452,"ca4c1bd7deb306665a1d34791f4f1c7296aa6281c4d0e467abbc2cfb517d1575",9.317957166392093],[10814,"5ab37f8ecc6302bb1d0a3c5f1b82b436fdeacc1b41c99b2ab4cf181fa7a633b9",9.917710196779964],[9498,"4119e06d57b9152b3ee741d488ce43a8d625eae506ffe69a9f797a0a039cb1c1",9.917710196779964],[542,"0922e8b229408d89d0dc1ad8ffa098153f989775165da544c90ae0a557b657fc",9.917710196779964],[9107,"81f12294b9cc34ab7f35486ab9ba568dacfbb6816f1f51bb5112b3d800e019c4",9.917710196779964],[14432,"8cc6410b8a7623faa51998045965f0a3cb096ae0c929ce38c06ecd95c887a68a",9.317957166392093],[4037,"5a5c1779153158bc5ff31e60784850fde3bbe6b060e924943c1afe30b28982e5",9.647446457990116],[12988,"839630f9842831fe8facd95b4ca0cfad77b943f5faec01ed661181918086afaa",9.917710196779964],[10610,"cebdc2a71049bb1e6f5d72a28a612ab912ea2da9962416161f931125e8069bba",9.917710196779964],[10019,"d67a190ebca7bfcb3742e72aaa3c4ee5aa9536d7fc66096e3e5b6d75b65036be",9.917710196779964],[7730,"07f052f5b192100ac6aa8ef08605948cff751746d2ff06962ffc6f7a470e4acd",9.917710196779964],[15835,"7ec5d415a20fa8587b6c29ec6fa1a2aa7d1ada843832e7f663a35c07ba8b9b6c",24.715425531914892],[6809,"403611958d97f785ad791fb1b1cefb28d4efbaaecad01635bc423f7968f237d3",9.917710196779964],[12995,"7e91418f60a4ae589aa53269da5da70a4d066d69bde454ab1d1b8a295c489daa",9.917710196779964],[13894,"c74529694b718ac7838796bdbffcf2f408137c0e9a4496a13bbf2ae3737f2997",9.317957166392093],[8680,"1018e361c5c304ac82178e7ce9033a6a7044ae8794a76fb5191660735ef1d1c6",9.917710196779964],[11624,"0384c11f73645d7535f1fdc153f7f6da88ffe221bbe00a9c0b89f87b35bbbdb3",9.917710196779964],[17062,"0c043b5837c237a164bd5f282c6355e814d251a3faf673d3d766edc19284cd50",9.317957166392093],[16552,"47ab858f9614fa70c6acd2252ffb318532d731a1243b0ff2d664b4aa1b56fa5b",9.647446457990116],[5137,"bcbd715a1559b2e590181ecddf2cc10ad6bbd3942ded386bae8365fd1f5866de",9.917710196779964],[5425,"1df11220a2c186dd8cffee8d6b586d193c7f1b5b541fc26b77f6eaa26f50a4dc",9.917710196779964],[10781,"6aabf9097553658f238fcbba475afb8fce706b461e5d7fa2c05d3e7369ce6cb9",9.917710196779964],[749,"e9265e50919b018b595e7531b9b3b6c19c641ae36c99c6bb6eafb3a0dc92e8fa",9.917710196779964],[16970,"30686ad62036b21072d92509cf46bd2158d6fb67ce578d5d07a79f9329b7b652",9.317957166392093],[16488,"2ef799efc88af15776054928704ae9aa25f27e5164aaa8be69f5dcb543ea7f5d",9.317957166392093],[16893,"3fb1c5c16384468347883b4d466f33b4074f598849d3b45e7b5bdc7bd7c45354",9.317957166392093],[5624,"74c201320c0c46be69288562379acca08e3e5496d34412237cff6ce87c8a86db",9.917710196779964],[23,"2ded328f342675d236c9be943d7297c680a5b684b5a128d439fa2088156ee0ff",9.917710196779964],[15857,"5cbea38f15e6d0a5c3e18ee27579e990c621cd487b90010625f6b3ff1e46fe6b",9.317957166392093],[2325,"7707b060e1a07880b5cb9ca15d811219ee892fcc8c217cc734d0316a8d87e2f0",9.317957166392093],[18833,"e3081866e233e212495f004cd85cf46fa7a643d0633eb8f5f3de360ec1259125",17.027642276422764],[5600,"d1c7c1e5f77c29489e3746a75a36b7b96569031e762a28357890e1016233a1db",38.0936729663106],[11109,"f3550ebd9437f0b1ebfdc4a64bb27a04899ef3d7c0071719185c8df073fd33b7",9.317957166392093],[15632,"ad8881710a40160f11167731c79a22ad84a2e259f1d21561ab74ec5fc018ae70",9.317957166392093],[19779,"bd5308ac018f25d64ccaebf295e5ef020782e7eac9877e99e9f22e6dd05d7d03",12.03183023872679],[17219,"fbf578755c535fcad3dc0968db9b9dfc5d9ebcc538811771ae4518fe8cb3874d",27.093534144161225],[8409,"d3dddbe478d656dfa5f11546b8b55be4770a0364e56014007d08fda703a290c8",9.917710196779964],[9560,"6957994badbee328925eaa80c14b5ac8f0318d199942250312eecefebf8a43c1",9.917710196779964],[13069,"8eeffee23dc6e72269808849e67c3856a00aff01405736b8feaaa0311df12daa",9.917710196779964],[3446,"ed66ee3c4d01d24b289358f40ac08f9a89add7b83130cc3c88e86db7624666e9",9.917710196779964],[7339,"4a4ebed3cd44b71076a21ffe90bdfebd56b51aa24c25a826cfef56a383cfcbcf",9.917710196779964],[11660,"c54cb635a8a728990cdca5f06b87b68767c9fb543ac47291b29482196e1a81b3",9.917710196779964],[3767,"0c7241bd1986647470ed16f2d279e53d71f5f98d9070ca5067701652d7582be7",9.917710196779964],[18242,"302f557c5e5256baa3bf248ebb22ebeb7200010e0d27d383236b83a62e101e37",9.317957166392093],[14314,"5d6c32189ba420694ae148eed6e8d6cec441ae1810f5e485f154108e6701488d",9.317957166392093],[17370,"f7dd1d78fdcf7388d02d2887463cf3a53c9ad510d16b5e640117a6291ed77c4a",9.317957166392093],[1487,"39ed0410df95f0520623cdf0a1291290905b7724d07b04bf342d2f3608ce36f6",9.917710196779964],[286,"5e94092895e34ac6a61358a4594a5b9de09d536e430e91ca5382f9292c5708fe",10.052724077328646],[13861,"99c04fcfa21509adc3989e44b208c2753d313b1b017020d7f342ce1ddccd2b98",9.317957166392093],[15991,"9cfefdb628e60daebb8d7787a1afe9888212c26b42355fecc56f95a06138a668",16],[10858,"e74ba7dcb623ce950c106f318df02736b6123625568182799e2a985434d1e8b8",9.917710196779964],[176,"a3c56a2e83edec041b798f53b85f584f6504c86fd38269c7832802ad0b42d3fe",9.917710196779964],[12421,"e019ce6bcbebd01883f31b78d847a8982074f9e66f0d94be31c4f2bad2c474ae",9.317957166392093],[5560,"74359efc42a65a89295755274787f9c66808a3e6f9284bdccacfc51c70b3dadb",9.917710196779964],[8508,"2ebb99bdc154a3949058b49a04a4ff7f8e2260ed0969ddc47b5a3efd0690fcc7",9.917710196779964],[126,"6377e84d95266e4729fd1ad2dd309cc2c0b8b139480a513fd1ae9ce5821a30ff",9.917710196779964],[7705,"de68b5bd1542ad93d98a50764984da7cdc33551308a7911a8ec5fd10876882cd",9.917710196779964],[17270,"6c3889be1a394469c654a61b90e28e06584cf3560f90aa2fdda40adafad5c64c",9.317957166392093],[19629,"4a60d4bc39e18f4b958cddc333eb82003055f4ed2e324a961c76b34e26a17c08",9.317957166392093],[908,"61de0bb6616f52b05685e52b8e9f2d8b26055606d9140d302977937319e1c0f9",9.917710196779964],[3291,"4e79dbca66205f69417fe404370ab2d24c375d3c2b18d758b89747fb813975ea",9.917710196779964],[15790,"f768f4ad5dcb5d9d1c14db5ae4c77b7c69db2924db9065ae300880ca4ad6896d",9.317957166392093],[4878,"8366e31d0960437aa410977370d825b39f3a051a862c4b7d6fc3344637caf9df",9.917710196779964],[2891,"10174cbc67fa6f8db2612c76e46dd7be98a6b6c258f2b829d6a5b08e024a31ed",9.917710196779964],[4355,"65ff26b4753e7ddb824cd9cb95461e91b49c28b0c0a14a25c86c2bd915185de3",10.052724077328646],[3045,"0d1fb99d24dc1df39ccf2e1964ac605c59269a3395b5d0b27567595b45e104ec",9.917710196779964],[10850,"0282d1aef4f4b0554075218ff1d5f683358c0e07e3418c90bd07a8676c1303b9",9.317957166392093],[10505,"37a0ab18fa32ef1c93a1dcbb1b630f4197c1cc28b214f5bc3c5144e3063c28bb",9.917710196779964],[236,"9dab46c9eef3e07750cd0e0653c7a1d68cc5a0a016cb88dee38f9f7ac6506bfe",63.625835189309576],[5113,"6eff2c6b1f10307d82755f3e449ec605c42aabf3d14d18a6eaf3091efe8f81de",9.917710196779964],[84,"c8ba30510e20fb808e2f2dc4abe5533b46915aa82fe7e3463ffc67db5ae473ff",9.917710196779964],[16146,"2fcd9d30f49d2614e4fbd25ea92a11c5a4aa032b5ba5770716a70b76d4721865",352.21768707482994],[3616,"030b59981fd2045b22629399f5faca45fbf717faafe3353413eb3473b72020e8",9.917710196779964],[11977,"dc4ada863af337d9b6a8fc06a49ab05fd3b08fba5c274f15f29e4dbfd7a573b1",9.917710196779964],[1396,"d2b740019fb71eea73b3f741d8c3778ac6e18180e11986d65e6fab0471a8d1f6",9.917710196779964],[17667,"0bfde1c814ac58359328e3b5cdb0169be4c331bd6a666f1abc269e20b101cb43",9.317957166392093],[19761,"a12faa1009eb7a4449f4d3c9ede3a7a0d69d2752917fd1ffa0a3c314fbb03404",9.317957166392093],[7340,"a14bc8355ccfe594ec66ff20a1ed4afdf749091314615eebd37ef3ecdca8c5cf",9.917710196779964],[496,"4df36ddcb63c789e2f7a6471571d06e61cb54e273a44667308ada2a8939eb4fc",9.317957166392093],[1059,"c6bc9254ad8bc66c426d7d801310f8db719d31d91cdb2a355953d175cb31ddf8",9.917710196779964],[5380,"bb821e2463403fa8ea558671382c3e560e1a6120a39c29565a8df8cc7e16f6dc",9.917710196779964],[9750,"2002ff15b58ca8cbfcab0f6c75bd0bd365bde515596e1e417a551f71cde002c0",9.917710196779964],[2181,"fce3b2ec55226ff10ee854d636e9ed4600f68ec6cf428e71cfa63301bf71acf1",9.917710196779964],[11964,"d45d5983aebb2ed68ab7481732dc19f65285eb9f16042358727829110d958fb1",9.317957166392093],[1393,"8b1ab9d09f2af610e719003683ed5dfb8307ee6fafbf63f059d8139ca35cd4f6",9.917710196779964],[18542,"5f200081558edda0d0c1ff7a0c74555063d0915d9a5e5871e950f6dd7bc49130",9.317957166392093],[17795,"7d32ef12c6e753fb34f5c25906e0ff80bcdcce5dde9cc3bf5699e1cb60156a41",15.944153577661432],[18981,"e8ff34e11f3fa45ffa8ce47cdb6cb0ee4ec3018f3aa44db63f881cd7ee0c2121",9.317957166392093],[9260,"a60ae9a09c00ec30f67522851d2bb1f72dc378cfb9b7616abb92cd194d8814c3",9.917710196779964],[10487,"615f6ca485554c05388eb8b00fba699aa0dd37b8e8609f718fda83f283ce3abb",9.917710196779964],[2127,"e60db43a19483b1499306fe42439e7020d4a2fac1eaa54d9588058c3200c12f2",9.917710196779964],[14867,"b82eecca2f36f5a9babf1df0d3fdef73eb2b2d0bc491d95dc2f11924173c7481",9.317957166392093],[3638,"c80dc394ed8d29cc320185105dfc11edf1db2510f86e7088fd2bff42e35d04e8",9.317957166392093],[1470,"93a5cc1a09aa7348d8c51634e8b1888b3bbe44eb5ec692f707372292059657f6",9.917710196779964],[9316,"4af1c3ac048b4bb757531406f72abc1e3a2dd7bc20e2a57d2dbad40c02b2c4c2",9.317957166392093],[4106,"8b17cf07d0b7ea6323229c02f756f1c3ea47bcbe92261585e0fbdd43209c02e5",9.917710196779964],[16134,"199032680fec6d02bfd21e2bc93d3a3dd4a47f505ae402935aa5dca1927a5d65",28.149732620320854],[3272,"6fc28ae51f7f93ba6d4029788bb6be64b51a3093acb869769c91ea1de74691ea",9.917710196779964],[7620,"74ef0f67f9a49a4c06e2b34c697deae1b287cf59cc23a49e1028ecc205091bce",9.917710196779964],[4658,"ba7230d2cb93aa1753d87c3205c96085542d27978cc9b628911560a1b1ec3ce1",9.917710196779964],[18116,"7a1db081626128e4af95382c427f2a707ae58bca343c9963f8ceb846bb16893a",28.29268292682927],[3674,"16751800eb2e1f66339fc55a1a0948499c14de7d463758191a052a42749ec5e7",9.647446457990116],[2205,"73080c0206764d04e13969f4f9ef9c8bb327107518f5f708e2710a1cd74182f1",9.317957166392093],[869,"4541c73357e43ef308cf2482bdff32ff5ff71b54dce46e1b7faff5e423271cfa",9.917710196779964],[3929,"3877a41979a5b8384453cf14726bf2bef3fd6308d0bb0e8df7d8b1918db929e6",9.917710196779964],[4141,"abaad5e47d42348cc11c0951720a02f605cdc8fe40e5f0987d829f1b4db3c7e4",9.317957166392093],[17211,"2a3746b1c83ebc41d284ffbfbf7e56df4605b8d491ab5e503ea4c48d59799a4d",9.317957166392093],[10827,"9b854e8a0bc14366b8a511d8ddc384a4930c3ae7882648696ebd366d294f20b9",9.917710196779964],[17737,"5ba965cf277040c478d2668cf938c64f2e92841c26b88aba8624be1bd6ef7642",20.106951871657753],[4158,"315519c17d631b48d4faaef154d2864242e2c66f20a6e169a451de4ff30bade4",9.917710196779964],[18585,"1cc8c2167df63441c3078f7e2a0953b468fb3af4678b8a0cfae041a6a85b432f",9.51504424778761],[15282,"6c63ad51b035584262e379bec37f37f744e9664b6ca81c9d0fce5deeea20b778",9.317957166392093],[14907,"1cc6a381aec613c84fa224aab5377ae466f55cf685781589b3ad91cc223cce80",9.851809304997127],[14922,"73b4da1b88732c2c55fd382fac0e730d579266570c6fda9b0e6e6959856a8480",9.317957166392093],[657,"7584520ed6d9df6519b177ee1396ccc3a7e632092cd8d488884359bf518187fb",9.647446457990116],[4373,"d1315178057528efe7c7b374b40bade7332511072e3e2ad55806d62e4d3e42e3",9.917710196779964],[11844,"62c4c96abd83bfdfe980c93bf2e3fecaae14a290bbc25d01c4d7831f00ff6eb2",9.317957166392093],[8875,"40e88aecc2d51670280825dd69bf42b2557b4ade181c793d293521fd9f1497c5",9.317957166392093],[13408,"f836e4d4c8472afc063ec3ea0481aa1416cd1f1a472f83d30724d09fbf5825a2",9.317957166392093],[4236,"37f532ab136dc3fb711e767add9481f469c891d9fbc8db072b69aafdfb0b31e4",9.917710196779964],[6677,"761c028e9ce89c1d5327aa3ea38df173574ec6f84a6987514a7fea17bacb22d4",9.917710196779964],[17005,"5657f520942b9145636cd85e54b7b814ebf72487ee30c4c651db2583059ceb51",9.317957166392093],[1438,"52928ed80fcb67d3236b86965d7c73bdb715b9a0a8a8530a7c625b770e2b94f6",9.917710196779964],[9970,"ed18a610b242c8e895590fee1f576e22f61e28920248b00228a9c60eedf880be",9.317957166392093],[9684,"f7014542aa399a25c2641166782ec96c765a4a94baa85b0f1e11fc0a3adc7ec0",9.317957166392093],[333,"4b8a8736a00e01800dfc41a3aabe597feb035981fb77656acd6b71c84a53cffd",9.917710196779964],[4467,"9def0515f59711299be1dc55e2b46cc9f59afbe7d4b05003c6d163d38c889de2",9.917710196779964],[14754,"bd7b3f118a7f6e19518136dd31761ad9648739e604c2091dc1ad56d78842cc83",9.317957166392093],[18381,"2c0e3fb0952b5570ff625239d45df097e6818d837f65ceb0b2d7ddd32f28f533",9.317957166392093],[10133,"de623240bd6614ce66d8c4f36ad08f60c639b070d85367c269966d5026c97bbd",9.917710196779964],[19193,"251379cd2ebfc91e4dfde1b47a4528037e9026c349868f451dbecb827629cd18",9.317957166392093],[18393,"77e7c24da368f392404c1dfc644bf924a0778a9905a895fcbd2f8e68555c9933",9.317957166392093],[13800,"b787f16aa66f6f3ee021b8babdabdeaf389378521e958046935c8536cf1d5999",9.317957166392093],[712,"7456a10cf27605262af9a6a355560aeb5e7c6edda0e3052b80f3443be8211ffb",9.317957166392093],[5668,"a302a67d930061f8a4969ad3e404527af013cd9eca48d3c08e1b552c257336db",9.917710196779964],[10523,"d845cfc1636443eee573027bc37d2d18ad2eb9dc614e59d0a07146ae77d605bb",9.317957166392093],[8479,"bb70c054e137b5f573eb055c3599adb48523d601e17e5f18f8bfbe2bdebd26c8",9.317957166392093],[15998,"4b07e876184265f62b3d48c7bb48ce3ac0b82f23994dc9041138810eb5778968",9.647446457990116],[18819,"76138bfde55d4486df58356f49bd6e2b64668b434c00e7189c3f6e213eed0f26",9.317957166392093],[19246,"4d039bdce762b7fdc299211f8afa31fb167336ada2b8c47f025ee62608ab0117",10.052724077328646],[7542,"3e6488c8dca82a3dfed3ead382001d019d9293374b273ccccaebe57870d18ece",9.917710196779964],[19022,"e2b3d611ecf6204143bcb1cfef08520bfb3e2170d0932b817e73ca2676f0cd1f",9.317957166392093],[17100,"9222e23b08f2a041876e467d0edf65cb39486260db3c5ce753cbfa62d0a3f84f",9.317957166392093],[3982,"9150c05afa290eb3f7c1a6c0781d3115ba968ded0b330d7e86917a4a439ed9e5",9.917710196779964],[7872,"d0296ecd0a6fc9420c2308e4b1f7cc8e08c602136b367d77aad539672ec46fcc",9.317957166392093],[14147,"963e07a1ff86de18a15783b0c9133663434096bea08bb4dd8850354072649691",9.317957166392093],[9278,"7c2f804043381e0a053b146a081af631d030b50df341026c802a4256ac91f2c2",10.052724077328646],[5025,"bf6f67433a92d8e7f9421172f5387869a945a09e29018bc9cb2aa6b639ae07df",9.317957166392093],[13981,"57ea965ee96aec0c3660f742f0a9c3be13679be1928d507f5144ba3b264a5395",19.80952380952381],[14651,"bdd3c1cce2e3cf4e81a04968855ec3e7356b0a628e77b3850167eadef71de085",9.317957166392093],[2466,"83b5b58f2d2c87476a0da290bba3d6a33ff8f667b6da3c61a50bec70152714f0",9.317957166392093],[6630,"117d3a3a6efdd6960dfd40163f1e5b3f0c302ff80a86e0c7f051519f063b74d4",9.917710196779964],[982,"f7eeba83839045800e62769b159af529236b2a4a82d9234c791ffac650fe50f9",9.917710196779964],[4041,"949d3ef065ca9eebf3565d7cea449c185d9556665b8d50f2e64260b4d6b57ee5",9.917710196779964],[3747,"eb924a8ac0df8c513cfdab808c2ce3660a76bcd9c79dd2db25c67086694b46e7",9.317957166392093],[4363,"aba5fdf1afbe1a774ae32e7f573ade391e613b8c5c76575e5402fb1e650453e3",9.317957166392093],[4756,"14189ac06ae3232de8f3e272bfaaa1358b39b0dfcb0cff70bb359ec1523c9ae0",9.917710196779964],[4195,"636f87fa600375df68d757c415c0869242680294b4dccd54bee7f526b52d73e4",9.317957166392093],[4605,"51c5923dfd715bb492d7481a48915bd143f88a29c707bba775b1d1cf96e798e1",9.647446457990116],[716,"79c743437760bc9ac932efa658959b136e4407d134e2cbb6aea638e202ff18fb",9.317957166392093],[15385,"ff7b16e7b9f91f90ebe07723387a97233b78db5088562991834cd445196e9676",9.317957166392093],[16937,"eb8c533c374dd7ca04272b29fc88df6501035678c5755075a2c3f04694ba5353",9.641748942172073],[18692,"5bb484fb906d8c0b2f559b6780012b438c8e1e4892316236e2c003030e169d2a",9.317957166392093],[10930,"68072c3752dfe8edce0bad3ee9811492b8067bc8dcbaf093d6bbacc6d53781b8",9.917710196779964],[16021,"3d1151c414e64b4ea8e061c8ab4cd18cf9f8cb4f07ae2efe53a88c0df4050268",9.317957166392093],[14070,"0f2493493e50c15759c895663e8c08c7da35a6426368d505eecb3a2c7dae4693",9.317957166392093],[13361,"db1702d158c74da986f22eb9bcdd65ab23d1ab243141096c114e8e80984242a3",9.317957166392093],[2920,"c32640059287e07c20d927f0c79e6cad859a999431437556b87320da2d55edec",9.917710196779964],[8145,"ffcb9b6035014c7297d4e2ff1fbb9dea976490d964f271e674e3cc479ef167ca",9.917710196779964],[5258,"93314285605655cb668e74c32488aa2a869a914b6fdc4b50f5de2d47cce5a1dd",9.917710196779964],[16615,"8bc6e86bfa53d8b19b71616572995eb06cb534c067fdf052410a09f6abc58a5a",10.052724077328646],[18941,"790d9537496b7df4b53d25e392fb6462d5bc18e572380c0bb8c567d6d35e5d22",9.317957166392093],[6068,"80a8ceb02db1edf32b4ccf766be28bdb873935ea63229575edaa44d82fe2a1d8",9.917710196779964],[7511,"c82ab073c73a377f7c13f665f56b97dea812756d8f986c7258081dc83013b0ce",9.917710196779964],[13770,"d1dc1b5e92f3f3fe21422a4254d3603fcde991131e39bada8dcdf7b004cdfb99",9.317957166392093],[6116,"a41d303fc3c3645f653084318c8e008678e63a2383f24844704120b265a153d8",9.317957166392093],[18228,"583c3504778ae24130a7d9a5963500b0bf0f14cf19b20f7b027feab783216e37",9.317957166392093],[8263,"15edec71d6c4f1f9f26469ddeaa92990ef1668f6d459dd339c42f6e38efd95c9",9.917710196779964],[10447,"180fd14dad1d1958fbf62e1a9efa51abb5dd622577790b962c98959875af70bb",9.917710196779964],[4885,"07a80f6cbaccd57398f7eb96960744f95a84aef6001f1d4f581ef2bbb00ceadf",9.917710196779964],[1110,"94c2daa57f7acf4d0a06eb33db042c1f9fafbd18de42ea155ed937c0f6e683f8",9.917710196779964],[19569,"6eb424d77c86421daef772c129e246ec1195d0baafab55e621d57650eafee20b",9.317957166392093],[14309,"ad52afd6f40171c27a70af0c495903f73affe8cb49df52b5fad8abae09d8688d",9.317957166392093],[10778,"97f2f21a91c08d522011792d76c62f19084d5c808c23e61c2ab277d6d7956eb9",9.917710196779964],[8415,"0bbc69bacaa57999622180e5da74a5fb45dc50dc2e4a7d6a61a98131a49087c8",9.917710196779964],[13146,"9360c787a01dc1e33d46b90257c658b4f98841370557ebce78cc2ca83d6a0da8",25.829596412556054],[8612,"543458cc680be6ea239dd1813b9dc81969ae5a01a54fd62a367afde1c66056c7",9.917710196779964],[11537,"98cd98e785c9a8c93e0e1b28ea73fc29f2e76c2a3e5448e0ae09936437e54db4",9.917710196779964],[10537,"4a2b58f07b1ca9bf4fa2db8c40f1041018c3ea0b0a067f107bf2bcaa3cacf6ba",9.917710196779964],[492,"b5bb9c81b5b9e28c3061b7ab22f89fd2afea126ea2ce0075b3d14012e7a4b6fc",26.00263504611331],[16237,"31767f42aa49c11e4f1dee5b28064e21db56e87094e9c4f5e20713c2bcb4d062",9.317957166392093],[13610,"2904e4eefc5b4ebd7f213efa77f6cb34107ee460061cff54a05dd85eea8c359d",9.397642257991386],[3343,"f79dade4480b43da0016160ad38c565b801a8e894926404d90087131d4210bea",9.917710196779964],[5758,"1f8cbc4efcf04495e2f2a2ccc9e93b1c62abc657bc78388367758b448ae2bada",9.917710196779964],[1720,"ebc12e0746939a8cbe5cd7fe6d683f2b259accce7d1fa3178d7831a8fe21caf4",9.917710196779964],[2433,"92534c868752ee69424c10b117104c63dca1407c73b71ea5bd7477681e1641f0",9.917710196779964],[19329,"2d979f70f3bdfd6502a60eb333f41af6c650cafa4f3804892dc46c2ef9fb2714",47.2],[10069,"b60b1d801eabde0284ca50c0c261188378b4ba35bb8deb32ba97b4e31daef1bd",9.917710196779964],[3948,"7db56eb563f966a7a93173723e568559b27ddf1d0c2746b9fcc04d925c2802e6",9.917710196779964],[16829,"bd78d187452df65a21d4ec7e0a021b9689742ace28a414d29412fb09002fb655",10.052724077328646],[5688,"5e2bb46fefc7ef56b0aa312a9c392a5013e671b661a4437807066fdf72af1cdb",40.71301247771836],[897,"37c4c9e14078a1913c99f44bcc31b043383d9a6627a44f3e622f0447d987f0f9",9.917710196779964],[1259,"dc446efb7f45727c2e3d36401a33e61df54485d51b5f3ec6a6b8dfb9ac439bf7",9.917710196779964],[16279,"dcfb969e7319d5c3c70b5d35afaada2cba6cb87cceae65b2cab3b65e7d889d61",9.317957166392093],[11161,"468880dc2e349fd5cfbdbff118cc6f378df51a40307fe0c9609c0030aad0ebb6",9.917710196779964],[12647,"ade1d16b0266eac025ed78363a0bc1985ce783640012905712629c1132a3f0ac",9.917710196779964],[1235,"a1e36fd2d4ffa923cffe54d2af20938ece5affe4994ecf8d753476ee4ad4cbf7",9.917710196779964],[7600,"32a973fc8e4b4b8cf0419351274d3de2e374d38113d02e56c5eee1c8861c2fce",9.917710196779964],[13698,"924d7d66f308f358392ea2f2115d0c4c0078b73cebc2679905ddded498ce519b",9.317957166392093],[16341,"be9f0eb4368dd92f2d0011aa5eaad920b5816e0d083592eff09d49fad8dd2f60",9.317957166392093],[9408,"4cde8e28b847eefe94ff5260fe049797f41c4cad3d0a67c9d93c3b955de33fc2",9.317957166392093],[12951,"c5a6e9dba82da43a519fb9e17e8bafee8c5f967082649c9416caba7e4f14e7aa",9.317957166392093],[2234,"5450a2d43cd9e3be37b993f9c6968192a9ec6f285942c4dce4710c50422f51f1",9.917710196779964],[1803,"a91e40dfbcc3d4fc56eb9dad7a6db9a29d2e68aeb78542fc4df5f1d7664439f4",9.917710196779964],[5028,"10551fec11123d15c850a59eb91a47ef090adc26137728b5b86dc553f7c0fede",9.317957166392093],[14092,"19bafdd42b855b02e919c097aaea4238a9e061d887fe2bda38411c43508fc092",9.317957166392093],[10848,"34bdcb87b1cd767cf03119a17b4467145100583505f056179fbae778abe503b9",9.917710196779964],[7868,"e1573440a42ba6b98d8a47e98fd91323a09f01f9bee43c237206f544402072cc",9.917710196779964],[11416,"3d60059576d7988bf958d39eb226d4600355a418545b15e16837babcc9463eb5",9.917710196779964],[7099,"c752519965d5ecad07899136fd5be104acb2f2cb013ef4bfbba7842281ef5ad1",9.917710196779964],[17968,"935f69ac024a7e6400784cb636e0b8165681fdd47b3263c7c7b2bae82efcc83d",9.317957166392093],[3006,"8797329216f8a178a56bc6b38587dc2fb433dfd4a98fae69586335c5d92f40ec",9.917710196779964],[12021,"c4e457ed1110a21ca62f3f5e395f6412c2ce64fe936f77aabd21b4ab337634b1",9.917710196779964],[18637,"a8a3ac5ed0479b09da53fcf382431656bd2f017e64ce968a25d22467996d4a2d",22.151515151515152],[6161,"79895a16566cf48a75678497107f48620ca7cff0edb1124c4797b5dfdfdb13d8",9.917710196779964],[19547,"7a1bcfd2a98a3aaac4ad6c44318d8bd4292cd4f343a21f7b8d79318c7f15bf0c",25],[5634,"c27f144309e83180dbe6f66048bd186509624c3892bce8ecd9966126d2fe6fdb",9.917710196779964],[3105,"a78a310ee758352205328310f7061ddaed8648ad028c867a895cc2953a869eeb",9.917710196779964],[14226,"b698efafa4f4773342466fa8ea1f0be07ed409d79db6bafe8c5a8719f7b48e8f",9.317957166392093],[6858,"d8a3087fd8d5315adbe1dafecb55a9b008615d463f060339c9772713e7c1f2d2",9.317957166392093],[4107,"3cb00f297bccc3f562b4edd4e7c8dc87bba9469410030984909369f0bb5801e5",9.917710196779964],[16315,"bc7a27dc346dc5bf2cc41be7c6cbce0a22310d17c0126c76f966b8d2cc8da860",9.317957166392093],[9096,"6c5c5c9f22b4653f176a71f2fdc946e52a0107cf227c1470f3990ddb478a2ec4",9.917710196779964],[1724,"3217f19884abddcb72b4d7540d0e7f35b59cc3646ddb3c77278ae5530ee3c6f4",9.917710196779964],[3629,"4eb1677337df8cde795191e876fe5935a9c7215140f4fa2130d64ae9847010e8",9.317957166392093],[7110,"47a2b76ecc2831ff42056d74ba64cf10a72b07cd8c0106ec6f8d8e5fe85c47d1",9.917710196779964],[15678,"8e03346e7778da2ff3a37904371e32c343d9781ec8ec41853501c0218a96d56f",9.647446457990116],[16119,"e043278652e9c475b36df2ad409d237cf3714c020312df686a259a628d4e9365",9.317957166392093],[16180,"1e48320a2656f324ca4911004401d90aa90817e9198ebecb89cd131c4b4b6864",9.317957166392093],[16511,"7107404b0806769dfdbcb07b2926dfc9526603d21836c832a906994ee19c045d",9.317957166392093],[1680,"319459962610b4366b2f0ccfdffa2593cb120196f40593e4b9a15dfc8e340af5",10.052724077328646],[8724,"f590d47666678cc00bbd6baba8c6bc0f488f260496210032972ca66b585189c6",9.917710196779964],[3662,"efe3039d527d02078d9a98ea8ea7ac6707baed8df8c6683b2d176a01e705dce7",9.917710196779964],[3146,"c5572383da7ddd1aaea8f1e8d767c05708caa71ac64d3c17c63f5ec5edf765eb",9.917710196779964],[16453,"544c554a2039e2f9863eb5d2aafa8b232b25e387060c6916b31b13491117245e",9.317957166392093],[4767,"abb462c284c0522701330a120bfc3983f49d356dba9e88d20922f45a571b8de0",9.917710196779964],[11521,"19d191eb21776313ae675e6cc208e3ec61bc74c2d8738c6c4ba84363403662b4",9.917710196779964],[18357,"7fdb8afb378ee47b31673cc0fe88fc8dc4673bf1f7e987dd8d991d0cf2769f34",9.317957166392093],[9553,"2efae45c88f114f2f980f2d2a0dfcc9906a09219cecb1d53967ae5f32a3c56c1",9.917710196779964],[7507,"f3fd9648c59100b776cee5e9129ca4dc3f2e35debad743930acf3c31c6dbb5ce",32.3006993006993],[12,"a9c5c7dfcd55c829e4c0709db8d0c6060a25f6f3552d2bba8710dc3953f8f0ff",9.917710196779964],[17195,"2274c2689fdc381f5448c0953f4ad524131e3d2b5c6cbd14084845999211d64d",9.317957166392093],[11785,"af6507a71629fab95c8efbd6342463e6d192a82167232a713b53db1bafb5cdb2",9.917710196779964],[8948,"e99021e4ebb231c9ad8b8b7afff08931cc7d9c6ab8951b442958c9631ada20c5",9.917710196779964],[8717,"a9c7978fc5d6b13b13b5dcb5a2aab271f364f59e6e5a829d9909484dc84a95c6",9.917710196779964],[2218,"0695ec885db7dbf497f17173c7659478ff6870f9f4072eaf693da528dd4564f1",9.917710196779964],[10525,"e62a958b977c387f9f9eea83b3ca561a368b4a787acd494e4f2db144282103bb",9.317957166392093],[11958,"5f962236a56fb48393858f947a59c552ba48d1172abbcd810d8bb1697b4d9ab1",10.052724077328646],[10441,"8192550ddcd713ad6febca4c7b2c4e8e096e785e429d1ae1aab89568e8ba7dbb",9.917710196779964],[6528,"37ad33902ccad889751eb1d17cd3a01717ae46fa72f62ceae61987eacc063ed5",9.917710196779964],[7332,"450ca1d414d3231a57abdef58a9f331138dbb3f2cfca0a1ebb45ebf7a116d8cf",9.917710196779964],[1004,"8f239a022bf64c2c9e418cb5724dfc28f96e33a31141243329675a3d9cde30f9",9.662745098039215],[12598,"dabb1ce8b4b635569e112ae2ecf4a813880b03eebf8a9ed625c3661e2b7549ad",10.052724077328646],[15474,"98152558608bc39c857383337b753fdd426a619ca870083629adb3e0eebd9774",9.317957166392093],[18130,"a49e481925c1bc300284b53886a1160173a31a7a7d713d9883e8ec5867233a3a",9.647446457990116],[3988,"5b248d1408798dd1f18479a9314e44d52aa2e40c164fc7647ebed922a020c9e5",28.06746987951807],[7813,"efebbca752b9576e532b19f6d7ad3de3b4ebb52beeea10a22e96ec8af01daecc",9.917710196779964],[2639,"2d09c6f14ce55d635c1f7c55f7a4dfdeb945407f5fb9fc46de47458d1198edee",9.917710196779964],[10560,"fe432869ca1d882b441a735a16b190ef71e97e3333011e47fc9bd027033cdbba",9.917710196779964],[1027,"260e6710faf634b1cb3a4049d52d04e41e896382b3eed10bd3ddf1861d4a15f9",9.917710196779964],[7266,"a2ecb9a51e4b4ca743b858b04803f4ffeea58fe85d1fe6b9ad62033d65733bd0",9.917710196779964],[647,"31d74bebb7ab017cea556b4f16e03f18db0e64e93e3fabb069f1cf3bf0969bfb",9.917710196779964],[10660,"b5a1a70e6b1f65835d3a8ebe1b1c8da8b27e619fe91e6a172e40172ac9954bba",9.917710196779964],[18147,"9482c6603839ae5774de1abc7abb88a7b58b5615788e0ffd3136a19ffdae9139",9.946524064171124],[9417,"7edbbc416181a824b5ec6485661edf1e7357e1b11902045fdd7990d2aa6e31c2",9.317957166392093],[9207,"c8375d16995e5fbbafe2190a49ecd1fcda36eec84c213b3a12dc103dda5065c3",9.917710196779964],[4522,"a3db9c8c1114ebbda98e72d6a48ada22a3ff8bec6e951c583d7bd521074b36e2",9.917710196779964],[13416,"83e7abf89385c28a5fda27e36e503b421b91469c6f90836e5a9d23c3018005a2",9.317957166392093],[4750,"c9041f1426c60cde71fa70aa9cebd0cabc69c2c05e722eeffe72bf079550a4e0",9.917710196779964],[1636,"a56a70dcde46129ba3d9d9f285c9a31ba7624f3a4100a3a47f7c46dad21c62f5",9.317957166392093],[6866,"fd01bb230e34558bf1c4c4d339ade1f1370db3764f52c2d5430746be75add8d2",9.917710196779964],[3139,"0e77e125c7b5d8d3746cdb9760e71171a6bdd36cafff6c6fc0a2c5ea6b336feb",9.917710196779964],[15276,"d9421a9c710f9ec2fcfbaacf7003bef6019a4b2ad28ad0f99ef4bbfd185fd678",9.317957166392093],[13444,"0d053a5740f348669c10b7442c7e72cf95d17c84bc3f25029b4f3613857737a1",9.647446457990116],[11367,"cba0a40c72570e6163146a1c061a9054a2208aad3bb7ac395d6b777dfac698b5",9.917710196779964],[1907,"3549482caad0e837b4e4230b8dea7e4bc871add5e4b63ca8cc20a9a8faf097f3",9.317957166392093],[19118,"5343ae08685216e7e1d1717cd17ff6f6c819fc548ecc6133d21118d3e0a3b91b",37.936395759717314],[12568,"495c89288e55513843300c0ef0a8d3457d3907d3f0c3d5a042b94057450f7dad",9.917710196779964],[16766,"369941fe2aac68a914840cc3f1674c0b95ab1548040b0a57ce7b594871f11b57",9.647446457990116],[151,"cce348a76e885a682809a32d29b17b2f4a1419363198fe5eda21b98e9882f8fe",9.917710196779964],[15153,"a9588bebc19ec3a123621c1f4991ac2e3b0c24b5db0e04398ab734fb9ff9717b",9.317957166392093],[15780,"57f040f9515403a2c727827ea3ded1129c7e98d1bd32065321244c10aae1b26d",9.647446457990116],[11708,"f76c2d431c169ff7c18d499c06d1533ca725fed53ec6ec281f4852efa84240b3",9.917710196779964],[14769,"9583b4cd5a38a290e2ce4b90a0da57916fc97b59201ac2ce26504436c6cf8883",9.317957166392093],[13622,"47ce6dc51707ab4236b50b9d9fa0696343fd7cab8b2422a694458517fef3e29c",9.317957166392093],[18308,"ee8bebd597b056c13c1cea0a8d02693f0a387f4d9dbf365546b8cf31d9d9b835",9.317957166392093],[13176,"05e619f0b3e01fdb2c4e2d38bb77919c047ba459f580ff93ac9e0aee32f371a7",9.317957166392093],[9148,"6d9530013dd0213affb577246d035386e6fb1b9e19630ce6eefbc1116cf6d3c3",9.917710196779964],[14684,"9be043ed6315757a1739bcd6c822393d0fa128340e8511e9a52015fe45c03185",9.317957166392093],[958,"7e169f1804138f0155bd3f2455e384c85fac084452987477beba1344820275f9",9.317957166392093],[5490,"395fb6f14ac73d8bc4c713205155cd384cc67647341e00b2cedc860e6a9e46dc",9.647446457990116],[3963,"8c2196dd2d322f84b0f871602e07b0b0feeb0dd02316b0d5ddb7c634814bf5e5",9.917710196779964],[9963,"fb536b732aa4d6cb7f3e73625c43d76054fc974b7e036f0eb011c799284c89be",9.917710196779964],[12128,"d2dd8cb725932d23bdd37cc27b85c8337b8bc1d9d2b97b80aaad9c2653d880b0",9.317957166392093],[6226,"76599c8c958f2d57a8149f88eae0130a1df23e89c1f33057d89d4990b2d791d7",9.917710196779964],[13352,"4225705f899b24f99d25f180e584c5b181040e3cdf6b97ffb222fee5caa76ea3",9.317957166392093],[6588,"753fa12ee401fe466d6e8fb882274a34cb74292efe1978da20ea16bc012bbad4",37.220238095238095],[18768,"1baa7e3165078422a073daeb86eb1099c7984dfdee5ac66f96253dc500101428",9.317957166392093],[18565,"cad9c73671c1a085ad4cb8c9ab7fad1d734bb8712d909172ea2db9343ef60830",9.317957166392093],[3722,"88f7e9ab03633586b37f57041137f4e17e480a21455430601cbf438b245e70e7",9.917710196779964],[14881,"f918426be750538ccb3ad1f8c70700dd36d2607ea53a6c86235e988ecd082281",9.647446457990116],[12275,"6d972ad55130a9f2fd4ca7239d341651478321a5fa6e9f9425c30778e7f271af",9.917710196779964],[14211,"eb95dd816c78cb958d7c1e6a236e0fc40fac904a3f4e61c4f0fef7a243a2d98f",26.52017937219731],[3566,"6e7f873e686ca3c77be58f30aa0ed1d14e1b074cb7fb9390d19f45cca1f27ce8",9.917710196779964],[11085,"b465dc44c14b3aa58c4acd5fafd16caaa464569cfb3e4abeaf56ec4452415eb7",9.917710196779964],[9662,"b09218b4454f67befda5dd53d0c9b77500d2d377c1401e3dbca4709b856aa3c0",9.317957166392093],[853,"044334ccb12b67091acc4f9c481e36df50bcbff39f5fb277b50630ab49d731fa",9.917710196779964],[9050,"d362f059d0cf00051fd002cfea841a3a4f8b620d98f23baaff8956ef280d73c4",9.917710196779964],[7475,"e085e3ce622af010fcb54f94b3f5cc718fcf23cb59211ee44e26b50ef602dfce",9.917710196779964],[5452,"35e615f4b709fc0d5d2060dd3c04c37d65678b6d82b4abda1ede81a2bb5079dc",9.317957166392093],[12011,"5591e97998a94c872abca008d183e7abb1c2b07090108448e581e2111c7e41b1",9.317957166392093],[2692,"6b419f38939730d0ac1d165e25d22fb63049ea6c066097c7a3185d1367a786ee",9.917710196779964],[11901,"81865ca6858ab480839f5dd658aa2071991a82f9b3b1363991db534eb51508b2",9.317957166392093],[18671,"e5fac35a3338103f2dfa937d4b93bacacb180d7fe97f90f3a33869466550c92b",9.647446457990116],[16938,"73d708915244dba5c9285371438c880b2c2de2709bea0aa15753489df4895153",9.647446457990116],[1034,"c4ff92f7fd74bd91c50d9e851aba2dd9cf653f266995cb7ce21f899cc22a10f9",9.917710196779964],[4032,"49cefc2c7522ddf2bdfdf11d736493d4aa14406abe249855a628a498a2698de5",9.917710196779964],[9480,"c4295df7b112fa6d30b5cb7593aa51fa835b5418edb51c571c0b34e892afcfc1",9.917710196779964],[11562,"c1b7f9228177f7260d564b2a9e3a436ddac09044953f85f0ccb33caed3a62cb4",9.917710196779964],[4557,"09a6946c2964b0fa412fad686d5e892ceaa7441a75d8ba834820fb94e684ede1",9.317957166392093],[11556,"ff0386440190b7f841a80b9010c6dc4eee55a9a8088e8f711a3c945a246032b4",9.917710196779964],[3723,"a448c47a37ac138acac5de113d12ca9515a9400143634a1ffa9a5abe744d6fe7",9.917710196779964],[1327,"4bff636ad2db328d4fe64be3ac73f4246edbfa7f4f7946966a454c3163cf3ef7",9.917710196779964],[13311,"077dca40936a060929134fbd62f2ae40b86313806ef93402d0e0383135ac65a4",9.317957166392093],[7096,"6ab0da96adffd872ebbb28c412dd571f3632ae47050a4b473851982ad02d5ed1",9.317957166392093],[14674,"53b73577064aae6ae8950fe767924cbe70e26baf39435e0c73ec911488245485",9.647446457990116],[1616,"656e122f331c29b902b3fbee8a9162aae04b8682cd8428d63f077e339d1d77f5",9.317957166392093],[5509,"7f1ccbc4a323b24c685189e03e2b1a0c183fadfe64995ac4c833b5f59f0b29dc",9.917710196779964],[14541,"3da05137b1f0708bb8bf0f413bfdcdc4476fa4056b4b1885a2ecfb2dd8b35588",9.317957166392093],[1824,"3abb797f2a79107da915d1e324200013df82b90e2301a26b643d6ff7c70a13f4",9.917710196779964],[18201,"393595c3ba3804bdde13ca7f9199d94a6efc06cae7ab108139f1031499981838",9.317957166392093],[17963,"37ea47751dd05f7766f81ef4626d4ccd4798346902548e04a5820efda6dcdd3d",19.211881188118813],[18658,"cf84c8f4a146ac6ba6aaec99164ffa86caa56c274776a26ee04eadca82b0642c",9.317957166392093],[12080,"fd0273d1f87aae37761cc13874541f1756a6a74c3400a2226f1b90e886bed3b0",9.917710196779964],[8928,"67c6885387c9334eac50c80e8c77c84c0f7b2ab12b71b168955cfa5771f64fc5",9.317957166392093],[11931,"8bb2b7ee7e1121da156398dbccdb1131214d9dd60c791b31f72297b2ad7bcdb1",9.917710196779964],[6655,"c391360cfc1d40612e3a533cb8de09f126c943541084d582a4437e14ed1949d4",9.917710196779964],[12762,"76938f114809ecea294b2f9e1544bd118c5cc67d0e95ba454b4005bf4ee527ac",9.917710196779964],[13664,"a9169ee8672b27342ae01c93481fae86980beebba9c4bec67ad4b8e1f130f69b",25.401769911504424],[10663,"c92e48e41b8f10ae22d28e7814caf480a47f45e0eaa72e87dee5f557f6b146ba",9.917710196779964],[12333,"fb0ed7c2d8350a01c3d17a6ad024ab5891257a5144fe11d2fd4b0dff69e701af",9.917710196779964],[1159,"af558d3effde071d9388ba3e646ed7a891a7829180e343dabc100a6fefe340f8",9.917710196779964],[9277,"1509ee3816742084c36297416bd10703f0df1b00cc5e68941acf64078fdcf5c2",9.647446457990116],[2111,"70d01d76ac57c950e260f8f7653ed4b32d5efc23e29649d420372b37361f26f2",37.936094674556216],[16730,"272410e4fc6852fd939bc21b9b007b12e922744fe1252443c148dff04c49cc57",27.851590106007066],[9304,"0d2547dcf9017e08d03a23e04eb38d629abf06ed0d10dff86e7507d4b4c6cec2",9.47085201793722],[3415,"06db7f3bd0b5b6f2dc411b4f6682ae70ff25da38356a93d7526b104ddc2592e9",9.917710196779964],[7080,"0f4c94b8a2b84ec09e691dbea7d241cdfda2489cf2c6e4a7614eef59407e76d1",19.20855614973262],[7054,"f80862684ed3e3fa92ee0d4f64ffe4017d35b514bf7062de3a94fc079b78a3d1",9.917710196779964],[10669,"20fa3743b7690f376a1f067568cd1da782180c7cd1dbb8874328a3068e083dba",9.917710196779964],[12027,"c67e63ebb186dc9e140b5cc028319061d2537df4df33d3c227be4e64b5a121b1",9.317957166392093],[16780,"43e6a1673ab7863189fab0b2027abd10ce663984f43f8a0ce45125ef59fcd256",9.317957166392093],[4294,"eadfc8bc7e731177e0ddd70319b2bace7fca2f9e9d1309f87e3ce0eb5d58d0e3",9.917710196779964],[6121,"3801a96d256a9e9bcb20c167e7a31ff6c512d057afe86768452935f8cc954cd8",9.917710196779964],[10139,"02bca3ad9b236c47d3958527a65b260e6ffe16a4007c587e9396368dae8472bd",9.917710196779964],[5424,"b4262cc4c497f6b3e2c1f42142a5c15b8ff9fcd3e77e63aa3f2787d46b18a5dc",9.917710196779964],[18346,"b1bd9d1750fa823375cb38b61961ce4b1fc44fde41b1ab76087c71c4ff2ae834",9.317957166392093],[8468,"ef9c22945fd5954b541118f27e62c3b593b6f31685ad021737006876df7c37c8",9.317957166392093],[14146,"4c156f0988e10f5245bc11e5d3e27cf176870fb57dbb87bec36bfdf925419c91",10.033508207818581],[9286,"75785dc6ed8085ec0504d1ef38dda2bb30a7ec70242071c2e3cfedce6d46e9c2",9.917710196779964],[14545,"1c648b69a1c758734e6485cf3d4a33b8b04a04854e007907594b255cf25b3a88",9.317957166392093],[6089,"ce897dbc3bfccdf7d84a55ff2cc5da0c4c8115cafc473c1f8aea865e4fd572d8",9.917710196779964],[16085,"318cd39f703cebff5c90e24b1acad47a2df387d7c7685aac78ec3dfe18029d66",9.317957166392093],[976,"2ba5d77ad850527cd94d629b7290e2de1af07625c1e142ee9b15e1cbdcd958f9",19.631858407079648],[14017,"0a194d6e792525c936c115ab6f7e2f9ab1758325f47f34644715669b4e427f94",9.647446457990116],[18424,"46eead5f0a276d46917643569444d62aafe471ff2a0a3a516b839f3913e62033",9.317957166392093],[13272,"bcd15ec653cc5998ea259c64e39388834e65fbec7e232376352225908b8c30a5",9.317957166392093],[6916,"c1f38ab1fb2944fff3d4c3253ee05d6e45c33c55e7bbdc679d7e4511220d7cd2",9.317957166392093],[14879,"6157f827fe4232453e85ddf9f025e0843778747eaedc8b9c4dd196ab664b3381",9.317957166392093],[16872,"55c15d8177ae026259914ce25128aa276091b03c1ff2f66c71683368b3a4cc54",9.317957166392093],[10609,"ea1df97ba98d2d6c3a714b99b7d35e1845988900a90e9d32be35ae56cff39bba",9.917710196779964],[17614,"ec8ec5d2268cc83bca186ebc23f3db427d03e3a9361536e8c1b0e0aa61b0e944",9.317957166392093],[2406,"0bb92a17f678bc6d41f809073daf8b5fe5b0db79e46a61870e49ad5d9e7870f0",9.917710196779964],[467,"d31a673ac0b1712a8d74ac1b28769aa632a2be29a7a497d370da9ef6b399ddfc",9.917710196779964],[14164,"1561533d36bc3871336b8911ec2daada5812521cc8e21158956fd32c2f881f91",10.04594180704441],[18923,"fe54c6ed42715d59aee8e9235e6efbd8c18e8e0ad11b17c00a49e72073b2bd22",9.647446457990116],[19361,"674c819538da0c28c374652d4be1d9cb2c21604c1f9688b94723a1f081cf4e13",10.052724077328646],[1826,"b34d4afa2f682bfa585925c955024fd92c197b78ca2b6a8bd09281f2cc0d12f4",9.917710196779964],[11892,"865976fcca60d510e6facd15e8db77bfe54157634a4be3420649d379946f11b2",9.317957166392093],[15965,"60deba671f0d9c3ce5e2a940b0bdd60a5a79dafa1ad86878c348ae9d6c647b69",9.317957166392093],[9887,"ff99751c97c3d256097c0e2d5cb58d708cc84b465652f97ed0f360fb938b04bf",9.917710196779964],[19131,"ec1fefea6bfd54279cd8673fb64a9c9d474727e73c01c085b4882f931da41e1b",9.317957166392093],[7934,"ad915e2612229bd5ae105f34c423c760dbfcd9488d97a7bc6651fbc9d377fdcb",9.917710196779964],[6666,"0cb896ed7039a98e999e67204eedc459070d6930f2e6da491afb53b4445a31d4",9.917710196779964],[18367,"d7e76617e7b170230cfe09f34b2e2a95005eb398be82e19952787686089e5334",9.317957166392093],[7217,"3927b65beac6b9f22a917e5f013b6758e2da651cff32a6d48dbcfc30fdac90d0",9.917710196779964],[18403,"b8eb9ee9ee37db09332c240f798a12353d741be1b98f9a3963f26145c7145533",9.317957166392093],[6072,"24504376ff551d2d4abf4871a80320a031f810d0e52a5d6bf886734053f398d8",9.917710196779964],[5935,"cbee5292d5e6a1e723413e82c6f50e60b730fc58ef70d01e2a6e2a63408f78d9",9.317957166392093],[6175,"db6073c7ff73f41b3efdb434eac9091dfd67b4a4f77df44286ec76da8455f6d7",9.917710196779964],[7589,"191e00623ae79ccd050a4e8c6e4a8bdb453b6759ff326bea4dbf8ebe50b240ce",9.917710196779964],[18950,"01b4a1fd3a0a6b2e0748212a59450066f8a34ffe9e8f0930127aea93bdd12222",9.647446457990116],[8643,"316c4bc3e326e2b7db1dfaf20d6161030d1c9cca13ea151acd5596d35be11cc7",9.317957166392093],[4566,"c5685c984bc33b16e18e5f0ed3c4456d92b0eaf5de074b3c6c177af11710e1e1",9.917710196779964],[5289,"88f7271922c63a123731976da1f29ca1ce84167431a25bec142c7d7d049075dd",9.917710196779964],[19610,"0501586d3f2f2752e1af83bb7d60af1260782c89fc0509cefe935812ddc87509",9.317957166392093],[6953,"9c41304539d7998142bdc55a75c44b5bf61d10cc68a5bc5befc5fd344fd03ed2",9.917710196779964],[18281,"1494bb50188e83ed47107f8280b78cc2f5b61fb893001fe355489fb1d33e3c36",9.317957166392093],[3130,"0ca3c569e72f901934bb5ed644cc8c3de91a382d23c4cb5af6a7f03d75f377eb",9.917710196779964],[17543,"1dd39a9348861a23ec6eda8e175c638678004352db27033f250315412e5aa846",9.317957166392093],[12050,"ea37177848cefcd9abc351e34f0c30d93b39664b20769adb259baa64b3cdfab0",9.917710196779964],[7015,"207256d5a14d132a196b379b9a845a7cb947cbf647616fbe3a1d8fa44454e9d1",9.317957166392093],[12105,"c31c883259f0d8a6a265482ff97470f485268eae03c64c42350f8c22b0e5aeb0",9.317957166392093],[14135,"446317779226226e123c5737e368c40337f1abae820225e385aee3aef21fce91",9.317957166392093],[6688,"0f643d93a868679c89d0543362786cef601e6242430d7bb83dc7575cfbbd0ad4",9.317957166392093],[13889,"001c3355b1b4acc152687d42ae40d4f4701a18705a5e3c49abc5119c03684397",9.317957166392093],[12941,"a528d14b5aa3e4c063b09796f8cdc77800221de6d90fd11c72576ef2f6ebfcaa",9.917710196779964],[15027,"1d37345ba67349ad58c737549ed7c14f2847c3d3091a56ade66437d0b435e17d",9.317957166392093],[15706,"4c684a50d65b071b82ad61a7b4010d61b261df3ebfd7cda23b2ccdc7b5ad606f",9.317957166392093],[1156,"2f531f9b7be8b93e17867605675baf96d4e825abe2fa457f50f95fb8750844f8",9.317957166392093],[943,"8a23c6791cade666ce03698c1b554dea716bc7bc5bbc28d8e11270d0580888f9",9.317957166392093],[7601,"7529e023e2a5599a6860e26d465fee0f026092068460ff1c09a3b880e7e72dce",9.317957166392093],[11476,"b5ad34fed448a29c1159a9f44fb454e1733f080790f32ad27265dcd528d9aeb4",9.317957166392093],[12526,"3d6084b592561da0ded42f0c46565739e6d54ebd2e7be134c6f686abacdac0ad",9.917710196779964],[17230,"2babb8992cabf646823ebadb7f9f0f0ab62001aa2e692c273087f9ded7fe4e4d",10.016260162601625],[18845,"a2f56107aa4ee976939069ac0ee01b643ca10bcb1284c2c01853e86657a52325",9.317957166392093],[14573,"50e5eaa53230d399e2f67f20d7a27978b038dffd099085309eb386e0a37ca787",22.17102966841187],[18763,"d7529e44231b62365e33879274e7041933d54b32d750bc842087ce66ea302428",12.086330935251798],[4952,"79e98b56ab8daec5dc27919fa5b0e685495d5d35d8e1b7f92488bfc23eb087df",9.317957166392093],[759,"62b2d315b4d2fd9729389e2c47ec7a40fa7ae4f60ec134f37af82114e363d1fa",9.317957166392093],[721,"7c05d9db6311dd7cd84121bfd05a02a5b526aa8d6dc7b892ebf67554637e13fb",9.917710196779964],[16316,"78142070bab16110c84b88da1fa3ac399961193e83c662cc7aa2daa2b7b0a660",25.356890459363957],[14465,"d16653468ecd20e8d500de261613556dfeffe019ce2c45c9affa9914eafcfd89",9.317957166392093],[4918,"39e5c86928fae77397f4cc4ab9ae3fb05ea2584376bd52f349c03eb54e7cc0df",9.917710196779964],[7196,"51df89d61539d68288362760b61c0e6afa2c321fb4ee83d53e53c9d5971bbcd0",9.917710196779964],[7899,"a2428668183b3307012cd012bd87ad69835c473a616eb4712af028d27c173ecc",9.917710196779964],[17865,"86b5670b1615162cb5324feb4d5232184197bc79970b9109724dee6d3031df3f",9.647446457990116],[996,"0cbeec46987f75767a92764c60888ec8ad0265cebf12b8dd4f3963d111cf42f9",9.917710196779964],[16704,"fb6d2056949cffb32c48d53b369243819267490c0542668862fbb03007657358",9.317957166392093],[1779,"9a568f77cb4fab4eddc4de65884b8ea4163d51f5bf2d61be08c956a057015ff4",9.917710196779964],[14098,"9e7d54d92cae9871768d65ae0d7f083f9a0104b7108867cfe4f33b6147c49892",9.66349670811997],[3923,"5d63ea25fc6e31a660eb787d8ed49e17a5a3c2e163d36e7005b7efbd25b730e6",9.917710196779964],[5066,"a94eeba863dfad24514ebca924071991db521777118039dec779c5adb7d9bcde",9.917710196779964],[5968,"12d3fe0f4046d7cfaf951a2aacb9c35fc9a885c449a741dcbeca4621369b4ed9",9.917710196779964],[13200,"28d6d7de9eea920631366baaf66c676ef39f7828eb90310f982fd94c553ce5a6",9.317957166392093],[8091,"c47570383eb580029936d824fef3ed299ac39113875245449db65f6bef0ed3ca",9.917710196779964],[18627,"aa519434d2e6688dd2da3330352402ed530a695949996df35a9847fd0522d62d",9.647446457990116],[4706,"34e00be9b04b19c3d9107d2b28a516f16a5081ba35d682b62a74d356306ef7e0",9.917710196779964],[6070,"0c22cb3264a2115d0d70b34bddcdc198e0af7cfca60b1a57b29458f658ff9cd8",9.317957166392093],[1445,"5dd1ff40010f38e099becfb72916afbbee7f15c941e2615d02beca394d0789f6",9.917710196779964],[14572,"34ce700e6d9cbd3120154ef0ed3a3499c4a735bd902fd8caef595619ab2eae87",9.317957166392093],[18958,"2801e8df6a1f027e14fcc9edb2dff5570b8b50b70a2de5cd924faec49a30d421",17.046062407132244],[9929,"4dccb34de213135400d968c727b68c77a0d29c1b31f615c8de9e5f23c479c5be",9.917710196779964],[3755,"6de54851b320418d9b2806e2eb153bc645993a8702aba43283bcdc6e527939e7",9.917710196779964],[17379,"4a1edd380a07bb9f0b23f2907ba11cefe8ba4e12509f735ab76bd17a0ea2374a",10.052724077328646],[4660,"36d20dc124820964344411eb94c886c28b8867397f5ed1d9ebd20bb3cb673ae1",9.317957166392093],[2580,"65c04652cfc283fa650095758998427d7972ed47b343eecd918ce5df0fa150ef",9.917710196779964],[18925,"2c327ea6b9070842cf2f974e65d18e2f11c3877e630cbac6041f1a49ddc7af22",9.647446457990116],[11443,"9455302210ff7389b25af6adc0b4ec40030a175b97dff6e0bd1197f43e01feb4",9.917710196779964],[7663,"70c149fbd8ea3b39b485b93399a378bb9ceaaa27ae36f6e458deebfc6fcbd3cd",9.317957166392093],[9445,"0613278b7fcdd24f5fee84f65d4a8194e65546546fc89d77ff31ad14833c08c2",9.917710196779964],[13707,"2418a7cf018250327ef33605c0eb08d21ffd763cdaa3c927e1d881046370349b",9.317957166392093],[19107,"7d94672207e3e9d26d769071b930cc068b33ae94df166aadaf9ffc1e62d6611c",9.647446457990116],[11166,"d103a796fe9ffa48365eb38e74dba51b3bc9f8ef61f777c6e1881ccb7b35e5b6",9.917710196779964],[8364,"fb2591b92856049cc2e114e1e3c42bd5ff837afec9f3c6d503f40ccc1784e0c8",9.917710196779964],[2635,"14887a2be9bca004576bb0a326e38d9d1fca7a3500a41e6e6235ca985759f1ee",9.333333333333334],[3131,"0d55a346b72ebba87c76794f526f90f425c8dcb3d0176abf11985e0bd3be77eb",9.917710196779964],[7443,"4d0a5588582fcb4bded0fd19bca66b6b30bccae4ccb12ccdd64ab8aecd0d1fcf",9.917710196779964],[7750,"57f3e4447f6ed534a022cebbe8e2aed712d04fb94132684508c10fea210922cd",9.917710196779964],[5806,"8c8bcb6833532323629ac3dcaf6755f893b60af6e91b319a1e0683352dd459da",9.917710196779964],[14035,"9e355701714e1522bb6898952258bfec85dfcfb77e5c6d623fb8c8455937fd93",9.317957166392093],[8558,"a8af06b79843a1ace810e566387efa3028878b935ba46a957acd1b523cb7a9c7",9.317957166392093],[1152,"570ad5911f271c70178fc2a384bb63ba5c53b0bb698aa121b732a9b8bfe148f8",9.917710196779964],[18486,"6761387bafa69f58a6e7add22c71ffd964de9f14992ea5e9c70456be3d1bb331",9.654676258992806],[4469,"cb02493788715efd3209aeca12b3b7ac662ec92849f0b8a24ced9fffd5219ce2",9.917710196779964],[14324,"682837a48eacfffe7296ee465d34086eb7c3b15aeee273895fda79a8c064ef8c",9.317957166392093],[11774,"eb09f4345a44f512f72222d12fac7397228a46b726177529ac0db9d93b76deb2",9.917710196779964],[9451,"95eb7a8bb29a6ee24649d7a6c3ecac0313120cf27c5f52bc1beac2786ec202c2",9.917710196779964],[9010,"37216cfd168d7703509f9b1b8b6174b838bb8d7c748c03ef879b00e77e1cbec4",9.917710196779964],[18129,"2f7a4812baec43e5bd332f6b166c2de35ba8f65acbc852260061902ffdcc3e3a",9.317957166392093],[10207,"12a21335a3ca05eadc0e67b8f9f269fa4e65d531a8c95da4b32a2d4c17c3eebc",9.917710196779964],[5435,"12396bed9cac7d7eaca67a886dcab25eada247923a335311bdd3c00ebcb090dc",9.917710196779964],[6518,"c62fc68b1c5d5a98f9e21fcaeb5b5520583356ed6a6333538b2e29bd01d847d5",9.917710196779964],[17595,"9fc801ea34df402b86dd11d1cb7ff140ce93b5f036e3e7491adfbf316b054945",9.317957166392093],[1574,"3a66c5f5e55a0b5bbed83eea10648b94ad6f1b370f7de4ac5d6c3cf69de4adf5",9.317957166392093],[18662,"590c50b7ad7da94d07e56f86e265e267e293af8d1e393d8f94eb45a0de29312c",9.317957166392093],[3246,"818421c4a349ec198cc1d7a595fa177cf9a388c0b02f0988a566e406dbc8b2ea",9.917710196779964],[220,"815887d0efa24291b7da766af44fdfe1cd098f8e2a9ddad8a655a40ce1fb83fe",9.917710196779964],[1737,"6d68c2f6d5d345d2b09804cc45f70a8749af41c5a7925f11c517fcfbeb3badf4",9.917710196779964],[5958,"0559eaf2ba947f1d065cdb4e414269a0ca301f98208cbe74c78c1f9ca1a15cd9",9.317957166392093],[11794,"b4e2135d974084127a4a3fffc7a83e379a2e0ac8078ab23228853b044370c3b2",9.917710196779964],[12076,"d993b88448bbf270b6e5f60feea42896de4c9b89744f17fe9b326a1a2d87d6b0",9.917710196779964],[13229,"54f0cb1ba13e322c0f13d7abb57355698ee0b62b541dc5f3a709b4d50b1a56a6",9.317957166392093],[9911,"da0dbe03ef3871fb3c49f89a98c4bc408a853e2c9612d2f11757ae120292e1be",9.917710196779964],[1448,"a9047bc5fa5379ecd0a813a1f514a4bf5eb88ca97a106dd304249eed729c81f6",9.917710196779964],[375,"15272873fe6067a019f4fc5cf74e1320a5e2de805d13225e18e0665c051188fd",9.917710196779964],[546,"c15ed78561e63f4582b74af28fbaaa18efda8f969d1d065f6bdbba71e8d14ffc",9.917710196779964],[7361,"0d3e5ef8284749b576d91b7b0b159b137916e1a5b5143b4831a5a865533ea8cf",9.917710196779964],[4051,"90aeb90be693ff3df0c5b1c86c3749c222b87a4b92103c11e1076828f89e6ee5",27.900591715976333],[17942,"0afee8871909bb410c0847d5c9c2ea37c90bf57d305e18ae73cfb12e70a75b3e",9.647446457990116],[19785,"fbb10e2afb433c059d4eb5581a653bbe0381ae8dcbe5835c0ff221a26fa44703",9.647446457990116],[296,"fff5794886c2d3768f352c75a1fbe6346fc7d5486dae3ad564a870e8af3afffd",9.917710196779964],[9571,"5adddecc31b5944ccc9ccbfec497834ff7a4f6f352a8a19afed16e6bfb102fc1",9.917710196779964],[3474,"6707cbbebac1c92c0f674df4068145080894bf395b25da4d353d2580856c33e9",9.917710196779964],[16788,"265170b2ff8f7f83c73dc8ec8b70d66fa4b25d202f434efdeed70cde26c59956",9.317957166392093],[14962,"7cf543ec46563903d414876a7052f7dfc9894804237a2e609de3502b4e9c637f",9.317957166392093],[5799,"911f10c3a6ae54a795d0ce25fbf03bccf845806bf380bfe2589e90b20b9671da",9.917710196779964],[173,"ac424188d9776cd092d94e3dc24b9d2619d34ef6b9dc0a55e3b7df850af5d6fe",9.317957166392093],[147,"091d7a4e38042a9b078d15adc8c0548dfd8ccec9936683cecf0f462e115efefe",9.917710196779964],[4138,"ccc5ae156d77b97191870807c86c515145b64820cd904947d49d89e191eacee4",9.317957166392093],[15956,"8207760fb2765d0d215d939be7f6d502a2e281ded09db9dd5e87ec3a846ed569",9.317957166392093],[7682,"6b0178304aa07d5956291f9dee3aeaf5fc2c41be146fa6e449cd362a261bb2cd",9.317957166392093],[7987,"9710a2860bbd595fa8ebaf676db2b0fc878f37e8b557a30bd32c6af1ada998cb",9.917710196779964],[14566,"d5c4d19c070b05e8c0f16cb730a175ea6bdd73bad2d607263eb4ce29f601ce87",9.317957166392093],[15375,"03ed1ce3bc9db95655c4f3013e200a363a4bf229a03a1a23ab1c8e669de5dd76",25.92170818505338],[14721,"fa92be5e7abf40945256d01c4b95eb8d614fff12125759c505051c27636a8484",9.317957166392093],[105,"3c3f8bb8f2efb0df1de362ced474caffacf54c37275ad72d730a732d16c257ff",9.917710196779964],[16592,"057e4f97d96296f72f7f65e022a26e984e7c88b2185c8e12aecfd3801d091c5b",9.317957166392093],[16330,"73d034ffc1481defbd35ade0eed534ecac5e4b6390c5646aed85ed9687ff6560",9.317957166392093],[10171,"97f4cb7f0f256a57fba878b4f880e5f1ef0315b4c6b209794842606021bc47bd",9.917710196779964],[1154,"2c5e81e228dcc6150d2a4b0bb621cbc9f53ca988daae5c759ab47bc70e3547f8",9.917710196779964],[16244,"3d7b0e3dac6ddba98856b178172ddfd5e49843682a6f056fac2040cabf789962",9.317957166392093],[7779,"9985351ffdd6b9caf0e2957e2586010f8568c961411d87065d2511b9a986f2cc",9.917710196779964],[297,"a725b2d184ad1322facc8a8b11c8e87beb87a64f2ff4e75944c9f2b0a62dfefd",9.917710196779964],[14413,"ad9fb568d3110b26e8f4731747a5332e9a3bf7c84225f80ac09c29d28a7a238b",9.317957166392093],[18591,"7bcc9c44ff1336fe8dc2a5e126562fdc791d08a56b0438cee76f1db34d1a0e2f",9.647446457990116],[1080,"de4455d97ce599bd06f31b3b838fd5f66c152ca0e4078c5d39fe84a64f2ab7f8",9.317957166392093],[7684,"1ebbb29a1d3d326a39df281cba540e261074295e246248f0e2a74c55158eb0cd",9.317957166392093],[8336,"2cf178b88ca01407e093c5d3f17697eacd02042f2c129e61f1fa81bcd71a18c9",9.917710196779964],[5902,"3fb5cf2d753cada3c596103c9c03609af0a65c6a2994ccf59c0c5bba20b7afd9",9.917710196779964],[17773,"99043d0c23397612cdfd256d13b82380df9c6d169a6030ea2d6d2d7224c6d841",9.317957166392093],[1533,"32686693895c533c0d73fcf875f2735c3b54f13d754444bf2af7135f71c1ebf5",10.052724077328646],[5778,"83443f0c91ec3843db2280410aceb5cff3bd3d27e37a83afb1c7b3f873dd93da",9.917710196779964],[2609,"2ea95d78b53383c7cf9570b4328666eb454c1334273ef10c683350b13d431aef",9.917710196779964],[18805,"c7d13697298474dcc9f8dd3f015f925bd3c243f7b1da9284fd02628192a5d326",10.052724077328646],[13148,"7fee0fd415864667701c766f4d1cada2b2523d96733f71613df0008cb92a09a8",9.317957166392093],[5094,"7415c6d58c773d14df518d95eccaef51037969fc407d6060fdb7606375979ede",9.917710196779964],[8486,"157069c7a0a5d1fc99801a75170290b8f96875a5035b20989526ea68d33e18c8",9.917710196779964],[14697,"e0060e52f1e6078b699db06a00137e88564ba733ce9123b3403715e96160ed84",9.317957166392093],[17917,"4ad17943fc057293e2ed992cc85507776a55801eec3fa37af94d717dff10f13e",9.317957166392093],[18293,"904ed3a494e487c7daf0c4aa4b80a7069d8585d68cd02c65262866fd579af735",9.317957166392093],[10306,"e23a0e14ea92a6dacbab8db0d62b7858f9d8af0d00c3695ab8e26ad8789851bc",9.917710196779964],[7337,"51b0e0e44a58d941bd37d040e14d2b0214b3182ce72d316000b2b2b2f29ccecf",9.917710196779964],[10056,"35805250325b2f4da13f02ff345511ce9d7510843540854cf90ecd951f0202be",9.317957166392093],[6664,"1baa120cd98fa73a78e04535a1b23ca86d169e379bc305420fc933486a5f34d4",10.052724077328646],[9950,"921493178c149d7a8a5f5115a9d22fb7c7b2e9c08a71be40a1eee000a6cc9ebe",20.07662835249042],[4426,"77b0dd7b4b9b3f309840581ece1a89a8d34e80c116405c258cc7c25deff7e8e2",9.917710196779964],[17097,"c7a3d1f5e20f7983976ac1023d4bb1edba207c28012148db17aef62e62150650",9.317957166392093],[5327,"de6b988eafadf3b46bda2fe40c9755c06cbdf795912af85e7c055d4694fc43dd",9.917710196779964],[17209,"9e22be69efde659dc224678e5f8c60442d2cf4065a74493647d62d2681c79f4d",9.317957166392093],[483,"15f177989fa506a5e8ff02c06822d72a0d96330d7d490f763fd1099f5bbbc1fc",9.917710196779964],[19263,"e1d07893e5aef6eab9c8bce111af13d29cd0ac97ec6da3c7765629f15c703516",9.317957166392093],[12262,"66413d3b4bcb4ddb9c7ef2d4d0283341fb7252e1bc54134c8947472ad4e99caf",9.317957166392093],[14327,"e37217f3a4eb81295c0f0558612b3957cbd2bb662d9c33169da05f0651dae88c",9.317957166392093],[7671,"a6e91e92b3120af2e3c6b81a94e905b4f6c7ff74ab5607eacb1eac83d5ddc7cd",9.917710196779964],[12265,"28fbdd0fb500f4748e54551beda5728c77b567adadfdc3770aaf72f3345d95af",9.338112305854242],[15850,"09db06746ed5900065e2a7c908dfcd5c8ac3288c455ba69fb08be93775cf2a6c",9.317957166392093],[8443,"3604a49dc1249585b76ee4406d203f979e8550f0d095964c21a3ddd1e4175cc8",9.917710196779964],[9109,"f3e8f7195371774bd6a84e26e940066504a8ed92c03ddfc8e71a940e2ebe15c4",9.917710196779964],[16130,"89eed669689d7fb0c16585f376be9c05243c8aefbb7beff1f640f12996716565",9.317957166392093],[6179,"c11a8dbf80382c4d61f23445fe7d7ef38a4a9ffab6a47ba33fdec3ecd982eed7",9.317957166392093],[2499,"d34ef6715fe1bf2f9fb3ede1d784464f2df90f0cdbb745d6ed714e7800d4d8ef",9.917710196779964],[8576,"637089b45a6908978f58a71db556885dbdd39747856e4e0df20cbbf6e4b996c7",9.917710196779964],[3420,"a142c648a1519fdbf5add7e31072c7bb2bbc3276d4a145afc1e1c2952d6686e9",9.917710196779964],[4585,"ba044978aac356aa5b77ec5bae3dfc30eac17272fa30b5f4d73060198f9db4e1",9.917710196779964],[13290,"80a8d3c5d767e24265d9da0aff006e5b417dc409a743cf25696a646254b6cba4",9.317957166392093],[18298,"fff7594294e825fc112b0603d10d80d771e338d3250a9a27a6cc85ba054dde35",9.317957166392093],[2792,"51391a48c41ae431a540340b485d5bcd3da91a445a607ccc6f941d4368edc5ed",9.917710196779964],[15386,"272585b599d8e3a1666cb6f66949af317484d0adfdb0e2b019a10ddfd53a8e76",9.317957166392093],[4083,"cc71d8e1612da8692570a2ca69183f94c2e4c2d4ea47e5a2b04ac13940c82de5",9.917710196779964],[16265,"18a3f76ff60bc80234d35050dcc06c4e2e578687f20742c1a704cc159027fc61",9.317957166392093],[4517,"da5a539b6b63956c6bed3483ec219fb1ad3238ebf167865aca21b2cf07ac3de2",9.917710196779964],[5378,"7ff091b3089122fc841499f88fcada60669e3ca03b4ef8b7cb03041c226ff7dc",9.317957166392093],[6616,"a2227c8b0a36bb3b7ce23753f0d22ae7b09606ee847fb4b5ccd902304ce987d4",9.317957166392093],[13749,"fab344536ab79775ef1a4d8892e84c8e3fdcb448e13dcade71832df8cdf1759a",9.317957166392093],[16589,"428c41610b8b57c6905781896bf67979a7e1c8fb2d497c0264d08c896826265b",9.317957166392093],[3094,"ec7d7dc08943da7a32d9241e796620649cc1baa0db1a61ffdaa283343ea8adeb",9.917710196779964],[9311,"ef701989aad9b086594ec134656e3949448dea5f7f5de7ef3ca781edc6dacbc2",9.917710196779964],[12017,"aca7cde6b70e36e113a3c095d1db10cdc7d9af1f27c8c12f5341e94abd273ab1",9.917710196779964],[19581,"33a6ad95ba09e27152ce8feb9f39856ff4b6e25e0482a23b61e2b3146f33010b",9.904761904761905],[157,"c58a151059a290d42da98a2b7062aafd5bb689da8818839cd2e5c6409381f0fe",9.317957166392093],[4212,"48d8f53cf9c618c4dee4485492ec156977ea4833f0fe84f1bbfec653fe405de4",9.917710196779964],[18327,"59c55bbf4d7057e09752aad95e6f5fac3c8168776db66f09eb8a4df9859e5335",9.317957166392093],[18369,"79a4a383caf45975f27a5fa57a92752856353183973029264884a8280e564c34",39.76265270506108],[2414,"53f6e03237cd09c21f4d79786c57eca063df9b96b446c6574ae1c8e52bf65ef0",9.917710196779964],[1789,"e4441dcaf4343f87dae901598f17bb1d33d96b4348747586bd55e94db81e51f4",9.917710196779964],[18266,"efd3001a8bb1a4b169e964cbde18e9c151bc07920a1e9671a6a8dee632d79c36",25.130890052356023],[9273,"529a4ee4f2acc7b9c3553256a9a76097f0074a1ef7699693be1060505941fdc2",9.917710196779964],[6794,"a48b3b92c2d94b287656d38279253c6b6befccb99bdbe708e18a8909b31753d3",9.917710196779964],[8689,"e42b8723d0ee834eafb4361da06ae65bd80b1f65a9e7e995c0fb260dae9cbdc6",9.317957166392093],[15621,"9684fd21d256cb9866271843db269551551ad945a70efebbfc3ec3b1f10bf070",9.317957166392093],[10172,"505582998e07edea1052e9b739772c28d73c1ce3dfa4084f0b73342889c441bd",19.0727969348659],[1430,"9301359458edafedb045456bb6d9c2a7f7497131212e62615fea86f5125ba5f6",9.647446457990116],[9426,"717626aae208c1f237ad05c0260bbea6f184cefb6fb447e036d0836ffbc42cc2",9.917710196779964],[8258,"24de35a577643f8c0ea729e3ef975538f0975de309c34de1332c75106b869ac9",9.917710196779964],[19539,"9404b14f09e6f6c08a1c7bf4cea1fd25288a35debb0390055cae6bffdbcd230d",9.317957166392093],[16468,"ab5231f94020a50008396d0b9438acc017c33d9eaaec7346b57aefd080f3ea5d",9.317957166392093],[6667,"18a5fc44ad1030a5924126ddbc93d76238ef3c31345c3cf453fd4d15775a2fd4",9.917710196779964],[10567,"3df2a00e1004061dd9ae9cb5c0e01d74173be08b7c3a43bfd6f82ac2c429c9ba",9.317957166392093],[4552,"745a0edf3c312c429733b719fc72aca508594deaaaacb2390f5f5aa10a66fbe1",9.317957166392093],[6421,"42480f64a6f8a48938cfaa775393c42e4fb75abc797d245811cff348548228d6",9.917710196779964],[18528,"b34cd1e650bf14886d333839b7c7f0bb8c816cf51e95be2117161d38b8bfe430",9.317957166392093],[13829,"3def8f90553fd2128d3967e39373b34b9ce7b5d8bb607f4251dcf3fb1d06c498",27.144385026737968],[5382,"c0e07cbd2e8324568cf5f44295a3c9707050ba090499ceaaf7257ea1a275f1dc",9.917710196779964],[19335,"562f432c9946108a8fd26a303ca092526f18bbddddaa37a3321f3c5cec3d0d14",22.174688057041],[12022,"7b5a35e458cf806c90caad777cddd1634093c964b88cae6b952d595cfa9631b1",9.917710196779964],[15238,"c891e2163fb73636c81ef72f7aa75530a983d3d842d74d59f247ed29a486b979",9.317957166392093],[2896,"5ab405019cf2d1381692a308c535df5e24198a52e2841404047fb4a09beb2aed",35.89380530973451],[12948,"5271363c3f7012e1d08859d41c805c9c3181fb5d7b3bbbba6939cdf5d32becaa",9.917710196779964],[8215,"4c23fd750e7fa6a1dc1943521cae3ac191da331e3da3c84da19a17162e37e0c9",9.317957166392093],[8658,"c541db41913e0c5365764eef06f2c021b64fac13900db4d15b97e2c19a7bf9c6",9.317957166392093],[15920,"a0e494eb4d324f612f23ade720def9d35b472580501f1c2fed3235859c73b46a",9.317957166392093],[3673,"6bb2ca27b48f2b99a196539a3f8d0e00fb085f1d6f42574331f4950e7b6bc7e7",9.917710196779964],[18882,"e2c04a6d51f4683dc095cb25ff17f4bf671ffc1bce1db948a8bb1cba32bf0124",9.647446457990116],[4197,"641a279140ad620ce8cf477225bded1b48ed74dffaad9b33409a29292ed470e4",9.317957166392093],[2108,"c585c6a7d9cb0c03268075d3737e92185b8143c1d12916a8512e3a63f24b31f2",9.917710196779964],[10407,"e7142cf132ab544d1b18c50d21b23bdbb806405bceb06b1342aa73d12aa7c4bb",9.917710196779964],[4923,"ea5deb57dba67d53c3742e86ebfb613269a5fa20c7de8a852c33682342dcb8df",9.917710196779964],[6912,"b569836639cd6f473b1be8026976decf8f8a3d1a739a21823a01cc223db17dd2",9.917710196779964],[938,"541044c1ca2a5ea487784314043acd92c57a33532067bbe1dea9f75a08d794f9",9.917710196779964],[14315,"1d8efdc9f1fe6be2f20cfe965014b8d2e82519ac491ebd7eb6f1bcfe5403408d",9.317957166392093],[3414,"ef61c12ff143791fb7ffae42532596aac6c87a17819a35251fea08ecf73a94e9",9.917710196779964],[1262,"9d913037a8371243600deeaaff2f1281349274840e4aff17e274f10a5f9f94f7",9.917710196779964],[17520,"93e4292a9a029e49e4cf7a33ecd705754f0ecc6342dbdd4ffa4d0b0412d22647",9.317957166392093],[12942,"ce446fc37dfa5a78b4b879536bc439375612edec7e11b8b04ddcca496dcefcaa",9.917710196779964],[930,"b4be727d3729c6cea1bcce14802e052bca7dba1b8e04a9729743dbcab80aa4f9",9.317957166392093],[4405,"be2d7ffc125c369a625c9362ce1142bbb01759b9ca1332dc06f27e9786150ae3",9.317957166392093],[2621,"a7a1c7a2e5e3dba6a394e025cb1d1cc17cbfd667e858fe40c4bd22eadaeb0def",10.052724077328646],[1683,"00029a626c8ea6f339ffeb935d3c37c494b510178e6bcce079e8c952e01008f5",9.917710196779964],[11572,"b543e0dbaa21716e9f541ebbf8cc7c6afa5117237088d404c12323782f5c1eb4",9.917710196779964],[12244,"06422dfbfe4fd6bdc4392676ce7094cd089209af161b7c9f6c45f02abdebb9af",9.917710196779964],[13759,"f120f2a5108f4dbbdce7748e88057528c6a0dde6f08bf8bb67b7ab4a23c71f9a",9.317957166392093],[17382,"4e8bd9361af83bbbfc319b3acd21eddcb39321c55d0f725416ae16fc8b30294a",9.317957166392093],[7407,"063e20fe8a1a632545171a8918f7a93b565a70a9efc138fc09713526fcc75dcf",9.917710196779964],[10928,"22250a35ada9d0f171260391c7359ce0cd7a74de47ce98c44dea45da220e85b8",9.917710196779964],[16433,"bd23a895f85e86625c540e9b2689d2d2a2664f42558ca8300c2d26ef3cd0775e",9.647446457990116],[2574,"1d76d241b4f16202bf8ff87be79f3701212a38965357a598c327620d77405eef",9.917710196779964],[14005,"b24e6b60598abdc5b19b301be0e4da6b6a0759557ce7c73e97c956fb2482ac94",9.317957166392093],[9492,"05247899bbf666b5f149d90947e4c513ca14fd35846122f4c997c5323fb6b7c1",9.865470852017937],[7243,"758c1350d74afc6a40bfe13e060f578da3142a34f3d5e054ceff1e7f03f26dd0",9.317957166392093],[1775,"f6cc6a193faed5124deb87332a00293cdabcc40482a0cf2831c0ed3a49a869f4",9.917710196779964],[4189,"5384e231e904e29a429c6021356282423b132eeae28b63f75266be79e6c67ae4",9.917710196779964],[15847,"f4979b165a0709439f0be4b118c8b4bd255700cab00198982f856cd6f1b1556c",9.317957166392093],[17972,"91ec7d4e5fdcdd9fe4b7f3a4ffbfbab94dd12098dcc6ca3c3890a3cd22ecba3d",10.052724077328646],[8971,"e1850b55a2e5d66c079f91c16c72aa586ccad34261d51e5899b95cb36ed9fec4",9.917710196779964],[13832,"a2774d4b9a808cb8e673eed7b5d4d395b45cfad84781344c7da2c5d1dcd3a498",9.47845804988662],[6934,"fa223a8ac7b5bb802a05cff3b7545284ffc9e6d4cc5c6d69946ce81fa38c68d2",9.917710196779964],[2239,"8327514fc44355a1a65199a0727216e6855f5df7e08f0e94b804f87f303e4ff1",9.317957166392093],[10349,"79bdfc6ca3fc381685bfaab7535b5890317e98af1cd4de8c6a9fd8c0b7b10abc",9.917710196779964],[4116,"9ae91232d572bb23c7f5d1935eb8eef185ceab406f916bc2df6c714499ecf2e4",9.917710196779964],[9549,"2e29a890186c1588bf4ab6134b2eb5cc01e8d8955cb1834429f1c4d3f9e365c1",9.917710196779964],[12025,"91d98f7975a30de4bfa63309dbf21901226668143a4579070cdf34f5dea827b1",9.317957166392093],[2476,"7b01553352488c6a5eae3e66881edff9b2d230fcc7ef4d9d43da190b05cf05f0",9.917710196779964],[17824,"1b2af1f3c577bf888d244a7e083792f89bdd2980dc8c5b11978b65e33bb3cb40",9.317957166392093],[884,"3998a3f5585f257a99b430026ff1d636c6dede573fe487d575170d41cea900fa",9.917710196779964],[4225,"de626ee6cb585d8e04d30322ce6618b7cdf9a8415399b9d392025689777641e4",9.317957166392093],[2020,"d0c95b2b4017b969d926c28574c5faa6fee2d610ffeb16ce6eeadf43e8dad2f2",9.917710196779964],[3472,"02dbffdde243626956d3c55420ef3fc8d2e394597fc02e6738011f580b0d37e9",9.917710196779964],[199,"67a135ad01a92353d779f0d6bf98cd48333556dc3d02991cee685db632fca7fe",9.317957166392093],[19740,"5557bdafb403dff28374dd864de50ae66cf06db081929c34025fc23a30c46305",91.48727984344423],[17192,"d7b33e7c7305fc063e7dd8d75565728de4209ed33216bc07437ab2e8626ce24d",15.943362831858407],[8970,"52318804e92195d614b3e939b1ec583bef6a6ff5bfa7071db3506b71c61603c5",9.917710196779964],[9935,"b5e9b8a2b88927171d9f9a9c403e7874c0d9a7c443f3ed7229f9aa3fbebbbfbe",9.317957166392093],[748,"672cfce8b96da5e93dcdccc58c02c471d805033cb95e118707dddfe3a5c1e8fa",9.917710196779964],[6551,"a04459c29db45aee66cf34fbaff116e2132ecaa66fe9542d3506e67479ce01d5",9.317957166392093],[9238,"8bf5e3653c943247265136a0ac964a621ab50e92ed66debbe9617f982ebe32c3",9.917710196779964],[13596,"e719ad2ca9feef462208767eb2f106a70e4f68f5c4533fe51c40f8a57f83919d",9.317957166392093],[17246,"1834c3c6abde7afc093dc83f29bd56f91ddd325a9847c53b9e8fdffb69b9074d",25.401769911504424],[1855,"6a39bf709401779525e46fd663658cf51e828cfb68c0f323c2d02eee215feaf3",9.317957166392093],[503,"51623b52dfaf226892e9c9de18186f2d551a68a9460ef4cc7c66d06d01bda9fc",9.917710196779964],[9003,"227c91f799b8020627b36324541c247f9936042ea7dc0e2bb2afd88287b9c6c4",9.917710196779964],[737,"428d17ddf52a0f688b18d9b5113474c2e888f20bc49191b4d6960b3f3fcb01fb",9.917710196779964],[11559,"023d085944d4b16d687414324070d678ee5e9ab4f0f00c9aa6b952302bce31b4",9.917710196779964],[4698,"d0740c547891c0e0554d82c23e19f877370092b13083de02dff395b5d2b701e1",9.917710196779964],[1285,"3d0a353e073b2412089f287f021be05d9acbc202b81a088745b4e8568ada74f7",9.917710196779964],[5972,"55b2cf4f54889bb5e3683b462c61ade3e735bb1fb50b59369b98d335a6bd49d9",9.917710196779964],[9881,"a6e075da9d18074cb5bc97b8bab174ed0a62b0c6524226fbf5777e951e8911bf",9.917710196779964],[3715,"c6cf1b2e4210ba6699d6c1646eb7d86dc5af38511333d6f62a98a74eb86281e7",9.317957166392093],[1071,"caab1c8c6133dae011b28e2a83f0d1a8f7e4f2e08ab66eb063ad9c24264bc4f8",9.917710196779964],[8067,"4200ea9eeca290eeadf903cad8eb437b3cd18a1f7a842b80ce5a9505ec84fdca",9.917710196779964],[15186,"304ddb1d3b676676fd6143a743d882fbb9894f5dfd92fd5b0074beaf3301c77a",9.317957166392093],[5843,"868d17ed78aa6fe603c40bdd7db323b3184c200472cea2c801df3613f35b09da",9.917710196779964],[10849,"a7ca26ec77aafcbb79d36e8b5914577309d94f86ec97a2a2131168149f9903b9",9.917710196779964],[695,"22d04de7f616e83e9c4d62a07a591234c2b9397b2639276598c03bfd40c944fb",9.549738219895287],[10324,"e6f2ea3e237f2c223949af6ddea9bd1913791cdfa0166ce787286b05ddd22fbc",9.917710196779964],[5433,"30eb83553671a8763464f2d3172ce5d0bba30739e4102a96252a83bcf34893dc",9.917710196779964],[9643,"9ef659c41594f06f0d113a09391ce0921066cda9357986b045ef8914ca28bfc0",9.917710196779964],[294,"385a9f94b992d58bc95be48c982e6aeaed3e11130d71315235785affc12c00fe",9.917710196779964],[11113,"bc389851e4871ce73ec150f8a0614a53291acb6384d5d26dc4af7321cf1130b7",9.917710196779964],[5117,"b4a16e5652c0637ebb553262a7be195176b2e96fed31cd80cc29101a0b3c7ade",9.917710196779964],[18895,"e3b1e26cc7884db2c95dacb287e24c703d2be994bdc3ce4237ca9d850a729d23",9.317957166392093],[17410,"a5af6d8c6a06c1d2e62f58badbae6cc6f56747c37540026862ad677425529d49",10.052724077328646],[9448,"e9652a8fca139745882bb44e6075a5f528f8908350f62583e7ca4d7d8a6806c2",9.917710196779964],[19744,"bd079d29315cbd890ee221fd0511d40b6fa11e84f62a960a5eddc301d7c81a05",18.136216216216216],[3191,"263c6e12e7e3b422bc78c87d53548a7fc4d1bcfa4ce233ed4a521ed13bbb16eb",9.917710196779964],[2714,"4ffcc7e0236da75c3c713f92f7b53f68aae6e0da3446e6984a92b886b72557ee",9.917710196779964],[10436,"eca24153b30d469ab4778846284f61b58438c76439b24d510ed7349864a093bb",9.917710196779964],[3026,"0f665aa346c1af7892f9fa69244b27ee300f41c252301e4f32a8011151ae1cec",9.917710196779964],[2333,"8877a9b0e741d3d8bed1eafc7a738692417a7002429cc23f6cb51f6bab15d5f0",9.917710196779964],[1324,"ddc39c8e36242f23c8eb5573a024c09073306111d062594d7fa82f2764b640f7",9.917710196779964],[18177,"7e2b3cf33479b1d3a2e377a0477848945ca2c4f2669e2c2fd0e3eb1f2f4bc338",10.052724077328646],[11540,"d43af20969150954a433654e44e8cad9d36aec911aa4906324d4d34a2f5d4ab4",9.647446457990116],[7617,"1d992f91e85baf06d22a3b5fe001e6d1d6d2066ff59b3cb0ac12d689674e1cce",9.917710196779964],[12356,"0a89d871e84421cbb7c8578cd9bae4c644800c9a7918c85087962b2ca5a2e2ae",9.917710196779964],[7968,"cc2528837cac3fbe9a2f92e33aff8c73cf0c888987577f7c56021665cce3c4cb",9.917710196779964],[5547,"d4560b9d23f0496a6a8f38ee2468b3caf296e014cdb46359012870d7fb7cf5db",9.317957166392093],[6773,"27180af4e50ef90e2c15e62bc83887dcc7c892c4e090c3896a6269b5c3d277d3",9.917710196779964],[18589,"77cacd92fb6fe1eaa6b1a146fe2a0756bec2b44b978234be5700a2255ec4322f",10.052724077328646],[13194,"e0e49e4d1ca75e6aa0ebe150b263f631cde058cb3a4ebc9fd6c1e5374e38fda6",9.317957166392093],[2306,"1df0e08869e16c972e45cb92ff52a451443f0d50dcc539c1a12d205837f1fdf0",9.917710196779964],[8144,"564b8e17d9d8678f5ad0d38a3e67d629acbee14b9205bda2c2036b491f8068ca",9.317957166392093],[223,"84409a16fad021338b6a0e0750a8e069e64a950fa5ac3a4276aa79aaa9207efe",9.917710196779964],[19808,"2694f7216c5675b207b30e50e9d2adf2b1ed5d9afc43a78ba0c23a7483995202",10.052724077328646],[18175,"d0e049ddec5d480b11e3718b82d0e0c21e566e1be1c3a6041b3622ccc092ce38",9.317957166392093],[11254,"28115b8e1efeb6a18e552504a8bc8e68c0950a3fad2c8abbe4ef5f84f5a950b6",9.317957166392093],[14821,"ef7e744c5e92e720505b4b034f5ab15cdcd4427baf9dcabf240e36488d876482",10.052724077328646],[5135,"897b04937959194f12ac0843c3e87ecc7fa1feb2118cb2cfd7032a644f5e68de",9.917710196779964],[17858,"abe6d1b4d45b139e26b71aeadd08880b0a417cfa0e5e04a57a96914193860f40",9.317957166392093],[7282,"31df839e11124ab2961f72cdcdcbd7fab54a7a7a662a8c851db9f8e10e0929d0",9.917710196779964],[246,"79aca0f844a0126396336577c23d6fb89b76905c05ec57ce17e61eb8250754fe",9.917710196779964],[429,"e9be3386182198448d135fbf008ec5d8b904068d3d2f11688794899ca3c228fd",9.917710196779964],[13340,"51830b2c266a57b221695a5e7986ec18cdabe67f9c30fb858ae26693ac62c9a3",9.317957166392093],[4763,"ee202af079b2d26b31842032df3f2c9c9f01ed80a60939fb44c61ae55bc28ee0",9.917710196779964],[4938,"5d07e5dc23205192bbcaada07e86a7f510a1fd5d4504001ecbe7e5da5c7996df",9.917710196779964],[15821,"1393359c86588eb3afac6134d39a3fbc1ebbb4afe53cf4d450e28a352455f66c",9.317957166392093],[9347,"b78168b0070ff477983774d3299bab3202a9992126b199f2f6ffa3d332389ac2",9.397642257991386],[16132,"d6ed4bfa001c25d181afebdb47b638bdc239cf2fd8ac4fbd0a426cf05f186465",9.317957166392093],[19295,"bed215d08f7bfb6f0674355e596ee92a10be2e071a5ba278a2fc96d5d65d0415",27.150442477876105],[956,"43f9945a35c105da0cd7b65e738ddcbd740dd022307c2b67b3940c88878e78f9",9.917710196779964],[5655,"7b99e1a9dc1cd08e0d2365fb9a252a24fe5a481285cd39434e2900f1ade84bdb",9.317957166392093],[17277,"67be2f57af3cff17b08446839fb484914a4c93a9c44c2a4c98b9b6c20673b04c",10.052724077328646],[3318,"254b8c467c274b118c8ca2612689d6b8ad18bb87d98fb3a2b0901f5a0e313eea",9.917710196779964],[1572,"105c1544fefcd3f63e630c8a64a412b5dc89950ff9f825fd2285bc154602aff5",71.65371024734982],[17363,"c67567153f9d48213bc43954f009d798c998892391f12cd3a61c668e77dd924a",9.317957166392093],[7557,"a9566272e5e9db586e69e74a4a739b0da2f6d9eb545087ae413c5e1996cf75ce",9.917710196779964],[9331,"70404b36ad105cbf77e1c410cf1faecda8492a1ed8ec82a1c863d28a0425b5c2",9.917710196779964],[13877,"e205ab0b31c03d240302717b6dbc0c3aca39ba871ff83c97f6c97ecf0704b897",9.317957166392093],[3861,"1b9ca9b3453d4e858f70eaed930d5b90414f97b4d020e4991b0ee409128d9be6",9.917710196779964],[16459,"31b0d816718d38b47d62e829c87d712e73c816d1522883c3475b6c8d27f0035e",9.317957166392093],[3841,"9e2493231f09f4edeea33a64819f98286bb5bdcab1717c87a0aaf1c6c926c7e6",9.917710196779964],[9508,"f8c0856e9f3e054e27998d365fdc9d0cd13a531315c4b542ee2d4f754c3ba3c1",9.917710196779964],[12088,"09ddc976eb29e75af3bdc6310b6e8721b5b59535c267d8c84742528182c7ceb0",9.917710196779964],[7686,"2acc3eeb280d63f2a4ed3d463cabdd30582188fa01e803d50688cfe5144fa5cd",9.917710196779964],[3903,"97605686ad0dd3927ea974db5e81d477e6e14706d02ca07e1dd43644beac59e6",9.917710196779964],[16648,"47c98f2d6f27b528640d66819a9c1a648306f4743ca3cfe1419d827d960ad159",9.647446457990116],[8463,"3c9ff8f3a100f5edd39ddc861d5a3284761d194d70b8d1b2688dbe0320793ec8",9.317957166392093],[19307,"0a0bb7545955a82b4098ad5d93a739b2d1429d4bb646c22655e3e24bb25acb14",9.317957166392093],[3058,"a0d864b9b4c0861d4ce8f4731b5087836ca434c2a53829791aaf7428a499eeeb",9.317957166392093],[9725,"e327ab9c230945342b817a16e18d2f40f90d0d22052f1e1208fd3a7c5f9d29c0",9.917710196779964],[10305,"27c0b741407a6eece2a2b1bcaea75f0517fb2ad4959eb356808f76fa468e53bc",9.472566371681417],[19806,"4ef623675b58ca433f03013d69c7c9aa0b8e5e08e2bf1df1244c8fd831125402",9.317957166392093],[19553,"b7a3d132f33aa0f44bccc290f5b5d371771b0ff0d0b24a6d282af63d5c3b7d0c",9.647446457990116],[19427,"d5dc3d03d2fbd7463aad963e729221a540fac3f7ca21343ae2d1450307678e10",252.98329355608593],[4297,"11034df960342b5027d310098f6e9f35d8ef0b6eeb659a4f490f3bbc7e63c8e3",9.917710196779964],[2361,"042893fa4d31ae797c20b7a5c93bd0f0194221c7ab99248dfb195021537bb1f0",9.917710196779964],[1642,"d68ad62128f6c6ffea0f2ab4cf5ad32fb14c6fb1fbc331f6ca2a00ddaaef58f5",9.917710196779964],[11746,"52281ab29082f27c9b9d302baac505a0e7fad92a854a99ced463be518a9e08b3",9.917710196779964],[9190,"19753a0fac7647152eb6c6aac1872085eddc1a82ab7caa02e905ba86995a8ec3",9.917710196779964],[15376,"e0e07ae77909cfcaeabba563ca4a1be6921b39eefbe3ed8554cc08a8288ddc76",9.317957166392093],[9695,"ded35809d3152e94e3a676a08e67ea1bfdf2ef228df58b4aa127de9566ca6fc0",9.317957166392093],[3817,"865ab7faa7495e1e1ba3b3058fae4f55559aa0ddba299fceefdb8ec25425dee6",9.917710196779964],[5118,"03104ee17f7b592665f04467a47dee640448658a8a1e00002b64287847f079de",9.917710196779964],[10122,"b0547a167cc160d412e7cde8265fdc7f46f502be17ef2088ba4eae2fb9558dbd",9.917710196779964],[2851,"563ee1a3a4415306d586209c4ab049cf28a193e7e731e984018bd3d343455eed",9.917710196779964],[5598,"278248e8bf0fa3323dcf17a43653d00bd301330c92a9368d79251b1d1b33a5db",9.917710196779964],[17237,"ebd5089ef1064a2036a7c64f5559905b05da99874b463dd33a6f9b13953e254d",25.158813263525307],[17778,"3fd4e5f9d6a6f0f042427b6077da86b77e8e3c4168d89421745756d87385c641",9.317957166392093],[3136,"a095dd9654171bd5fd3b55e46d6fa583d8dad60c94d2712b5a6fe22960b871eb",9.917710196779964],[1197,"7ba9154a803191e1ff1febaed0c325d308d8eced1227ec80479d4c82f1b807f8",9.917710196779964],[15247,"b0a604440aeaacc1237b62bcbf571501a06d2cf379bb90731acc02c66cf68379",9.317957166392093],[17290,"d227f3ee9b253f9c4c911066e6988d94dc8ec315a7ea88aa37d9733f6a91654c",9.647446457990116],[11340,"5af74ab9da7c3174dca659879a96a7725a05d773a9c33611c9d096723145b4b5",9.917710196779964],[2976,"c86b26ed14ec09aa6f0f2a5d779869ba3259130d6ffc3ab165a0c3fd172e70ec",9.917710196779964],[4761,"9d5129f0823f89cad83c2c0b7e6d3d07d353f3a13dfbb81f12eec87be75f8fe0",9.917710196779964],[14738,"1bf3a1343fdbadbfff4afa9cb67951619f8b46ed1707f76bf62ac933201d1b84",9.317957166392093],[4951,"a28b56f03529890058629654beaea8165db3df997f258e264061f3990a5e88df",9.917710196779964],[18222,"8b563f96d2773d23f8b9d9b373d21b28123065b9a52cf9072ce63ff0e3af9937",9.317957166392093],[14559,"3b2c6b982701772a66fbc489d9cbd4241a3886fbaab6cb6d73debcc8f8fadd87",9.317957166392093],[10991,"7a12091c651eed14594765473a4708da20ef1472906bc76a893799e51c610bb8",9.917710196779964],[10347,"f553f726327d5f2f8898601130b11727cb17b8ca7610430395059680c7ae0bbc",9.917710196779964],[17749,"66c86a50f631febf199c89c3483a706d88c043bfb95f3428c072a09b459a3242",9.317957166392093],[3471,"40a0ebe0a4cf9ccfd3cedb3d14388306c735b6a6b72f46e90baa27c0c66239e9",9.917710196779964],[11125,"033aa39525215bca66a58e962778fac6c3cbd235fc8c15f4d2b47586e0021fb7",9.647446457990116],[13802,"af61bbcad7ac074d1fde1a9e7b61140ec849565bdce7b3e43b420514dd6b5299",9.647446457990116],[19266,"10d85195e5f45466dea852462f766672f039984b07ab273a908f5247da7b1516",9.317957166392093],[16755,"3e608f90b6e2eb0ce327b40cd122e3c357634b93b32c9afb6b1e0ed1dfe25b57",15.003322259136212],[4310,"b3298dd89411fb8804bd2769794ace42b369642a731fcefbb9d48ce458f9b3e3",9.917710196779964],[19341,"f5755f65db2de440e2326b6e5af380e9bd39d2057427d0886971f99e09b9c913",9.317957166392093],[7729,"31fa587fd8a3ad4dbd3d0f619a25f6a427faa79cb88bd1a2f945c67ebf7e4acd",10.014641288433381],[1279,"466b82d3b01cefb3df6e65b3f10c7fe89ed5a9f08158b828bf56c279a6197ff7",9.997888067581837],[1360,"80c42ec9a9abe3d09590ff5e0cfe6174a3cd1eccb5bebd22f777d49a6b12fbf6",9.647446457990116],[8522,"807058a209642943cbce2bc984fbb74981f467650bff2e591767cb976910e3c7",9.917710196779964],[9201,"9a152558db0344c41973607e0ea8beda7c71c2415efd81d49a124bcf531b70c3",9.917710196779964],[4439,"8309d09a58ed1bb6798e47a4bfae71ebfae6c0588dd31043e206795a8739d5e2",9.317957166392093],[12806,"123b74e0b2fd9c9805ff769ea5bf1806621b8c7cf5d0260d83401fcf2413e2ab",9.317957166392093],[6417,"dad98a335ec42e78fcec9a33d2a320b91bc17adece3a9d33f6656c80224b2fd6",12.246461282264779],[17391,"d97ca9ff2dbca7e24b590d5da3f68c9780109c5f4c325d3b97c99b0bf2faec49",26.13903743315508],[11454,"080290b998003d1ca9fd06402d511a49de3b346db468fe331264a89d1357e5b4",9.917710196779964],[19637,"ab09b9a76723912cb901e0ca09fb834adc46710a1644c85e8d65994868494a08",26.002607561929597],[16274,"b35c3782ac171fff805e4902aa0851f762aafefc40ed14fb386440879ea9bb61",9.317957166392093],[8668,"b35fe3be8d844e7f6ee0de09a8df3e0924a4eb788b8c192ed1eeffa2d771ddc6",9.917710196779964],[2294,"23c1d669cbd27d721d912b417a1090779cc969f4f9049f7db8d98e79d88a0af1",9.917710196779964],[2999,"720fc1941917574004a0714ccc94b507b471bbd386b811bc9e043272d9f647ec",9.917710196779964],[5469,"10252f90f893e4ba3443015c4176910f6560b2dc6c1e37e53ef560cdd31a66dc",9.917710196779964],[14813,"2d223fe3f41b9bc326880e024f6ed5548b9c5172c3b781e6b392372985828282",9.317957166392093],[1669,"28f049e6b90691258b9a0af131d9f0bf8bddbf7b63fd3f66492923329ad721f5",9.917710196779964],[3444,"3c8f427fd5fb68a72b5e4859fb1dea559689d660a2c009f8a7aab7a8e05768e9",9.917710196779964],[1240,"45ee2ebc90a9a72c0a2dd87ee6cc0190104e4a42f0defa5490118a04eee6c1f7",9.317957166392093],[10169,"87d9718ac166b625b1f13fdc834aa07d8fb9ca2abad54c154b254809168c4bbd",9.917710196779964],[11247,"19b3044b2ffb0ef3579997b4672394d3c2d09ec8b332979b3e058d66b9db5bb6",9.917710196779964],[4338,"7e987f4a2dc4724639dca8cd4b5d4ff41a93dc480a5b6881878dd665a7bb81e3",9.917710196779964],[3056,"b7e299e852661207f221a18cecc474f3932b37714ed6b36be8202d58e61af1eb",9.917710196779964],[16567,"4464d5f524af247870e9b2fef553716d4f9127546123c33beaaaa342193dc65b",9.317957166392093],[15979,"e97eb40ec383f38c0509f4c45b3a64fd4662dd89523376308375931860f2f768",9.317957166392093],[14287,"fa4fcf2945a87b64ebd2c47641118c9e9019d51b87fb63d4997f9df9f19ef58d",9.317957166392093],[2242,"05f3e2ca69ac9e76653dd321825310e0c6304fc03fec5833962777d657ae49f1",9.917710196779964],[13963,"b624a24407621ebb9835491726d308cb11282b6f35e7242c69a0e78f87d5c095",9.317957166392093],[5182,"f39c14126fd7f335dab30e7e23e01c3406a3740450b42c325431a538874a15de",15.91459074733096],[9898,"6c343ff6bb3773eb238e276fb261802be76ecb1cbccef29ed79c4255c8a7efbe",9.917710196779964],[16509,"b8982536e828582c6b38bd4f42d9d83b167149522a65773a64a1f650e8ab0a5d",9.317957166392093],[10348,"be5cacf46500bc5459363a75e4734ab9c8d95e85a4f89ba779e07b360e3c0bbc",9.317957166392093],[18628,"276f9468348f46129c53eb5226bf597ea8bb7b08f1dc03c409eb86597215b52d",9.317957166392093],[6217,"18ffb06709c381f701e5b7dc6a4ca2dd74bf5173004c2b324e4592e4d719a0d7",9.917710196779964],[3905,"c3207d992c91a099e962c8b853204600099f7cce8f7328c20edd5266ded254e6",9.917710196779964],[2660,"92a17921908ee947ec907c0b1504bd7e334224e76605044846568e58b9adccee",9.917710196779964],[10148,"bf9be44ac59826a2321ac4377228e98a1da848f709c47d0e738be787d30865bd",27.097238895558224],[11771,"afed91e2c239810cd4b5521e5a2048ab363aa9d858a0c923798c8af30e7cdfb2",9.917710196779964],[9018,"e8c38ddbabbdec7d014c956eabb734e698c222637e5d69327febc5409165a6c4",9.317957166392093],[3547,"d48124c025ac16168b85f9b3c8bf1f85510522c92967534ba06cb6496614a1e8",9.317957166392093],[13593,"384f8e45ffbbabb1d2f66d29aac58633cb379ac24706877070b79640f3e1a29d",26],[18543,"edf3a2217c3b4bf9d3a1018d0ec6dc40486bafa7c0c53c5c38f1988cb4509130",34.004576659038904],[2951,"76e04ffdb3c93240e90a2e6be1c836e78d88bd031973f63e98e76d86ae80a8ec",9.917710196779964],[2298,"0c374261f6852a1cf4d853a1704c5b401da4b7f212c4562730bc669bdff106f1",9.917710196779964],[1418,"0828d981a7f0ed9cee09e5497e43293743b6a2ad85fd0160fc8ae3a6dcecb6f6",9.917710196779964],[2102,"d8fe9120e1909a0b8523611209bf26abb83e37261cb4494da78976af8cb236f2",15.078847199564981],[7193,"d824118adfcc9c7b1fc2909aa12a03d5ef7ae48567f3043e717e0758cdd0c1d0",9.917710196779964],[1982,"aaa54c8ed7513b340b5c80d439691709b0a790242baded9a6561e10c198e21f3",36.07578947368421],[1520,"73c4b8900d16ed76f69ca654a76329dad25f2e08ffc4e2900309ad36e7b9fbf5",9.917710196779964],[17204,"3e8553ac72a82770b8e7814dddd8d21c83bced808a9d99eb4a6b711e39bcb04d",9.317957166392093],[7774,"91b94f4ad2f6908eebaee38527b2774aa0b620e3e78080b86401f666b239facc",9.917710196779964],[1672,"5a2c9fdf033fc048adf3ecc5c14929d3ffff90781dd1f80dad0d9b62b7131bf5",9.917710196779964],[1697,"bea2b6a5e00d5684e7940947777e4f6227720958493e5aac27f7bfb713b7f1f4",9.917710196779964],[7367,"7afa7e3168d8695a50c78d71101b818b7bfcef9185967a80064e925333299dcf",9.917710196779964],[4976,"a780274afdf52e1bf20d0e816dd6baaf56e6e2cbd43c46796f47ab2e082757df",9.317957166392093],[12004,"1f073218e4a5607630c081ed9e53d950cd80258e28dda38a2f8a281b02404bb1",9.917710196779964],[18511,"85f0f7c21cf4a2c1857d44794bdca4c201734e42ea5630a9f57cf59218f43a31",9.317957166392093],[3102,"e1b049f12bb4f1e591ba838fec34ebd9008fd7aba5f200fca97015513bb8a2eb",9.917710196779964],[4358,"9989f7642ea8278f7aa8a290092e668543d819037b55ce9025b9e4c808c75be3",9.917710196779964],[19634,"347aa2e03da56e7f872d1a6d74df511bdfa49f5209f22feef0794a9faae35508",10.052724077328646],[14400,"9fa6649555391522223ecc3a0a6cec34070f66be8424a0ea86cbb24b28ee3f8b",9.647446457990116],[4242,"804e40761fc81e8f4901ed04894dfaab004f8e3d1a09bce7146142899b882be4",9.917710196779964],[15021,"bcbecae7227224dfb525fb05fd3aabfb38c7980f357d876ee6ae44ed12d2f17d",19.066666666666666],[3049,"3cc4267277dffd263356e7c4e27c66f2431c6d6d8f609d1193c0eaf6ec9efceb",9.917710196779964],[7262,"92ab77d856dc518bbc980d8fb44a493ee4913f036f1310d39b9849c6bdd641d0",9.917710196779964],[19782,"e4c436a2494c533872a985d4397fba63267b15ea3d1714649649eaca3a355e03",76.4648493543759],[15653,"b946f8c0cf458e9d7d9ad189aafb68c8371cc9f6b8fa2a7b79f6fd9fc9444570",9.317957166392093],[8720,"29571a43134166722505e51ba05586f593b5b052287df22f63a62504d4818fc6",9.917710196779964],[2511,"1bef220a2419d896da87422a4b77c7f5972bdbbf4961fc972ff3f78fec98c1ef",9.917710196779964],[3563,"7ed33cdcf785ac0e796cfd4f635b3fc0510e3b22d7ad8ace40f8e3e4fc2681e8",9.917710196779964],[14026,"0bc14b0b8efbe939588195c41709addd05b78bbd5756e71a13a7c2a7f38b2c94",9.914008321775311],[4774,"3c87a8b35b770fe0d803d057ba08cff176db3577f07ae4bf395fd77c9fca89e0",9.317957166392093],[11350,"d74a50d09b34a0eb1a1d0f2ef8bb1798b19009a1cfdb3d657b6f4740bec9abb5",9.317957166392093],[18919,"79f384c82266a59b76678f0be7cf98864d40c00d21ed519f3b87a8a78e2acd22",9.695708712613785],[6243,"feeab19f69a160f96a7028f0af8a013e690aa32f0d76cf0bb7c32557893570d7",9.917710196779964],[5558,"7f7589312022f829b1affcbd859fe66f318aac35d5bf0216661b129c6ba9e3db",9.917710196779964],[12322,"3d4ab692ca5bf785f85ce456b9a7863f710b480551878a210f2277241e6214af",9.917710196779964],[18438,"941fb51b3190274c22f4d89bd6ed937e27dc9ded0ad34fa31b96de1976bcda32",9.317957166392093],[18746,"f0d2781f7bb54bc1f414747d160493a7d5a9d5a7c479e0b167420e6153b8d328",9.695708712613785],[13933,"97115a397802227b4903bb3f4068d0f46f3a09098060b54d707ffd9b6d3a5196",15.073170731707316],[17332,"58f9e49eb2c0c2bdc0de942eb205363503631e26edf81e89a925962ef25b3e4b",9.647446457990116],[5888,"617aa3c95bc1d6bdd2acf79bb379e890a7d63fd5aef8bef031d525a4d1bdc0d9",9.917710196779964],[7742,"f1fecda136760933f67c4fdd22495233b00ec43c1a6e6b38120b74181b6136cd",9.917710196779964],[15560,"1d5457343ec887b54b687704a726720307f4f6862756a475a0f8bf9bb29a8872",12.905432175998332],[18650,"cc04e69079a7815b44303ec2bb7a3e13cdc99c3e2c7429f6759d0ef3c03da22c",10.052724077328646],[16050,"dcb1ce93d550544cf3db4567e53a1fd5198ce5c5dcc8b62e790b977a30f16167",9.317957166392093],[18823,"f14349d67b1b1e91b0c115c5f27e1d7c114393bf7c8df6db7fa9972227b6fa25",9.9938274535872],[8016,"d3e25b1c67c6a588728694446b769b56317ffbfdc23a52a9f8fb6278b93f72cb",12.183856502242152],[13464,"59a183c0008ceb952f533999e53d7cd79dbfac8fdc4d88237fe2874b0083c4a0",9.317957166392093],[11989,"be4256b76b21b7189051567ea4fbe4ca27c2070f927346573c13502505c462b1",9.917710196779964],[17425,"f41d052067dc5ce23353d939addef8a35a57fc31df78e72454e6606471ec4f49",9.317957166392093],[13343,"ee625e155f45a16e8c007116370414e4ddf1050b9fbac20ed33c8ca225009ca3",9.497326203208557],[14159,"b803542ebf034edcf2095a18e401d3dbb43fc6d10447872c2b57eb7e09134191",9.317957166392093],[14212,"137f019f93c7f4ba14e53261aa9ad76a5014829da8670d5319d15a3fc46dd58f",9.317957166392093],[7563,"36292607cbd24c7e9fafd439873342a675b9f8e24c177a384033397acebd6ace",9.917710196779964],[17651,"83bbd0dc7e33c63c8b97193f9f7c74397dcd77ef7822ea20f9f0bbbe4ef03344",9.647446457990116],[18969,"3dfddd48ff829c7906642c9372eb1aa743bc875738f21f8fbb10a742a5d99221",9.317957166392093],[14700,"04c5efe2c032ab743a2a23efdda77e594884bbfe27e90e666278090775aed784",9.317957166392093],[6390,"4b644a85d47de2309499c34dfa267ef31534d49b93f984c27d090c94073064d6",9.917710196779964],[12253,"8fbcb9f683f5687a5de66ccdd9bd41d74e21d141c6201428ea22dcde8bdcaeaf",9.917710196779964],[1460,"87624321790278e01f390d85f5ac4da7d95dd15ce9405967a16e9ea6631a6ef6",9.917710196779964],[17734,"cd2d58c0f304fc1ae796bfc975112db5d646c71e028d402b948009fa37868d42",9.317957166392093],[19199,"5334363b2953820969285c43c320b120fae358904b5e279d445865bb721db818",9.317957166392093],[16169,"8f0fabf330b594a02eba2cf3cd9e93ffc5ab16904c53193fa3e5b22b4e149664",14.931818181818182],[10037,"7006d3da36341b94beb986ef5917dfc539adb8f81c2314fafff102d18e6818be",9.917710196779964],[1161,"5d402640dc9cd0675f6388852057da738dd896b73678b6506342ca4882a539f8",9.917710196779964],[1716,"c5495c4eb39972cc793e1d71d87e552bb1376fc25f8665445635c7b1514fd4f4",9.317957166392093],[1513,"f264dc35dd79ef6bdc328a564d21cce3f053640f9aa3069ca929227cafcc06f6",9.917710196779964],[18221,"905b050c68c59cbd5c99ba0078b024c6a960fee3efd2c70bc28cde5cff879b37",9.317957166392093],[10902,"cbb114327ad8b87d5f7176fb40f828f02bff9d66d7dc37720b148b309a56abb8",9.317957166392093],[8043,"4d16b1aad5738b0245203c93dbe0c3e62861ffbf7fb06b0b7288a23b42cb48cb",9.647446457990116],[12629,"64331b05c252c8dc125318c9a9cda9e3a17e182b7f34199fdce247b5944415ad",18.57371096586783],[10705,"3239afc9b69f9372d0c8a89608adeb38c46f8ea2ffa1663d9b8e20b55c97f9b9",9.917710196779964],[2645,"6aa0526ba6d3705ea490dedef820d5d8804b1e5efa439109bde9524b75a6dcee",9.917710196779964],[12436,"c0d2a9e8436178e0978c89d598f999158f4a0b760a6ad46c6a2b92786a4a5cae",9.917710196779964],[336,"6e725fd85ab7b249ae9939ae5e6ef5dd3966d49206eb1414d6c0ab19a390c8fd",9.917710196779964],[10192,"8c4deeeb92143f12156339d155e1b60d446766d3cd1c879da97237dbeb250fbd",9.917710196779964],[12122,"6399943811386cdf3402c840d287388d0471a81d9a7777da31a92a0542ac95b0",9.917710196779964],[4824,"436b888ac89ee135e938fa1c2cb7a7cb3c46904ee8b74e3c24e83fa86d6341e0",9.317957166392093],[13141,"e0ed8431428dc5474d35a71711cde2d2052cacd13ac8b5dc0af124dbb22d1ba8",9.317957166392093],[1663,"3174331f470a62bf50a418811cd2f07690d77b69de4cf87add2c1f52ffcc29f5",9.917710196779964],[4489,"26f07a5a77bf8cdb5858089cf125a70624325c16459c7df1b4c540f67b817ce2",9.317957166392093],[10202,"71943e3dc08cdbc89b04d5027e1c0a7a8d9eb30c76bf9441ca1dfa51689600bd",14.188034188034187],[5667,"6d684f113ab5b9b4beb24218ed2a3ffaa387be869e5e2a2f2abbd8d4d74838db",9.647446457990116],[15284,"29933fd7705f183aec0fe086fc9d03ae028d1ae1a9aba04bcf6f12ff6688b378",9.317957166392093],[2731,"3de9f1a38d253e913ff302d81157e3723bbd9ed9e7c57524a45ac45cf75b39ee",9.917710196779964],[1003,"0a068423d45fef7d687169b2ec743f76bc9ed09f2d51b9b379d0952fc65f34f9",9.917710196779964],[10016,"77eb53e8696d964caebd1f024a18f6ea77a25d4ba2ef47f80c12c2d904bf39be",9.917710196779964],[5890,"b41bd7ff1a07555e7ea6663f062465fe9ac16e686e1fa489b0eb141d8471bfd9",9.917710196779964],[12072,"77c13af75cdc2c062a91aaf8baef5d964db36e71fed351ca22981e75fc61dfb0",9.917710196779964],[14717,"f8c9f071404502a4ec6debd1155a3347fc17c45053951259f26d6cdf31459084",9.317957166392093],[16007,"6300fd69da8fe0340add898966072e143489653b2ea127c0004aeb5c11f85268",10.052724077328646],[5422,"96f2d91c5742ed94185d17f2065947cdda165762c92cdc5872c2b78a2044addc",9.317957166392093],[10628,"92c265766a0b4787c3144245dd577fb3c1ec8083a26acd5aa8e4075da16582ba",9.917710196779964],[19332,"e31257a3ef46feb9cca41de61c198fe0ff0aa2d2d48f034c452f019636842714",27.144385026737968],[18053,"3f4b5eb31417b1d7db70e7d2111f714c1961ba62a4af4140ee53d1078b9d253c",9.317957166392093],[3648,"a5e207aba85f5eb62cd84bfa3758f119c0c9f1b83addbefeffbe735bc0bcf8e7",9.917710196779964],[764,"7b8cf28003578a1123c7acae31cf6da94008252f9bbc9254377e814d358ccbfa",9.917710196779964],[6406,"091ae562035b91f376f2556662831a64c0af8f6fbf2c098305c0165570a549d6",9.917710196779964],[6093,"5d15f57ec8a4acdd6e9199e044f5712d787efa6016f6b78dd4964d18838c70d8",9.917710196779964],[13102,"5a48d45101714364a662139c704b67fc90d648dde77fccfa55674ff7298a2da9",9.317957166392093],[834,"cea8fb3ad3219df6e52f324df59ac4d4eb1aab409c6e1766990fbceae1f451fa",9.917710196779964],[19798,"ed6c868d919fa143060adcb90cb6fbf6acbfafa2e58f8db2bdad120937719902",9.647446457990116],[15391,"f3abe69b09ab20665c6d40738e2d638676a13c4990f78b7833d793f391637176",9.317957166392093],[3174,"1cd56608e9849551e7d984880804fc445e5e704bf504582f122c0568636b31eb",10.052724077328646],[2182,"2bc16ab6c5f146bf8e4904fbed4cd52826daf8f61f140610d7970c91729aabf1",9.917710196779964],[5967,"2dd0d074e4a2439d403036136aa1b627d338b47f7be0f8ddeb3fba5a6bb44fd9",9.317957166392093],[16968,"6beb2b528ca17e24a5194a57acaf19da5ab9c70f90d7f60c24694192ca83b952",9.317957166392093],[17027,"2f74f50028c2e8f1874b0354705abff733d646dd55870a49c2a88b6b34a56a51",9.317957166392093],[2164,"a11be8aa47f09a5af700a1d3461473ac5abf7138ed5ec40a21124781f7cdcff1",9.317957166392093],[13795,"624710b50ce02ac52e83ba11f1dd3826aa5daa1a79e5aa02bf8133d31fa67f99",9.317957166392093],[9268,"4bd36ac093f2d894d7313d21ff1278829b4ab04d333732e416c8b4bdb4290cc3",9.917710196779964],[4575,"7d3112f368a231206cbfe76f66433f155dae265131a05ea7489453968a20c9e1",9.917710196779964],[9516,"cc7ead2c286fa94fda43808fc4459498820beaaad7060910ad9cc0fc4b1a97c1",9.917710196779964],[2846,"b17d164e4417352e7ee7b2a1dd35935b7d88ee3158ab25b2156baa3f2de660ed",9.317957166392093],[19070,"247723601e4095b0a5f30231b2eed26e4c445a8ffc0b54cc7c988fcfc0d5db1d",9.317957166392093],[6237,"6e33fcd423cf17a0800f147331df012650f86f89d68602f51b97e0f6b2a57cd7",9.317957166392093],[3641,"a9202813abb1782740fc36ae9a5282f66429f3bd4227a5d8d88578510cee00e8",9.317957166392093],[10557,"005a7ec9783e2e911f2f6adc4370641c7ba2ccb03744f1fcdc6b91d41e58e4ba",10.043290043290042],[5641,"e2d996e3dbc1daa8ca1b30cafaa30aa4ff0758616082f70286d37d58e54863db",9.917710196779964],[8941,"bc85d353c7181b32b667b90546c43cd71c6041f72e8b6432dc78613f05183ec5",9.917710196779964],[14737,"e03c77e00f4bf345209327add3d0c992f28ed20064d42e301c4c28c1f2cc2784",9.317957166392093],[4995,"0fe13af2391a30bc6a8af0e10ab17228b39f4c0fda0d34363998a24f546d38df",9.917710196779964],[15712,"41dccb2d4499ad2fb172a8cc579f2e0f7f8aec0491bc33355637c55053213a6f",9.317957166392093],[6930,"65c075f217af3aa664b6a051e9d08bb04c455ea4d32799dcd372d30f0b446ed2",9.917710196779964],[12474,"11190e197bde99b7dea0fb346d56b18c242f44354d78522be78e6e56298d1dae",9.917710196779964],[17038,"26b2f7377ccd7e5a99d3ebd6943f5fc7e1973db78625a891e0366414b2963351",10.053475935828876],[18419,"d15577dc745796a4be38df609f2d696088b184e1d05db6549ea74ebdd17a2833",9.317957166392093],[4118,"18e8a237240d5a8bc5285edf46a6203e0fb5fed6faf44ebf71838b401800f0e4",9.917710196779964],[4893,"8f996bcc210ce5225deb471bba61a013c4198418dc017e5cd0a684d4cc3be1df",9.917710196779964],[4483,"5f35d58c35657cad5d016feb7ef3e7a8d5be833f15c2effb3f8a657f436b85e2",9.317957166392093],[11436,"c731b5eb9d6f0b215de3c78b278c89de057dec62fbfa31bdb36eca4446350eb5",9.317957166392093],[12757,"6d2486634f70c7cd676bff5dd021ca09aaf72d0a6d9a84b7ee5a929b9f3132ac",9.917710196779964],[12314,"838c51b5e78e05fc0adffb7a10e7e66d7c73beedfdaac152e0d5bcce3d2f22af",9.917710196779964],[14988,"18e100582f02d35047f18f0e1866c5e7c411ffc747693002963bbf0ec4fcba7e",9.317957166392093],[13826,"27e5b7847f6cc4971c60b01de5a2160f9433155be43f8e76462e181af482df98",10.052724077328646],[8142,"6dbcfb9a7a0e03ef5628ddf2b28ade72eefcf3836a390ed3b177d42c1bb86aca",9.917710196779964],[1474,"530b388f077177815dd484b5491926838532a4d63429a76b5a4e5e1dc5fb51f6",9.917710196779964],[9901,"a8f9f2e0c27b746350f4b00782ec466f31504ddf2fd75a56757fb0f4cd90edbe",9.917710196779964],[6110,"ebf6c13558fb96bfffa21ad384a348e675980766b10cd4def25abe2353f860d8",9.917710196779964],[15443,"32a869bed33ccac8764f31eeb05e50ca0f22edc2f0b6cfec716e8040297d5075",9.647446457990116],[4792,"4e1166ae3419366b8c4975087eda3bb182223ff9254038001db2d57112406fe0",9.317957166392093],[5287,"fe1501edb3242e4cecfcc8414dd3df94eb55ea139e4a823754ce3b2d02867add",9.317957166392093],[1970,"c653a869dae8ad7a02252e19edeaf4e92ebd6792e82bc1af70d76b9a938033f3",9.917710196779964],[11882,"261330f5b602810dc2d54aa5099cc0c834f0f52be2de623c31b5039d109724b2",9.917710196779964],[10783,"22d3be8a19bf8c5322fe7143005e76d47c289e34a170aed715729a55832a69b9",9.917710196779964],[14221,"25d312d1c1940e9baf4c14832ceacba6e60a2beb335cfb70c068f0155f60a18f",9.747538048343777],[5969,"f44fc36d68b4d50055f63b211202be1069a655333481740c1cec8a5a8b884cd9",9.917710196779964],[12151,"b5687a8a3b4ca1be874d83970d73b15701ddb1dec71f220c764ca25d75c45bb0",9.317957166392093],[2088,"2204fbaba93f3fbaf2bd393647eb35bb9352666e13759bca15d1704998d54df2",9.917710196779964],[11151,"03ffcbf5bf55734dd256e2d88e4eb6253e1f1c3ead5b6b855f2dc10ee114f4b6",9.917710196779964],[2223,"08417ad7c7037d7567130f31919f8fde5fe327005bb315e293f26f3124185ff1",9.917710196779964],[8814,"bc4b3c590c73aec7e1dd5bbbb184b51ced25e9c033dd707b4cd0cd5f474c04c6",9.917710196779964],[8365,"406c5592bfcd297a8e8925bdf1004ba54d7243a212bf4a8f130e66db2e27dec8",9.317957166392093],[3691,"6b8f181de48b717fabc9d0edc0d5c38959bd8d146e52fe663d80f7b256c9a6e7",9.317957166392093],[11032,"b54872b3aac4a43ff73c79e90ba2728c2e9daa29df33ce0da4ff2d2cc5c9d4b7",9.917710196779964],[6777,"4df1d71a2b8807fd19fdc64b98d533a31ebcbb2ffed8349f98dd569f52e86cd3",9.917710196779964],[16605,"f003e7b792574f218476db5a7ce672abd2b1de67bc5ae96204d06caf43c1b95a",17.975975975975977],[3394,"8cc6f19da3c1b61803b73fbd8885e318b45f21d37f24e6a3a6813d1a77fdb2e9",9.917710196779964],[12617,"6029b5c571abf713f505e98d0843db0bd06e9dc7912d794f3d8e70d8cecf25ad",9.917710196779964],[7532,"7c065123d2f45795639a6105620aa1818ea27ef20accd4adb20c3897813597ce",9.917710196779964],[10788,"02598a15cc13c3d3aadcee847aa7b81b436dbeaf2947c9bb8e3ad795bf2860b9",9.317957166392093],[756,"2ef665b66939706174bb4d815540e49855b65f498c6eb9c5b2501cc32a40d3fa",9.917710196779964],[9467,"1b029ca9b25e742883e309c0efd55272d3cfe6db8c11870a1c9f57bb7306ebc1",9.917710196779964],[1216,"e602172d6102c0c7101f60d8ed1fbf6f13f0080a237f648ac751cc2a0658e7f7",9.917710196779964],[14977,"4daf6b76661f5cab864acf435b23b5a2b3c5bf2cd16bd766265a54ebe33f107f",9.317957166392093],[19665,"0d96afa5facb67275da30196eaf0919f5012a1e0df20f4e83d586156f9cfa607",10.052724077328646],[4412,"e5f501a5f081a73a04db4b28bc32454ff11f20749842d3047f1c85fd725200e3",9.317957166392093],[17835,"355ed36bacdac0bb16517565ad09e90b4b9e8409973142234db1abcc64789140",20.03647416413374],[14836,"0e450f95f97f3266fd43c6eff7fb7f6c7afd61a668df9db17be3b57eb8d73082",9.317957166392093],[275,"d476e21f3cd00f84ac63779c9e52609429088e98eea33b1b97b739faf9b61afe",9.917710196779964],[11676,"196ac44223392c63d1973d9cfc7718af458547b029b335a78e624c05533b73b3",9.917710196779964],[14910,"5a8264520a00995852d879e16660951154cbfe1065b4c1cfafa6069be9ecc880",9.647446457990116],[16928,"b533f85a8fef0b042e152ee7e59dc7496c71cc73e7c271795cef09ebc9538b53",9.317957166392093],[1567,"ce03f1a8b0176253187658c5594ee4840f85d5090680fd57516527d7b0c7b8f5",9.917710196779964],[14584,"33987c5ff9852eefb09ea9ce730045f57b33e75c5dcb12432fc5bb4b869a6e87",9.317957166392093],[10507,"9a47529342ef7ed8f5b6dfa024cd4601f71012a12c262a58d89f2666f23823bb",9.317957166392093],[14173,"437f4b1f9abe27a84c23c5a3dd2ec40f302f6356cdb427189e689f98d83ff290",9.317957166392093],[6971,"be469131c38baabf0bf8f5397e482b223b3e48b544a241cf5db0b834aa2429d2",9.317957166392093],[12254,"3b535dc5a8346229585af1dbd6f6c42a73edddd53370a5d2377fe3b313b6adaf",9.917710196779964],[17402,"6760b0dd3add51cc316f977a32fb96debad0ad3bcf07f2b500d612149e4ebe49",9.317957166392093],[14515,"a0da40f1826d6f95d79a02745cd6c700b56f9e6572ef5d3f57c6c0551e4ad288",9.317957166392093],[7354,"b7b835c1742973345d111ca37ef816a85bb466673a0699b617ff16f8a2dfaccf",9.317957166392093],[16156,"aa32b8cfe806a88e34ca9b49232f819c1e87503ea982d3001a0736056d8eec64",26.173719376391983],[5960,"5eac037f49341aa6e87613e9e3dcc5714b7a3e4fe00a6bd5af6b5818c6a859d9",9.647446457990116],[3165,"87ddd2cfd294f077868ab0f853165c34bbf29f3bbd614504dacd87b8f6a247eb",9.917710196779964],[66,"51bbbfc643354c7ca9838c517a80afa2f6b8537ea4a06c1d0ba9623667518dff",9.917710196779964],[6359,"efa682fb8c2da58156bc40cc00c797a787483b8dcb2db9485b76625b97bda1d6",9.917710196779964],[16033,"134d1c8e66d06aa73bf5667903b4a1db799b200ae2cdb15a23038e2b9f42c467",9.317957166392093],[4849,"e1914445988e96abed978cc7f9292a14f96a042df581d42c5acba556bc7525e0",9.917710196779964],[14392,"a2a0efe8555bfcc3d77a7fdc7917e3c300a0c60edb5c9b9d18f0bedc2d7d5d8b",16.975265017667844],[8044,"ef3d88819fecfb8dd624a57fda9e3371eb78de93a6a2ccbc3721004d36e841cb",9.917710196779964],[11595,"f11f9f5e267c8498b91f0c8992da2a7bf4a388c59a69b7ea1977f1a1ed69edb3",9.917710196779964],[6538,"a983137ed0e58b8ac7c2ec0780db2f0dad8b928d7d6629309b46f009aaf61bd5",9.917710196779964],[7387,"329a6c44215e869c7c4fe047365f6ba29c06c747f9d1652dc1acc9b8f07b80cf",9.917710196779964],[19158,"3186b4e8b49975e1f568ff4c36d760f0f149786171f961ab9bfd2303549c431a",10.052724077328646],[19287,"d1826849ec1683e9304e37a35c437c3eae277a3bb1e0420d9c4d4ea02fb63415",9.317957166392093],[4215,"3e61e4e9c7d69b45d3aade0ea88554dc84b16c17e2ce6414e99537650fad5ae4",9.917710196779964],[1193,"c794653caa16f84deb849431987bce32eec53c3de1faccc5c90e68d5fd100df8",9.917710196779964],[5754,"9dd8fb48fd67624d74906c0cd54d0821e8b9951f9bdf547c2e69b2d60f80c1da",9.917710196779964],[13642,"de5dfec989fe6baa4cb296274a81f0d3d3cb54dbdcfb860e68eac774705c6d9c",9.997888067581837],[6213,"47a81714c46724d0e13cc9aa03f17173f865d4cdf3a72a01f47450f9472fabd7",9.917710196779964],[4082,"db2c68273271ae4d19cbb827abe069aece48ab820703ef5a267e9462500e2ee5",9.917710196779964],[10442,"d719aae241cdd7bd108efd0d0cff58a9ac7f046d21d130493de78fcfa19c7dbb",9.317957166392093],[6478,"11987e534a2f7acca5ddf04bb6bb7e106fec6400a943e4ff40ec96ddfc619cd5",9.917710196779964],[3684,"f09c04c441ec818cb3ba5aaf2bc774bb0b2ccb1df6f05e08df664a3eced9b6e7",9.317957166392093],[7862,"46a49631fa65f5a9c54c0ec41443a9d45cd6218bdf3db02e5e58f6c656c279cc",9.917710196779964],[8751,"03a5fa5ced01c03c3c970c58c6da6c23abadee17512287b349c74bd8e3fe5bc6",9.917710196779964],[9966,"fa53b3a0d1dadc78e7e989add878262e8667ee68d2bd16aaf67a6a9c601a85be",9.917710196779964],[3978,"e27be6ea62f3b9f95e36075351c2b8bb90f331bd8cdb197c51e650191688e0e5",9.917710196779964],[10728,"60388f0259911b479f1e46eabe73c89a42e7d39d68fa86195fcf221a6706cfb9",9.917710196779964],[13189,"738f8e4e77d5ebe43054ade78ce4348df1efaf72f16a292a92c5fd0cae051ea7",9.317957166392093],[13123,"17901de614c16c2d560fb475279238cfa72ba5d6f1ce70a2a21f6c5685f27da8",9.317957166392093],[6998,"45c282207402c30aef9ee9603552de691c97279910aa1cfab0d3aa9f73cf03d2",9.317957166392093],[9381,"18d3a01e7dd9a32f82de0ee1e8d5f0caaae77b0d2f79deb67a510411ab3660c2",9.317957166392093],[6978,"afebb8bbdf7a10a3442f77374e2627e3395ac664ecdaab2f491161cb482c20d2",9.317957166392093],[3631,"406b6738ea26b2ce542114e88ff035fbb3286f0d482135839c46275048250ce8",9.317957166392093],[9734,"e6c25832a345b25e83ad0a0ed594703f51d13dcbe7501552d54fcedc53f614c0",9.396192203082503],[9604,"1ce48ede0157a4f2b39403628f8f5dcdd5c28867262b4daeeb204f9750c403c1",9.917710196779964],[4233,"4d9c59277a17ec896bf9be35dcee8dd9cee0ebad8bd6033f45512d9749e831e4",9.917710196779964],[14941,"c88a2870ca234dbaa9a0eb691a012719bf9ab0e418bf4155bdd1e6afbaeb0380",9.317957166392093],[12576,"89060392845af482014143811e40e201dbfaf8f66f3149fa6204178fbaf969ad",9.917710196779964],[11467,"807ae2209972c0d2c6f22d30a3d7d18fedc8117166399d98acb1bdbf2b49c3b4",9.917710196779964],[12029,"508cf162318149675b1b211c8e473ab29c9508f5df96bb1248dc0e9bcc611ab1",32.348688627552896],[2487,"257e41e7300165f5f64233cc27d9fddb4de3b57d9bd4057ce20092d83c14f1ef",9.317957166392093],[17229,"a65953cbe984c48b15ec690604da5da1fe5f3e8dc8bfabb5eb7f228c47f0534d",9.317957166392093],[15543,"8becda7b0cdaf4859966aa1e05846860dd299d2b263012f713579c30a7922073",9.317957166392093],[19123,"d992d3b452b0a317d56450899d01bb6ce349614e29acf5cae1b77721b6ec691b",22.3018018018018],[6659,"387066f6dd876dbd49efdc0f4abcf2ebf39070c88eb3a4324c8655deac1f42d4",9.917710196779964],[9296,"d7b5f3e3c771eae08731a6086554b92cf0567ee0d2aface767487d00fe89d9c2",9.917710196779964],[7416,"f737952a3c3f60ff0e2f7ab78af858db4dfbf5acb038acb6046dd434d5c948cf",9.917710196779964],[3962,"5fde6f2a5846a309fe675a0359c4b378a58fc0ace089b7ed80ac39cd1f2af6e5",9.917710196779964],[16860,"35ea2f47997be231e5fdd6d065ffc40d678f98e0726954985a3c2be720801855",9.317957166392093],[4342,"0cfafdc6937dab57eada0bd2d3ba3d0cf5629c44afaffc74bb4f9d0df4b077e3",9.917710196779964],[9294,"3335620c748141f47c52b024130aa6f26eaa547f39cd4e1257ad8acf4e1bdbc2",9.917710196779964],[6140,"26dc8e67ae1ab05be8c718cf45973a7f8e2816660b38dc66ad4fbb66009f37d8",9.917710196779964],[14789,"095c245aae3729aab1a45ada88748c3d205598db7089e069f465ab3763951f83",9.317957166392093],[5853,"aecfc6f26e2b3c1d314d078e4dfdffecf292d6ba477e495d441208855c81f9d9",9.317957166392093],[16861,"0a24cc615fca4fe127d6dd89a7737f5f5b5f4cbb8f33039f146301b154351455",9.317957166392093],[12400,"793504bc73c965f1249a42ae06445a5262dbc1ee89b2b348cc8dacd524af99ae",9.317957166392093],[6434,"4a35562acb537ff474edc7677bd06ea817f1c00b64a12e0823c6ec8f560707d6",9.917710196779964],[6319,"2608104fa5ea9065a70133252bb2c84fed352e159a1854f0dcb6d7b31f44e2d6",9.917710196779964],[14066,"fac30e50972271fa1741dadebe34c7196593b97abdefc28c531f8030fe9b4f93",9.317957166392093],[364,"0722171df75a262f0d4e216f24cd7f09433734db608d0b2c4f568f59ab66a7fd",9.317957166392093],[18380,"3b94707414a03b8dbf4f47692b5ce459040697d7fa47c9b40446a89ce4050b34",9.317957166392093],[6675,"0eebf543f5c66511ac00ae489be79ee8453ffd37269da21cc34fc97142fd27d4",9.917710196779964],[6397,"ddd92a714e4b9fef93591cd61a36a5f4740a6077343b5442404d230d38495bd6",9.917710196779964],[11654,"5d9f3f1b90489c8c9eff1f1a49cbb30b4f77fbd185cd3ac169b372fa092292b3",9.917710196779964],[11233,"84d8415ff7997708a2a440961bd289001e8157786ba1029e3618fc93de7678b6",9.917710196779964],[9708,"44ec7654ec6d5d9eefa9a9ba3a76b04a06d9961cd4f553c39c085d1e05c34ec0",9.917710196779964],[3973,"723187b15c0248d7cf0f1beb68dee15890de26bac077320b55273b046330e7e5",9.917710196779964],[17777,"04bb7e132eb111b317f5bac623430eaa504f1dc2046d8941cc2d3650943dc741",9.317957166392093],[2728,"02a8a0f62e0aa8acc7f18a1e36f8786c659057eeb52fcec641b7ee30651b3dee",31.40916025358511],[12390,"b118f3f12ffea21d2b6fbd704ee067c6e2859a49bbb9ab8ed2c5d41fe3b0b3ae",9.317957166392093],[13634,"8206d485ad13330d2bac25f8d23e0e96fc77a453e5a3d193fa93e4ff42d0979c",29.388392857142858],[12226,"f795cd6f52e83145ecd76767791eae9a1de7892fef7408f8ea2af0ef6104e2af",9.917710196779964],[16793,"58916ff4696e7666eecb62ff3e9c73fb5271106833a834413a468166e8cb7056",9.317957166392093],[5051,"a57d5d1daa8ed545e6aa7790f699f8088267dd29a15d649334bf14cfb9c2dcde",9.917710196779964],[11574,"6b11675d91904a4b93482fa3f167de5e4f8b788062deb17371e31292699b18b4",9.917710196779964],[4559,"c9a2813246d3dacf6f01a0b686f4606e6503e9cf2de92b3d22c40caf4758eae1",9.647446457990116],[19058,"15bd12707b71612b04792b32db9f52865b8285cf7a0c0bea8549f413e0357a1e",9.317957166392093],[10065,"65af7b33ca7e23689dc21f41105c5c91a855e57e7f4bab7af960ac82c082f8bd",9.917710196779964],[13909,"42078e35ffa4694785061ccb5de6aa7d3243d8a8d292c2e50a7be9960b72df96",9.317957166392093],[2953,"dc0866d75f2ce5c1c98e64a81383a96bd338e6df529ad3576b0931cd2a91a0ec",9.917710196779964],[14091,"1f85635ead7b23d7ba4191009be49e974359c355463cf48232e98a444b6cc592",9.647446457990116],[10099,"73be06a2492da4c16ca384ba4986cae1774beccf11b762a60f32300c94f6b0bd",9.917710196779964],[5970,"64d3a21c97e285aaff29c3714ab33221e73b0e3f3d3869d4824e334e49194cd9",9.917710196779964],[18083,"7906df24d3c79bb66e450f81d47810a5c3db1cf09bbe801990e82f64c5fa763b",9.317957166392093],[16135,"def19bf9af45e036989ce291ce73b840c342817db5bc08b526e3dc5e1d065565",9.317957166392093],[11635,"330a4479bf20e2febb18d43af78ca7e2091f90d0d39720eb0924239de393afb3",9.917710196779964],[11122,"82f2406a25c84fe5a697ca37319265cb6e486b98746e1331ef7dc4b8d23c20b7",9.917710196779964],[11082,"2cfd204c9248466bb7e7a096cf6890b16c8c1815fd0af78ce66e72052ce563b7",33.37251787132645],[17534,"9195133733f2311f932d46d0a887de0411ea352ecea3347102b459e632dcdb46",9.317957166392093],[15339,"cfdaeec42235940a7a233c1e677273f67ab34e275ca27bb479dd556e28a69777",10.030959752321982],[3863,"80c63d0b0bc7bdcb8e9c72183bb5756d36c30d37bd6189d337180e1a1ab596e6",9.917710196779964],[272,"f4780896fbe98a30941bc2f724c7d2b940f2d7da1e924d53746d1b8e94e820fe",9.917710196779964],[14369,"e4bf23fd405671b5cc4a77623baebfc1e63fe64a3bd0ba49bee66bc5ce9dfb8b",32.191953465826465],[12290,"04646fac750ba91cfcdaece71b3fd9f0c3eeac260dd9eb2dcc0d6032f1ed52af",9.917710196779964],[16194,"72c32527ec8aff746cbeb2e1c3c582b58b0caab31c083d31a4fe1641f4fe1d64",84.9795918367347],[11698,"7a67eb28a15f09ffaf750549836c8a91910220c110dbc63a44d4c46fece850b3",9.917710196779964],[705,"2bdfe8044c62b81b4450fe3378528ecc8ace0decd74e2c358742a3bb00de2efb",9.917710196779964],[3676,"054f866dbf61f70e9804764b335bdf9924e3f4b74cf01f63e58cbe717827c3e7",9.917710196779964],[1497,"403beac8d785f82106165ea5682922a19456d6f88757a49eca38d4ce684d23f6",9.917710196779964],[8649,"fe84d9a74df58fcb6271c726676d9471e2e4f03572297f12a646951b8a760dc7",9.317957166392093],[9591,"425f5d160732e95153929530b3bbb85e084ff15b3e431025bc91156dfb690cc1",23.227272727272727],[12103,"aedc0f8f879950b1ee66dc7ee99ae35fd335ed0ae5acbfa9a64bb32faef6b0b0",9.917710196779964],[4943,"38c573e1701fb9e38a2065eb28b048ff09666c5da8404cb817b587d504528fdf",9.917710196779964],[11659,"c3f40b0697c0bd3bd2551a6720528d6bded7c3bb8dcc4847fc16ad393e9786b3",9.647446457990116],[11250,"acae84e394311e524127d07938783ae21dcdc562c2f8eee6bed6fa55b40959b6",9.317957166392093],[17429,"cf535de92803cec913c6a2f60bb5b0cb2f2d5ae8f130825cf410bb1f754f2549",9.317957166392093],[17433,"52379af14b13a4ef3be9e88056f111af6aa3c12f3432cbe2e82670e692df0a49",9.501030927835052],[9833,"fe6bdde6c850602712b0238f8749f76ab361a691a212c96dd5edc253d3fb65bf",9.917710196779964],[8857,"828a6be2c266253bea691dfb3c2b12e484ffc636347dbe3ff31fa3386e8bbbc5",9.917710196779964],[7308,"a779f32c449e69204f7e84ef670ce00c939b3f2bda107e2da6cd8452a3ea04d0",9.317957166392093],[5879,"1875edea499372dc37e5c907886949b0190fb60ee4ccb8b8a1feb4ab4805ced9",34.89679715302491],[2168,"02fac7807ec9bf591d7764c5950e5344b537ba1308ce383df5f73d6b1b83ccf1",9.917710196779964],[4386,"a3c4e3498991e0009efd7f62e509d581eff5878f7e113a42dd785bcc1b0229e3",9.917710196779964],[2832,"55f8259d0b8f193acce6b07a69a26950d4b9c1e25b33b91e842eb29525827aed",9.917710196779964],[1069,"a4ef9a2bed6fedafe8edb6793ccc2bc0ec43b45d3301a3cae2721d14b978c5f8",9.317957166392093],[6215,"5b8766af02fd806084016d8d611ea6721a0af5308c4016c215813a649c8ea3d7",9.917710196779964],[1256,"5a624e2006ca20223859f52747f95b485075a0ee07104d6b0288dfcaed2e9cf7",9.917710196779964],[7468,"ba8f483a68ef1b50bc32f63433120d39f7524951c23507db54938df15704ebce",9.917710196779964],[15548,"411657fb007910cd28a766539b51876a026cf2c613b352b3998d1fa6795fed72",9.317957166392093],[17233,"f3b2a06271031ffed624845420a4f11332f093def132384b860cd9f653b63c4d",28.09964412811388],[9726,"49986361e5fdc1fde7005dabe51a9eda973f2032230eb449710b6a6e47b125c0",9.917710196779964],[8526,"66607be896644f7e5129ea81422dbee76b36b7a541669dc5a02bf97d1477d9c7",9.917710196779964],[7070,"c6ad10d5224680d6190662e7fc46312610c793c84a4ef4c2e735d1c2d6ce82d1",9.317957166392093],[14143,"bba95d72a12bc99a46cc18f60645b1b6644daed088126e85b401feab5b27aa91",9.317957166392093],[9059,"1f694f4b3eee9a417f9973dca93d90a0fe77b578667e075689946490ae1f68c4",9.917710196779964],[13321,"8cdab05829fcd051bde2a5a94b3a3ec5835c2af84c93d1650037635c5df631a4",9.317957166392093],[2509,"ea46aacde5c74c9d68f7b790c5840b3deef3fb3f572cc21a8ab424d99c8fc5ef",9.917710196779964],[1312,"910f67de2a579f9a4894917170307be127c565d72ae9eba1258b39ae22dd53f7",9.917710196779964],[16222,"4e3745d42f02077337624d97c6a6cda8d91065d05eece41e64575b4b8e0d5063",9.317957166392093],[2247,"3e09fce2ad854dd5343fe58409241a98924f8454a3378dd72d5d8144ca3243f1",9.917710196779964],[9861,"3e05dc1b9f6168558a63db6488b6c242ebb0f58835e030a2d3440833162636bf",9.917710196779964],[1580,"66f93f6be5ec1364e45fdcb2fec02b8dbd2d16bc7c702494bd8d8a4c6290a6f5",9.317957166392093],[16786,"7f3de4fe48b7330ddca3bfbe5b1359dc29a6a16e5aba3486af33b64e8bd1a256",13.22340425531915],[3469,"e1f38978641392985915e776cecb7dbcf2c3647d799ac244dfd67e465f8841e9",9.917710196779964],[11814,"e316581cce3e32c6cc63e1b0bfe2d5f7b002885eff0d9ac706040305a0429fb2",9.917710196779964],[4481,"1e65699c62ce373a1c0495528e835b4f9f15df3bb3f8c7c1dd28ee033d3e87e2",9.917710196779964],[9770,"f68a063fe074ee8a1cb837d5d44c267ab5ca8500f868d9dab03e3af56254d9bf",9.317957166392093],[19054,"df39125f47023c4c5c95b0b90d13b043ed488b0bbc953c3884d4fffddfe1a41e",15.003322259136212],[12927,"ef40f03812255599370360ecc35774163b5a75e5b75c711221a5fcc85c271aab",9.917710196779964],[8801,"270736e8a75de6a9c45c9d5be502a53994e09fac22259e8d3fd218f1ee7a13c6",9.917710196779964],[11007,"a4ae7493e8c6b5a7c5fb7dd15bc6e618466a367a5be1c1edd4ffbf588b25f3b7",9.317957166392093],[17235,"40211a88a38606d3a73483e8725353885ce0e2f5974abf834e5eeed92724344d",9.317957166392093],[19052,"c7c6b6485f0a87ef990805a66b6c2631422fe13843103e79a4f8922fe882aa1e",9.317957166392093],[8610,"14c98fac476f82f9a4f11e1e2dc5aa2df404ffb519c464b93063afb9a28d5dc7",9.917710196779964],[7253,"6a78d84ee92812ab05da2a7d7c53a8f291a7860343372e6edd87746b9c615bd0",9.317957166392093],[7189,"506d7cc40a6cf9e8fffcca52d24a60ebda0b28b9bbadc07b79a4a0d13f1cc4d0",14.92526690391459],[4927,"de057700f06208e838eef567c6c99953d0d6119bdccae5c13589df54c6faaddf",9.917710196779964],[1676,"84cfbab11ad6bf606d82e9e552c4e63c41152e33bc9e9eb2eea8640a9b5c12f5",9.917710196779964],[12267,"a5954f907d52d57d99c6d445ddbdc3f1da25fe72e7692cf256e9999dbd9290af",9.317957166392093],[15527,"5f181ada6efba620567cdd7b751dc5692a281ca9dd50bab8e5981a6980a86273",9.647446457990116],[19439,"de28cf89d4960ebb609b6c9a0cd9a39becbfed44e0164fd8ca761c2292502810",9.317957166392093],[15304,"11f2aad48589643470e5b72766da20341404abaa703ad6f16d765a69f2e34b78",9.317957166392093],[9811,"3f60b0d98630ad76248349f69628dfaee3d9e6da34d1f5ed5154043895d390bf",9.917710196779964],[8838,"7bdac251dfd86789bb911ec4a327150405c5d209f30a8ea4ef1f4b5ae03bd7c5",9.917710196779964],[15691,"7d9d6ff954953cecbdc69dad4bbee9775a7315c68f0b76b0398cfeaadd3da66f",19.23112128146453],[9921,"c6ccc524acbaf99fb309728b497dc7010121742af5a42a0c4d9abd97aa93d4be",9.917710196779964],[3347,"3ebfecf9a61cccee54d6408cf0f371a983f374d6f21679d309171b8efd0505ea",9.917710196779964],[16659,"55f83290afcf303540f55dcf598fa911dd2ac4e86cc054280ae2460a3e5e8459",9.317957166392093],[19656,"20a78604a385757984c1836ca213cae77cae97d187e2b06b05e3435256d7dc07",9.647446457990116],[1491,"794f228a31b8d4da72f4879d58c107a02fe7d2670c028711cd18977a83922ff6",9.917710196779964],[5693,"3a79123edd869a857106229adc4e6693fc9f5dddd8a22487f64bab065e3616db",38.00356506238859],[6894,"974f4899cbd2315739a96df30e68f1b264dfa95e84058f100270ecd1c963a8d2",9.917710196779964],[6789,"dde2ef340b32debe468082d6e46cc3c58f2042a96776b4b66dafece256cb5ed3",9.917710196779964],[6876,"d7aaddddd541ca9eb33a45588de4354ea141aab15bf34e87522e3e1c1a63c5d2",9.917710196779964],[4775,"6d6a7885bba0da225ee2eea0864a04cd67722f353d48cb6a9716c4dc068b89e0",9.917710196779964],[18545,"d78ca60197c696b0c38239a9046c97b6997055004a49435bb266d8dedabd8e30",9.317957166392093],[16957,"3c5192cccbead6f7c197beeb042f08e45bb966d0af872ce90d4654fa72800553",9.317957166392093],[9230,"89b781ce52faf2b34232a82ea6fe9ac23acecab0e33b15f137b5877d4cbc39c3",9.317957166392093],[8966,"367ae36af158df7c59a4a7b0b16957afed7440fde7dec42ecb81e7dc40160bc5",9.917710196779964],[6468,"733d83753dcfce815e2466eda99bea7328c946cae2c8979b7d2ac838a732b1d5",9.917710196779964],[10643,"3459e5eb24ec99b2c80a403054ca9762a055bf91c8dfc56a6ff2dfb0677767ba",9.917710196779964],[9709,"8e4fc57b20fe9076699effd2883944d5cca465db764054c1a2ba7e3f73f44cc0",9.917710196779964],[5707,"c6861e7c45e8f6aa098b819d121f56cf949001700cf8b170374ac5114ed303db",9.917710196779964],[8445,"689a25dd8ac678abd054e25f033b089a55ad43a052c4d244e3f8107df95458c8",9.917710196779964],[15680,"ba7944b8d364d378981e614a1090ebfa8cacdd4eb5b7212aeb2b31ba0310cd6f",9.317957166392093],[6813,"668e740c5defa527381f5d7c7b833baf8712f5221e5de7b3b71b076fedbe31d3",9.917710196779964],[10383,"90b793f27e84b8952aa4ef54d66201e70cdf7be53bd0e6b4f4ee427570b3e6bb",9.317957166392093],[2055,"f6738a1d668dbe588b0437f0e943d941780883a6c12a5ab72260f86dddd894f2",9.917710196779964],[18933,"49d61c0b0a8edc95daff5da4602d0f044c5dfeeb1112f1d63fc26ff5514e7d22",74.15384615384616],[16227,"f660d24b144e8c450ed122dbf88d2246c5ebbc06a4b15407b87a0a6b48f81763",9.647446457990116],[18970,"f9919f4f09bdf2cbb4fbac673baf6b4be87a26ad6efca8a24775ca1824f18721",9.317957166392093],[17872,"3bc6727e6ea71880f9a9bd1504ad2c55ff98be31abc31cf447c368975ec7bd3f",9.317957166392093],[2591,"cfd0abc4fd7292dab361f8361521a37d03798fc7157db7bcbf25b169928034ef",9.917710196779964],[11068,"d4d3301a9c8145b9f08f056dabc6a96402272b9366c69dd0935a48a7483e87b7",9.317957166392093],[6163,"a8ebbaf42ee67e2a3d3717d356f16391258038b069c31f6c7584e53a0f1c10d8",9.917710196779964],[18477,"a62145cff730b1b690f1a152875e126cd7aedfcb56f8c3af39e0d42ffb1df731",9.317957166392093],[4981,"976dadcf53ddc1c82fe086130a48018dee633002c97b25e7fd7166cab3a04edf",9.917710196779964],[10511,"28b56b59ee10dceceee3757def01fc6d72ae40c8e661c49e9190b3011a761cbb",9.317957166392093],[2266,"9fbe322cb00281eacb98ed76b9d8deb0ca0d2c51134f9f796c21b84d9ff52bf1",9.317957166392093],[8247,"f076a26c9580051558e24bf714c25dc352ebefb6b11f13357382f06e9c9ba8c9",9.917710196779964],[18998,"e54a8e9b758e05dfc97827b4785bbd626ff80e4c31a7887f922e2c5d9a559020",10.052724077328646],[16302,"07eea4ca8d5f6fce6e526fc3517d138fe53f632e7d8034fe461adcfc79a70f61",9.317957166392093],[17515,"58f7f95853547377495bea033a015a9a24b1450fa7497458801ededbb4c62e47",9.317957166392093],[9154,"7b1417b8a958ac86fd95120cb64d8cd73765bc304d523b2831eb2a09ff65cbc3",9.917710196779964],[5681,"8b57ebd57bdfc9e8465a5fb7af6a52af674695f8e8d0e1f149144dd2f08129db",9.917710196779964],[5942,"b1c77acf86411156ff5e06f268aad3fa7ddb9fcfa105bb56ee5b72c3d4df6dd9",10.052724077328646],[1667,"56e772b9d123086767b270f25dc0cfc716f4bdb32a129d24bab802c11a5222f5",9.506082725060827],[2371,"766cf3ae5f0cfe09125146d62f457db5d0d2e964996087451c31b05dcf02a3f0",28.12785388127854],[10022,"0cfe132433e8fe31942efb704832ac0ae84311715f546b15fee87184e01d33be",9.917710196779964],[2799,"c87aaf48cf714beefcd8a430c462355696455932c57f4f13e7af0424f409b6ed",9.917710196779964],[7004,"3aad47f028ab5e329446ceba3be7d6aaa95db8410163885618660ab8bf7bf8d1",9.317957166392093],[9198,"cbe2c225ad3ed194b69634f13edb3c02e0a2e0ce73ed6abea621b34b261473c3",9.917710196779964],[6209,"d7620536a1992a280340956982a492997f8cf75dde657f25fa09130273f0b0d7",9.917710196779964],[17840,"ded892c8831f424c949d4b0db37b93d90078f47ca3664158190a2f5fb5217440",9.317957166392093],[1821,"537da3a207348a0f862a017b7626df1584df08a191e532179733527cced41bf4",9.317957166392093],[5423,"d9f6525967cb0315ffedf72d64674688338fe89344dfe74e59079f824a3da8dc",9.917710196779964],[5048,"31d464ae76159ab958105492472904f5a150a0b6c791217f10aeec24ea0ee6de",9.317957166392093],[7297,"9223e06443aadca4bb2d8d7733e5c958c3667a3ef8961c8aa034f183153317d0",9.317957166392093],[17449,"915260ff005ecc6d4efda46f67f620a745ba872b4fa99c77e107144c5a3cb448",9.317957166392093],[15644,"bc530fa4d0ab31b19f13a4c4c825693b33621edf4487aed429e415ee09d17570",10.052724077328646],[18683,"2bb9889b56fbc55b8f7d332a0392b53e7e54aefb888c4e35cc23406e21e51a2b",28.187082405345212],[14707,"4e86a2fd2c04de745dcbb6a22b446583800a691171467170944029bf8b17be84",9.317957166392093],[16352,"7eb1c66a0693a9a9849c3b1e2ea7180eadcbff7389d3ea11079d48eb33a40960",9.317957166392093],[6275,"f7a0cb3f108408598a7ba98b1584eb100271135264560dd71832e5e2c5ce3ed7",9.917710196779964],[13190,"f9417192435dcf4aff6f2551b20997ddc7906496a5143c77505ebdd37d0e18a7",9.317957166392093],[18962,"aa733d34f7ec3efbc1b18a0a9dbe41956025d13c0e45fbcc34a652140eeabb21",9.317957166392093],[4686,"0c6624719aa8e16443c42c78e7a3ede27d9d08377619e88436b8b7aa38cf15e1",9.917710196779964],[14982,"c8e71b253420f072d02c7e0da93488e7ec53d6e303b29794cfcc369255d3e77e",24.70110701107011],[6200,"54f8a19e29c7d8d93511b818ba7fcf564322acc4f8cf3832044fca504cf0bdd7",9.917710196779964],[690,"2bf2db39f2a7334a93435b559893852f740b7e71f982d11497f7b224e60c51fb",9.317957166392093],[4486,"5bad36088171143b48b74434910d2de104b01ba833efa226f010931f6b9081e2",9.317957166392093],[9471,"0831df8b8739866118af4b43ef40e3e3952a59437d956688ec17e8beaaece7c1",9.917710196779964],[12344,"0f2571734ced867deb4f26658cbd3202b9c84b9248a79f28c4a6a7eff159efae",9.917710196779964],[16147,"3680e10dae62c60793a66e49349efecb109d5e889357579067f23455de461865",9.317957166392093],[7766,"d53ce4680470f5ce07694a93f7ce62f28fddfb74076b0803f944ba07b7050bcd",9.317957166392093],[17151,"453d4542c906f492c3402c5e3bf3d7487a50a7572122dfd6c8ce7b7370fb0b4f",9.317957166392093],[6652,"aef7618f8f7fa40c8b48158eb7e111569494c0312c571f466c6ebae7b6b64cd4",9.917710196779964],[18197,"14ca0b164e6356cd93691aebe8f63278c1977473c95c9217cb417db886ef3f38",26.002607561929597],[4872,"04d9c256b2fd8a6d50b2cbd17ce9b9911344efb7930d36f01a42c0525b1d02e0",9.917710196779964],[13570,"b6f74fc1cd68337d8e8d956b2a613c0605036512a64ba8ed8a46fca81091399e",9.353846153846154],[10406,"d3982c65f54c9a242988bf8fa0fe5c1b01ddf9e7f32bdd2463efe36ee4fcc4bb",9.917710196779964],[16376,"b2d19c49f6f447e6f6ac53c9a20e6ff40c1e71f05426978304f562b5e767905f",9.317957166392093],[666,"485d6c2f35d40c0912e281ca094e26d47053acbb564f593768c17f13edff78fb",9.917710196779964],[1321,"e6cc1686d41b5ca8a5e6ac0f68e163114d0dfa0e6114edd339b0893f3c3c46f7",9.317957166392093],[2063,"dc5ae2efae66dbb72fea83a2456e421e6f59aeb981b05e8927ced011dee877f2",9.917710196779964],[14030,"5b2a401e49206e9971a048e8e4595c0315f5f56af678a3c043d6ae9e25680f94",9.317957166392093],[86,"0a48d23276462c23f267f0b43ebbc05926aa0ccc3e4a69c7bee959445f1470ff",9.917710196779964],[17043,"a771915cb42099164268b32af32f52e3c24c012eb856082c38818a1a10132a51",14.11916541191654],[4690,"4a8550bd0ffd6e5827b013b98f28469129e6311deb6f7e51c19de9472d960fe1",9.917710196779964],[10741,"4a479d8e01bbe74837c4756e61659e17ca084976ad4d38fb71fd041e219dbbb9",9.917710196779964],[6701,"1ef9b5c36fe8826300218d8aa3afae87733c3913b7df52d7749ddebdfad5f7d3",9.917710196779964],[6449,"1c95660777d3caa3afbd64f7ea8cb2e9630ec6a8cf1211e3bf7a33036800e7d5",9.917710196779964],[6019,"6a9f2ff179eeb2f798505ce7610840d83b14b625c08a1d0d9e7f2ff97e1ef2d8",9.917710196779964],[6227,"4f96fff8cf684537e5bcecb6135b78133b1fb95c8f329823781c7fc1d0a091d7",9.917710196779964],[3435,"edd9e65afaeb9db028fc6d01b90a4021c95bb08cf84013916af60b21093a74e9",15.956521739130435],[16908,"4cf21d56af4e87c8e25789a7709fa3de031a1ad4407e285c9f62a6b526faf153",9.317957166392093],[12134,"9d151cccaa093956aca21b5adf24c34f2616396333628f2be187fe146fdd7ab0",9.917710196779964],[7371,"e094562af2d2596b50a46338c8fb972166597013f800786b8337cfd7233f92cf",9.917710196779964],[1615,"00bbe37a0e4e93e6a5afe8e31fa66943b50704f676cc935b3ad6a9654a7b7bf5",9.317957166392093],[11351,"2619e728ea2adc8dc9ac2447cf2af83299b38c4153ebedd4d76ac06ec940abb5",9.317957166392093],[17717,"6ee52a2fcff859482534496cd0d2ad74948c8a745621df745d6c77e7d82adb42",9.317957166392093],[607,"9a15a1358f9a7cb0798a5f82763854e4676575e7678d59a06ed3dd4fd12fe6fb",9.917710196779964],[17702,"87ad7921468b691bbbb7255c5917898fe1b6160126965251004c326026382743",9.317957166392093],[3784,"6b8815ece5f0b704e35ba7a4b5663135eac753b0d1c4ffa90aa15d7617600de7",15.003322259136212],[15502,"ae10dd01f1c91107c3a0e908aa6a1622aa65c12fde940f2cf5e2836d46f71774",9.317957166392093],[660,"6dc2937dcaace9dd1858b892739e46f0e0dc0649c5177293cdc487422bda84fb",9.917710196779964],[156,"2587bcdadd103a476b8e45050a96cba854a2cd03140a7c3c0a787d646ae7f0fe",9.917710196779964],[9293,"4b9db4c27cec5fd96f1cc79270ed49d32259f318cd63e13cd9f6aaf0a082dfc2",9.917710196779964],[1921,"28917fee220f7d08f828e1f537401632f0f64c40f5661ad66296cb6fba2389f3",10.052724077328646],[2467,"9a11cf2a6b7dd4ce9ecb80326b78b3b5a47abcd3bcc52586a75a07b6f81a13f0",9.917710196779964],[16415,"188531c01046411568244de07657e2810fc6ae3c238bba105c3259f3327ac35e",9.647446457990116],[13518,"ab49e1be871cd9c5e267f7285afdf17c31cd480901dbb96c78d5ccc0c30c679f",9.317957166392093],[13887,"ed760d8c4847830f0708af3581f4339468f2264f1066dd156525f83f7ea74997",9.317957166392093],[16308,"73c3a2195246a25e6e1225a08243e5cfdb3f03fa13147e4e9d7e40e1fd21f660",9.317957166392093],[6029,"92fc92b3a773a56745fe382d097cac69e59c127a3919d17906d90cd1c538ddd8",9.917710196779964],[11950,"7cf035351f1d85c5087a0c0c8dc6483939de561a36b617bbdb05c18ad1f8a4b1",9.917710196779964],[19138,"1eda24ae9da7ffdef548bb5b0c7f874204de0641a1d49d9314447fbc9e1feb1a",9.317957166392093],[17383,"43baeaaf586e54b4075a662da1377581d728e5d88c561f667faf2ea79473224a",9.317957166392093],[808,"87d27bde1689e22b0af090dca9b9cf4aaa7f13f0c6f17a716afc1d147c7d81fa",9.917710196779964],[19703,"4953247d893a38fa426c7d6c7f47192aebf64615b8539f7df98e72be2a84c106",15.003322259136212],[4398,"677f4d2e58069d352413e575dc7dd463a0bb81e38bc932c34df40fa6adf018e3",15],[17612,"01b5e3bd28397465e1cfc3a98d70908451c20ba33f7675bdf6ba76d51ff1ee44",18.313588850174217],[8400,"00ae03b4df7539d74d9f5b9c6b09137c450cd215a88fc041d1a3c83de01f98c8",9.917710196779964],[11993,"c02c9fbc670a8eca896d729c185062e28e83f6bb4356c1673e9e183b57ba5fb1",9.317957166392093],[1871,"2a9830a72d25ed940870e717aecda2a21d8058257903a69b838447b30727cdf3",9.917710196779964],[10274,"cb275ed5b4a59815ee82a6d98b58b2aee027a356365185b8f9b132add6b08fbc",9.647446457990116],[185,"e5ebc2d2d78306ca4282eeef1883ae1a7ff91cd4cb061cbed37b26ae2d38c6fe",9.917710196779964],[19452,"404a675917c888acb7ebc36fd93f85e221f236b70c318c98b23933f3c42bda0f",9.317957166392093],[1881,"cb66698b9e38fa6c7a5fd7e96d579ee03f142da0f8e534035a843a011e84bff3",9.917710196779964],[10812,"be661fc3e5fa324627659669d60c6eae19376b11741fa6ea27c27aa66cf834b9",9.917710196779964],[19462,"005cdecedf476270c5c682ec850ee717e775d20b93184733d696512929089a0f",9.317957166392093],[12184,"efb2433cac04c53f8d5b836f368fa52b74820edb5ed9065d014ac413b10928b0",9.917710196779964],[14155,"5bf7ae0dd7a57e055d461961d6332c9c312a0109bd32f9b03d5c8fb652a15391",9.317957166392093],[5653,"0a35ae09d99abdff276c5873c183148e39d0542b70ebcbed428109537e844edb",9.917710196779964],[2470,"d7abc94c1d1cecc5992339f38c1c81e8094f7d0bf3145ebbd51198fcc78d10f0",9.917710196779964],[4171,"55f2636167c91a6633edd33550a0659d36079599a651b3a81b29923766ee9fe4",9.917710196779964],[4128,"b252b3532215ca1c238c94d3417b158b016a902c59b979fbf59ed466462cdee4",9.917710196779964],[17173,"897113b373763306ea4a8a358b712e090db0679dd34cbab58a3b9fcf74115d4e",9.317957166392093],[7825,"2c7eae0ddbe24c49662e227089751ecc506b0ea65178e08d2a2f41a87b119bcc",9.917710196779964],[10606,"46fc55d2a78342ae5d41a5c670368457927bf6b7613b269b7fd6a63e25659dba",9.917710196779964],[13687,"d3de8562d571440c3a370e78724418a88b5139a9eeb6c2d4618425f9f7676f9b",9.317957166392093],[13891,"32c1aad8408c8b66f2c2de472e110c9b5adcfb08f751bac228319014a0ed3b97",9.317957166392093],[11839,"34ed753a23ef9764444d26d7617965dc0c761743d365abe73aadd83f40b277b2",9.917710196779964],[5646,"f182707a5afed27ac1741a750f3ef366dab05ee80d89621d0996842293795cdb",9.317957166392093],[12117,"c33e5bb27f2d6df633af995d572e7c27ba7d4aa85b0526563387baf02a70a2b0",9.317957166392093],[5234,"f0bc3c8dc45e4cdb298ba36a9e2a72f8942c642e9a39eec0070db624dc79c7dd",9.317957166392093],[4173,"31f61bdea986400e2536b6c7049c0b7911df345a63b9b1738ba982116d609ee4",9.317957166392093],[4519,"90938ec1650bcdf2e766b01c4896522949004367db911d10d846e669c6a23de2",9.647446457990116],[11123,"83097cbaa68a8a45747a8562a3a9e97625ca6f84ee8d82920e9715da0a3820b7",9.917710196779964],[15513,"ec7820eee4246844253f39008932ad72d5b90e26ac19bb98cd57860b5ac5cf73",9.317957166392093],[18834,"a1ab48e8d84ede48cc010beca3e4401695ebcf7ae050502acc42bb45a5eb8825",9.317957166392093],[2523,"8b83260b2e3205144a836230bd515e8fa418f4fbdc30603a08e2319c86cfa8ef",9.917710196779964],[15723,"ad741c1fcfe8cab0ceea756a4d13d0585095f97caec10c8832c69591c60f066f",9.647446457990116],[19153,"45f5b403f29bdd8c9a72ccdb7d494ab1bb80948053cc709de48c4478709f661a",19],[5833,"70951de30ea23877f205ad71ca1638ddeea22feb97e6d0a8295d020eed5826da",9.917710196779964],[15906,"ed6e455a746ca7c4a3db916d6161841fc261548e6746daaf1ed3230b72afeb6a",9.317957166392093],[17544,"bd20d1a3ff170abe95394d6d9b3eb376e94156c011f8ef898f73df25ae8e9d46",9.317957166392093],[15545,"426d8b58755d4e971fafbc4819c13bf0b948b1c0d5137e14e96dc95603e81b73",9.317957166392093],[2036,"f3661012d28befd409777a261cf38c61e5ea84f3cfa4e68c14ddc676b01bbdf2",9.317957166392093],[1640,"77330d4d2f6055cfd14cba3c40ca9153c44b4b8b62df165b271572b817be5cf5",9.917710196779964],[11279,"5f17b45947fcf33714ae8934fb90dca2d6a0dff5def0f4c62463bc1b6e862db6",9.917710196779964],[10839,"be8a00b6caa5ad59698919d316bb926e91e2647fa1116c529142761b33a20db9",9.917710196779964],[12220,"d14b992fb857de7e32ad86398956d43f3224d4118a5f12f529d3e7c41319f1af",9.917710196779964],[16150,"1e039429b1f2448566b964fcc2007ea0f9f74d2b819e98a2116e278e1dec0e65",9.997888067581837],[19181,"b1f3ff35b457b069294cd3b3236459bb64863b1e047d328f7a7432a8e60b3f19",9.317957166392093],[9088,"2855f90b5dd92fe6226b38905951be3a341f702de59e7ff34bc64f56b1be3dc4",9.317957166392093],[435,"675b96160a1f5a4b1c3a84f190c8ae77cbb07a450f5547cc6a50517b748021fd",9.917710196779964],[10486,"c2bc047a10aefcc41fa9f2ded0a9874d74cc9f2f99ce9049339da54e39ef3ebb",9.917710196779964],[3849,"ff0273475ddac98f045d1309ad220fe80d61e288c0aba39368f99d741af3b9e6",9.917710196779964],[6187,"2a62d263a89bbf4a30c88959f19285c1eea3be2ca0860bf59c3506578fc9dfd7",9.317957166392093],[7007,"3b0ff81b8e81325846c54a235b0794b8a2fbb6904643e7a92494d53f1258f4d1",9.917710196779964],[10575,"20ddf6dd36c7cea38a05fc2292cebe0570196dfe1e43e8bdcc7226ca443ac4ba",9.917710196779964],[12283,"dfbabe233beda454c51f3fc07adcc296727318382e96e4e10a1e2408c12263af",9.917710196779964],[12015,"afb733685dbd3cba51e4ef3669c60a6dfa1df78b06180eaab077cbbeff843db1",9.917710196779964],[17145,"715206731ffa3f78a05c48af67971ad9403875d6ab99832f7b7928a1979b254f",10.052724077328646],[16418,"0cf5804ba985ae3f5ef226a776a23fc2dea657394a5a186f1d25bff38618b55e",9.317957166392093],[15628,"f9b202a65cb7f7178f3ce2620262ed5987ad76b5af9f1a0e81b3bbc1f301bd70",25.7864768683274],[12417,"1430e2f11a18de62e869181a22d92e7fc135f66290b1fca9fbf1cabff6097cae",49.67259786476868],[5777,"23865f483b492aae42cc51b2aab5754878d0498f8628d1c7efb8c613280894da",9.917710196779964],[2030,"a66dbdc932853fe9ea6f5db173b9b6f9835b9e117dc4176e8eb84b818b8fc2f2",9.917710196779964],[4948,"6803112ddcb589c7b464d7be116f82123f05a9bb975e5adcec0067e0cd4e8cdf",9.89247311827957],[16331,"753eb373e9a7cfbef3fca92de36e151b528d8c337872e072cfa11b6af4f46360",10.052724077328646],[4464,"7293d87803e6f5c39606509314df2f8820970095aab1bd22a1f046b5cafda4e2",9.317957166392093],[2505,"42c3fd4a32642ed4e07c2ef355bb1150d720ac52987ce2dcd5e8dba4b98cceef",9.917710196779964],[5828,"83194abf603bd5e6db1e83364aec9e4afa0f0884c99bac3da169ba32a89c2bda",9.917710196779964],[5483,"c13dc8f4d59ffbfdac32026adbb43194c21c63ae8865728c5ad0034ed9024fdc",9.917710196779964],[6988,"42a90aa966af44c1cba2a7e45f9beaaca8c67e9b3a1fee98a35ad33c167915d2",9.917710196779964],[4673,"f0302a9abf986bb3d90efcf6c7127877c722c77d6b2225955fb70d58f52729e1",9.317957166392093],[5702,"83d276f2ec9313b2f949236ca2e80e5dacb21902925766887a9446d8dd1809db",19.192118226600986],[1485,"7e490fc54826c210a618be9329c3e35585afa00dec50089973232a44dc4337f6",9.917710196779964],[12563,"b1af07ebcb25e22ded0aaeef931239f6f69994f6a51f8f8e9215843955a98bad",9.917710196779964],[17653,"0c055bc9d305e70eddacf4603d42c4ca50d045faca7281fff387a1dfada62044",26.077611940298507],[8577,"0ef750fe94a10dd9a21aa046b476c8063d3a1a398f005d05b10eb39fca3b93c7",9.917710196779964],[5549,"4478a938dda358b1eb134dbd424f81487ded2c4f7137567afc811fb62b31f4db",9.917710196779964],[10413,"62864e47cddb5faaf0924eff7fedf9520a910e9d8ae20490994ee3a473c7b6bb",9.917710196779964],[17448,"418c94cc684a0c13c5b59237fbf60c7c1828b0b8dfa801299ec0f0d44000b648",9.317957166392093],[1755,"83e527316fa910c2b52a27c7abd254af613b184911d9696f5ef74a03ddd58df4",9.317957166392093],[12545,"665c4c3118a7a674ac853abb2663d6de146e4ead5ed595840023d2d358d5a6ad",9.917710196779964],[9361,"0d36d8c80bb0199ff173a76ee91b53398ef265caee8fe66a82eb68af932680c2",9.317957166392093],[16306,"2bd08532772b8152c80f3873788b36a3d6a660c08ba3509f7408b0a4b8af0261",9.647446457990116],[8282,"ebc3d481685f93f9d0dc20c06b4a0327a6b6199b21c1f76b7719a43cba1175c9",9.917710196779964],[5278,"4d09349c75ea5daa1a3755f9034092f553f6071116b83d41d95d1d86187c8add",9.917710196779964],[17385,"f621a38a4e8bd8c48932ae1ed5e0806ef563a513791dc565ccc4e04e91db0b4a",9.317957166392093],[4356,"5fcd8727f5940f5191001c1afbb9993aab5b3fc22d1431f4cb6b442f1bfa5ce3",9.917710196779964],[18616,"814907f4c14dcd45b0c8fe274cca8b4df5a786b7e6994157401e3a6f9ee63e2e",12.023062139654067],[15297,"b66d0fb92f3d692d635b01e55ab433c69e261f436ded8655a20e44a802c59478",9.317957166392093],[13401,"3f7f6b8a4f0ce4fc9028eb2b87583c99bc41a5c5a7ece55d9c2108774ba83ea2",9.317957166392093],[16432,"b7398d941f686375a7fec010c7e989013f42de3cad27197979892ee8376c7e5e",15.91637630662021],[16429,"0e1837523dbad665084253ee765a747d73ef8da1fd25e6d7e4ad6066e5fb815e",9.647446457990116],[17068,"27713985fa32406f97b33f0e3f01354762d86ae65e5c27481e1d21afff19c350",9.317957166392093],[19676,"01fbc23b8f6262926f2e1c703f682aa2f98536857c4fc12e7da8b69921a97007",9.317957166392093],[18633,"c971131a91dd110a8bcd9343a6555bd84b811b33053fc2afcf7e70a7140c7b2d",9.317957166392093],[12152,"d776b8ee8b24590501e185caa91709c040854cd4699467aee491adefcb4654b0",9.917710196779964],[15950,"79abf59ae5addbcdc9464949ecf03fa2f8798727235c0e74e5c3cefd465ef469",9.317957166392093],[9548,"4f4041ce85d4a4bb90009974216c3a99c1540a9878fbd930f8381c76035867c1",9.317957166392093],[9601,"82f5404a56e04548f0add1d3673221b39c048697bb4de42fb003aef9795e05c1",9.917710196779964],[3966,"2577f029e472510ffc4be047b449959da6257beaacc93980ed8216c1f89bf2e5",9.317957166392093],[5030,"e699c750928ade8ee92e2d4c968a10bac442f3c22f8a82c2b06e9d3a98dbfdde",9.917710196779964],[11289,"f47aa6f86da640ef5ad05f7e5f8bd36ba8664c3451ac14cfea1fcddd679a1eb6",9.317957166392093],[15096,"5ad84e20f1bc97ac49ae11cd2c765b6cbf308ae975d3ef53d14326f99db4bc7c",9.317957166392093],[4443,"b9f7d9f1667d54f08e7cd1409af6ab916f5c8c90fd10a0399793dd1d14e4cbe2",9.917710196779964],[14676,"c591f592dc086afdd15f425601feea472ea61d2b60c6fb91fe8809c185395285",9.317957166392093],[11448,"317175c1fab69fa119322e1e47740817dfa6172df19d4f0c4935284b8d57f5b4",9.917710196779964],[713,"0c67b36a5e717e29d921f1c9feac094af4dd8919698dda73dd4365ed8d571cfb",9.917710196779964],[5866,"79420ea07fa54c1f7a4399aeb05f543462d701b57d9bb1e615084e2ee96adfd9",9.917710196779964],[17755,"3758fddf71de80bdbb887cf3feac00d4424e377b739f657789f40c1318092542",9.647446457990116],[16152,"d53822e43a500e1a1ae002236fa672ad865264c508b38db9121454e6ad410565",9.317957166392093],[8199,"420c12e8258d64b5302166546c52fdb5a088bc6fcf187b42c7413de2bef1f9c9",9.317957166392093],[9843,"1331a698b674bad863b4c062fd27ea2c7ae6da447693fb0534544c41841f59bf",10.002054653790836],[15992,"b5474f1f8496e1b64729abfb5ec100561fe9c4aa97f389acf7ddf7391ef99d68",30.756302521008404],[11245,"bb72ffba8e6c88bde86badf7a65d8b307e5aacd490738b2bfc74e489d63063b6",21.950113378684808],[5325,"27c89df607dcbc216e2b89ff3e215593bd64175a32d6598d725656ebe7ad45dd",9.917710196779964],[535,"e4148d8d558e3fe8e16a8227231a7f1fb9639a56bed1884bc4c2ecaa43515ffc",28.09964412811388],[1747,"5aec8326d93e0740f0126d478131bb199bd916f3829ed19a6ecf32677c06a2f4",9.917710196779964],[10397,"793379ba88b7334d587a0f8a442f12d06ed734cda9bcb032f46df09993f4cfbb",9.917710196779964],[4174,"2b025c2e8ff3e56b8b4523a280ac27f95a5cc3466a2f842598c32ca037c49de4",9.917710196779964],[14777,"bb3e9318fbbb372aa7c59664d236eacb8dbc596e130249fe4f8742f696cd6083",10.013605442176871],[16529,"a8ee1c8d994f0085d7c47f4a531ae458e426df65b38a62b7df13248ac5d1845c",9.317957166392093],[10025,"bcb4de8940c8eea594d6c01abcc2b0337e9ec718b5b7579b43d3374258372cbe",9.917710196779964],[15446,"7cea50fc7da1d4cc4e4d0c2d6574aab880e95831c5f0a6e248ed05ae5fe53275",9.317957166392093],[18896,"0c5c7187e492501a6e63bb5946bc164c5f6f53b52f99a15293bae51aa64b9b23",19.212653778558874],[317,"b0b72b7ac46639818fc909694ccd43a02357affb230694a8d4fbb788f235e7fd",9.317957166392093],[16814,"741ad339d078633aecf4de1ceb59bafca3a499f279940578c0531191415af355",9.317957166392093],[13878,"b34eb5b74e7a7be0fbab12ab01143a533cdef0dab687575a4258672d9b31b697",9.317957166392093],[2125,"b7f6b5c2a534926faafd97528ece441f8630f14ba569996c6e88b550442818f2",9.317957166392093],[8767,"b0fa99f9b5dc425b2c652f9dbd8c21fd653e3e1f401f60a8997eae21183f40c6",9.317957166392093],[18003,"7483976e4a5416ae1f13283f298d313f6eb6ffbe3fedce2aebfece26658d393d",9.317957166392093],[3228,"9b16c6b0e6c39358746acd5fff9a83d26050bae2497994f26f1e65b554ccdfea",9.317957166392093],[17724,"e2f717d3638fc10314a4f255097484f70f85585012e43d1fc9f371897a54b942",9.317957166392093],[16901,"3789d46fedd05c7a8b561177d04a62d6f18d9e5fb83c630695222e61cab82354",10.052724077328646],[17701,"b5f44ca2abae7c77f19a0b459221812e6c92c6a971bd70ec5055804dab502743",9.317957166392093],[15324,"86af02966b7ce31f497122e944f4e66a17686e917ad5066077ceb9ead1dadc77",9.317957166392093],[18661,"26788924fc04cf93b9ab24c79f70face6f249ff48d84a89c3e9c63b8e1be402c",9.317957166392093],[8063,"a48fc783b095e763be1e26ce90bec79819ec889e358e98067ced7604895705cb",9.917710196779964],[273,"2cc4e918f4ee652f5ea22aeae34faf79584503a4d6152ea7088ce24f13cf20fe",19.23112128146453],[11359,"3ae4cf94723d53f6ec4b7cf70fe8a896579e32c69398adc0c3db176ef76d9db5",9.917710196779964],[14345,"10eb657f2888bad88c42a3a2af6b6f81528a22ef8900de1937e06fb1ec75748c",9.317957166392093],[19129,"9ad9c99447af590abfceaa156fb711e52db93d70fe037adab790e1951ea72c1b",9.317957166392093],[8812,"674497ba763a3e7ad81a2033ec54abe011e5d14061a0d0ecc03926ccea9105c6",9.917710196779964],[11808,"f8743ee9ba473ad6f205a0d8dde3fa5cc95d43a7beab483621cb6ee87474aab2",9.917710196779964],[8769,"a6cde919b2f74e174afe1e7c6e6a60572fa080888394e4fb3d5ab547f5c93dc6",10.052724077328646],[6154,"ada3d27fb8d51b4c97dea08bfee5e09f570d711341fe04816de657fb844320d8",9.917710196779964],[2985,"df3e09dad0e1385fd1bfa54dbc046818b04a1b4928e1111d451a91394c0b62ec",9.317957166392093],[15699,"0b18f5b0f4291bd05e299ff23c422b9880929881fac0f40a3b0443a19ed6826f",9.317957166392093],[9840,"75db75358e8f21f329d85eb324ecb53f0ff8699f5c7f19eafe236d17a4905bbf",9.917710196779964],[10210,"fa95152a6985ee4f742fc698dc2cd44f263ebe995719eecddf34a0616070ebbc",9.917710196779964],[3114,"4006f67988f39ba6af60066f0d7c59aace9d58a8068a6257a6d3b35b10f08deb",9.917710196779964],[6817,"1e1b3e90e8fd5e973cf687a30b66d6b5a95f18b7ef7e1d219e026fcbbda52ed3",9.917710196779964],[2146,"e7ff1badf11038b73bc815474f271da28c3ed6eef9e17cc5ecd7f64982c7edf1",9.317957166392093],[14698,"4e597fdfede0b592414a5b8ebf975cca57143e32846bc61bc9d061dbc609e684",9.317957166392093],[13110,"0cda2f3a51c7078a3613319278043da4773e25ef9b731fb8d2c913d18685cfa8",9.317957166392093],[9697,"587953254527b5cce36a81559f8aa32b2369e0663470f8d534dd40352b286ac0",9.917710196779964],[14044,"554f857588124a78231a0f48d8b6e5b997a7a2bbe901df23bca24d6a1bedd293",9.397642257991386],[12701,"d87567f553b130b3951f07ee8b8027e0cf7d003de68bd1469d0967d5adcc98ac",9.917710196779964],[10563,"728a43f0c377de9d7ea7d3ba4563fd3339bd9504756b988409643c835526d3ba",9.917710196779964],[2078,"0794049d1808b03c85260436f4c41608ae2bb4c1e32ac49fea00bbc23df562f2",9.917710196779964],[4901,"ddb063ed5a71f0aaacc031e5616d17916fcf87a0083a78c0c28602036e13dedf",9.317957166392093],[3150,"d009434dad58f1708ade2a3c7bd7796f6a3685ec4a33d10ee16647d58a6e5aeb",9.917710196779964],[8381,"ea6e5b624b2b7413613999c6fd36cf383bba45fec7084fd46b738826e219c0c8",9.917710196779964],[16444,"119bd0d5a817dd1ce8405e8dcc02044acf196b55717b21bf0168216354ea4e5e",9.647446457990116],[1241,"d9f8600d5adb6876bcdb1f97f7315374370f7a811184b0f004ef0506f907c1f7",9.917710196779964],[12521,"720ff7531db30a2b4a6cce09d83665954750385df455069650016c9faaa2d5ad",9.917710196779964],[9192,"ab8e9175b4b2343303e74d3290465a4850fa8290450a3d5ad633778c7fa687c3",9.917710196779964],[13890,"4538783db946360a0af7782c8f8ba67349218c54798dff5c79deaa16a8894097",9.317957166392093],[11954,"15315f92bf7fcfc5ec8522536cb60d32bd5d20e4c2e69c73f13a8edb4df9a2b1",9.317957166392093],[2469,"d2712395e5c00593e0de846c8babca8983cf68d8cae84e2ec52403444b3811f0",9.317957166392093],[14639,"296962e633e714916d33ac354820719f1a54b856b6eaaf65815b6daeb0eb2d86",9.317957166392093],[9382,"4c3816d3af3da1730ea27fcdf5d7eca6d09c2bc316852e3e8574f477c7855dc2",9.317957166392093],[4130,"a53eb0c6bc1cc99caec90de4280ee113b88793d3c9847b176c58ebfbe5f1dce4",9.917710196779964],[17639,"1cfe8c93c7773a982e92ae2bef5e3f9487538a60d59edb516c465c0a3f626344",9.317957166392093],[9816,"04e0979d0188b7ab9fb09d4653b4c40a1500f1d440e7e3401743fbc53bdc89bf",9.917710196779964],[15573,"35e7eb8326683ab2d84098a1d20a304e39332c95ee6fd2a2da222b2e833e2772",9.317957166392093],[9767,"00877b9a412bc8b7e9c5f675e701b68b7b59782a7238074c6a62597a02badebf",9.917710196779964],[14254,"b4f276f7dfa3fb1ae3c2971ac1fd240129d9fc3a3904bff3ef5942fcc938e08e",10.052724077328646],[3536,"f040d31bdee1dc6e8049787a63f1fc394ac0b62e85303162bf9f594c9e9fbae8",9.917710196779964],[1649,"04030367c10d19015fff13ef6bb33ee0c1baa06df6884809a85dd969036d47f5",9.917710196779964],[9580,"d2ceb4508aa52ea69983a5bd0b42449e7a5ceb2a89ab7e60924ec58c95db20c1",9.917710196779964],[4696,"5658d63fb947060665a64ca83c45545113afe1040ecb8fb532fe337b901f06e1",9.917710196779964],[18243,"f3ae920fc2984ae749a96e6ab335cb53e6b5dd853c7b8188aee41473e0fc1d37",9.317957166392093],[15099,"447a423462fb1232bd878041a8cc854e36c5bb24489b2901bc488564e6509c7c",9.472566371681417],[17150,"92006be8d5eb7c7d91d30ec763913fe12c4a3146881e58954368331595a51d4f",9.317957166392093],[3161,"0d2e79ba178d3831998af5666db2ba04df348b08767d07f560682e1e48eb4eeb",9.917710196779964],[10885,"d09dfee8a85a89b0c0ea1af65ff8b4452d7b04e54c1a1d9f20283d167631bdb8",9.917710196779964],[18828,"1651f81ab317c2fa0bbcc70f44736dd87c73af4a9c9fe4d3697ba86aa064b925",9.317957166392093],[8663,"b23976249ee0d9abd7ad414ea6c8974cbbda044993346f408b996bf71a1eedc6",9.917710196779964],[632,"483cc2ef26f54f2c54269e4748b8ed825cf7a5725d629e886501b89f6967b2fb",9.317957166392093],[18652,"42e4cfdd55dbbfda0f7df176a7ab6be8bda1e23fc2b199bac90d33ee0dec9c2c",10.052724077328646],[3716,"76a33fed95ccde00e7054f6d2931680cebdb91769d463c9f2b67faa7e62a80e7",10.052724077328646],[3400,"4d7e1ff6597905463d138cf4857bffeb3eb541c774e5579bdda8b96f67ceaee9",25.94856278366112],[1215,"50363601d28ebf608ee1f71918f3af33134c2f68ef44d4644d5bb03d7ad4e8f7",9.45790934320074],[12628,"dc80c78d4363b3654389025a8740196a1b1a6a56b8fe603a085289fff75119ad",9.917710196779964],[5728,"64ec635ec5b697cfb5cf677d8496023a3c716590ba1fe402e7d0f6d09e26e4da",9.917710196779964],[1774,"a661da916f1ef0d6a2e56ca67e2f07ba6601d7e7f353a4441be06b1cd5306af4",9.917710196779964],[14048,"6a7a75dbf13cd0606c2119d59a2ada04834342f927853ca497a66c4b3d10b793",9.317957166392093],[7719,"1037a2b929696bcbe5c8b294451518985500b4a57caf2b2ad72e03d0c17667cd",9.317957166392093],[15217,"0de7dc39943e9c9b2c78d3d8cdb1707958bb58a28e6e0e7ebeda65f9f7d1287a",25.950738916256157],[13706,"5b1bdea53f38e524d2f225b7576b943c0943be54116cdaa20aaba4e32ec7369b",9.317957166392093],[3035,"1d7f53e5a1ed581fc6a218ff6637b3bf740b846e45007843a74f3c4a703713ec",9.917710196779964],[17274,"0de5881c2ca9f42359d707cc4b687bc135770da69f71db584115bec00635b44c",9.317957166392093],[6502,"23fb2f1dc7cb0e17180fbe7d0fc979ab95bec9f26680c2657e41704cadcc6dd5",9.917710196779964],[18806,"9fd9d7c6e5983854ae678de87b9d5ba360ee4c49d5fdf413731d637479018426",9.317957166392093],[5605,"4711c466a64789d12379687451417b6aeb16c13d4e33834d6941101080b99ddb",9.917710196779964],[347,"1c0ec17165dbfa981652bf19683d92d883339fb5c9235ffccef1a74e6ccfbafd",9.317957166392093],[14384,"f9981e2ad2952ec64a13f344f0f8e6cc5c0ca88606fb46966c832cd49b7aad8b",9.317957166392093],[4392,"44efe1826193a51864f6636e8e0b6ded3ff8b93acc43217beaa78e296cbb20e3",9.647446457990116],[2061,"be8a60745175f2eae2773458940c3f5b31fa079d9d4dc1a5859ec3c9daa87ff2",9.917710196779964],[13151,"85e674d9501340a0cfebbeb67c698d099cdf30af231559470d5762d39d20ffa7",9.317957166392093],[13656,"fd8545ff98c6ef101d73890380f3c90fd3384e874137f509b1e254072a351c9c",9.317957166392093],[3830,"1e39a86435e9d39b6eff26bb7c40e670ac81d9171821af6f3a437e25669cd0e6",9.917710196779964],[112,"c5b9dbbca672c179dc26d6285cf860008f75998a9b503ec5ed5e7cd8056050ff",9.317957166392093],[3898,"ba1942a490b5f7c654810c31f81358b0853e5a23582330b4f5271961160d5fe6",9.917710196779964],[9237,"c418877f227dae7b882281c1af68bbb55f782484cc7d652ac0a1a2af722733c3",9.986882620162103],[11483,"026a5d5753661506148ec202ad657f2dc2db398006d8d09d23554d0504b59eb4",9.917710196779964],[1889,"0b10d3ad6c007e82cb1b88f8b411536b0b441a73a423dc938c1c317fcff7a9f3",9.917710196779964],[12864,"fc8684b7e8a0a52bc1ce2bfb2e434a84d36d6b8a3f6a6f25ec5b7234e9f67aab",9.317957166392093],[12635,"84793212efea9ecdec53bacf8690588f0868756081b6bce699ba4312cbf40aad",9.317957166392093],[15673,"031c444b1c66e99a47fb7a000d037417fa98ce5ca91699c2afc64e19ca95f16f",9.317957166392093],[4354,"9fb0cfb194757e686b1d9970ed1685b59a2cce33317dcb29bf7c4c0d54385de3",9.917710196779964],[13236,"257f974034a6bf082fd3d7a8ec80c19c4f495e8c94b6b65cec96df45883328a6",9.317957166392093],[6650,"32c9bb50de67065dd4082199439525e786c3af5a7f5e451eaa62e6cdba7952d4",9.917710196779964],[5486,"1054d8747879b80744b981e3ae1a8dd580c058387687b93b49a7a071e1904ddc",9.647446457990116],[9174,"f72b41f6bc917aaea3ab1d7ac723ac3d1595535b0e06e779ec676e7dd5a1abc3",9.917710196779964],[16220,"3e95457a7b373b1eaa7447eb332f759fbae73bc04028652424f7d4d4de516163",25.897302001740645],[18260,"380eacf303a94e4bab66e92418d62e156e20b3eea8d5ad406c6b7c50a584cc36",9.317957166392093],[3538,"b2d7497f8fdcddcb55ffce1e531582bda12fa0f33efea752e408675a11cbb5e8",9.917710196779964],[13598,"d2059a1ffb494a098463d9b4be8bb23f050305ad79b8ea06e1c22973ca49799d",18.309927360774818],[16036,"54011d7a136e1236a972a7ba138c44d2bd72951b56e7d9962c339a8a46a2a967",9.647446457990116],[13944,"b0f8efe84cbed7f54c86c00a080ae515862f1110454b658744ea9c1c6a4e2596",10.052724077328646],[6950,"973d75122e237301aee66f94fb54d52ddc2ba8a0e7e7518eb6ead439919443d2",9.917710196779964],[16300,"abd1031c020e661e1eed44a85a5db3c6b213a085d02d7af2e3a483d7834d1a61",9.317957166392093],[3880,"021a4451b34091b1f43f456c12be51553b8729a9937e2cf20c975f9444ae7ee6",9.917710196779964],[7849,"5ac1883b303731d8af51d34ac7410dc31db2126f586bca07814cc3a105b181cc",9.317957166392093],[8530,"7c56c5f6970b0aaca9d154f98d2025aef8ecf67a7dc5397c35b7f077d58dd2c7",9.917710196779964],[9318,"12264f76d22a927af282fa5560d1fb10f6d11797336f9a6299f45316a1e0c1c2",9.317957166392093],[17318,"e8933e520879c2020918a0c9e6d4bec56ea93ab18624dce2d79a37398164894b",9.317957166392093],[15135,"489008a597f751df6c9b7a0ccb4b6cc35c64922007e533609fbffe9a215cf67b",9.317957166392093],[1467,"06d50fa9e62c3a59cbf3ac46c6adae3efc732de93c8f1c1f7640385b380a5cf6",9.917710196779964],[3775,"ef11040e595ed5d845c03b1501b9b5e69c4d22db9d573803da123682b4c521e7",9.317957166392093],[2664,"fb7de38df7986321cb88421120119023411aefc495aba373556482253bd7c7ee",9.317957166392093],[5154,"624267c80ccda809474efd686a143a23a3f4b2347219168567333f7cb13a45de",9.317957166392093],[13502,"7631bf0f5800ce59bf4fe0e017b2edfe4107e8b4bf75b771adfd42cb60dabf9f",33.97168679516916],[14018,"59e0a09baeadba744020b7f4f51384a9c3eef326716fdcdcab68124fbd317c94",9.317957166392093],[18712,"518a36e3684c2e2b1d6da1f5b2ca361ed181bbf90a510b4c767952af3e3dd429",9.317957166392093],[12557,"12d36c7b6783eb2b6ddc8877ee2c15226b12491480f062c1de8dfac885ac98ad",9.917710196779964],[6578,"90c1c02097bdec74737e1db826b64625bcf373506daaad7c6c30d34fefcbcdd4",9.917710196779964],[8213,"13e3a0e9188ef9f94199dd3c922d1b6a17116848b6bfbbe43c6e243d8691e0c9",27.87443946188341],[16991,"888ca107b60f421b179d2d310a87a92936c2458ad760114cc9eafff17cc33f52",9.317957166392093],[14891,"6623aac3a04a3d0b6d87559621a92a9aa8ecaa02eb8fa9266a99e7463e810181",9.647446457990116],[18196,"5ca065324b338073462acd2ee93caae9c3edfea48fb5056e86d6e61595404938",9.317957166392093],[17822,"6bac4360e26c3a36bda0d6f853450838bafbebf872f582305c7f2c349b4cd940",9.317957166392093],[1246,"84b8f5414dfacc85b6b4dfdb0c5671ad41c6143af0b5f0aa8f05b6e6860cb5f7",9.317957166392093],[12909,"a6b581f7ee3e58827d7373f1e350a66ef430cf2ee435abd85a23c940243e40ab",9.917710196779964],[18269,"0de63011576fe5d3ca1b70c190f8d4850e60b078199dee6655e059518dab7a36",9.317957166392093],[1454,"60beee644be85e14bf55f001edebc556b8a10ac212bef98cc09f55afc80a7af6",9.917710196779964],[16343,"f8a83ec7e82498692566a2e9c4be649fee46383f3660160d5ea35ccfaf1e2f60",9.317957166392093],[11992,"aa9ae3a72323ac79b76216b48a75cf6e020dfa60b5b6b4da8a138e73caae60b1",9.917710196779964],[7544,"5b0f109c6b527d716164297d062937c83c94a0ce219524aca652e48284e68dce",9.917710196779964],[12157,"db0f336ae2d9911cca33be6386954981ffa19d313afe7f59b8aa1df289e64cb0",9.917710196779964],[17282,"84e66bb48b53804ef8ea31b0f91c31b9cb32a5e7133ec9a023354a11ba388d4c",9.317957166392093],[295,"a9222a10b2e18685417ee4fbcafd64927232f2f9e94f5901756e54b6877efffd",9.917710196779964],[16706,"33ca8500677b3a86bcbdbe36caf67371af3580978abb8800f6c6c75bcb7d6d58",9.317957166392093],[411,"ae0aa379d753ca2c728faddd0129fed39c7912e3628273fe7c790438540e49fd",9.317957166392093],[8809,"cc7357ac420429b71c81cc05f035a8c39b09e4845b17bd0ddbf841a4582a08c6",9.317957166392093],[7859,"77bd2bb6033a37e8afd42e22eafd1fb4e1210ad535875a1d6909167681c17acc",9.917710196779964],[7578,"e56923add1d4a1d3cbbf7e7e6622f68f5f306e712a11f4a488949175a23c53ce",9.917710196779964],[10264,"e4d1c8957f3272c5b3d573e20dfede16679f81d8ced437e28b9439f7a66b9fbc",9.917710196779964],[16818,"332dffd680e7c01265d4b7768d0f7339f1a5449cd5ffefe743d6bc01a1f9dd55",9.317957166392093],[9470,"df95269845665efe83e648c2403d526f92e54e61306a63b5df8f8b43f1ede7c1",9.917710196779964],[16082,"a85751e41bc96521c1db23aed2a5d671912c42d77bd7d384b5dd7a755ddda666",9.317957166392093],[4000,"de035fc326325e39909c126b343fd9d4d4d1a4badc6d028999dadf7f98f0bae5",15],[16395,"a8c9d1254cdbf2abdeec8be6b59d048eb965f3ae470168e7be16ccbeb8b4295f",9.317957166392093],[11107,"0dc65495ed0b900c46600d1a1acf5f7bdad11464b065faa76c191420fa4435b7",9.917710196779964],[17424,"164417836fd149150d3e341c00577ff197de6fede05fdbb0588fce246afc5349",9.317957166392093],[17500,"f6eed99f25e4fb1cb649a6c5d763c317f1801287433cf3c3468233ad27c59147",16.056140350877193],[19640,"258f0421dc87ea68551528faffde008ee5f690093f200df15943683163893108",9.647446457990116],[5363,"803bddc70cf12c4d5ff9f048ba97441282d9bd538e279ee5e75eaf4a69ba0edd",9.917710196779964],[8589,"0d2fb95aa3b9e2f8e4c3213ec047570ce1c026ff131acc572ec52b6bc4687fc7",9.917710196779964],[18963,"ec1912f4ad351ba036bcee0f749079f09320190b24c75bed60e5d23f77e2b921",9.317957166392093],[2163,"d88ef1f970179fed8fce6732acc67a3d34f970210dfccb52f09202f51da0d5f1",9.917710196779964],[10751,"fcecf8060f94aa8406b4d716247ed88f534e26fdfa4d28acff068256a284abb9",9.917710196779964],[975,"9cb9632ca1ffcf1f9fd20b68886a81e07608fa620490e89da33eecac3bb459f9",9.917710196779964],[3797,"74ce1c6dc24b1ab44c9aa8ac5a508940bbd80b70ec592ed27f391cc8f880f8e6",9.917710196779964],[5492,"ef962a6cb3c95cd7ce040da9c7b667091f97e37dd5e4f7d443a51571ff9444dc",9.317957166392093],[11466,"cafb74fdedb7720a6a6aaae57623e83c1b8852d4afc0376bb1f9d1b13fd5c4b4",9.917710196779964],[47,"48e54fab47cdd55f9f3a49648d182ac879349e3e9cc36f1450e036a4ccfdaeff",9.317957166392093],[1037,"44fd1df569590d7570b2eb5850c8c031f2cd73fda85b5fd9a5d59ca188af0cf9",9.917710196779964],[10102,"97bdfe37266e053ce3991dcd31d6853010a13d8690bc58337efb243ff1c3adbd",9.317957166392093],[5590,"37373cd1102ee884c689aec3916136dd0530826f588d419247a858165edbacdb",9.917710196779964],[13794,"55a98347ce7bff4310a4227a3af2006517749812a8de98332661d38c55348299",9.317957166392093],[16424,"d081b0c08ee591b31a7895c067105831d57e1af8274947440d4d912f1e6aa35e",30.604982206405694],[2165,"d9f2db2ed4c395a20771b518c02acc88d480b770357224603a2d05f6d980cff1",9.917710196779964],[18075,"3018e385b2a2b37298dd15f754e490b3a34faa8b504c77d87647ea986557a23b",9.317957166392093],[637,"27ccc5f6ed938013253a856237ee7dce346fc815d69082b5d7d00c612321a9fb",9.917710196779964],[4850,"e6854e893fe879f2d5707dd5a8329f4d94456dc2c0d34412043eaeb276c124e0",9.917710196779964],[1268,"73e88acfd3bc5543d24238961b6fcc3efd36f57899f3803aa354582a75ea8df7",9.917710196779964],[13920,"644c819b4024c4b4fe98e57eacb942022026934571eb26373dc3a6ff30f08196",10.052724077328646],[12612,"87f89ec8e92d8c1a42e49c79e1a266ac0efc8028a31dd51aa3318febafc22bad",9.917710196779964],[17493,"70ed4d0baf0068d9adb93d9b03f5f525c4fa264bbbfc3f9b0d1f4e321fd1b847",9.317957166392093],[2677,"b04895118c2b9300f4208278aee900577037604a163e291a0c9127012b1da9ee",9.917710196779964],[3979,"1d82b5d9cbf4f26a9fa11c6c500658d1fbd19fc3472ddf64bac701831ea8dfe5",9.317957166392093],[10433,"e890d16aebbc93ed769f7a725829d18adae41161cbed785e1cc77ccc890496bb",9.317957166392093],[18497,"8085da766cbacf812813977d652dd6ab29704a0dbca90f4fb8d91ac133ef7931",9.38219895287958],[4284,"5e4fd6b99af4ef0878b78307c93005aff555098a7129fc542fba4ccb94cfe1e3",9.917710196779964],[15957,"d22bab686d08cd722eac5d103eeefb5d77c905bce9c9a12c2b92600d65f6d169",9.317957166392093],[19797,"b461dcc8cf8e54a998244fdd26d54925a6960247c3e2009d0b625906ca66a702",9.317957166392093],[9479,"819bf88d54a0a495bbe7105a6288552806138362ed985d5ab8f228efdd7ad2c1",9.317957166392093],[10847,"3d50b74db746d3167385132e8df2c078e9e20f14d0772d1b0d229f158eaa05b9",9.917710196779964],[8344,"6b8ece7b05bc280fddbe3b6c12e07884f50b61c9dc647ab5b7896a68fa7608c9",9.917710196779964],[366,"93fef5e269bee76a32f38cccabcd74bb56f16b320cda1133f8caf4bc0da3a4fd",9.917710196779964],[14180,"297c8e85ddba7cd22d1d28cc0c5d7890d588d97478a88c2890984508b27bd690",9.317957166392093],[6056,"94387e493c2653fce1550d16fbf46febd27789011e5f4d337ae29429173bbdd8",9.917710196779964],[2372,"a7fd31935eeab1ce0383137505324efd6a9e898ea4be225028436531a3cca1f0",9.917710196779964],[13126,"26c4a0dbcce00887604f2c8f20395ec783f5c45cb877069a54a7133be2cb78a8",10.052724077328646],[1184,"372daf1eaf14ae5ccd77d29c5ea6d163a7f6c77c00690f9c56cb3760839d1cf8",9.917710196779964],[7448,"5a14b346ff1bc4a39dceca87d87091d41e6d8d3f6cebcf0d0699c70177bc18cf",9.917710196779964],[5390,"1dcbc59d077f23a56b3f3e346d82b7c0bbbcdf3e161ef267c25d6d8f8f93e2dc",9.917710196779964],[19502,"748ca6ce7ed958f3e4c5277abecd5cb5f4989b93c594c48f45c79a1a5289460e",11.550802139037433],[8261,"2fed08ac973aa4f42667a6e0fcad4b853f0c082679c50ff7f1eee185655d98c9",9.917710196779964],[65,"cff3327af467af2226ef6f525c41a51183ec6dae795d4278921eef91755f8eff",9.647446457990116],[12192,"d79b1c796ae9e0282eeac23d598f42961b46f996ac2207843556f5e272d51db0",9.917710196779964],[2887,"9ccc441f3d045bc871047356c5d15f2d1cabb95ce0590a60b9f3c45c187b34ed",9.917710196779964],[18964,"1d8633729f24a64aa98b3ee013cd5044f35d6a223dc84d0b4ca4b75027a7af21",19.80295566502463],[14726,"ef740d7f6b1a293c99c91945096b6e1060c19c2fb720015d8a541f724a076a84",9.317957166392093],[10127,"933d8f0deebe8a4c189c185ecc5a937731f3a1a92fe591f311924f19e47482bd",9.917710196779964],[10176,"8dd8f69ab902302bd3ff1787f06c7521e39ad6c4fc10cb316b2658908d8731bd",9.917710196779964],[15359,"138b1ad01301731b759ad3f8f8895c8e63797af0d116c9cb6de1bb8a00884077",9.317957166392093],[18246,"1f316f1f29957181e456e11dfdb673955911edbe2091729f44100c46b1b90c37",9.317957166392093],[8799,"adfd11f40db9a550dfd52e3c400e03d2283d6bdf29b170a7bd763d31185d14c6",9.917710196779964],[15887,"8edd89de5a5c1eb8ba3e0f9cb66b18c22e7c69feeed584e9d5a35c09096d3d6b",9.317957166392093],[17336,"43321b457f76c3c80d8d4d06205a23b9fa33f918852b793487eab4481a3e314b",9.317957166392093],[16752,"c333d21319eec44cc3d2b0369c314dcbadd1b6d2ad38fe14223780faf4416357",9.317957166392093],[504,"949f6fbdce02774fe19e31d2cfe6b33cb69481906bd5e12665b62ee82fd8a7fc",9.917710196779964],[9683,"010fafd68c4c71b9e1120466c6dd964b07ab767fb918e1d953d24229a50481c0",9.917710196779964],[3927,"9296c28feca4876d1699f2e5ea8ae6afd3b8d96946ddbffa540ee9321dc02de6",9.917710196779964],[18754,"3a258de859d712af5bcb45beeabf912352018179d4d74d2d192f3d3d08086128",10.052724077328646],[12347,"f9afae9d058be59117f58b555be88d4053e0e94ce43543f3ae0e077840b5eaae",9.917710196779964],[15689,"064622fd540930b2a940a4e84812e8ebb502fd7b9d4c9fbad1dc08b0589ea96f",9.317957166392093],[10679,"cf1c4e934aac6e47dcbab1c2d4acceab595aa06ab1de80f499721dee50b12eba",9.917710196779964],[17152,"df9a7d05fa9aede6c85c594eac4ad5d69e9964acf80465bcf5e0b631e0b20b4f",10.052724077328646],[7280,"3de1db3d3ddbe4db76c91520878910e22c6799572794d135c0428ce9133d2bd0",9.917710196779964],[9276,"0736b0e79b12467eaadc470fa66469752df7fd305adb8f1369d76e43c5cdf6c2",9.317957166392093],[11894,"be4544b32b438fbccb4819d81922826e6606fe4e1c3f1081dcc5881a78eb10b2",9.317957166392093],[16746,"0ee2880ba7c14ba6905489b925348ac25807c8c3bbd86254c1f728181da58857",9.317957166392093],[3844,"806909c33f2f00b71c53fe35f184170ae98f9404dc0520782bcbf9d3decec4e6",9.917710196779964],[19136,"c6f41b9f29d99e9dda5e183a6c8e3da84c540f5861357a7ff55ae8d670e8ef1a",10.052724077328646],[4626,"41f0be227f2ed9efc47f2a747e8959422716e59cdf78f2a3532f708e505974e1",30.134529147982065],[6868,"d9d2e83d3c9d775d5cef4436596608ba206fa43c980bf6a7cfa59cb5d2a9d3d2",9.917710196779964],[16345,"8b1947820dd007c16020b6d5453aead483049d08af97290be0e40010faab2760",23.94295900178253],[861,"a94bfd83093284f71f4059610ddae3269b33828393ded648067ceddb67b328fa",9.317957166392093],[18015,"595c4ae4abfde1cf03a780996a7e5b404048e1294d376c7f5431eb8dacf9ed3c",9.317957166392093],[3831,"875f03b4e1ab02b9128b2199e9a2dc9110c4d498a2a464649c28971fa165d0e6",9.917710196779964],[13132,"1f63031164c318f652a0e735bd79b4ba0260ab3c72a5d28380f6d381f3f250a8",9.317957166392093],[6875,"498c5a5b5f51c4961ee0290f3ab0070b9b88f1c82e6935359d2860555635c6d2",9.647446457990116],[13720,"c870503fa0dbab8ee11917bd33397948fe2a6cc31e4574917c65e4b759b6f49a",9.317957166392093],[2582,"632cf0c49ec93ed3a9ad3aa6f1490e5062bc60031436e6670535d0cf38c244ef",9.317957166392093],[14834,"7ffcd01a2f71df38fa4a1c2212870ba4042ff0b1b55133a0094d310d470d3d82",9.317957166392093],[8864,"ef8ae5e60d03c1f591403e2a4e017602b116dbbe60d367116717c50c29caa9c5",9.317957166392093],[16906,"0728d8e5e7520968ae4b518f637e659146f5c3f18e16e2c8b3f9f19fe6230854",9.317957166392093],[2510,"313b6eb49a04c6c327764a8b681c49965df954d02afbfcba12e897f850b7c4ef",9.917710196779964],[19194,"b370376f7a8c27d1e1c520bca9cbe3b316ef856744e497e2a44da5b0d429cb18",9.317957166392093],[18272,"4dc570dfde140f2c6a90345043dd85cc2115667837663113e9801f8ffac86736",9.317957166392093],[14823,"7c4679574660eb7c57b21b5c036e1d247e21aac5a24ce47353aa9dc5a75f6082",9.317957166392093],[9746,"2b8fdf68dfbbfb531028609de1af79822be6d19d02bdc681554713871e2407c0",9.317957166392093],[7454,"1d230ece3855e8b91a56364e062424028b82d2aefaf2cb56cc71f89641b50ecf",9.647446457990116],[8500,"14a690b07280dcdc9903cef8ab1397bab8478b2c1d4ca06877b319f3636406c8",10.034527113939475],[202,"674499b0afc657b665538ecc99d8c6f7a328ac80aeed41e1ef4a0f756e92a4fe",9.317957166392093],[14149,"90b865f0c74c241bc020ceb8522afd4bbe84616d6aba6f930c00b7da483f8491",9.317957166392093],[13838,"07c22e5570824f6b77ef7c10b499cb3a48ca0739309fa2ff06ffc1f157ee8c98",9.317957166392093],[12343,"dece7b38bcc639915ac368681b13068796971d1ccf358cd6178e4b1017c5efae",9.917710196779964],[18410,"d07446a4e15c57bd4d0d98a1db572ae77eb5c55f8324279704505f5fd8664133",9.317957166392093],[3222,"fcadc9abb7f3ce735bac677e3371c2c58fd47e1341cd34e244534ef7f1a3eeea",9.917710196779964],[18104,"d1a735d34adc1c6e70b40ed72737fb4352581ac4c4e7071e9716462e439dcf3a",24.64625850340136],[936,"667bcf068063414862a37b86dc68d1d56dbfac3a771421c6ebfc1919469097f9",9.917710196779964],[11427,"68c50fd0eaaa9f797c98acc481ecc8d4278e51c857237dbdc4309a9b391f24b5",9.917710196779964],[8945,"68c6d8c5e9e920d8bbbb0cc22725a70593217211475bf00489a86322f8eb21c5",10.052724077328646],[15406,"4fdcd5eaba8576c870da35c0c25f27dc43e8fe3c3ad015f6a88873c505012776",9.317957166392093],[7486,"b92c5e41c9fb1f0409c68f435f6162ed803864789829e0bf92bc3e3ac604cdce",9.917710196779964],[180,"9b9a1acfd55c4e58c3bdbe0d8851de5257b0a9a626efb63ab503905510dfcafe",9.917710196779964],[1618,"d9818fb32e5f1d1690efe2d5e3acd60f3f5284c7858643294b6e44e9178a75f5",9.917710196779964],[4988,"c18bed5826e99689385644d9f480382e1d1bf1afd8338db1691e22e9f87143df",9.917710196779964],[3604,"32445ffb5fe7d6f08589cd549f612d5f985d711430af43a884d004f2e93430e8",9.917710196779964],[12331,"20ab10fcd700b666a2017017b466c8e9d87dc311d74eb580a1935518506106af",9.317957166392093],[14285,"5ca4914537257840384d8473ab53c7bdaffd7bcbfc3c690c73c39d9376dcfd8d",9.647446457990116],[15533,"117198afdba81fe8a34f72fe2781946d66ff33d683de90eea4bcb43d4e834a73",9.317957166392093],[13501,"d4a7123df6059f51cda6c1b7721de3bb572fa8b97de8e0cfada308b936a2c29f",9.317957166392093],[19145,"e957c8ce55d8cd99c5b97f593cc53700a7702f64601cecf6ab713dd091c09c1a",35.82958579881657],[10766,"0c3aa570817ca5bdaa244a71f685322f7c64c9ceab0bd65765c71b4131298cb9",9.317957166392093],[16789,"eea6542440a3eb1239c5b197dd560cd81c343d71275c162e46eefc9d25649456",9.317957166392093],[11374,"d86981e5dbdd4b02e34012ee3dec11e45b42fc7e66b35e1b8ba1c470092d8fb5",9.917710196779964],[3601,"2ac186644b7b2da29930a03f100c368f481b494357e7499f83958c01557534e8",9.317957166392093],[2659,"7976de56fe25e8ee237af14184f1dd6b63b3aed8dd7ac16982561002c97bcdee",9.917710196779964],[5485,"16fb0b370db5b68eadf4eff154fafc21801bd3ad74561be9c72ee7f34e2e4edc",9.917710196779964],[6303,"62e6d223004ddab40fb5979c0833057c0f45ef6d1a608086a424b1a56c1302d7",9.917710196779964],[8079,"92a7da2233fe1f244c81ceda30c6d2605753a44ab3a2ee64d2f9c413825fe7ca",9.917710196779964],[3549,"4fe0bbb531028ccfc57066b6cb0b31dc2aaca56ad39d1b8de09908081c439ee8",9.317957166392093],[2184,"ef3f96016fdfc670b7f99df0669a3e9c298d911e18eda8ee755aad7f3a48a8f1",9.917710196779964],[3635,"b4c701b9457d3b467d2c7c17cd69815077a08936c968092176b7d33abf5406e8",9.917710196779964],[2569,"a2eb1f58967d3f4238beacfcbc0c44eb98c9836b5b2f2efc167c71e210766aef",9.917710196779964],[15942,"c7a9af56a1ee31fb13018e84ce6d60c1b1f6be87121e187c526d8bb3954e1a6a",9.317957166392093],[12978,"17e581f240fb225b73d785a70bcf24ba06bead68ce8a756e0bd3b987a563bdaa",9.317957166392093],[11951,"ad9d5a4950842e523f1207a81866372ab2863d8fb64822dd253c7436939aa4b1",9.917710196779964],[14601,"fc4db742918168f547d0e62478be8eed395a4bd0df4c03656d882aac9dcd1887",9.317957166392093],[1707,"cb4526c2980d28282743fcbd97037c17184165866c13f0c7ab0fd8c1a2e4e0f4",9.917710196779964],[10695,"bfb98030d7479f82c1c175083a55863dab74837d98ec88922ed652f2eae309ba",9.917710196779964],[8435,"f75896f1408acd5a521ef3c0dd1a45ac2fae922ab073a97a9f5a1b998fbe6ac8",9.917710196779964],[4904,"b11d816982f31aff573fd552d1fa1cf91a7e890697873ce6fa4be5dd7c30dbdf",9.917710196779964],[1400,"b55a47d0fd840b5470afac02bb8b472ad9b1da51f44f5fae884a0aba6e41cef6",9.317957166392093],[6611,"c4fc8a045ea2f3d35136c7124a48b968529e69e13db8796216440f97506c92d4",28.933638443935926],[12111,"cf7c2631d71a685ae5d1d72ff7d5024042acfeef635562e9c8c634ae31ada9b0",9.917710196779964],[3931,"3d34b5dfa385d928deb9bb0ddc2cd848252773348bc1ea44f639d4098cb428e6",9.917710196779964],[4691,"e7b5767a8f03bb544c24eab280a502515d11e916306e800067272715f19d0de1",9.917710196779964],[15908,"dede6832fcea7f2dd36832e7bbc0e91b52499524ce6c83df527e4eea7851d96a",9.317957166392093],[7924,"2a12fdd357cbbdec1d349a56453b8b1660eb0a1f3bfee856c2e40f4ce85f12cc",9.917710196779964],[8977,"d991d4c14a6974a4e0e6d314d2575f99474f291148e5f516b7c8a48ff748f8c4",9.917710196779964],[16798,"edb98eb6634043041bcaedbc69ae681638dee29c6bf9804c515e0929f6085756",20.02998500749625],[13405,"2910018f0db6fd529df9ef94ee347426815cc672dc20e618fc1d0d74d7e02da2",28.863961813842483],[3545,"2822b6bce653157734c57d16e9d935a981725dace1855e75de9708276f8ba1e8",9.917710196779964],[11033,"6962bd60905c84cb62305b82856b85fdfd70b7f8f770114e5a7bc59087c4d2b7",16.849557522123895],[16489,"4f3abaf2c8e51977ad10f3943c0e9b07cfe73c0da0ad557a17898ea725857c5d",10.052724077328646],[12005,"836dc10cb86eb4eaff7f4005ad596281364e27b2989802ed1103285159d648b1",9.317957166392093],[10558,"60a787ca6996cf9b98fea0955f842d7d15bbe6977dcfc98cbcda75e84508e1ba",9.917710196779964],[2301,"8ba8a3132a34af52f2499c5a3891d0ef2110effc917e029fa54295ba72fc02f1",9.917710196779964],[5836,"299cde8a50a3c7735d7715fa9cabdb5ee09609346be7801190fb438184ce1eda",19.218142548596113],[7676,"43f80e977586e63dfbdd87c31903da794577ebde59c08fef109216df1572bfcd",9.917710196779964],[5790,"7d2dbe41afce15b0515e9d9519d1f8a6df014001a3c824cc777f08ec6d767bda",14.864253393665159],[6482,"ac35dd15044faa115cabbc811a18da4bdec2b330e642a56f7f4c9993178098d5",9.917710196779964],[8413,"ebc82b214b450b76d671ab37dd4020941273c93771082802410f96a9013a89c8",9.917710196779964],[1177,"e5d5926d8ebc75d84cc72e845b4d0f209f9de0ae59284967e3fc901541c523f8",9.917710196779964],[423,"6686ccf8da37b7b1385df6263cee9ab332d900ee3c632fb01a6b40c2a0273afd",9.647446457990116],[10717,"7d78f04b6b95b88946a47862bc79d3ca9cb906fd73b570a75ed588abc71ce5b9",9.317957166392093],[14522,"8a3b5eec0253e64641e64fefd94a85238ab16264876448f5feef5c9f490dc488",20.106951871657753],[18959,"47e282817e85805533e75b1b63a8b2645ad351b2d687d50ad873346901d5c021",10.052724077328646],[3575,"23f8465ea1b38ed07c6f3e8f4ae0d01a5e0442e0ed250a8b197aff5dce4577e8",9.917710196779964],[4801,"5228b1088ee5f109e00ff8b492cfedf90b10effe6b6aa168643460c104ad60e0",9.917710196779964],[17167,"b1d8f99ffcb1baca4aea0b80ab958c50cd2e008635ad6a32695c4bcacfa3944e",9.317957166392093],[888,"58094b01036e3af7f5c355a2c77b37caa613de872517638236397a923656fdf9",9.647446457990116],[14688,"7b0c34c5940d4af0c4c5bb64382e2b363db0b76c3ab652f630de81a913041285",9.317957166392093],[4662,"4520d8ae9f01680724d2755e2f20c6caa00ef014fe39a566f21b30d549233ae1",9.317957166392093],[11718,"6928481b71a60a50cca626037df7ccea8194cdcd5e383cb5b8622a709b4b32b3",9.317957166392093],[50,"cb5ba6f3b15ac992b67e2a71d20fb8f69cf611d465c23ff530e24f0361d0a7ff",9.647446457990116],[7754,"9b11c60927a36a5165950acd0c644addb23b9a0dff87a5f184b5fb55a4a41ecd",9.917710196779964],[2276,"0f93fcc6680956698c9c30b27e1ef19e47212d79b8c42ae1acdd50d89b3620f1",9.917710196779964],[16610,"496c78ed7a5d19056495e1eed259582b38004f74f50f3fba2df6735310869f5a",9.317957166392093],[7035,"4e34e6731cf551c176440295ba42d8c4f7324d51d61867533ffe01f01662c5d1",9.317957166392093],[6598,"3f01ab4ab61fc3c4c7494208c82f8d1e12c41cd032b847906fdfe3d37aa6abd4",9.317957166392093],[13173,"e01a5d562280b03ea63587a37192b9c7bbc08d4b8b9cc3ab9c06cb088ec888a7",10.052724077328646],[7025,"8e721b927833e65bbf97c964629eddb4f76c3b270d44f956924fc951e625dad1",9.917710196779964],[6196,"87f4d31a5c51c2a18238fd6b36903909908355d4797ec258ede8a1b30542cbd7",9.321196358907672],[8568,"b7c6af70fa5b8eda5aeb8f0651e22fb4d5116b1505abfc2f477f47f47f3b9fc7",10.052724077328646],[4198,"39c242548619d4f1a1e7dc4c90ed8795a0ec3936d46b589342fd3b90976c6ee4",9.917710196779964],[3126,"23d9e10f141bebb354fb633ed80b1da3d915184e7a8f64b4a236e157327282eb",9.917710196779964],[4389,"118352aa46cc69466b1cfe2534df1e125069b93b96bdbc690b67c17396d124e3",9.917710196779964],[10355,"b1200fa7820081d942e8fc2a1e8170d57211dae3dfc585f03419d9c1946b05bc",9.917710196779964],[7168,"14a1c0284406cf47a8d60f01948db7dbbd7607b37477807c77a737b06b19e9d0",9.917710196779964],[16707,"2f63152a6edc03f29f75e73428a3dfc748e8e51525296bb331d07e20196e6958",9.317957166392093],[10265,"0a6a40d95e03933bd9d9b8e3bdf4573501cdaff6cff9baa1fb274a5569a59ebc",9.317957166392093],[5814,"b85e43687414cd5957032fc3fd865fb7dd401703f52ce99377b148281e5c4fda",9.917710196779964],[18852,"117e063412203e883821ba5d4aaacd674eee11c505d058231148a60f10ef0425",38.336898395721924],[11770,"0607e09da6d071c75749d95fbaedbcc0abc526a2d91586ccfadd494feea6dfb2",9.917710196779964],[1651,"c6d79ccff95a17a2a7b48ea60a13ea7f30ae8617808a83063d3ca4952ae944f5",9.917710196779964],[10456,"7095958455f1d3f63a4bcdc51589fb9d62ce7398d7789a365097a30029f663bb",9.917710196779964],[15882,"e492eab50a7ecc0d45800a79394a5661203f7f25794fd8c661903b767e92506b",9.317957166392093],[6949,"67c107201e7b2dad2deb31a8a8ccd5d2cc47789e980d7e1cd8e3367d9f2444d2",9.917710196779964],[5458,"849c79035605f11d041e98cc2305d131e25ff676e9e7ac77477737feb82c72dc",39.13879003558719],[19339,"26e5902c18e977f0cbee7f6cd1299bacbc52b6ee3c61c55aad18f22b7fedd613",59.355932203389834],[1410,"9c31949a4871052f078401d4c3ecf27179ded03a9abf8040f4d768287abbbff6",9.317957166392093],[5629,"8e204f752aba4b0df54010b2da1819f17dde4e9029586850fc51571aea9777db",9.317957166392093],[19102,"881e95cba709055cbedddb04477a7079969c78aa5db91afbc1630e38df28a81c",38.00353982300885],[5715,"e0c08cf599711fbd6ce2c15120251833b6e41f9b1b2b2dd894bfed92bbe8f8da",9.917710196779964],[8278,"61a23f89bea3f3105f7207cb1d168e2d837d411576285d7f95a39035f4c57cc9",9.917710196779964],[1981,"9c017c1d0f0896ff06c0d55dba3850413d7ed9551ff350d44438f504dfc721f3",10.053475935828876],[8493,"b84f08b76fef4f8183afb049a78c89ee3a7abd05deee5d6597224450647c10c8",9.917710196779964],[2633,"6104a2856c93b38b77a61661364c98a1878ad0f64521f4c0f84e94a19d3bf4ee",9.317957166392093],[3490,"dce69fa1382a62f6b4bf8e37e9ba53b82f67d5150e417061412f422839c917e9",9.917710196779964],[16250,"416697b2de1f81a0a45ad5f90bab0f055d217ee3b267f54c71fb47d2fe904d62",9.317957166392093],[609,"c70480e832f14a5d1314ae82c7a7261c911c57618fe3319698e734180af2dffb",9.317957166392093],[12606,"9f36d598180c830d12fd25409dd8e9da5623c6e98c7d112fa498fde88ba639ad",9.917710196779964],[18791,"9e553769f100dc9ad41560ac3308df74af1b174d23fc03256a35f6b9c3a84027",9.317957166392093],[12345,"40c006b2fc9a04d1448053f341ce974b3a949478983cef0cd9211503f511ecae",9.917710196779964],[18735,"dad4023654804c74793142e8a9ba71e69713e25eb0c4af587ea243217e273029",9.317957166392093],[5358,"4194cd868b192be982fa7cef729ff1d297ea6619e2810077acb929d0755418dd",28.063492063492063],[19436,"2a6201127b2e608ce1ef18ad06aec1c3c7077e42155ef9a6814fce32ceac3d10",9.317957166392093],[11584,"0d22d2d08e40b19a0e3093a2d553a1668e7fceefe9d9322c19246a96596df9b3",9.917710196779964],[11011,"75c60d77785458fdc271f1dd25ae8fcb2e80c779681f857dea8cfc8c8fc6ecb7",9.317957166392093],[1912,"288f64f97883dc6aa811dd231b484a9fc03376e09d3c17bf313767fda83793f3",9.917710196779964],[11663,"bb93d3c9e6b589b194fb2c903d442eb0d4c20bacee57ffff46ea22cb63c97fb3",9.917710196779964],[15140,"5914823b8fe5ac9355c3faf4304eb93cf0a8ffceaf7c4d40c3ffa2993100b77b",71.301247771836],[285,"eaa5d5705874956ac59f45ad30bc53f7fc40ed4a5c113e2339c60d3bf3b70cfe",9.317957166392093],[4240,"c569bd108010caef371eebcb511243ebe3cef42f66b3d71524562589d4662fe4",9.317957166392093],[14666,"702e848cc4b1a90cc92b14e0c63f06022c7246f823d0d82303b3813641419985",9.317957166392093],[6992,"51a301826829c457eb5dfacbb27876a25ef3b36b9fe49c67a64ea042a3c80bd2",9.917710196779964],[14290,"3068de8c802011639c9b864302c5268cdf626cfee40a1992d3a2f6b9bf18e88d",12.750442477876106],[2456,"54cb594d1968e4f53e1626b0b36d8735ede84a4b9e77f94fb36db451a39b28f0",9.917710196779964],[18827,"37fd1509cabffbc5cdff4c04bbae3c7847d006693885d5a478d7cdd1e958d125",36.16143497757847],[17623,"b025d1f3b126ca12e2ed9d97e507bb4495d213eca87ffdbb68552b340868d344",9.647446457990116],[12734,"81a2dcaf4177540202fa3c38eb22f153879748fd133dba04d4bd2abfb3705bac",40.71301247771836],[12458,"bd9f5c4c483764fedabe4d498399a895a57a57f61ddeddbf3945109f583d3dae",9.917710196779964],[9977,"6a3435555d215e89ec79941c93074c3ea4ad85bc3f7f4aad4cb93e8476de75be",9.917710196779964],[1473,"7bce0e3b796ca6c4933d0e042408051b3ba51c5e86643cb3ae24961d686b52f6",9.917710196779964],[4021,"f256690a52d66a85606da2320799fbe2458aff41983843a0207947fc8d0a9fe5",10.052724077328646],[19294,"3cda4019e27f29ae4f1d03190c44fbd0ac2ba119af27292d793bc39e6ec20515",9.317957166392093],[9646,"f1f98d22ee5089eef1552dd3ee4a8700dd60a904da72da5a46aa0a2a92b5bbc0",9.317957166392093],[7786,"fbd3318eb6642e76ea2d2a0846b22ebf95bd062a84b1cb2c63e229122316e8cc",9.917710196779964],[891,"486611199dfa7774bc4e0764017ea6312a2e54406bc29a7b6760a450f185faf9",9.917710196779964],[2706,"8641d98d1c0dadc2f2237ff6d4edd3f516682d2468837904732309b96dab6aee",9.917710196779964],[16324,"826a8ab18bf15c33ae5110e8ac8a43b596f0d4d07f9aec312dd1840d7f0e9960",9.317957166392093],[3159,"6a8011adc8bdb2ac7a1bc6e7ccc99c96c2ca69d796748104edddd80be67450eb",9.917710196779964],[13579,"aeeda1fee276a78dd26781def9e1a97fb8d839210ef800044710efc8cb82eb9d",9.317957166392093],[8465,"5342f713eb454934e1cb364cf914dd56bb7b0f2c923b3eb19f0c35200b973dc8",9.317957166392093],[6627,"059e27ce830417b7449609954f2ea38fe4f24b36476c103cc10aa1abeb5978d4",9.917710196779964],[7665,"34c7ddc6fd073da63ffe85d88b9bf49d35ba62892972acc88474a34e75c1d2cd",9.917710196779964],[8385,"1117f5733184a1ddfb2ff2b7a3f0f34937d83294ce6fee5db6b371d3c883bac8",9.917710196779964],[12972,"1e2079d6e7a20d8a24af8fc14770a38b1091a7387d0f92f8c2cd457ffcb3bfaa",9.917710196779964],[1432,"383dde3b639b61b813577164a04af9b909596cd3cae9318589aa288e022a9ff6",9.917710196779964],[12809,"4c71c9352b0b5f9815a73545e0375dc64ae7a95285d1efffcaa7bc17f30fe1ab",9.317957166392093],[3813,"c17ec170d6b30c140e5087e331ceb5b2b8715b54d876ff2c2bdbef392dbde4e6",9.917710196779964],[14652,"ef0d81b3723da9ca35e75571a680a4230eea3d71a76fa3ab39b1cb0a29d0d485",9.317957166392093],[1753,"5b857dc9051b6b3a6709897ba90fafae481d815901f52186984efbfa9a9b98f4",9.917710196779964],[18718,"a7fe17abe399d109a26ff045209a9d03cc83a815ae74210874025e1e0672b029",9.317957166392093],[12566,"2d24df8f54b87dc5105bbd7f15d90e2264a3c1d0c23c08b896bf50835c2783ad",10.052724077328646],[7212,"2feda3d656e9b027d504b20d0a5eecd9a4f65998e38db5dce7369af41fb09fd0",9.317957166392093],[14014,"806ee16f522ab91d076890fa111fededd0b72eb3e09fa7bbb43be8ea3d4e8694",25.87108591365024],[11336,"1f76026cf6f7b531a40110d6f12da887e3b06c98fba379dc537017d689a0b8b5",9.917710196779964],[14940,"dcefd3465ea3f92c389e00a03878a742c37adc9e18168fad00025d1196690880",9.317957166392093],[11593,"b5d9193034ec7bb7273d5993634380a40000ec8756fdc4c8f2db9955b4f9f0b3",9.917710196779964],[1867,"7cc136d1f1685ded5bc20bc83614dab722aa9ace008a170a918dba73be6ad3f3",9.917710196779964],[5067,"957ee79da9c9c489d4092b098fb24bf703451462a26906ea90fa97acb7cdb9de",9.764180264180265],[7827,"e5b308cf17c90f1ab0d6e86e85eaf0e533ad9f75ceaf761c1bf25710f7b098cc",9.917710196779964],[15182,"d2ef5e8bedefaaffd42835a844d08e36d348a56689838dc8c9fd217ecba9ea7a",9.317957166392093],[15323,"0908c0265ecf028b9f52c3f4242902dbb9a0d72d4acaff3df7b29813cf2fe177",9.317957166392093],[7673,"023368dfcda82cba7034a9d688cb8d46c74108ac61891f18c8b37f32829ac3cd",9.917710196779964],[4230,"4a49837cdb4a1a3fb0c554254b1daf14e81cd518df87b428c363f93631dd33e4",9.917710196779964],[7079,"322b9a03f968dd2aaaccbdf1b35f15e09014a7ef94003f6c7305e775a1c276d1",9.917710196779964],[19233,"b867827e969957be9cc32c4937782385edcb528f0e70ba01ee809262d2068917",10.052724077328646],[8731,"24907c61165f1bf029f39f09325329dafa93965c8008058b4a7b3a27339f83c6",10.045662100456621],[5877,"ab3a2ae1fd398a07af4c84d89ac3133f8bf46be46e69fd1121ffb24e06dccfd9",9.917710196779964],[10676,"761dccff51cc916e2f1f2ea94be81cc2e18e2a2314baedc331b8a2dc166f32ba",9.317957166392093],[15055,"02a857cde6d18652386a7319a421587a82f1b754f9a3224bd3dbb50aa33f717d",10.052724077328646],[6266,"357679078234bff92b016d94f590dfeae196a0832ba1392e5423e0dc8c644bd7",9.917710196779964],[8820,"4c4d737d4c301d274a5a0673af7a079b506cb1ee0540e61ed4ab2d6a3b6df8c5",9.317957166392093],[141,"2ba0459a68cfa0582cc96caaaa2452678138ce3d9b381f106e6026c4b5050dff",28.097560975609756],[2321,"74d33369db406a0590bdf2352d8aeca5d0c84d569664a13c7d3039d84724ebf0",9.317957166392093],[12512,"aaf942088792bb83325e0c5771d0b922c8313779f8cec9551cc4c4b2e6b4dfad",9.317957166392093],[8055,"9eef7ade4af10e45f37fb2974d3725742e3fb60c5dc5c614abaa29b33d5922cb",10.052724077328646],[19871,"3e889d8c44ea5a60af0b5254940012f369c41ceed333b58b3c9f124137ab2100",9.317957166392093],[3086,"af895abd969b142be956a6019a4648ee3acd77f1f6040dc93aaa912f4ee9bceb",9.917710196779964],[4249,"1921f9fd5f52147521f58f88ee082864d5eb4661fc83a3242e9f6d4274df22e4",9.917710196779964],[8080,"48e154a73348e8c9618742a1050565e5ab896c1260dfa54a8e136ac3f968e6ca",9.317957166392093],[18756,"b3525d0fc4e19f6bf9a2108e135bac20b634aa42e1b2b115f6cc1a8aa8625828",9.317957166392093],[14349,"e7cadc1ec10ff12c50f8a8f392c0c3ee3330fc10049b9fa4bade9bab497a5b8c",9.317957166392093],[7642,"e6116a9b4255d87d0f11e17bc4bc62e4562fba3ed12a2784a6db6dfc8001f0cd",9.917710196779964],[19203,"4a1810e5bf02675e2e2173503fa87485803840787cd16409ab794918646b8418",9.317957166392093],[6317,"46efb4ea265cdc5fed097847f4af68e29418caffc73b649a008baf04c16de4d6",9.917710196779964],[10337,"8b801550446438a80c78144e48aee8e8cad3c3bc4b2cf956b53f49cc22e61bbc",9.917710196779964],[19077,"7b25ba136efd0c9f080cba168ea0ec30fed1f856c0aca095c00849be3be0bd1d",9.317957166392093],[5279,"a8252c75b8e8afa40a3cd1172b2b69e6fd7113c1123b7b42d60fc7e925f487dd",9.917710196779964],[13256,"77d3f1438dd5ac26d23a694e023f1093efebb2d45ba2c93cfd10b67f7a2e8ba5",9.317957166392093],[4915,"2e083de8764d042c5733ce418519cf60106bb6a39f59edf8ac66ef051225c8df",9.917710196779964],[522,"694a8fed3e4179de478c31a30cd555dc46e7b90aec0ff88afb30ac3f9e5b81fc",9.917710196779964],[3182,"f263498586be6d9c65283151bb138961374f018b4061d2a76517f9ba7f8123eb",9.917710196779964],[9885,"7f3ffc310642c31c56ea5bbd670d6fe1e0fbb03f5cabaadc88723f1294f908bf",9.917710196779964],[12798,"0fc83e2ea223f96040da50bb296ca0bb7043189d661453c4803ad772605eeeab",19.066666666666666],[12839,"d8b53a4c0a0d809b05cd3665bcfd3cf7802105ccdae07aeab1a6d8225da6b0ab",9.917710196779964],[2945,"d3a5058840b7fe770d95d18094973930732a7c4ed621a840719dbf5147ebb7ec",9.917710196779964],[2638,"7d7ddb972052e1247c2f20b323f49818e11a5f97e41e28e76f830b4a310fefee",9.917710196779964],[2287,"efa64d646da256ffef95e544d96767ee51d2dc10f4ff6a14dc9bbdfd42dc0ff1",9.917710196779964],[9576,"c9654519e2bc4140c78379c1d061c3871888af1f6fc19082f6f74abfba9e27c1",9.917710196779964],[15508,"990ff9d743e14d4f9ed6dc196620cb899e9b1bb9e9b68685a6c52868394ef373",9.317957166392093],[6000,"e2ad20fdfbe33f0091210833e979ef592a2eacd0a85798cbce9959a35fbd10d9",9.917710196779964],[5397,"2891bc1c5b18ed775ce034257f7c714c3ec7e7328beeb7ceb139bed9932fd4dc",9.317957166392093],[13653,"76f6fd019d83326fca8eef7eecc089b48d297d18fbcb3979d162c19aaef1209c",9.317957166392093],[19409,"ca08c3544f49fc200e799b0e549b5d3ac52dcfe8b5ed9703b53741bd65cf2d11",9.647446457990116],[18599,"95ee552020808eaa9937c4fe686ab6120994576e5a7bd1c0d60c7426c20eb22e",9.317957166392093],[5817,"0cc184d8db7d94b936918fa37597a8ea1ca75d52266ea5393689b44737c847da",9.917710196779964],[10074,"1f340fdce35cf0921aac6f4390a9d29377e5c3d8ca833dd4858735f5e7b3dfbd",9.317957166392093],[14677,"083cd13b73e93b93e850167e82412aed83ad8fd0a89d306189b64f21ad165185",9.317957166392093],[11849,"c5aca007a6996cfacb1cdbcac1160c6a1179123d29462e347c713408886760b2",9.917710196779964],[8469,"5aec5a14be9ddecf2993dd44d0d6eb96acec4dcbcf22d22115a9af50fd0b37c8",9.917710196779964],[18839,"ac188d4d10892f5ec5cd22d3318a26c5fc12dc62a1b33028628a73cf610c7025",9.317957166392093],[4488,"15d10eff3dfac8ba49ea2523bc5deac21d358c9856b1a926c93684a3099b7ce2",9.917710196779964],[10409,"6d3fad227a8b18d66f9ad0f9648001fe71d096c0f26caa5523e4cbd201e0bbbb",9.917710196779964],[5905,"ca2e5d2687fadd564b77b5bef000fd9441b360db0331c91341f3ce316e95a7d9",14.112994350282486],[10497,"c69c2e34dfac4d699ebf2b1f8afecf7753a6976939415b38262c421985ec2dbb",9.317957166392093],[10945,"eb66e27a40625e45452f7cf43ebfce7d6b0c3805d32a82e3defbd636e4fe69b8",9.917710196779964],[17437,"594368265f1788c767560d7b7d1c3616911d78d65cedef7317ecf128d8d4e948",9.317957166392093],[7697,"e0e4fdf6f87e3479b0057d3e87cf581d122fd1a2df4d89e5ef73510f7b2790cd",9.917710196779964],[10470,"2ab9d894559afd292bef6fdf76758d094d726eee7cfccc47d968c5eb46934fbb",9.917710196779964],[13824,"f4b95fb19bdfca226bd30ca824c48bf58dbd91229cee25eb41ad71b80c6fee98",25.748086290883787],[6719,"692f39540ad7ac4710910e3afabcba07be855771c6176d559572dc7c6e04d3d3",9.917710196779964],[6575,"2a0bb4e62640a7b0c80b8246300667f66b7ea00078bb9b61db37583d835ad9d4",9.647446457990116],[8546,"2f1a62465d800b765efd742e30ea749ecb106ac7316d331e996c889d1ebbc2c7",9.917710196779964],[9998,"8344216026e85c22019b718eb07d69759de77c328d124e4d33490bd393f859be",9.917710196779964],[2367,"0e8788f1c656a4c3615e03ff3d43157d8d5ab15ad13a75db8202b53ba57ba8f0",9.917710196779964],[5254,"2c0ea91c635a98c41ba61246087a06a43fea105eaf36df0ef40e98ed4f21afdd",9.917710196779964],[7565,"5beebe67bd8cc777708b97a4357c6a6e94264a3444d7e8b6b34b0d358d6567ce",9.917710196779964],[4978,"ba533f7472a4b47566eff2c86a4eac2262024aaa5fd5696854c2812c435454df",9.317957166392093],[12906,"6227a4242bd28dcd0cb04c2da65a8d193305ab390ab0ed42fe1d534c40f846ab",9.917710196779964],[15813,"f9dcb6a3e060055f48a352004b148d0d87d2896d74b3a1c2f57d8d769955296d",9.317957166392093],[16363,"f8c3bf8e8c83e342f7ad5b18fd946cf99b05057f752a01076489dc3ed230ce5f",380.95238095238096],[10469,"a19236ff4cdc26c7fc1c9f2842b1f1d5a08f226d45dd0e42570b5f8bc7ea50bb",9.317957166392093],[6122,"ac0a41e3bc7770452f14038ad0f9125c913478f2fced9b30c995e1a8df384cd8",9.317957166392093],[10064,"4a02a049281d4769e578ab21d19317d079aeab28bf09d072ce1155b735e2f8bd",9.917710196779964],[14799,"fa5afe2a78540213ef40dfeea47484ec406824d44f2b90fb693eac5004d9e882",9.317957166392093],[9173,"3534a3ed650875e6b678aea1ea510edae6bbcb4ef8835414bcca13e5abd0afc3",9.647446457990116],[7125,"95e82050c357643dafe2f4e12afffd64c842f278a57cbc664e596515e4f12ad1",9.917710196779964],[8908,"13fb61231530043c30bf482b2a411031a3486f87d8855e0e795a1a9192ee65c5",9.917710196779964],[2514,"6cdb45cb17682338920469f610a881831f31cec7021a08a06069946f5516bbef",9.917710196779964],[6632,"d67eb1d44fe7894760900a81e0987a0a2f0a56b0ed4accd44a14bb11e08173d4",9.917710196779964],[12623,"9afc61778408be8b46774c06944f29b86a582a3b7481fc80421fef8547de1ead",9.917710196779964],[8761,"9b93837953305bdf93b40a5f76ea3061abff2cfefc627a8086927049ca8745c6",9.917710196779964],[6828,"f314a30225e4802433841fdcdacf8e71cbc8053e05cd8089ebfaa34f176b12d3",9.917710196779964],[18284,"810f2bd9bfb4ba23e2de17112638b6adc3ef3f88981036ff4f6a62f8bf892336",23.05764411027569],[12853,"708748c111b40daba63a8533575d2a9b9ab4d4377c85141e8635cf7b5ccc8eab",16.975265017667844],[14532,"378a20957cd01ef868b008f7cc04db2a213f2c82b2a2cf28d700299493359288",9.317957166392093],[17319,"488c5276fd8ee6016c247e5974b49f78e662394e961c7d4bcbc34c862a6a854b",9.317957166392093],[9678,"ddbd70399fe173271ac0366265662278bb22d009a4fd9db32446b66ebf4786c0",9.917710196779964],[8130,"88ca52fe142562d7897f35a74c29a542ec487e0049713a519f777194909e87ca",9.917710196779964],[19623,"dc9fb65a5a24a5e70b1bb82d9ab884ef56699abb3d467707c2c6111347d5da08",18.09557522123894],[17471,"017d8ce28aa196fd2df1a991e64f0d669f6f4a3c8e2927ba51d5ee99ab294648",9.317957166392093],[19506,"ade23d93c91d39d007a851d1ebac963c9b16f22aebb4cca30f69a8a437b4100e",10.052724077328646],[11021,"d4f6ebf8d28900e629b7e4839b3999eba80082b261df3e0a9b644aa4cad3ddb7",9.317957166392093],[566,"8d0873f3b565960b133ab04d673b83535273360b13c64fbec89bb06de8d228fc",9.917710196779964],[10969,"6f76efd19cd6b461caeb6e367e65b7f829a4511e4c0f4d46eaca35ae036738b8",9.917710196779964],[490,"de02c950b39cd893bdb6679e94a58544434e0a27c4b67a1b5f5d22aeb9d2b9fc",9.917710196779964],[15460,"288c05e5035129003f006d6e1cd505d1ec27ee763181bfcb158fe3726cdbfd74",9.317957166392093],[18340,"af0e117ae4bc442d67c4f98f482833c829756b4989f41e4a908284258b680d35",9.317957166392093],[19564,"12d7efb712576fbaa4018c74755ffd2114a7b318d9c9ea937ccff361efc92a0c",38.70022883295194],[16576,"6f3b270e144f45d6e0b5787938b72a17d023633a467790568aa258456578935b",19.066666666666666],[5951,"db0d49189b8cf5b75f77ced9afc2224c50bb00fa3db51bfae936315c22f868d9",9.917710196779964],[7478,"15ff01b2cb55bf43a6a0a1a764eeb38073d2300831e3965228e9d07d32e3dace",9.917710196779964],[4185,"3ff9cfdefac34bc96b7baa476066a14b1fc0b702715c1825bc8b682832fd83e4",9.917710196779964],[12750,"ed94fb464bcdd9adab96a59fe9923ec2009e46d249e42fe0c0afaa36e6a93cac",9.917710196779964],[11604,"9b79041336baf8e01192273efe437ac24a18b935f08ee58d0bdd1af859e8e4b3",9.917710196779964],[5442,"b1be0a43638cb87aa1f5ad7d9d19d53ae5dcaac5937f05858b1eac3ad63e86dc",25.358885017421603],[11688,"22e72a729cc336576d3820d67a15ce2789196b0cb2aecc14bea1e3e8e5c260b3",9.917710196779964],[3236,"d6853b5f0130dc0b567ad815ae4eb9ddc1f0500bfc21a2eacc64547ee570c5ea",9.917710196779964],[13188,"c64c90422a3bf3d9e3eb7c05abcf67b872abf9c8bca4eb5ee9b4eda9f8a736a7",208.46715328467153],[10580,"d60c9b3effe839cda5e925328436b4c77f15235135c6b8f53f25ad7b9e3ebeba",9.317957166392093],[13437,"b759054f70fa2bc913d82b4a7ea65252953c38e8cab4898ca1b7ac74312e90a1",9.317957166392093],[13455,"62dfa6aebbbff69bfe3e10e55cdc4e53dc1b372f028d72d4e33fe20df312f3a0",9.317957166392093],[1876,"cafe1beeb900bc91013f7724f916bf456dedf3c8810948d05630721f0d6bc8f3",9.317957166392093],[11684,"87043039cfaed4e25c34bc8d6cf2c0f3dfffd16cfc9a8bae75ef62846ed467b3",9.917710196779964],[16744,"51a5b2b6ef08ab97d20e04fcb903221da0f87add84d623ccde3159af34799257",9.317957166392093],[12161,"9b8373ed362d286762ecdf501250900811f25028cfd04a2f7dd4a0f3fda049b0",9.917710196779964],[10974,"70bfb6eaac3f3a196c4e593145bbba5f6e5b7e7e31d2400b51c605e917c532b8",9.917710196779964],[19270,"a0c5eb57c61ba8f711c2e459f102554bb1bf7322883774b4a6938c46b555e815",9.647446457990116],[5192,"436907b5e36f95a36e6834a626fc03b2d346ef4154fb239a7c73c7ddd50607de",9.917710196779964],[6345,"2971a58502f5d49dea05853384fc95556ec076d1d698cba37efb2189ed4bb0d6",9.917710196779964],[19589,"542a15390566688571c37e243fb9947a7672b2b5fbd74f79f35df0c56fda9e0a",9.317957166392093],[11105,"20830591fb3b1a08e4a169186846a0e45053f8ad7f94f05b118ccbf93a6c37b7",9.917710196779964],[12723,"8aedeea9f7ad2a6802e41c1b04c9cfec2c17733771b8a77dd63b514d4b0a6eac",9.317957166392093],[7923,"945909fdd7862d5de44c9922b608ccbe48dc27f174be3f1c0eeb8b9cdc3913cc",9.917710196779964],[15361,"fb032c363cdc9b97e6369609aa2403d368934cef0c8994ae11deec019bc32f77",9.317957166392093],[533,"01adecf58eff0cb0e46bd0b611c4708e7fdd3ab14352e37b10b9aedcd50171fc",9.917710196779964],[17531,"774bf4801df444d40a3755c3a0ba0462c356dffff32b806128207e05e632e546",9.317957166392093],[388,"1bdb602b857991ae2227ec0e75cc59ed0cc3c1072511563b06c1da18e59f70fd",9.917710196779964],[5896,"d0603fbb997140348b12bbb9f351b63a32cded56322f58b70689ecabbb24bad9",9.917710196779964],[10770,"a5b99b1b1bc0abf5bfd979a7232d12405863ae936d4742c9f7d05f7d726782b9",9.317957166392093],[15151,"3c57ecd84d0f1e90792cf8bc4dd073de1c3a4b140dc1f5f1f8c0d3bb6083837b",9.317957166392093],[3412,"018d44eb39bc64764d5828e349ac5fb8b820f0755287d002997e01201b3d97e9",9.317957166392093],[17877,"878e2579a0e633d68a80ec3d7db3ed435e86b0e3fda946c1aeeacd09dad7b43f",9.317957166392093],[8822,"ee029b781c414e96767a8645147b3016e0e63fbe502511d05c23638b3921f4c5",9.917710196779964],[10245,"52ab7e581582e582bafa83a0a8d416856505181d8206f1c3a25ae83d91ceb9bc",25.84237680128091],[7149,"b30eb5e3cf0ae25bb7722519b358e472b6eeacf4da24949ef768a953eb1306d1",9.917710196779964],[14638,"e9eaf79e0795c421d923ebce36055b7450c7fef47dea24f2fe664d93b2413086",9.317957166392093],[4882,"8902bcd64916919bd61aac816cd019c87a08695bfeb4add29946bfe21c05efdf",9.917710196779964],[6425,"1c57e6f118c8214e29503e01a0ecbc12b08b6d53437d58f6c8668e5c85791cd6",9.917710196779964],[2570,"d04edc01514331a93c229cb10fcffe5d24c3692a916f40c0d2f55a11d1ac67ef",9.317957166392093],[15407,"685d8a893a378174d1ca912af275d08659c7cb886bbb257cbcf12330519d1776",9.317957166392093],[918,"2f3279d11e0ac19d042888afcedbfa39d1b7d28199a14778ff7ea5ef3631b2f9",9.917710196779964],[12852,"24b2f8293d9ba7a4d61c3faffde30dc89d0f2d74dad8cba4e59ab167de3f90ab",9.317957166392093],[7712,"aec776f51d1cb08c7cb034b5dc409ed5addefd818bef9807953dc508392777cd",9.317957166392093],[3807,"d7b7d4a829fc26d1a5af07f246e777946677eee2be49154f0abc0895a02ee8e6",9.917710196779964],[11220,"5cf588b06634c7a0c5f074044406a4e8f4a4e6eba1c91f754c45fc68bf6695b6",9.917710196779964],[19611,"c1f3c8734f5842ae54bca657700f56a6695f33bd38a6acc9ae5673bf669e7309",9.647446457990116],[8153,"c4a7ff8b30ea9984f7f11dce3ab1d299e4db498f69027f7901a7b937c94154ca",9.317957166392093],[10480,"e9fa41d0042d82294f8291b506290125a5d8a40d7f48af17dfea16499eae44bb",9.917710196779964],[13747,"f5bea686e98c3f76c9f18d4446895039b403ceb1a6ce4cfee249dc6a4318859a",43.79342723004695],[6716,"976bb27db73349f31139dcad06a0fb88b932c4b90722398a95fc508c8e58d5d3",9.917710196779964],[7338,"761253bc6715c0a6264f8618481bc8e774a5dedaf7914e60eb4049255fb6cccf",9.317957166392093],[14178,"eab058659de5e1e12082fd6e60e4ce46a6926b6545931d0edca2570ce90cdb90",10.030959752321982],[7391,"b4748e43c0fbcfb6001a46ce8203b0ce397c3ca9e5360f762708ff91fe5a7bcf",9.506082725060827],[9886,"fc187bbca5b57c7f46a76c216ec1904ca2b1d14f27c403913c6e8fd92c5008bf",9.401360544217686],[6313,"23cc8230e85c8b73aeb68a287856e1b5ed4c0f222a94de4778254a0f7ea1e9d6",9.317957166392093],[13351,"f85bec44df1600a9de0968e0371d6a13c8ecd935be3d0bf768b2bd1c013874a3",9.647446457990116],[19686,"c57eddaf25c86a555d49747bd4cb0792cc3bce3d1395adbed146ee2da14a2507",27.014778325123153],[12034,"29196b41e9a4a439e79f60cdc58b03d93d9f48315750c088e12daa1e314b15b1",9.917710196779964],[16734,"bc11d9b920fe9b13f9caec856efac0c392f9d9cd4b9207ebfb27ed08bb1db257",9.317957166392093],[16758,"e11dd0813814e4c70469a46f5f414a5003d01fc771fe2cb0f67eff5bbdb64757",9.317957166392093],[15128,"ff463680a92da73af769724c44b720becd0efe021d913b533c0f152bfc7e247c",9.317957166392093],[16287,"f2b140b3c62ee86ce2097199ba6c7db6b6ee04b435ee3a0c75a6596566458861",9.317957166392093],[10528,"d4b3c5beec985978b56ff2a1f9cffade505ca34196e39ed7091bbba8cee700bb",9.917710196779964],[5096,"6c290af9d5e898a7555da5a90ef63ae5bfa82381ae69ac5fc8db43ac9f209dde",9.917710196779964],[13262,"6d788692b3cf9435788f2c9529ffd4484de422fff8dab8f46acc2969038675a5",14.181818181818182],[10871,"cfc481ccf3a16639d20a4221fb899931e74794ad4c81b1a8d50cc61984b4d0b8",9.317957166392093],[18681,"c931997dfad9abd8c2178223343232f08436cd783c6b43eef89f5d11475e2b2b",9.317957166392093],[39,"5a53f67423bfcea269e19fe7b6961e4a0c5027402463cd809a97d83b9145c2ff",9.917710196779964],[13927,"3fb6d828589174e2dc1fc7372fe410786be496423f28771ebebc3b93a0336296",9.317957166392093],[12489,"294f6df574f68a8957a6b56d0421a4b9a4eb482936a8b356de8c485e12e103ae",9.317957166392093],[5082,"63e4aa1ba77717082f119d4c1b643f759ee16b39975f5cde17729d151254aade",9.317957166392093],[11877,"dba855ad422ab68234d493b979f5d4ba947b27d7281d4b84e86dcaeb4ee034b2",14],[18926,"43558393c610dd8f65c6f51bcfd6c4f2862b7c4c6ffd05c6b3c0a4c8de43a722",36.07017543859649],[17871,"3b82a20d5f38704626113a7628167b03b26c4c62d3970ca31fbd5151228ac03f",9.317957166392093],[10878,"d556378276d17d3d6a39ab739bd66077e254b1d3008814ca983e424ace15c6b8",9.917710196779964],[11600,"67a3ab9bd6027934471a560e330b306f3a1b72206e0fe53da496e49e18b6e5b3",9.917710196779964],[18709,"081c7b6ef8c5e62138d0e4d0640fa81bb3420e753f0aab9ac763be111403f429",19.075734927752865],[13595,"7ee3ed53f7c95c67aa681a29ab0f95c484e6a331337176cebffe37e62e0d9b9d",9.317957166392093],[6959,"41a51429e2d1e2e05cf08680ac0ca1a187cf3266dad20b0d2c82df11dea536d2",9.917710196779964],[19119,"e0864bfea9e6fa40b1d0162df318a74eb2533326c95a44e2ff9883624726aa1b",9.647446457990116],[17214,"b66b20e75fc29fc9184991dee0ca5c918623f1f965f853d2fc2655abdc1a924d",9.317957166392093],[12131,"f42f0b6c844560bd0d314c5c4bf1aef81bc4ce412481361b3fafe38108f27cb0",9.917710196779964],[12998,"9c271b20a23def681f93e529bf07dc96ceff911e754efbca569c0a1fdb4999aa",9.917710196779964],[11002,"083e78704566290f6da216a940a8c8c66e481842ecfeffe68f5fe3cac5f9f4b7",9.917710196779964],[10674,"afef39092735b895a03221bf66c98fe0b77b3a8e4767a980491011f4ce4a34ba",9.917710196779964],[19819,"7fda85746df4b3c3049b16e646c79797b64f2a6b189e13d02e48e6548c35ef01",15.026455026455027],[6931,"2b1254c0e4de105cf6b07937e829432afa6d19d3631dfb027f55687a44836dd2",9.917710196779964],[17698,"40e5ea470922d1dc26417258b621e5ecbb53f43298d971b45e82c1c363523b43",9.317957166392093],[14649,"801b4c227a5a81d2e5f51eab89d859499712c96c9480213f23543d271d2be485",9.317957166392093],[9952,"64d8491a28ea9e823253bd4bc455b96f47aab19a0de5dbefbaf9cf341b6e9cbe",9.317957166392093],[18432,"6ed824c1752fbff0aec991180c440eeb4722739f87fa2a82ddd94fc89328f932",28.955436720142604],[8266,"565479e261f406724f8bf975f0f56bc849ee8896e8054770c7694f07b81e87c9",9.917710196779964],[18091,"03382780703b956d6ebb5650f10fba536c715c1d610d4292ff69f09f6c4c223b",9.317957166392093],[17769,"bf8ea042e91e668eb225dbc7e551549e1581449fbc226f4a279df6296247e441",17.008521303258146],[7652,"fc50bc37a2bc4aadc9da34492137f6af9ed3a39f74ce9b7d32e905cdc8a7e0cd",9.317957166392093],[738,"43963403636e0247b0e9bb20986cdbb75afb7fcb6758dcfbb6d1908f92d7fffa",9.317957166392093],[18095,"8f56229af4c4ba035a1d71809239280c1f7b98e8ee560b3034b4f59580460d3b",15.915194346289752],[7763,"4ab92ba172d14c0c3c122659cf29ac2efa247729933fb3d98b1d9cd5f37e0ecd",9.317957166392093],[931,"ba1b016ca8fea33264284a93568de7485aa80831ed3ab3f839abf12a42e7a0f9",9.317957166392093],[14484,"e6ce5c577f1bfa2d0ef16d58ec538e5486cf309ed0e20cc6cee8ca8e6d318889",9.500303951367782],[10919,"f932da3f12895b092fa9de6960b748cc063862311e37f483438dea6d4d9e91b8",9.917710196779964],[11704,"ece7e293254911f7953170ea4033d9d4c76433db8f2e57e6ca2a77f95b7946b3",9.917710196779964],[1388,"46ec569b4d29c33b9858d48b96ceb04f5f2ec1234766b6e996bfa8d02453d7f6",9.917710196779964],[3071,"bb24ce8337dc5c44c3d39b426cd8832ba6928a4bdcfcdc19fb6a04d4d23cd5eb",9.917710196779964],[19391,"5d22c3f2af6a2e1351c86f800a731441d5baa08131a06daf4fbacaf3e2c62a12",9.317957166392093],[13258,"7a67b17a9f004daefb4656d19737191f528ee51d7ec9dcfd0deb6ebc6c637fa5",9.317957166392093],[14007,"874a8adfa76ff281c9adbefc176aae76bb0e66e04d62beeb516d3c2c86bb9f94",9.647446457990116],[9101,"0e866dc3c3c2525f8cbb25ff4f62ccf6cdfd953ff3e9a53b6ccbe7f8d6812ac4",9.317957166392093],[15694,"643ab7ffc9addcd85cb7257065bc38ed6fb58ba3f0aaf3d23d45d4dfa3719d6f",9.317957166392093],[11590,"792de8a432572fe2922ed1616494e150b08e36f8c2d21b205eaa15d70501f6b3",9.917710196779964],[4768,"f7eeefcaa37fce0ab5cae2e5c5be8ef38c889cc76fa11883afa915a1dcd98ce0",9.917710196779964],[9152,"ac4064dbe4662c6f0a0b9da953f07a477d2621d98755950f41fc25c56172cec3",9.917710196779964],[13959,"9cbba459ae3fc7af7fcb3b562dfcf68e22b3b4403c3832429d79dc0dad9fd395",9.317957166392093],[15973,"d695c723aa66a7f802e8528648b9b20ab146669d0e29c2354dda38c078f04769",9.317957166392093],[6628,"2955dbb8240aee98a263282fcf119e884cdc6a534fafc668110da590fb6576d4",9.317957166392093],[2518,"58d2f93e24db29da303789cc5f5b419c5f22714e9d487de190caeae47f80afef",9.917710196779964],[10421,"40d9b11187e72b356ae0c42bec78ab78e99258547969e6babfa307f3f272acbb",9.917710196779964],[15539,"0f2bd676e3c7e28be3bec817a00218d006c0d34d5bb342551f2bf94f3acf2e73",9.317957166392093],[12554,"877f327900b3ff7060d49cc9ced29e18ddc86cb8ce5c693e86d4dd63f6739cad",9.917710196779964],[17217,"14b03824e915fe3de13f058a56f5bc386b6b4b900c8a6f97b4a737ac76458f4d",9.317957166392093],[2043,"b6b42a9f605273f23a634f10ef444079c307c91f8fdb78a001ee5b3daa48aff2",9.917710196779964],[16412,"b9141cbdb71527cc69b9fc4aa39ea750caa061c55cf60b07a9ef853c7941e85e",9.317957166392093],[1847,"f811b348f98e9b4274789dcdded90f710fae4d8ecab6e415f3e7e9f807a2f0f3",9.917710196779964],[6767,"5847f16bc1f80ceb936374ff726888d1e21631ff40fd4d1bd1078cf2179e7fd3",9.917710196779964],[13973,"f10c7139ebfa1a33b9f3ec1bd83bbca9143081a223e1a806652dbfb995599395",9.317957166392093],[17090,"5faa4b5c0ec009cc39393defcce0e5ceb8d646a39b6ade941f40dcb966601550",9.317957166392093],[19450,"96d7f3667840699f742bd64ec57df116192115a6ee0bbb7a27ee22599c13e50f",9.647446457990116],[9493,"c1ed7435ae44393aa6648dc847e7d4fc888b5cdd8b9f5444a980186bae60b7c1",9.317957166392093],[8040,"69964ead9a68ce378d0a142b0a5d40d56aa67c6a67f3fac970c289eb038d4ecb",9.917710196779964],[1146,"d2e848842d2f7196c35887c2fa1e6e62e28b09c2e92eb2a572340e7b4e6354f8",9.917710196779964],[15291,"f1f622f328670ef66e7bd5ad090d11ed5711a5c38b10887a4220d85a5e2e9b78",9.647446457990116],[17924,"2b4123aef316d052039df7973841857ea6458079e1b13952d0e604afee94bf3e",10.020293122886134],[2889,"31a4bc2eb2098e95620ed814710a5cf16bc4fa932e0575f7148e87cbcb6333ed",9.917710196779964],[6987,"8d3c76d5d1055876cc38e4424821cd5af4ace6aa1adf8be22e5b86729bb116d2",9.917710196779964],[13386,"f46d4c8b9573dd69342398647520df3a58b1a3c307b96e25aa0aaeabb54ab3a2",9.317957166392093],[11558,"70400c577572d7015c088f66276765030a32389529551cb205b1a7b2d2e431b4",10.068649885583524],[5682,"4219eccb1d29a5a4769c568bcb6a7dd333d9ac6d16d97ed472ea5275ef6227db",9.917710196779964],[13492,"b6463e9f6cbbe622e7e165f6335a72a796b37b1898f6738b469526a372f5f49f",9.647446457990116],[10943,"5c5533c5a5f3f16dfa314d9726f241b943acdb98f24a08c380ae995864ad6bb8",9.917710196779964],[8058,"4233b39023cd631bbaea0f9c56dae3e7d13bfa20bcc24ae13a9f093acb7f13cb",9.917710196779964],[3477,"e5150b4b8020e8a57f5af5a487a604061d4dedc6718e93f7938bc5ab24e930e9",9.917710196779964],[11423,"f73510aad1e88680cffb8358ec046fb37d06ba7a5a834b19b2a4ea1c4f122cb5",18.190045248868778],[17617,"bedd4ed4d8e936b893d08a7f331f951a1ddcd0e7f26b35bf1878f21c258ae344",9.317957166392093],[6990,"ab6db36c0b0ba9b5cd7f268574fe8c78b86edb6e864e2a73403a677a562e0cd2",9.917710196779964],[4048,"56a6e433bd675010e253b765ede65cd5dd7d454febed34a42fedb816266773e5",9.917710196779964],[8579,"d960ffdb08e85cc0e9a81ac5494e90be6e66f1fc66339531647385b6f99992c7",9.317957166392093],[1167,"5132fbeaee2ef6511a0a75c52f8849b66af8df571c2f568ca9e332c849652cf8",9.361256544502618],[14292,"37b7217f4b2292681c92200a567715981ad28e1b7514c117cbbd68de21e9df8d",9.317957166392093],[2261,"9f9d452f3f03c837438e7d64cb87412893ec1bcf6b2e53652a656674057631f1",9.917710196779964],[2789,"b6721dbd74ab5da829e3698f3b385eca7e2f1c5133176c7b482e3ffd9486ceed",9.317957166392093],[11381,"7405b5817a2d2631bbff6b629465dd7e90109ea69aeea68fefb3f706866c82b5",9.917710196779964],[14308,"10a026ae0b441aeff0b4c8a3e7dbeef2b5d7265a15b6fc30bf85174c7a05698d",9.33803810868031],[15937,"afcd4212e93d3ac0f6eb7dcf3b82802841303f58377c2ddd2f1c3af1d4004a6a",9.317957166392093],[14034,"f948d36b0a86ff0200fbef0955ee9fddc24c9e176600a82f53ecf825e7ce0094",9.317957166392093],[3184,"3953d1a72fb2da729be1a9dc9485594dfd26cf30e8ffb25c2518f05ee06520eb",9.317957166392093],[8100,"b65e96d933fca1821be07aa805f65bf199124762461ddfc0d4d266eb12a1c5ca",9.917710196779964],[14125,"629a146e4634ac99884f1a16f3da616c93f6b026155a8ae7967c8bcf2df2fe91",9.317957166392093],[14843,"53a155c6df51987c1153594f21f9b51741e7aab6e169c99bfb9b774847f21282",15.9236276849642],[3646,"d57720dd9336aad2a9b82c9a291cbcaca6b70ff5db5d25b0637dd8e786c7f9e7",9.917710196779964],[1743,"fb507e0ac2b4aa09f7d4d81184ade27aac1adf6eb11ea670787318d4f5d8a6f4",9.917710196779964],[15169,"12072c8ebe7b55b78c18f05e3ea9cc23ee4939f3c25786787b60896b644f1f7b",9.317957166392093],[2522,"198ce288e544ed9bbc2a9f65197f927930fbf08ec12b13c24819772fe21caaef",9.917710196779964],[10236,"4a54473fbad8b1a7d8609a0533b407aea7d8eeb2dc80362bb427d71642efc3bc",9.917710196779964],[6797,"62d4721022a31c59c0da9cea7fffed827ef3d3d30ab7c4ec9b64d52daaa649d3",36.1531914893617],[14507,"31fdeccfdbf97b4d90175fecfd7d372cdbb368c6a8d65b6e3c606a483a6df788",15.080789946140037],[15785,"936f53941b3f14ae9adf42a0c00d0c0c760dd5fb1ea7e1d6ea962f432e4b9a6d",9.317957166392093],[13970,"70bf516d375dfb79fa1d75a597c534a964d6f42ef3e28ff9c87560b3e13ca395",9.317957166392093],[2134,"c05c31586834e543a5f62e708d1a3a3ffd610a05071214ffb5dd34918dbb05f2",9.917710196779964],[335,"a131e529412b955d5a7ce2a39e5aa092e97c0b453b939b23bf4ee0666152cbfd",9.317957166392093],[7002,"1545bd319f5971af14f6a051115257302fde70dc043496517eeab3eb7faefad1",9.917710196779964],[4360,"82cc214c1205d9189a356e10a7426c31366a2db6714d3e46150ab5286cad59e3",9.917710196779964],[14884,"d5668aba72480708fe55d5e60382f1b1571906018c619e212c54bd83e9af0d81",9.317957166392093],[13145,"7027e3e00a79a4fef5402fb7bc1d0dccd9a02b9c1c9e5f3ee2d5ed06ae8110a8",9.317957166392093],[1302,"809bacc0fdc911e3ebb5fd5e08ce03886a73957adea90ac967da5d249eed5ff7",9.317957166392093],[3416,"143750417d9da42c3eec7f94abdf9182a5ffd3f3aed75ee9e2a844754f1f8de9",9.317957166392093],[16390,"90ccbbd94234496bbbb08d869f6436ddb6dd1ebfbdf1fc9721e10f465792405f",9.317957166392093],[5562,"701a7dc91617a22e2b27609fba3d4a259bea9d5e4aaea28613fd82c95212d9db",9.317957166392093],[4846,"d243b4f282ac6fdc5577eeb76725678852e6b57f1b4d21179b27fbd8729a29e0",9.917710196779964],[6207,"1899fb5751cf67c53e69381ba08719a0381b23237350889795ed91690711b3d7",9.917710196779964],[17579,"1ead71587a0b4103b27f5e622c771335f066a47d03b513567baccb70e90db545",9.317957166392093],[18060,"f0149d9bd80f0e61d3baae1a8fb4f798a8dd9b324f779c598eadd307eaacfe3b",9.317957166392093],[1901,"b0ba291c83bc3b2b6035b9338bbe35bd89431850c18d10e44ce15e4a30629ef3",9.917710196779964],[18467,"e57d2e95f353a75915172646b2ae5ba7bffc8b551b8984106b0787f343d23f32",10.02710027100271],[1247,"15103f23452014341fb62406208abfb8035c243fa6b28a7918337bf6dd22b4f7",9.917710196779964],[16575,"135ad80029bc31f5d484bda7f0fe9b89194f99665400b1999fdcc52313a8955b",9.317957166392093],[12573,"809b79268e7e7a820031a64709e79107cd38a70b11f9da9aa4b7ea1d8fd96dad",19],[17567,"989405f7fe04ac614ad799c8e9635d49bb8bb1e07a2b4f165ef4d317143ff445",9.317957166392093],[16671,"b7738e80e5b7037bea129a92609d1d7d6986c2d98f0dd4502c190038fe8f4659",9.317957166392093],[4987,"a005f150e19731c3472f97778244d562c761bdb2de41f647c4478bde139643df",9.917710196779964],[3914,"bbc6e4186464ac27f93cb89395e2134d07d133fc3bfb4f674fd5b843384140e6",9.917710196779964],[8728,"a031541ce39510734eb5f813b38d6b986a3a32742e3edae346968b42b81387c6",9.917710196779964],[8620,"121ca4ab422d24f56d6f382dfe6a91745ea59c40ff21d9e24590c0470a974bc7",9.917710196779964],[9210,"a800e6b2ae4d45d50207e1a816ddd846fb4a558da2a430bb031f6ac6b2cc62c3",9.917710196779964],[14985,"e4ab2bba3cd2751f4e2b63d761b8e151a891eff448a98fa3ad145ff2d934d57e",9.91150442477876],[14368,"1188c8bd38f5b95e8016f6744e421f2331b6045e5e294f79684cf5e54153fc8b",10.052724077328646],[5563,"e72e0db623fd9550607d25fa82a444d7638b3e1a3cd349cb942f7d387f7ad8db",9.917710196779964],[8710,"c20f4cf06a7ecd834cb8f7e696c46fcea4e61b8705e151c0a8e5c3c37e31a0c6",9.917710196779964],[14089,"6060a86396e0cd907b8ddf62ac63ffd6fd49c8ce3736289a943b1525e3bed692",9.317957166392093],[16023,"e2be897bd7d30fd8fd6101b15be451ef12e4a0d9946b3d5bf3346fc3a192ff67",9.317957166392093],[11178,"b91152af380e51801505e93f8f0ba3aaf501e11d9096ad2bab7d3334c663d2b6",9.917710196779964],[2062,"12ce8d5e044ab4624a2f3ec1c4ea5f7195cd1cb7148bdb41a3e5616a89e37ef2",9.317957166392093],[5252,"2073867949597435a03f94b18d07d2f10ad14e1894de3c07ef8f6db1b780b2dd",9.917710196779964],[4506,"5d56443efc7d048d51e2d68c7bbbf5ab3f4e5bcbb5c96cc99afd3390ad7b51e2",9.917710196779964],[3669,"a7edd3ad40926b76faa580c6916d2055fe71af18297f006d7688aca1909fd2e7",9.917710196779964],[11550,"2b38fc64d6b77ca53cc21ddd986fce0147f0cd80477bade4d5ec706631323eb4",9.917710196779964],[15288,"2cb885d1e095fb572ae74e57b029c6269f96ceb23fd2fb0906a596c27e52a178",9.317957166392093],[15546,"cfb5a8e36c6f303cb21cc796d49aeaa48f17f405ef81fa7f405bdb45322c1773",9.317957166392093],[3885,"f9d53160e3f169e2945c8a8c77ef3821e2fdc98325fa822321e7e5fc36c274e6",9.917710196779964],[11885,"23c19c6044286a5bac6020646f6a55f007318d9bc80d8ce8b8bc5e8849b61cb2",9.917710196779964],[14582,"eb3aeec180f26f9554e6f23bf7040adf8ddd879b3995a38dc371941fea0a7887",9.668934240362812],[6596,"3be4fa31849307a83f9032171558b533abc4f39292de1dc1f1bcfb6b812fafd4",9.917710196779964],[4371,"7140a273fcb8f3f5314e56e97399bb6e43ad552c533b24b11ebba9e7de7845e3",9.917710196779964],[19466,"a912a2fc160e43e54665bd73ff677c3bb72db4b563c45b962d67a34a716a810f",28.126696832579185],[7822,"a97bf1fe6dd72c3dd05a77a52f4864edf625baef3c64ccb3892c24ed3123a0cc",9.917710196779964],[9499,"7822d80beb67d0d1d8e06afc82d0e0f800354ecebad69b08302d211a4976b1c1",9.317957166392093],[8786,"9287cafb40ce63e8a5d66d557fe947ae2cc1dc59d74b1e0be89663761d3626c6",9.917710196779964],[397,"800d0f6bdbb335ceb586e5399e4e3ea8b10a99d728b8ca9e839d34b00d1f5dfd",9.917710196779964],[9346,"80af52945de2897ddf05aa036dd55e1ab12af86b0a8d1748bbcad6806b739ac2",9.917710196779964],[16101,"44b91b7ce613bad864f239e24f212808dd4aad1761dbbd827aad28236b911f66",27.36322869955157],[12686,"637b0a5e299fd44e06ec4c926baef4295ce7bfb6a7f8d1d080ea6138b0a8a8ac",9.317957166392093],[12824,"410850800213b7bcd8e39266d6de004a74d84d90b46f41080b0105a31aaccdab",9.917710196779964],[14340,"097e3a34ead1539314141439bce3cc7b863721d4c9d5678f7eb9e9a8ccc1898c",9.317957166392093],[17977,"27b96431a17bd34075cd36c82a02b37fb9c5644b5063edb9579d6793efa2943d",9.550515463917526],[10326,"b69e2c3062eae3bac862c8836c04c152a7dfa324eba9655e9703514c72b62ebc",9.317957166392093],[18170,"3934db2dacaa451a62767dc8a28ef1cb107aed523f3ec4573bd45b8ad477f338",38.72],[17687,"1b296b106a5c0e18ee912c3166050f24ee007fedd918651b82710463da2d7243",9.317957166392093],[1664,"025748059ba5e2f95a324afa76d41eceb562d344ce8d58d8a3d7a4969e1e28f5",9.647446457990116],[3290,"185fff2abcf64231a6cb51a23c221024e035721956b7ff8ed1bad1a768517aea",9.317957166392093],[8005,"a5c867ff01801b4582c3054160d2acae63ea3fdf612700624e917d7c61457fcb",9.917710196779964],[193,"49fa7a7e894d4238492655a9aec578d5c593b79a9a919b5c78da6208feffbafe",9.917710196779964],[17852,"d24727c5268da19beba7ad46a75420c762fddb36e0134c140de8a211f1f03140",9.317957166392093],[2170,"bf1fa18f06ebb44fe1e951950fcdd06ff6e8a4d67021a369bc7087bb97cbcbf1",9.917710196779964],[14857,"35b0921afc22b6a9db69b6d9801b93480f43ef39dbb7d526f6e686f4ada2a481",9.317957166392093],[7796,"b1d386e186396197acd57b8a1bca375e9eea2781a00ae01fd4e8da7f6e9bd5cc",9.604268563806135],[13207,"4f5efdaed6e2494fde56ff0cfd8a1e876c1cfef02a804433501d86eda80bc4a6",9.317957166392093],[16210,"f5bd6c4c96a2433d09ce75cddc655a616f7ae255f1a83863d2b15e68b888a363",9.317957166392093],[12164,"22e4dd5b8fbfdcca0ef98b8e568657e4ac5b16708c6e6d1579df3e6a889245b0",9.917710196779964],[5716,"6b379a5d55974f24cb0cee595e0eba6efb34a8517b698bf6946e2aecf894f5da",9.317957166392093],[13935,"49700fd27d43d27030014182fb35bdff6cd284d6161203603a9bb04e95354896",9.317957166392093],[7675,"42b6470a12bce649b3e5cc50bcf06bcfd743dabb5db430c690bd6191cb49c1cd",9.917710196779964],[10762,"d2fd3816ecd3784cb248ac4304406817b9a036330a86bb9baaf5384f8cae94b9",9.917710196779964],[8862,"b3bd199d1286e57fd1b7e6d83d917bc341459f693b8f57c5e872a9d050f3aec5",9.917710196779964],[18914,"bb18d2de9b82dd883708e081415909c00c4b75d8b5a701abe5029a776becfa22",9.317957166392093],[10920,"1a7ef9cc3819557a48a95005c1ee8ce553eaeed16dae364ba98a1c34454d8eb8",9.917710196779964],[4581,"47cfa5015fc3eb46dd2bae87900a2406a3e8b8c449fbb8303576095323e4bde1",9.917710196779964],[6594,"481f4316f12b1edbd45f9568011014c9886290c41a0ba659d520168d91f5b0d4",9.317957166392093],[9326,"d4bcd7468747ea472f9c2961c1a361af5aea4108075545cbe29040059f44bcc2",9.317957166392093],[10569,"8bf216a368193a47f277c7ed5641c0d462b2c3234ca9db5027eeb5436caac7ba",9.917710196779964],[1134,"1d1d455a17180ff7f2319714e3dc3b4c3eef25ef43f89442e8d16b32f01c63f8",9.317957166392093],[18016,"3c8476a12c706ffb218ab11a8c8e6a03153e99325ed48515944a982389dfed3c",49.13349397590361],[10044,"d1fb9e2b77fb6cf46ae382178c040af70ceadad9ba810313dc203077790614be",9.917710196779964],[16655,"80055b225e78b15d462178cd04e5065eb07fc2fe567836d169a1ec7da6e39259",326.0695102685624],[2959,"4858d24f7c9f7401c6c81c83b4686ad516b8afa28e7b9a26c23ad777349a95ec",9.917710196779964],[5583,"840258a25bd052e2b615b4163d5b37084d2c3eae2987c2f88401b7325418b7db",9.917710196779964],[1728,"384490b66f6741126a3b41550b99d67053ebd90f4722415eb32d6b2fb185bff4",9.917710196779964],[14603,"4bb28baf714b93fb782e10442ae22c1112249def284f1c7f6419fa09a9371487",9.317957166392093],[5200,"99cd3df5c5c86c4473ec41c605123fa11ee974458c93691405a3f96cce4afddd",9.917710196779964],[17210,"47d29676efbf9d5e62b7fd9e7f4b57fd4ebdd812273510221362ca1efd489b4d",9.317957166392093],[3909,"59873ee22a7182619e6e0714e8f12a8607daea1afac18a85585c36e6b7dd4ee6",9.917710196779964],[17738,"364e0ba4d0ae8af423496db75d51551722dfd3bae60d218d545571caeb647642",25.356890459363957],[15565,"a1506ed884f24022e00042d021f99c287c1aff297ecfe22bb672ae2520085f72",9.317957166392093],[9607,"a9038c89091e5d121cb7e6742f9b0ec8e7e2dee57da454047dfac2d7a4c101c1",25.68879216539717],[12307,"087c4c12613f7dac25264ac4d1a95cb0006038549d6095a4d80921866c6c2faf",9.917710196779964],[1984,"07484ffec4dd86259147c0d8d1c439b9dd19952275712a4550bb41bf8dec1ff3",9.917710196779964],[5576,"62fc9e7b0965ce3926f5bc2e53264cf2dd645c1f1c2aba68059058b41542c5db",9.917710196779964],[17302,"e3a9148490c9aa8dba15eeb649478770a41e59e628636fa25027a848fddff34b",9.317957166392093],[5533,"0c0275b6e8c6ffbf55aec54efe69732fc1c5bda3942a6ef4d31b85da4e3d05dc",9.917710196779964],[18949,"3a30c87dc1abb48a10ecbf5b3b9db68206250726a245542180bf4b7d2e383022",9.317957166392093],[13161,"84e1b4ccfe64734a7a7190d6a9e2d3816f299e59c72f5fcdf7d74023fd86c8a7",9.317957166392093],[7690,"d95462a21a2a48dda35f0a5ada715995bacd2175c54b167bafbd188663659bcd",9.917710196779964],[6323,"4294f6f59b68fee36903a94ee06805b167a36e7fbdb001aeff18708b8d45d5d6",9.917710196779964],[14266,"91e3959d670e18235196c9b56c8fa08ba817f226381ceaba431f488f9b979b8e",9.533923303834808],[5214,"6a35cc9972b333e6c0a606dcf92730298522eeef4aca5ad8f1646c7d4c51e1dd",9.917710196779964],[3532,"6d26a36451aab5cdba1ab4a60da8b4b5efc677a8873854e7001644d884cbc1e8",9.317957166392093],[16323,"e2e1c838f59f52928fd55a891568f1a636928505f0dea375d040292401379b60",9.71857410881801],[7709,"ca0d5b8a62fe63ad38ed5a3be24164f57cd2a22eecd1bc8bdb9791af13a07ccd",9.917710196779964],[11967,"e18cbf4b309780099122ca7cb21b3828df7a17ce0d1adc0f8ea2d722a53f87b1",9.917710196779964],[11481,"ee35c5cece3c0ad1fb73664fcf2898421ea79c9d3e848ce354d834a03483a4b4",9.917710196779964],[7717,"fe7456dd3970fab97a3e4d8c1f7a4aa7819c9db3eee4352948fde560d97f6acd",9.317957166392093],[18552,"03bd6fc1e38fa715cac0b72b7fd62a4b19372a50368162b7b0d9665e57196b30",9.317957166392093],[13688,"dfbaf5927964b8a09a009cdb751d758b69ff1d232cba2120b307f718d3ca689b",9.317957166392093],[14486,"a24433b1298d1e99a8634b94ce1fccd1320ce4d73dff4318d48f42c14a5e8189",9.353846153846154],[11990,"ac03a7995822727feaeaca5d2eecf3283c2c0af9f92ebdbb3bd7a75dd8ab62b1",9.317957166392093],[15833,"c6c3b99997da3d67597a498e9f691e86e383853c54cb0c1995f201dfd368b06c",26.173719376391983],[16086,"195c78e3d4846b030d9d8db6e514e51efeeddc3df73ead4279186e3444789766",9.905146316851665],[14496,"31667138e046ce82a203d965380172060dd70c63b3a22d3e03c5076717ce5789",9.317957166392093],[9216,"951694213105149652d63ec4ee4e450e18952eb483ef51ce2d2a7f240bcd5dc3",9.917710196779964],[8194,"9fb5b3b302bc4761e5ccd4a7f0e7bb587f6b61754a3698a40bfd522097a102ca",9.917710196779964],[19097,"f1f57e7f741dab7239a77368f53032edf2aa388ce1f842b38b482e36a979e01c",9.317957166392093],[18719,"4c400cf1a3f23c57e90b56afce9ce06f3ef3d7d270a3a4559677de0f51faae29",96.51336898395722],[19086,"70935b30ab729c53a52ec0007e1baceac2f22c31f5adaa034e52f922f068571d",9.317957166392093],[10280,"579dbeaf14c28b3fdd4567e1dd5b44c386448a67fcb35e9497831bfc06b785bc",9.917710196779964],[14104,"99dfa29b51f25c6bbaaeb9e927e284c0ecc570baa75b28e19b6d92f0ac3d8392",9.317957166392093],[18987,"e4a71ad411a69ee0159387b88fe376bb9c4e8a749ae53e39762f1db82bd5fa20",9.317957166392093],[818,"17758b46a23c7c2ae0e0521807e1068c00cb02938bf1669d2bcea33287a16efa",9.917710196779964],[7127,"371583269106ea94d35e2181d197f5ce2307e7ac2bdc5c5bda9e18a88c2223d1",9.917710196779964],[5105,"2e157a53b791f2ddbb55382b1a60815eca342136612bdb7bc62850bcc4558dde",9.917710196779964],[5220,"ee53bf9a0d2b294f688bfc944bf203d0f4d2458955f734b2b7754925dbf3d7dd",9.317957166392093],[7624,"385008d3b30b5ccceef6268472e3c025d1f9eaf80f08c7026adc397629c512ce",9.317957166392093],[11403,"f7c86a8a48db87905d8ea3a14ee2f8f6ec7198a081b4a301f81f27fd07a353b5",9.317957166392093],[4524,"c69c50ba506459005687712cdffe3c9984d3793bd7818719f842b64d6e2031e2",9.917710196779964],[14095,"d677ba1e7697ab9e9677ec934ecf43fda2dc51388fa7e50e3aa35e83cd39a392",9.317957166392093],[12148,"6d116ac78f2d8a31d7932dc36f215832a5d37e1ba8f920a86a8662d7e4d05cb0",9.917710196779964],[19069,"2463d66a15c382aea34618611638b538d43cf141fab828070c827bdf7266dd1d",9.317957166392093],[15412,"989083513b0df140934b07b9af5eeaae60bbef12f6a408aacecc1b29b4ce0376",9.647446457990116],[3095,"1d75a20e106ab89c457c45b4d347f0d2a239d97f2b4b790f785c9219dd6badeb",9.317957166392093],[12943,"e333713cab5d24b3689a3124f0f82681b07958e8ab713cd360a367a31365fbaa",9.917710196779964],[16058,"9df0430734c5d6cc8d818aa8ab1e4aef83455b6cbbc09f621e385f2b0dfe3c67",9.317957166392093],[376,"0f446704f9a40382f7be400208acdc45c2d4471eb829e6897cb8bc9180c584fd",9.917710196779964],[6316,"c6338def55ce90cc2e0d337f8067e1e9cc765516e2f446a66aa9f93170abe5d6",9.917710196779964],[12232,"37105f7f677adb4b13ac187aeea203f7e28690186de77ed7dfa6efb69cc9ccaf",9.917710196779964],[7640,"978a038d91472ad3e4a53def926f0a32cc582160ce97e7ccdacbd4278533f3cd",9.917710196779964],[5858,"fc32ec7aacce34d4bb6f6b51745d015e08e6fdd7196c3a96b9e418f74443ead9",9.917710196779964],[14378,"d9fc1d7c2dc0208d106262c3ac0f289dabce3d9c37a0128d80943a1664f1cb8b",14.061313868613139],[5546,"11ff089514f2c6d4d53d52a1ad4f77137c177188f0cddd095f83be80a74bf6db",9.317957166392093],[6307,"806f417a829e718a964261d27dfe40498c26925f0ead2c6c778f89cde41af9d6",9.917710196779964],[19261,"3596aaf95904314b51669ef35ad2f1a44e30624694ff370a2209bc20c3434316",9.317957166392093],[16965,"69085735a96d16215cdef7e3061d15f416e414d66471f4bf9c3473787557cb52",9.647446457990116],[182,"86ef451a385584fc51b7be0c717de15916b1f422970e726c053d37c494b0cafe",9.917710196779964],[17127,"034a4a110961be4c3f64b53edcab53665d47eb485df3e4a9002d12fbd16a734f",9.317957166392093],[16534,"4a7645c1e4e87ec818729200bd2c252ef0e884782b964ab2dddd3545bf7b695c",9.317957166392093],[19831,"23b073bf833af3c9400192e71b9dd3319bf6f39dfb33fb299ebb5f3e194c7d01",9.317957166392093],[5085,"991ab2a870df4a75dc2c716a445d9643d40d221d6eb17da782d01ee02927a9de",9.917710196779964],[13984,"4e03ca78ed507b576c60c521925f9923da7651b6fe32ef8900106209d99f4595",29.0453125],[4288,"9e77d3585722716c0d656e1edd2bbf071cd175aab3d1d452d28b18de7a89d7e3",9.317957166392093],[10597,"382c8c58e057be7be9c0dcca7d8c75f32fb5f049e765b49f8839816de708a8ba",9.317957166392093],[18184,"26761e9fa9138d15277ff431b1512c2722299938c617f1920216eeb654629138",9.317957166392093],[10897,"71086c30c202606230270e879633ef7fa1bba03f603f972ae22010e4a75bb0b8",9.917710196779964],[16981,"4c5991a83703ab9a89d9b6083096e398ed53797b0345e0afa75ef260e5427c52",9.317957166392093],[12911,"c535d4da13b6ac2c39ba6be77df45532745b108c9152536a348542e56f4d3dab",9.917710196779964],[10078,"a8e8cb955647a15a714474a79cf63920b613ab8dfad485a803b068978ca1d5bd",9.917710196779964],[18891,"077a9b1c342dd54504a9bdba12ab636b463a464db626dbecb32ec1dd2c4fb423",15.772511848341232],[5725,"8e63e6307736b40344d9f38287e21ad52bcaae24393acac9a4d2f0762b73e5da",9.647446457990116],[19035,"2737d0ae48aca61e2e89ef0e9576472338487b28d6fd41ab8b99e9f1cadb671f",9.317957166392093],[10990,"c4fb3a765ec15d408378d9dbaa808206eaed97e0b534ab6ee2d92cce583510b8",18.06896551724138],[10653,"398058ca3f03e37763f94f4c981234a1fcb5ce9321f2b44a58a3272bef095bba",9.917710196779964],[13025,"aafe4c665b9ef6eac16b02b54e1d6f99fa0a0c121974019f131e0f6b186e6daa",9.317957166392093],[16373,"82c50998ebdab2b1ec0e3a0afe0f459cd9c11b354dcd6d77ad0e1492a12b9d5f",9.317957166392093],[15538,"5fbe1da06808ed831b5c4fceb2b98027b44faf4de5ee198efcb281a581762f73",9.317957166392093],[1932,"488b7461f61a786ad2a6a5681005904267c57946c7151db5b66c2b936d1279f3",9.917710196779964],[9328,"c85800413772af7be56169edccf37f7c1245d955e0e7ad7d7a768dabaceeb7c2",9.917710196779964],[4769,"88c397458e90a21e90de30d2cfdee1a4284b1972b5e95207d2a2a3564cbe8ce0",9.917710196779964],[9094,"cd7d594b056a61c85864b925b6fa76274a8c6084f1dcb5d3a64c082d649a32c4",9.917710196779964],[3961,"363f76a83395acdccc5233579683667e431e9070a4d14267d936ab629265f6e5",9.917710196779964],[3944,"97ee1625a092f4f8959b185eafcfa9e9538848ab50068469d1ed85951b5d05e6",9.917710196779964],[16296,"0473ebe87db864f7396388e01c2cec1574731cf2d59b4559aae2f9045fb32f61",9.317957166392093],[2073,"864f8c742f8055ffff7cd304a916cfce95899632256661ccf5e0723369496ef2",9.317957166392093],[13809,"f3a1d908d978822d50a65f6b41d208591938b32cc35236d6505f5a15990d3599",9.317957166392093],[5521,"d4942c8dda67ee6da78395232fa04989ab95f8072591abf68316305f94551fdc",9.917710196779964],[19645,"cdd9c9fe5ba0384fb9f3c8ace444e156cbdfe2f8bdc4db5851ec272f280e2508",14.188948306595366],[2927,"5a6e0052e3ff0810d3e842665d2d7e579a995630419bd8a3d1f4d7be493fddec",9.917710196779964],[12740,"6f3883aceec2e52d31b66bbf5e99bd9cb4574c4663d370a6f88badee706150ac",9.917710196779964],[7453,"e6016cfac1db1f985013b11d23fcf1656f34bbcb316849b2f290cfe1f2cc0ecf",9.917710196779964],[14172,"c29b4d8bc2822433f85fa3c87db0369e83f0ada5c12d6e6d97de1704dc04f390",9.317957166392093],[1103,"6032c9131332a0bad04c9f76d16708d96f88f5cd94a9ac68d1f7849afb1d8ff8",9.917710196779964],[9013,"5a7f2bbc75c2e6811134cea267ef4713175c6127733c894a702f5e9cd246b0c4",9.917710196779964],[8108,"1e3c5cf7e674da31106de275e7966aa0c9e682912f6d4a6dc9b251c11d1cb3ca",9.917710196779964],[2123,"85fee6d2f64b0d624192b10346f62b8ea1353fb99852b601e0db32077a8719f2",9.917710196779964],[12994,"63c4dcd81eab7ffd5e534df07e3b79e159677f503e289c9eee780d760760a3aa",9.917710196779964],[5375,"aa87f75322792e55888ffbe4f77d9d7454c8d4aa8a03a01ac08eb44cf4edfbdc",9.917710196779964],[11036,"24d45e1e7d5afaf354b31a1adde533e7c5371f3c3a0ded717d02267dcc3cd0b7",9.317957166392093],[6608,"8e9e76138d82ab7b15aa41d2da3d21a44e54a4195895b74962bfd724cc6898d4",9.917710196779964],[15173,"fcc19528006920017a43a58719f04e9534b74fc99555750eb5de7e665896077b",9.317957166392093],[9577,"3d4b20d0e044342c4039fe5866017d3a5a56d69e7095ff32bdee6c3b106e25c1",9.917710196779964],[15929,"977fc4fbe3623eeb23b24a9a5dd295b4a8aba63c206d659ae35e5911f7d7886a",9.317957166392093],[1633,"eb6ee413307fd1a2d3199dd74c4ea23d645a83d08be86e3f952727bfe1f767f5",9.317957166392093],[13696,"9d0953534ea612cdac44824568b9105868c2f5f968db620e5fc77ae3be6d539b",9.317957166392093],[15418,"29dd33613f5030472f13c93dbe556dfa4a37af67be1c3f8b427b70406021ee75",9.317957166392093],[3540,"fab354521def62c0ccad8a0bba2701c109bd2e9e85ab261f1530590459eeb1e8",9.917710196779964],[2211,"8ac073249d2dc6b4e848c22fe96055564be082e965c097e43b2a6328f64c72f1",9.917710196779964],[18073,"21d9e46338ae27e6c322a13067c5fac3c3ecf6a705482f08e073b03edbd8a43b",9.317957166392093],[13409,"a38f6c5800a0190cdec179a526c6aebadbfeb4a8d3e93e619cab6f4902ea18a2",10.052724077328646],[322,"c021f9ae4413312e3176e056bfc0fc1221fe1de448e76a11fbce0558839adefd",9.917710196779964],[14389,"f8feb34c9eea7794c1a77ffe0d550c32fd15d2087caac92702656eefb811668b",9.317957166392093],[17196,"740da005a4a0dee6e35843406e79bd81908f99e9d3e71b42eb05ad0e2909d64d",9.647446457990116],[13404,"c2ce926e80619fe3f090689cef0fb39dc02ba9f8347efaf239436d3a3a7d2ea2",10.052724077328646],[18645,"bceda2a0495aa805000c98265a9413ecbfbe726d1678eae235fd95f004c1ec2c",9.317957166392093],[8564,"a6d727ba06f65887f947167ff24b94631e7ff1db6c2790d1bfb936a2ab4aa4c7",9.647446457990116],[19675,"1f8ac752d7dadc8d5f9b7192c5e707e3667f506e2db7b7749e026b5843c87507",20],[11173,"715504bb4a622c1bd0089b91cf3fdcef0c63424d50a807974793e075ab70dbb6",9.317957166392093],[14463,"f99baeeb70c3384197666df44b9a13dc6dad9ce7c096e64609a026672866ff89",9.317957166392093],[17309,"ec4a27cfb5edf20e66917a4b8a065f0897bdb8ed4a47911060dda4eb2cc3c54b",9.317957166392093],[15143,"4fd9c5f62ae467f37d13eac566855ecb81759d7d058d39653d4d09fab97da97b",9.317957166392093],[10159,"e06170bd966d4548fba30d96ad42ba53766449cd16461524fea614cc38575abd",9.917710196779964],[14194,"a2750deb27e1aed65e1678f01cfe606f574429fad0a665fe7b9a7ba105586890",9.317957166392093],[2894,"9055fc4ba17fa773d421ecb95cf6a4b85371316bae928c754cb3c33a6b9a2ced",9.917710196779964],[15883,"db90015400fcd59482a9a7ba611a8536bcb94f8e2f545c59648af0446a01506b",9.317957166392093],[13205,"a720004f24d8984272bbf6ef6346d9f1c38bc43f06e013bc1de207f28196caa6",40.794701986754966],[18,"4e4f184fc044d15476772dceec768b9bce102209285ec941f4fb93f44374e9ff",9.917710196779964],[16863,"beffcc41832301fa9500940abed6a9c56c7741922ce787fe0c882cb14833ff54",9.317957166392093],[4282,"98ff6a0a489f7e1d202034768b7a9713cc0e7bdcc4a495cca19ee05dbea8e5e3",9.317957166392093],[18402,"9b35f35b18ab794f50205b17a1f6648280fc7df23ef129670858701502fb5d33",9.317957166392093],[18767,"7b01e1a415ba7162a7a150304a3f0e26bd7847a8837b0c1e22f48f8b2e991428",26.092307692307692],[1597,"d43886d6e599c6c1805e3738005bdef905f8ba9125df7c85b22e324b310f92f5",9.317957166392093],[3510,"20cf6ce865e6bdf85b7d6ed29b3b2747fec63b63617a24f41dd2a4927cf5eae8",9.317957166392093],[2101,"60048279289226be49712168ead466724265f94d378802bb6cca2ee4d5f039f2",9.317957166392093],[4668,"56096065a42aff02397272495bdc26d5e05773fd43d7f2ef40dd319bba9e32e1",9.317957166392093],[805,"6ba3cf344021ef09ea1dc12388625fac5cdd848832c7f92568fb440e839983fa",9.917710196779964],[9477,"f9c03f29aaaa114209b107b969f31c834e6979750b0505d719a80b753c71d5c1",9.917710196779964],[4090,"8839ec6d5d0499aa24ae91afa2adb9f6623d549b3cb7ab7faf7496a99b5022e5",9.317957166392093],[6779,"18a2999f9d700b8cf847eb8ead0ac5b7de58c379ee4336b61565d7a8a0c167d3",9.917710196779964],[9414,"d1006bee1d7ad1d103866f0c2ff7190b13480be8646621489fe9a0e3e7ea33c2",9.917710196779964],[4352,"dfdae95dea7038cec2bb344adfff45a40ebb45c86d92761772ef3ce0e25f67e3",9.917710196779964],[10387,"e953425a6077036d0e51f474fd2f18150ac000686df7a5d2e306f3b35362e2bb",9.317957166392093],[19548,"6e3f998d3ef25da153d4461b1aad66d42cfa816df0193e8447d913f1d550be0c",37.98086124401914],[13482,"a7045de9101f360556f902fa31977ea2fe5dad0f9c45373545168861affe3fa0",9.317957166392093],[4574,"de35d30886c6740fd3538e63e542c3c4c7e467ad19c2a09c90ae8578b548c9e1",9.917710196779964],[1659,"4f60a7e580e6027ae5b323c1173b80383810cca0dda856440b45c3080cc735f5",9.917710196779964],[4936,"4cbaa858eb342065f239b23b7aad97d9d7a1e707f3bb9a4a41b7ceef51a99bdf",9.317957166392093],[4372,"5b607ff6ccc02104c30451be18803ea060022bef18277b58041293ace78b44e3",9.917710196779964],[14602,"8295db2227b76a8c76ec9e063da2aee32058a9e376ab392bf62edf8352b21587",9.317957166392093],[6890,"6304eb51f549c4e60e3f32771c9798f01c0d24195c679ecfff4558cbd2f5add2",9.917710196779964],[1223,"f0c1324118b20b14600fc5bef0883c0bf819819a1bf76497c696fb303d37dbf7",9.917710196779964],[3387,"b9ca65f37a8597703a1ec25adbdeca5b0b6422c436160471b6281dacd0f4c9e9",9.917710196779964],[8348,"3bb932b757959550c75de695fe70d0417fbaeedca821bd8af5d1746d8ab002c9",9.317957166392093],[5954,"f48b8dd629a683707f5c76cd679d52e2ce098d018979501c7d522590a36363d9",9.317957166392093],[16519,"7745bfc7d9e322728826fc6dc9860832eabbcc6157d1323a8aca8c825987af5c",9.317957166392093],[6522,"d1609de4239730e1d7bb030d12eee514a9424f212ee582b32c9fd54d604344d5",9.917710196779964],[13481,"b0eb1a1fa76edbce2872e0f4461e598ca8169b93f7f4ea079933ce6fdaba43a0",9.317957166392093],[8885,"c7f44067888f7222ac86fe028da3dc068c56f0b5a9598f5ee40f104369e18ac5",9.917710196779964],[15206,"b20f43d240489706e91e04424a8ab954aaf9197113fa8e467e04d022af9b687a",9.317957166392093],[132,"74c499acb8e7199e69ee7e274a2d98319cbd8f63109bb56034bd1373a7a51bff",9.917710196779964],[14031,"c4689ee74bb804a89f1d91541746a858b5dbce53c40528d2951e7f3529a70594",9.317957166392093],[10485,"93633de4ee64e34d0cd26fae0ab0d76e2c39bb17540560fc1805033961793fbb",9.917710196779964],[10605,"4a4195846a1e0e19c4c4b5d4a15f1db0b2c6c5d4ee19eab28c5b08c22bc09dba",31.23954372623574],[11417,"eef8683d3e8f27bf663be87897f00c6f412b319a8e9c19a9b78c8f5ea8833cb5",9.917710196779964],[3759,"e5030379005d731e0a410c95e66dc175a492621553b8d07ec808cf7f014d31e7",9.317957166392093],[9211,"ba9aa8cf41e9777b75fe3029ee2c0d58b87e70e0dcbbaf93804906ccc8a462c3",9.317957166392093],[1950,"689c035c2c508043570838d6ed47fe417c8bdb1d6bacb7306e506ce3383658f3",9.317957166392093],[465,"8b8e0f4ead3933dee87966c3eb2f643476ff741af138e98c05404d7225a3e1fc",9.917710196779964],[7629,"eb47ec5e1522042f238fc7c8a5bc2393d6f080a1fd504369be9427d4645009ce",9.917710196779964],[14610,"3934db6c3f8f1d5437a354e7179bb83c9c69821e2473957aa33c38eaa1e4ea86",9.317957166392093],[17900,"c282be4c7ca3f2aa2c022a1936f36c19841dcf046e9292634048197bd50c2f3f",9.647446457990116],[5980,"21ac036c44bb00bb9e07cededca1842d8f2f7828145548b2b1a8606c4dee34d9",9.317957166392093],[4315,"f9bd993a17344acb1668dda33ca243719d1c5187f8532912feeda66fa2f4a9e3",9.917710196779964],[18509,"4358e634a8175df204b62f9d7e0b56195987ec04f8acfe66e273963007144331",9.317957166392093],[12279,"66e09f0db7c37beca77910350a509b0a2c68d71d25517ed127c3b14622296aaf",9.917710196779964],[19472,"7248136ff45b714c67ac40d6c6169a0a4480c9cc968b579fe3e77d906ab65f0f",9.647446457990116],[14696,"c8d4f82a275427ca97655c77049da9a34e87adc25846a2c21e7500ca93a6ed84",18.05678233438486],[4764,"0466d1b45a20ff5793eea7d53f087d71e0665543db15a25ad1c2000838ac8ee0",9.917710196779964],[12720,"8413935040a1de84f9bd3e6dc1ca0070aa76cb3ee76c945fe1c41294d4b078ac",9.917710196779964],[7231,"fd7ab0ff94a4d37cb45d4f10a4a36034e584fef86a8b88ac7725041978f67cd0",9.917710196779964],[4560,"b645bdce2ab2afe19cd095b1b95095f7a8de4ec52dfb28a2331694956a96e8e1",9.917710196779964],[5341,"08bc0a44a9f60e763022bccc800e7701ef750e3c28b4e701fbc2535d65c030dd",9.917710196779964],[11611,"3c5003b5645fac55c0a54a98f644e1e4d2e064f9b856a407a46d7e86b2afd2b3",9.917710196779964],[17427,"40eb2628508ef7aa3dbb5c2f050e3434be38f50b177648dbe7f91e2395d53349",9.317957166392093],[6784,"beb57945b3c22e6680a5717ff2229825822ff1d52d8e336fda4193e455d863d3",9.917710196779964],[17753,"51446993e781f003063492d6c03dbffeb9a6527b797eb8826e4157d364f32842",9.317957166392093],[5155,"ef14a727e5a97368d880526fea91163379bd1a42d9f9dd08d291874f51f042de",9.917710196779964],[3419,"e0c071446410d7a539617e1175db91f21fcf95a8debcd6e0d0c1ac53aba486e9",9.917710196779964],[16643,"7e7514b4ca86001df477981d7debe505f1b08fa99eedbddcc73ca8715ffeea59",9.317957166392093],[14258,"d3b868225ce0b040a8f9dca833a45c7b7ef291ff148ad10296b931a9f8cdb08e",9.715399610136453],[7230,"b333fd7952662da7e186ed818bd838b90f5f39b609d2f223e0abc7670e197dd0",9.917710196779964],[6461,"80eb4b281292439c1328545e8a514e82a8ae34b2ebf8495e4a64dfb3580ac5d5",9.917710196779964],[3964,"ac9b57ef8a9e53a35e89f52694b3cf2e9da7b486ddbcd11acfbf9b95711af5e5",9.917710196779964],[7883,"ff0827837a94b50b4bb9fe994d1873fbec19992aab442a3e2ef4184d52d962cc",9.917710196779964],[4143,"0135df55a0c1c6ab3ff2dfd7aca76128d7832ec09631fab07b569b599b88c6e4",9.317957166392093],[10415,"f2fe308ce0a8a5d96900253b62241ac824e485b410bdaac22d1891792657b3bb",9.917710196779964],[3248,"1da55559a8b23e95a703c2e88c26f781864c54bb27d2688520113ad34ac4acea",9.917710196779964],[5373,"8107080b41bd0425e94268c1511c81332efe41e568548598a357f743ed4700dd",9.917710196779964],[10518,"a25c5760490a21806ef11395777164df17b777b1b4c5564cf9a8c014897e15bb",9.917710196779964],[10632,"1e893d7142a2b60830c7da8d5e3a20327b3449ce719e338071d4629fe87a7dba",9.317957166392093],[16040,"d08785aa0e42266c8a90c67d2bf52766c334e8d48e12d17e1e57bddf4b019d67",9.647446457990116],[2756,"23fb2b3c88867e9ded5ceb5fcbe0af37b8f960f8366ecf077c1d8d6538900fee",9.917710196779964],[8114,"49f5f0c465bcbe336e3b4fced643c388e5ec86464831c244aad8c2d44d45aaca",9.917710196779964],[16851,"25b80c371fb6027c1c67bd40f5cb8fccd78d1367edc76a587c7e7bfeb9d53f55",9.317957166392093],[9791,"e69cc5c687cee9b9193fdd98ef3dae788cba59ad2bb8d5aa2c3436bb5bc7bdbf",9.917710196779964],[15958,"ee5bdb3a0d0f0e7cf0b007c1623be7e12dafc609c086c3d3c43021255d72c769",9.647446457990116],[17713,"f7c42f03300cf69a815d2bf6da8eab67fa71c0390fc5b98b126a6a1569b7f442",14.89811320754717],[7648,"8103fec84490c71eeaccaa8b971b5ee1782aa2d7b836285318e5950d81fbe8cd",9.917710196779964],[9718,"927da0d2c6237ea63ed08925f75c96779657c9ce986d47858c39ba2036703ac0",9.917710196779964],[6265,"1813805c294ca4acefa3448e2fdbd4325ddfdeaf756d3a7ed9da0b6261084cd7",9.917710196779964],[5297,"dd251cbb7a5607ec62cadb852ccd4972462aa5ca99cf1a0f9991dddbae366edd",10.052724077328646],[17629,"1920fd8d617ce9a7867f1d0d2c47622517607e17f1e2fa2d8c664a2df917a344",9.317957166392093],[13296,"e5dfb5c4be7dd6b89fac82992e96cf0729296679fe3a16a955831e5bc99e98a4",9.317957166392093],[6807,"ec34bc944fb964b46c5064638f4109989e43a615a61125806637447bdf8d39d3",9.917710196779964],[8062,"28cf133ead828e3ef6675932f81cbadba18b0abb04b3854267ef28a6935207cb",9.917710196779964],[11349,"a9ea4b25d47b9519fb8477b100578df445d5ecea290769d320fb964c449cadb5",9.317957166392093],[11934,"5793aba2435b84a0eb16dc7e9decc88de9abc85c013f608282b6b5e4c12bc7b1",9.917710196779964],[19432,"a6542b4c79de6990265f2961d2db4a5135f67927bc13183e1f990c9856e66410",28.124444444444446],[9919,"30f117ede1e8c3686165f5770ae47de38f7529fd25c086f7f0df4ba438e9d9be",9.317957166392093],[8888,"aec38ee3d40545fdf3d894930ce576c5a69087a8d9cbe3cddad25a470c897ec5",9.917710196779964],[9446,"aeefb731ffb1043ab11ef1f60d91cf7286805e0e1837760bb0c3c708d83408c2",9.917710196779964],[15245,"d2c6fb5c2928e4303eea6f52f731ed433c9126e4ecd737c9897911b201c48679",10.052724077328646],[16583,"c25551fcfd2bc7cd88f28337048f6ff5faee7d706712bf840d1709da0f526a5b",19.80952380952381],[7292,"7665bc71585dbac4e8b72d80b573e3daf32ac1285ea3e82e23725fd1634f21d0",9.917710196779964],[1802,"84186f2eff4c305100161e69cd0076249566949e29eb943866532c4e81e03bf4",9.917710196779964],[203,"40eddd3313766251cacad2790413a22c80040fc58c0d2368e04777d485829bfe",9.917710196779964],[4202,"6e19c0b4fdc88558746c916cee013227837059bf77cb69730ce5aee452f766e4",9.317957166392093],[17707,"301c6f2742d0c352b5c7761ef3cb8a46a77c6b6e304ed655b9df398f21d11643",9.317957166392093],[7274,"ed0af613c3af90816b9cf9cee9b598280b5070635568739a20e8c0df257a2ed0",9.917710196779964],[18770,"d9ad9dbccf14381d65a3e1f7951a32494e5e91cc9b988ddded25143e448e0b28",30.557491289198605],[11764,"efddf68124677d5f9f712c65f74e54dfb0b6a5274fdd47ecc23e4cd4f793e8b2",9.917710196779964],[10325,"1de1299e9a5b5091241dfcc9282699a3100cf7caf97c84c73d8ab17608212fbc",9.317957166392093],[14261,"88802ac2a6828c824db94e5c3d5242fdc8fdd7821e232cb6c13ccdc79438ac8e",9.317957166392093],[10320,"8e9c2f9ffe958384efbe5b69592e2e0d7c7e48fd6243c750a4c414a9b50736bc",9.917710196779964],[15692,"bbedd9da4238bb80a56565562aa53b6aff87f0b87ac297c8f8f5491a333aa36f",9.317957166392093],[16558,"bdd5136683cbb97608c45e0a8c668eb829c30ad927ddabdcdd4630dc5662f05b",9.317957166392093],[14734,"4f571224951685550dd6bd4829341f86c1a49a4e8defeada981f3805ee523484",9.317957166392093],[719,"65b676ef22372d9ad96cdf90e3538e76f0840474f97b64b29679a158bfcd14fb",9.917710196779964],[17922,"c69a0423b1db7f6ad33c74b0cf54e0fafa45dcccef537186ff32b41845fbc63e",9.317957166392093],[8779,"f06e1e348a1bd4214753ded1d70189cdc2514422606635ea4336dd12259f30c6",10.052724077328646],[895,"af22cab97c9686f20d2a9d1c8bb0f5d99a3e5e5fc7230695a3e2f29035f7f3f9",9.917710196779964],[17364,"fbf36a2baa839720321e9d830f0dadcbeec84b3478a3a30d6a405b8db1f88b4a",9.647446457990116],[420,"17442fec681ac1d41a993958085535be567440b515d8d17435a3c0e9c43d40fd",9.317957166392093],[8113,"fbea2dac8a59793fc8a4d3818d08c033322bacd67d884013c6bad1bae2a7afca",9.917710196779964],[1191,"c588b42d8768fccaa19a72428f134166a8dda967d4d4f3898e1383d4517f12f8",15.072463768115941],[5660,"1f632242cba7eb4fceed1169a28a8d4573e112f8bf6eb36f6ba3dc9808f743db",9.917710196779964],[5233,"b2a33b75c1093697233fb46ab25d30f7a23b4e6f32507feb53faf7752fbdc7dd",9.917710196779964],[17943,"efbc9a2b80c0675f1f50b69b61e1cfbaf96d786509ad7ccdcfa68e57611d573e",9.317957166392093],[2527,"c5dbc1724973d5594a8b122f66d036783d45e3b2f475060c474b5fa68fa6a2ef",9.917710196779964],[11478,"87ed51a7d3f9f0f0e75224797b5189b755045a558db313757018b069ec40aab4",9.917710196779964],[3393,"179e2be8d65fad4841846a43a4cebbe315aaefb21fcea38b9d62c7f14a86bee9",9.917710196779964],[7463,"541d8c6284ba811fad403dbd2f13af737b846d22edacfbb4fdd273e43250ffce",9.917710196779964],[2766,"56e23ee274d83cd1db0b4ed372d15ea7324c099a72d3979db9bcea075c6cfaed",9.317957166392093],[2126,"84b6e532cb81ee6f606185b609d9f22b049660c360a3b3f2a8bc522330e415f2",9.917710196779964],[14570,"9f1f9970bf9246d9496da2c75e21267843bf677c6213876916cdce7443c9b887",9.317957166392093],[1788,"b7d16ae070953fee8a4a16b214284eaf2f714433e527e908fd13f06a6a6952f4",9.317957166392093],[9039,"73d7feeb010f3b9f92db606d7fadce4538ed482dd0db3d9e0c69c23ad27486c4",9.317957166392093],[14991,"edeab627867af9c1c93b04ab32cbb4cd9273ac702f0bd8d7c643102d9d5eac7e",27.900178253119428],[3271,"3a90bd8cf81dce653675e6e11e1f4432abdef8db98bee9573624c556ff5191ea",9.317957166392093],[17359,"6d2056129de3c96e78be9cb2ddbe1fb509bd206c22c2354a1a307c0b5cb5af4a",10.028818443804035],[11274,"d6f47fa7b73803283a4b853a6b1cdadff2b9ba3776468efd4e4f8d0175b436b6",9.647446457990116],[5613,"6b03c057e3cb1ebcbfa5a2504783e45cf1769e115043eefa1f83530a996c94db",9.317957166392093],[7091,"de48b4f36d0477268dc85251a094826fd765abb75a0aab1ef7fc73beaf7867d1",9.917710196779964],[14191,"2153387dff8e3b804fa2fde08831d8b1f0afaef6ecc698ce79c7320344087890",9.317957166392093],[6503,"33b55878b34bdee063800c6f7faf2c99911f30387ed8399d1608a1c9d8486dd5",9.917710196779964],[4908,"07656c1fc84ead0b5b619c1d12713d3aabac7026b938ecfb2cfd61418b87d0df",9.317957166392093],[7880,"1c5efc4bb09686e99d43e5ad7663e6cff44fc29482cef3c6f22705aa553065cc",9.917710196779964],[13947,"bef187abe2040e61031e243eff108ca1d7a16f71f5ffcb4dc638103dfc850b96",9.317957166392093],[16026,"34982200237da809c158a3d5889cddc156d508117fc331a9f1dd1a7d79c2f667",9.338112305854242],[17761,"3a747dda6b322ded1cd6091aec102af0a001cb667200e99db26ec59f8d5efe41",28],[837,"07cbf1edb5cc483088c658ec706bd07e94f4d37e62197af88fa42e8420284efa",9.917710196779964],[8517,"228fd2232a22d1482c557861ee1f2dee50a192b0fb786d3a8c23d2f53d7cf3c7",9.917710196779964],[15746,"596ae5838b6f0cb644eb6fbc9f39d4a228631cffe2b23e7987da6d4f2181796e",9.317957166392093],[1109,"eeb987199d85c0c2c84657315ab2c060e6dd24ab6ecf1818a1291126ea2584f8",9.917710196779964],[10786,"bbd96416f979d3b9849da8922cda88c6006572ca15dae397c10309d81ca962b9",9.317957166392093],[17172,"36b500299013d74ffb6d9c713283a7cada19560a319160d0e17bbbf2f00b5e4e",9.317957166392093],[19663,"51e935d87d272a46214b67c2288cedd50475679966e3bc57131e6fe86ddab207",9.647446457990116],[19407,"6977a8ae3d9315f86d726eda9aa289bd652295ad7bb7347fd837e34a7c583a11",9.317957166392093],[1455,"8141755f7db89f1f0afd2bfebc36a5ec4fb8edcc7620d22f166796ee08a579f6",9.917710196779964],[1590,"f96aceb659ea8b78674dc8589bba2072f375d09a8fd22bdcd5e77fbf24f798f5",301.3333333333333],[5862,"6df202fe30dff5b91aaea91be0c276d168073741fd634091aa95019a183ce2d9",10.052724077328646],[16340,"832de188d51c53b11a636edbf1dab4319006b11c50d29503ca90bffc388e3d60",9.317957166392093],[4569,"90e928badb4fe47b916e982a2a35ba00c521d6feff6840042ed7fe0f8fb0dce1",9.917710196779964],[4804,"c6f889ff403b79f3775f7284fe394a8a71f2e342d52c397fec5320d2b1d45ce0",9.917710196779964],[9504,"a1f941e4742b87bcefab26cf7a9ca95ef30486cb2c7ba0c9546d8651f430aec1",9.917710196779964],[9350,"31e4f67d45292e38b538ac5a36acee315e30dc016c6a57e56e8c370663e994c2",9.917710196779964],[16925,"a8f9e13d635e20ed42e612d03613d91dab923038897392040dd5dc0f1a2dad53",9.317957166392093],[11019,"d848df098533a3e8d3990793eed1d99b4c835c33b7550b255feb36ec0868e1b7",9.917710196779964],[2402,"8cf346de5661802bd8be4939be835b828191c5eb59a588bd46db8d7fc5fb77f0",9.917710196779964],[16360,"7bdc9ff0e7d98144e9665cc90845c7e18cc57e75d45a24059702c9c3edbfd25f",9.317957166392093],[7800,"a3c17e4f7ac646dd7b3c8ad42f4c5a0628b9a4ce4225ade3a0bebb3ad730cbcc",9.917710196779964],[3942,"2f1256ce5946c78b9da5c6e3a8640026ca0687e7bf4b45706cc0982c64bd07e6",9.317957166392093],[3682,"4cefd3ed7af26105144d999eb910393956462fc699bad1eeaed49b909451b8e7",9.917710196779964],[9713,"7ebce6cc1b012e6469d03da694f6cba8f1fb75a8a4bcbcd997963a5e491d45c0",9.917710196779964],[2820,"365e0882432b45172eb6bf0b60162dea54416abb526645bf466254101b0f8bed",9.917710196779964],[14079,"957bdc44f284f739219ba1b8420a767f607672d1ec59285afb6d070aede60893",9.647446457990116],[49,"912330736b046ccaec1e92d5fdc4716e66c480265533c4e27949cb8e718da9ff",9.997888067581837],[9855,"b99a34a18cd1713242c9fc7106e98a8bae29db7d5bf3fd24b1a86343dfd143bf",9.48061448427213],[7503,"cd531d1275e24b940773537d53f909460e5a8b329da6b4cc704c2005e32fbcce",9.917710196779964],[8471,"2a5f129fe2ab63d2c020abfbf8c339ff19a2c1fac902fd8f1332ba0d36c632c8",9.317957166392093],[17930,"37787b255e0ee6f5f1f86c8c555ca1ab9128377ec89934a85d379192e20aac3e",37.93997599039616],[14671,"e9081faa6a00758b7359ef3a2021e7f62a1421245dce7a3fcc1a4f82cbd36885",9.317957166392093],[14455,"23993c104c105ac63c8e944b006d8dc2c1781eb502d16f5a879faae610ed1d8a",9.497326203208557],[11857,"c1d928d1a2fc66286465e2d578eebeccae15f1f3294aa37027633a61b22754b2",9.917710196779964],[18775,"5c6a222c418cb548d9581f9329b781788959e7326ea0814b76409376a513da27",9.317957166392093],[14774,"63625bda1d980729a30eaba625b8318b4ef76ec3aabc93d04170aba09c8d6a83",9.317957166392093],[8597,"9ce85922380354c0a4ffd34df240783f580bd4ecd1267529abfdc16c6cc375c7",9.917710196779964],[15463,"bbbc52df1338a3a095dfdad1f4da8f9af0fb375294bb085a45e1e06a25e3e774",9.317957166392093],[19485,"9356ce206018cc302787ff7721a205b5ab7fb881737d497ede2993f5a728eb0e",9.317957166392093],[14330,"9dc0a0edbe1fd434c6f6884c13e0961fc9e2ccb139fd87d9394ae043c5dcb88c",19.22994652406417],[15703,"1870785cc3d05a41a2c767f8aaa3184bc46da62437ffc7247c05765a0dab726f",9.647446457990116],[3135,"0d5ac8b19b07a4949b4416d2a4845e154bbeafb3227edb6c252e3bfa6fd373eb",9.917710196779964],[15038,"98a9c60fabf875da0263f9a5c68c29933236f33d17d4ec4ba6839518bb4cb87d",9.317957166392093],[5781,"f17c6e45a512c2317f976fe08521f8618b48efcf7b3e800360d37f77cd8b8eda",9.917710196779964],[4415,"3347071e71cacd472c7fcabdf7a36e365cf9f0f6262699f7e9160546d189f8e2",9.917710196779964],[6722,"b4a37708a4b1fa6a401fae5b068c50f86e2a37d5a6261ee1e015b7ca9c87cdd3",9.317957166392093],[11691,"4cfe75a3f945df38d51fb9c53b094d5317275a1b2a9330da7704a0b0b4f254b3",9.917710196779964],[18324,"32981b43f97814fd30ee35351e641fda394eb1ca8c3271cfb43d06a8e56c6135",9.317957166392093],[2898,"fd91301ef847370b875f501c53c980d851c892d1083e48cdb8211e7f803f24ed",27.933014354066987],[9771,"08e7f8a95c24669965fda365dec0705371833b60618a3fea349078957dd2d6bf",9.917710196779964],[17392,"c36fbca10b6669b48bc97f0e0cd22f701f33d59935bad29b735e5622a6a8ea49",9.317957166392093],[5910,"c784b515cef9d5bce7574c08f258693bf8b0bdf8d8e28438b64eaa0ed9a29cd9",9.917710196779964],[3726,"4947607ba138653fe429177a140591dbddefa66d2845e8b88b6d41efbb1c6be7",9.317957166392093],[18048,"c0f4a791221ba2d5dda26c8d8afc3d53b46dc8398473dcde217190c4070f593c",9.647446457990116],[4289,"7ab0d3a4dad2a1ae0aa91ff4d607cabfa25abcca9129c0bec79ef55e0f87d7e3",9.917710196779964],[18995,"1a7a30be227e08aeb0bb61f2f4e3c8516f68e133fc32b7add8e7fa9053deb320",10.052724077328646],[15168,"78bffac330ebc4c6deff6e8c9caed3925fda77f0680c0510e10e98761b24207b",9.317957166392093],[16835,"24679ce5b1d669161e5721f0712fa8ec2a68deff21febf64935a8ab32c539d55",9.317957166392093],[18992,"e65ed2b2949f8bd1fef89a43bd7ffb26c2fee552d9ea325d603d8a59f458ed20",9.317957166392093],[3666,"aa5d771b4c3c18ae4e1a8b874193f28530a29fb1189635b45e092d9ffad3d5e7",9.917710196779964],[324,"680de37d71779698a6efa81ca96db1c46801f093e25dfe45093adb9a00d9dafd",9.917710196779964],[7264,"13f938761e8c25b2308a07fe858836fead8a31b385a6fe78b0930751b3db3cd0",9.917710196779964],[15175,"c7c587f2c90b49b052a2e58fca0201625bb1a6bc713fc9c435abdd87df71027b",9.317957166392093],[16024,"3558cacbee8a325c75f1d53becc443986be78b265519b9bfdaf96f815c55fb67",9.647446457990116],[14152,"da36406c2435036cb81391032aa10a3114c1b707035b3de370cbf7d56ebf6891",9.647446457990116],[14530,"c2ee56e35c76f7f26b9e53459994f59868cbc05e5e6110a6f62cb59fd2299e88",9.317957166392093],[8367,"eb7c029b4db33baf684c8e9294c40b3e6da9476dedbf8a9f9f9ad311678ddbc8",9.917710196779964],[6879,"84cafceba5e099bc55d229bdc7194a51a8d34de19326cde4ae4b09aff08dbbd2",9.317957166392093],[18758,"c627514a628a4732184bcb8779610cb6913fe0f237df8d9175ae2e5b4e734128",10.042313117066291],[17980,"7696f6d2f115bd299e1080e3cb2ac87e4b42bd509254628acc0179c714a88a3d",26.13612565445026],[11514,"c479887aa365004178d96565d1cbaf1f2fa6c5a94debc4a769a37e68778f6cb4",9.917710196779964],[10278,"02849f5b93388264a27d9214a64b2c487949d03d2b7c370e4206e31d314988bc",9.917710196779964],[16984,"8cebf0df72646f6d3aa3baee15c971f162648b4c322ed7ee4c0ef87df7bd6552",9.317957166392093],[18149,"de55fe892ef44ab3ec4e80d3613185924d2808acd28bbede1d4e9924a7b17439",9.317957166392093],[12490,"5c0e7336dc2ada55b79dcf3d504aa5309644af352bf433a8e8ffc26b81d103ae",9.917710196779964],[5471,"81ceea9b76d45696e2c546773cba2ec7852e1c80d161bbfa24cc30f7ed1462dc",9.647446457990116],[18733,"3047c9af01ae00c964a7bb0bd96959a69198eec191122f6d00735878be944a29",9.317957166392093],[4550,"cc12465fead92976b5f5923fe87c0eefd666cbafcd698fbc6c428de290a7ffe1",9.917710196779964],[5926,"39586dcd3291e41a78d7e0de780ff573c2f72def141a75d4da646e6de78387d9",9.917710196779964],[12193,"b4f071a5aabb2726b83e71074fb3dd22b0d4367b12fc10d407f9eba9895f17b0",9.917710196779964],[5807,"15c61b86e8bcf2e517120bfceff475b82c990b1069bd8eabcc156087bf2258da",9.917710196779964],[6470,"098c60838988d40fe80473291bbc33718ca4c32524c5449803f934f55b04abd5",9.917710196779964],[3845,"390e12d99f1f4282037442a98fec92a764359228a061883aa0fe0d8201b2c4e6",9.917710196779964],[17178,"4db8c81f515ea0f9882dea199cb640510b3ec0979a6ee7c509aafb2caf774b4e",9.317957166392093],[12567,"997148e771a566666d367eb070278b1d2bc291d5774935cea57980b9857582ad",9.317957166392093],[11296,"fb5369a4198f5670e28a3cc5839e58000833be61dde596bc2a39e206100112b6",9.917710196779964],[1411,"c14966ea76429fe75f1a9c8b2d62a80147fd34cb0e4698fc75f9120d9148bff6",27.900591715976333],[9712,"26c99163fe5bd97d850773471f6b593fda5c4e2ce70070f3988775bda15148c0",9.917710196779964],[8679,"319a113252db00ffeab5e0aa0d478a8db283681fa95b491b397484a087a8d4c6",9.917710196779964],[72,"02e0a82fa82be6511790d61995d47c3b37ac154aa016c125a4fdbaffeb0d86ff",9.917710196779964],[5191,"6cc120824ead0e58972cc2a9ac99b7b0113bf9c201015410a19a49492caa09de",9.917710196779964],[9765,"7b4bf3fb66ab2876e7d052b924c4a461f382061d9d9229f79760b1ce91f9e7bf",9.917710196779964],[17823,"2dc063326e38a34904f23815a2937b386ebc8d7dbc23d831a86792ccfb6ecf40",9.317957166392093],[8768,"b0a43cfa39e068b90d3a3b070c2bf8149c0796adb7637b99695b1a134d2d3ec6",9.917710196779964],[18474,"96408bdd88ae70942ba99a46602b117bfe3fd98207ecaf26eb80b6e327aa0832",25.359430604982208],[2236,"7c28745bba384ee04019be7a6ec337ced73c858120d1b3890c0aa30047a150f1",9.917710196779964],[2808,"3eaa8fd294036dc104e559dd4e633dc99e4773e0f30d38e9e5c432b7cce99ded",9.917710196779964],[16759,"062328d825d9a12e1762fd600cbd1f02477eacf97ce57f219972ccc3c0784357",9.628504672897197],[9392,"c648fa8ae855b373540efbd4defadb16eade185784ca47d36ebc8c65bab851c2",9.317957166392093],[2404,"df80c90535c6593471785a7cd1c8e07a1c59207df381343159a43f2ce1cb73f0",9.917710196779964],[15278,"1419aa7cfc4a056a98e8fbd4e54c768830d9ff713f029cc98655451ded6ecb78",9.317957166392093],[11577,"28a8067f2717d2509ee57195a5e92a1392f643ca3fac7828d83414cbb12a05b4",9.917710196779964],[2484,"1e3b06b141570dacc6bebe51cdb24239d5cab48c1996f313a1562f2e48c4f3ef",9.917710196779964],[17004,"f88bffa85f18fcf9b268ff0fca4ca9d3045c8ca1ad99ed37317d45c307b3f151",9.317957166392093],[4450,"7e21db09886b7098677ea4f3322b46b518f047500993d16bae5f1170dde3bce2",9.317957166392093],[18265,"d289d4ae4cb252229d4377dd7160c23ed86c8fbc75c168fdc52deb019d30a336",9.317957166392093],[15940,"3a7cecac0577cba8d88a4eb51b99a2cdfe7f3461d37d3ec370d8f1e606c7296a",9.317957166392093],[11086,"cfe8f661ff4ce6d09a97f8dd876715aed3a3596d3b064a0d256a6bbe395356b7",9.647446457990116],[14607,"d820c1f3eef0e144615c8f2df152c669caa6884b2e3f797ca05d22592e83f586",9.317957166392093],[8353,"73c8a8778a6029472f07a415f483722c5af1d55609e729ac01ac5d2c176ff7c8",9.917710196779964],[18225,"880615396a746e01e9e5692f954f92a8fc33bc390edb883bf97f206208e37437",9.317957166392093],[13946,"69198c79db0972f046e3c9073f5114ef3f6b5905e90e0fcdf55a4b32653e2196",10.052724077328646],[5592,"a2fd35885e5b8b8fede92c3842ba588ff525cd27cc086735dff35f66ff98abdb",9.917710196779964],[13295,"5ec0e96e0eb7dff8ef41b39554d00f98c695eeddc96aed86b6914d9f53c39aa4",9.647446457990116],[10826,"e08f8369e0f0b80aefecf9164de92e4b89eedf737ec1353ee75a56af84a122b9",9.317957166392093],[15834,"1a166cd428a12f690904449af09c72d2c9a8090d30ba0149df4033f3b018aa6c",9.317957166392093],[15904,"c878d2afef59ed89e1041b445ae88692a8676faac1d4bae71ef8e613a38bf96a",9.317957166392093],[9939,"65106c3fd506753cca252ed49b967efb8e546d7b5113846a2b1ddc66831ab5be",9.917710196779964],[10129,"84edb5aa34d11e83a2bdd8344c163744f15d395ad51dbe54db6befae4dd87fbd",9.647446457990116],[17405,"511d111c9cbce346427312c7a2d8f8376012d8708573f7dc469638faa3d3b149",9.317957166392093],[13370,"5df197b2540df4d17ee3411fe824ec8d9e2d1aac3fa4b92ac624266c34c515a3",9.317957166392093],[7034,"27e0d9a7993f18ab249cfed6b253d16276d8b5411bfe3f92e8d697ad7bc8c8d1",9.917710196779964],[380,"2abb5067b0adef3ec3e83b47d3988908e1be76c60302e55651a64c0839a77cfd",9.917710196779964],[15071,"f529f7df828dde8d7021a78f7e0e660dc864ed46b5f449b3267e23fb67c82d7d",9.317957166392093],[5459,"6f7921122aa8d8fb1dc454a86b52f47775f02065906dd7116c6969bc384470dc",9.317957166392093],[10718,"868d2683b8c88c853a09e608a3eb8358c358ef19bd11fa16145f0ff526cce4b9",9.917710196779964],[8316,"4149fc8702f14d666898989805e93abbb702e16726b0aab972690b3ef02939c9",9.917710196779964],[9564,"7f28e100e3bcac216177a082e1e1ed81a1d6895fc81c18b5ec3294dac4dd35c1",9.317957166392093],[910,"f4943364c0db8345a33c6be8b6e7ab8c94be43ce2325a000f6c271b7abd6bff9",9.917710196779964],[11420,"5bfe79b87f0f1b069f7410a84cb2d38e3d0782b395f1be033fdd9d2bf64439b5",9.917710196779964],[5256,"16744edba190ee8d082f1cd4370bb0a59b1aadc53073adb06e48ae6c2d8da9dd",9.917710196779964],[13261,"1421467821272c28e4075729a11efd97a6bf27aed7b58d1abb3b1425d51b7aa5",9.317957166392093],[13073,"06eadc99216e72b5a23f9ed2a57d38f08b36af13e5e0bb7833c5d7e4c03b23aa",9.917710196779964],[4911,"5bb41868fdc4e9f20db705c602db2c74729eb90fe2ece08bd028b46280f7cadf",9.317957166392093],[13542,"3e39be3f93bf18ccd65602b621c3059d97da8a9c8d5c4dfb74d4c307ef69e99e",9.7265625],[228,"291ba81f8866ab564069c5643d9f14dcd4e9d56e65c839d6d77e4cc86cd473fe",9.317957166392093],[207,"28a0827052eb2fea6ddc1ceda15295c2026659456a66d18462d94c8c463291fe",9.917710196779964],[15131,"c8239f98438db321e7e2abdea82547586afec44d1e7d18ed4637209d30da157c",9.317957166392093],[13169,"1383d93f871710ce1abd14b7ae8849c282c2b0216b56dd94f6f74fedf6b4a1a7",9.685534591194969],[13929,"467dafd755addd29a8e35a4eb51b6845f7d8e519e867d41dec9fc5c588b75c96",10.052724077328646],[707,"b1c365a3436a789070acac5c98b52f8f31c98a7501cd42223ab195c178e12dfb",9.917710196779964],[7772,"1bb7114ece5dcdc3e4c632bb6a080e3fc961bc791845d6a0368776f7fc51fecc",9.917710196779964],[13863,"27f7ffd770f25f941c6cc3a2f5a7c388eafc8994e49de33549a0cdbf9a7e1a98",9.317957166392093],[5978,"9e687ca0e9a6ec076fcdb49845b9e06c07bdb503cea84df33c232f06008939d9",9.917710196779964],[8084,"1ac0fb66c9fb0ca76ee96066765ff7c43940c07e97c4e60bfc84b57744a5e3ca",9.917710196779964],[9824,"3b5809479c9df23f46c2f509e88a14c4c02c0324e0b2942b3fb88309a4167ebf",9.917710196779964],[1352,"91b1c1f33dfb54a730d4cbb768044006aed6fa96b26f88f039d31736df1e0af7",17.969811320754715],[17388,"21be26b569553a42c1e4852a4b6194d300d057d47c5399a679ff0fc8f3fefd49",9.317957166392093],[11813,"c58db4d54c5c56c1127c3899d516a66d91b6f052dd92531d476ccdc6ddc7a0b2",9.317957166392093],[3959,"6d764dde7c37acaf7c702ad2b2ebf2106023e1303d51e9315f14ad690359f7e5",9.917710196779964],[7420,"943da923915a2f6931347d6bffe205542818de5c108b2818ea1d94c38f7044cf",9.317957166392093],[10033,"49d5945570e30fc172ac94b7a65363b6c672772e095fdf65dcf31466c4921ebe",9.917710196779964],[12565,"5e721421c749a6051adff79b0026ab488bfc9463a706d19896cb286b3fea84ad",9.917710196779964],[18371,"1aa0348934c2311d4f9c058a526e7dfbf19fd565d719c282e4d59fe8b0204534",9.317957166392093],[3022,"8a3701ce51c053ef252f5febe1d697035a0f46088a9b5e21a6fb1a19857320ec",9.917710196779964],[14550,"cbd434bf233c7654bbef077a8ebcbdd8cec82385389d1090f1318dd349191f88",9.317957166392093],[6621,"d6e52595ca5ae2748f336e22c1919d52dd5a2c56b316da7b045f09e722dc81d4",9.317957166392093],[6778,"7ba869e5de6ca894bf8eb09b70fc3bac14540c32e053adc8e23656d0702f69d3",9.917710196779964],[5181,"df5abcf63577ec0fe27f1d7d2b5ce40d079239731adf9663086885b5977a15de",9.917710196779964],[19568,"5f6bead29c1e618057d6d521a369fc8ae6ede73c8b6a013536f653475e6de80b",28.066825775656323],[2837,"e9d82836eb40272d8cd61e1f163464b268a94e19dbc9958922bb58718e4b6ded",9.317957166392093],[2376,"4d271f4edb13c497ba12370e55454ec2d55fd980f9dbf9e8262fdbabae9f9ef0",10.052724077328646],[8383,"145dbd6efc7e360d8e74d7c8a310a3e9702b310e44ac20a76b6921f47655bbc8",9.917710196779964],[16056,"ad04e6c93234b78ccff2a5df9c2c38e8b4213ddc438fcf9a5d21476917194767",9.317957166392093],[17762,"093d96bcbea7c7a0dd4ff433a14f8f675f4bfa6a60fb65d1b247b4d56f7ef741",9.317957166392093],[6156,"12d9900109ba15d14f8844229364c5716beddc626bde13926bfeee7b0f9919d8",9.917710196779964],[653,"2cabd98fc603ca955242294cce8d7d265d74b2e2753abc2410dacc5bfaee8dfb",9.647446457990116],[9650,"f48c948cf1f6d174b0389c7b694b6ee7ea2bc80670c5926a85543c7d6dccb4c0",9.917710196779964],[10780,"77dbe6dad6896fdf5467b0356d331eb2735fa8b550b35a9e4c0d1ceae0d86cb9",9.917710196779964],[11001,"6b28b9a232940d6b09cbc8294e3557f98b15ab7ce11d256eb3132eab2784f8b7",9.317957166392093],[6107,"c5893065c0afcb256d6a48fff2ca585d6e4f0ee2dcf66705a1bacf8555f364d8",9.917710196779964],[18489,"6441fd83f19137361f49125d765aa18af5c28d1970b2e7ea8f874cff73589b31",9.317957166392093],[8457,"8711f67817e465a6a3c5fab9dc8fc06cf7e0201ee197b3188f5a93107e194ac8",9.917710196779964],[3785,"779c6b1d795d3cfabad223d04660b3860bfea93fe94e1d4362ccdc379b450ae7",9.917710196779964],[8019,"f8cb8e9ea179e7d0a381b8b84cd06f9935b043839a70201702a028229aa66ecb",9.917710196779964],[7222,"823a57c61ecbf183b4c932a0b1634126bb08d3432c6e76add1a724a745b982d0",9.917710196779964],[1694,"83f3dd4aee156fb0f70f7a8c0dbf3f6d0d367bb9c53b1a6cf52bc0fca3f2f6f4",9.917710196779964],[13936,"6a0b89dbe4c14fb9e813c19087944981d43f5406e89490338b35b80a28da3996",9.317957166392093],[18408,"4bfc302498a479238e0b721615ba3866cd85f510b601a17a43be3a9f585b4733",9.317957166392093],[14903,"1a3a18cce70484f84060544ec1f5b94a7268eeed63bb1d7b151154320cbed580",9.317957166392093],[6709,"e4855c521419ebda143cba2ce0a1c549ba53d96b05b068fd80aa1aca8b4ae2d3",9.917710196779964],[15593,"056de12d12bf0929e3c598457804fa4c5c1ed0b3ec9a116aafcf3e72f2c87c71",9.317957166392093],[3643,"9eff4cd7e55d4c383d3ee66ea64a2c9068087306bd25536d72c82c6e3da8fee7",9.917710196779964],[3211,"7d62c7e2ac9da6a5b1cf255f3c20540e5ca29bd82f2de39fe0638335cfa9f8ea",9.917710196779964],[12288,"48d3510969500002a4c79815b3873acaf82be4f82dd3dd7fe0b0da31fab356af",9.917710196779964],[367,"26ad5b0ab49a7cd80778a10d2162ac7693e20c4225e0c5419192346ed3f0a1fd",9.917710196779964],[1655,"644bc316bfb5b28563ac1fc30eb290d28992c6361f52eee288c84c5223203af5",9.917710196779964],[13014,"615a06340792f62f797c56a6f1efc722326d52e8e534c45834a0a16e43fc7caa",9.317957166392093],[8660,"4fb491de42f68f87971d181a152c190c668537ba3658119e304c905ef621f5c6",9.917710196779964],[8634,"2fb0be327e75cf190eab97ce98e029b4a2c9f604d6f2c93fcef9e3e4c4dd33c7",9.917710196779964],[12071,"1636ae52846b9e31aad975ac34426f6980007316d4ce9b6cbd00682b07d7e1b0",9.917710196779964],[11406,"0edb17297fce3fc6c7e1ced0e40b4e32b432eac33c0821ef8067d5078e404fb5",9.317957166392093],[19327,"2e2cb39d6688b28c0c71280c26d37b018e92433fd5cee4c27eca7e2d28532b14",9.397642257991386],[4221,"ddb28c818f60641c5482e2261b7bc264971c109ea51266dce50f78f1f0af54e4",9.917710196779964],[14716,"2766a36c47c58220bcc44ecd864603ba84c7af50225b29edcdc6264203469584",9.317957166392093],[8047,"07ef59ee00e3fd43987b93e542e7f884d63a161e9c0ef7a27b256c3d8d4038cb",9.917710196779964],[836,"150a011d116fd2876c593038df6d542e9c2879bf828ea76a5a15b6675c724efa",47.673185571490656],[7960,"7ae280fccb791e0fddef150262d38e7d3b35a99d3fceb5b0020331f6506dd9cb",9.917710196779964],[17936,"c8db7544260436d439d327f431170a2c7657682ec82bdccfe319e124e706913e",9.317957166392093],[18971,"d63cfa51eb7afb372c780c78be4d30178d38cbf2b7432e882b4111875b0e8521",15.915194346289752],[13363,"29a10d6c7ecb169599d96d9b74f1727f8aeb9d8b52fb2d2a685fe0b1509d40a3",9.317957166392093],[5537,"de54f9a1895e45e2ad467b1c565f39d8f336f645b7441a78f9ed67bcbdd3fddb",9.917710196779964],[2775,"4bae2eaebde2cd744c8e96681f1bc6c768c232e4043806dd11ff05a00272f3ed",9.917710196779964],[1588,"ff6b28aed4097d849f23a89c62902578c837c84e05c7ff7e5afc80cf71759af5",9.917710196779964],[12656,"e7cbcbeb270beb4e0b69af4ffba98ca88999cfe6bdce64e413511eb75775e9ac",9.917710196779964],[8899,"e14380048036ea14691c259d9ccf99bf0080643b58c2e239da72f4426fa474c5",9.917710196779964],[7688,"2b27e3414488c6f86a6a2250c8f7d7e90f4ed7c92cb646fa45c2b66368dea0cd",9.917710196779964],[774,"d5127a25a84993016defa2de921d55904d51886fdb8ed4ef0ef03dbbcad8b7fa",9.917710196779964],[4219,"d31507e643304a9a4be7b592626bcd4ba12dc8dbf104cc5fb10a9791bdae56e4",9.917710196779964],[14316,"f15ef2723d1e4e474c94e0ae8778633e1775ca0da24f8efca404552f351a3f8d",9.317957166392093],[12531,"001df066ca02df3829e51303c6ca720bba5e826a94c80271212f5a05b90cb8ad",9.917710196779964],[13388,"73765ba242a0e7f6f3bde4dbd580b26b680f31d5069a712608120febc6e3a4a2",9.317957166392093],[9474,"5b8c0aa22dd9ab19f06f45d9cc5eb9128cdfd01f971925c0730fb99dea97ddc1",9.917710196779964],[16980,"d0dbd5622a6f793fa16ca893547e7f7c29dc0b2ad37314b65a2d014d93987e52",9.997888067581837],[14619,"a9594208807526860bbe1dada0f9f1f54144c473121d6fde3155a08cf833a686",9.317957166392093],[7874,"fce0ab3c095b8ef753b7d36f2190adaae73ea66acd85c86e4d31fd58dd856dcc",9.917710196779964],[15275,"e07574f025d0f16bcceeeb1772c2dd81d21aaa38ccdbfec8ee43f47fa5e1d878",9.317957166392093],[8244,"485730b181ffb1878ed03a485459ee495308799d16f502862f72f07c4ea7abc9",9.917710196779964],[9037,"d68d45484e6f21f48d3ceaf921e64b6d9ad416a9a48f741b4a65463170a48dc4",9.917710196779964],[12223,"e6b01e67442fabcef049f909de40d10da3cfbcf06f1d50f0a2990db01d19e9af",9.917710196779964],[8033,"96c68cd9692884eb91953f775ae868a89b8c5fa836638c06904292d61d3f5bcb",10.014251781472684],[7366,"bbff12cc61aa01c09759bce1d9821b01be7e23d601f82d87cf111c476e749dcf",9.317957166392093],[13945,"d77b9ac564a664fa53d4bcf951d822b6c342b77531230e46e3d3da8001ef2296",27.148342059336823],[17125,"cffca9fecef288d5d6de29603f4cd00ed76976c5e02290ca46f55a22c6d3754f",9.317957166392093],[16034,"6da8998d6be3a56e5decdfcff7f56a4adc4bacd45f3bbae4872d9454dba2b767",9.317957166392093],[10116,"13438a466785bf6be99a15295b013c4ce16068be505773f2794eb37ca0fd96bd",9.917710196779964],[13465,"8ea6ad97776f21a177cbbb9d8c97b984294fd5dd3f2ff389458a8b48cc7dc4a0",9.317957166392093],[14278,"888c33f810c5aa4b50252142f8208e64cc61f99bd978d1699bc0ea207d614a8e",9.317957166392093],[18480,"6c2ff53c293818db5b5c03edf3b97c5f681e0f5e7cc1e2cf62f8196a7d2cf231",9.317957166392093],[8677,"a2a78d6c2410f43520c051ca29c40665017ccd7897bb3caa8a077310b120d5c6",9.917710196779964],[2657,"a3e05cb08cca17bc190d0f03c51c1b3b7d817d08085f5fed00417559e2d2d0ee",9.917710196779964],[2960,"e8e19e5b81615881e8025ae66782416a8aa996a8a3103509c51551f40d1494ec",9.317957166392093],[3882,"a94b6800788ce7378b45a36746c87baac40151a5467976b6c0d77d02c6987de6",9.917710196779964],[7314,"50f79f9debc131081db847ff3ac2ab53b5544b40e0b192d37f3ef21afca0fbcf",9.917710196779964],[2431,"e3f53e0d7fe6568171ce333b4a748fcdedf9ce27f625a73611aa98b1f3c241f0",9.647446457990116],[13675,"309d19fd0426fa1ef31aa8e54d65d7bc86e3601ec7a96d37a95efadafa65c59b",9.317957166392093],[17065,"2e339a68df3e85153bd435c7b054353aa2326cbb799e0fdc269891ecaa28ca50",9.317957166392093],[15483,"f92c18bdedabe2c0db6f555665ca86651bc030d52b03954d88e13af6c9e97f74",55.24444444444445],[19057,"dad4145cd7ed65a8c95ae5c091f9a977519c2c8c2b23c76084e5197113388b1e",9.317957166392093],[1374,"f54f885392815c5736f96a70a4b0e883480b4370c0cb24ee5ec52b0f1164e9f6",9.917710196779964],[365,"3f3c110a0d114dfe9d69928bcf7005fb158653c53f738ea28fec9c8aa934a5fd",14],[4821,"e190f29de21a0af0988549f12e0e5b58d48802c69138f1faf3b74fbb2c744de0",9.917710196779964],[15721,"4834d728fa7ed5e6b2ac0248a76a1ebe1f0d09e18603b55b488de8b59c140b6f",9.317957166392093],[16716,"b78e35ba1fba1d561831ef8a77246fef23474a88c6d4b33801d8038f56a03658",9.317957166392093],[15637,"cee466e8f13f11053a8cc60d57d2ba9b8e8bdf0ef988a73f259b177a4af4a870",39.13879003558719],[5079,"a55b58032ddd4e69eab6824ddec7dd551c2fc7802f97a5c2c6a124712a27afde",9.917710196779964],[7964,"c07688bafccc39c75b78ad74aabfcb31df158024aa77de2127db6ddb1947d1cb",9.317957166392093],[16044,"84e3e3c63028bcb16f1eccf63c70cde134c709a40a07993290df67e8e6d58167",9.317957166392093],[11672,"d7d72b4838278443d694eb48d57936a8e0b4356bc8e89013b5b18628386e76b3",28.766146993318486],[33,"469e375685b2c7e1811b17e5e1ea978db8cf975cfb2843260bffe67147bad4ff",9.917710196779964],[57,"5332d619224984d7aa9a88bd182b0d2e682668430662c10ea97462a9db3197ff",9.917710196779964],[148,"2d6ebafcb9eb376cad663ef4bd6b0efa33d69387a08bc475c63e0cf4ac36fcfe",9.317957166392093],[13000,"091ce1d4e2312cbc8cbf1853584c237d73a012cf058604e021008ca1d79c97aa",35.92760180995475],[10068,"92468174e11db5a997684dfcbc91130c5e6d3d626b970e8e5704eda15d60f4bd",9.917710196779964],[17812,"0cd89d2659d2d6ca842b4000900c59a08d0d4b2f89fe1aefea604736e7c40941",18.130434782608695],[9024,"d2a50d8369cc94933202d4109e9158656fa7b267c0d99e0e285d9a149a42a0c4",9.317957166392093],[3803,"6772710378a9210ae6fbcd255201bff094e193c963b70a1b5e671b2f5a2af2e6",9.917710196779964],[10835,"ab794e6c0b0aedf0ba13eecd181ade5da4e728f741923eb0ff2479cd27dd15b9",24.285204991087344],[6022,"08364c5edb2300a71f9bc5d1129a88ecab9f666f1bbfc1aec5839cffb56ff0d8",9.917710196779964],[3162,"60b93b940de8008200da1ba0b7eb51a491d01e4f5deea24ab94d70b437c64eeb",9.317957166392093],[3834,"22c12a954323340546dd299b0f48d41f093f2c511102ac72977a6949c28acee6",9.917710196779964],[17555,"4045120d0ab1e66bd2804cc2ca4a0c6200855f5896ecc226a8b5c9f3ccec6146",9.317957166392093],[8741,"9d2c1b4f365dbfaffdf4629227e6546e27e1d3b2efb9cda63962881e221c73c6",9.917710196779964],[19360,"67761e10edaf4e8871dbab0853d0deeca82064489a28cf1524c24582fca54f13",9.317957166392093],[12190,"399bad50402d9ed9e3b4c2c2374e9e851a0821b7d5b6740ed80b1c00be8522b0",9.917710196779964],[725,"5a10ec5b90d283e50c01b9cb9ef0557de61b2115a9b0571b5f130603df820afb",9.917710196779964],[10719,"2dedce75bf3b240d2e9799d5110efe72a87826bdc6810a51aab62106453ee0b9",9.917710196779964],[8492,"3edd528fcb1aa049985e2b7ca2dd07bf837509e9563a8a51bd2dedd1b29110c8",9.917710196779964],[10646,"666f2b67350965862b2180564b67910ff5879362214ae4efd2b58589436e65ba",9.411764705882353],[19648,"08d8bae69624aac9bc5312cbaa65100626b3fd77fdd61925fbd78f4dda111e08",9.317957166392093],[4030,"707498e56f5a58e116561d9bcd171aa905d596ec17b6e72ce0dfaaac4cc28de5",9.917710196779964],[11809,"03901edeacd101435b6983c1be37ea0e744b28755a89cc51ff8fb19c5e27a9b2",9.917710196779964],[8107,"bb1767229fe5d587b95c7a1d7d57b119f701e639ec91d6285b8997f0b4cfb7ca",14.92526690391459],[19130,"894c302fefc169ef8d3642b6cd63f5ae154a81fe4ca1a09c271e93a72792261b",10.052724077328646],[16144,"3c3a53300aaef4906d75754dd9996b56c7b2f78e484f1e6212b20f5239b61e65",9.317957166392093],[19738,"7fe450bf83214fed66608f23b5aa875c9a7ff796c8b3d453f442416d5ccc6d05",9.317957166392093],[3788,"16fa30245c77fe8006de7f8ccf6b396d384e8aa7f1614ab22471c8cadfaf06e7",9.917710196779964],[17790,"ed9840ea6901a71f38a940a13525133ca2a9b9540f739ca76369ff54453b8841",9.317957166392093],[12736,"e8ad0a58a307d1cd29d021c16d3893f7f5c77bcad39db69e8cd64b4daa4458ac",10.052724077328646],[12761,"313cc8c885e878f68c37b95f15cbb302ffa87d6a1db20736b53a679aae1828ac",9.333333333333334],[7066,"9160001e31646962c22068f035a674a29f174425480798a5644ea58445bf8dd1",9.917710196779964],[4539,"dea8865b52e0b4f65c077dbc93c746a43df9b7d5e72d10e929b80e33edb319e2",9.917710196779964],[18185,"9853986f3c3d1af7404249fa0af14d5dff5d242b01faafcfe102b40e99429138",9.317957166392093],[5173,"6520bdd59e2e60b3a874a0449883c6c2c20595b703231992a0582e6356f823de",14.15929203539823],[13399,"b7898ebce3d9cf34deb1859aeb6b8202bb488d8a40e308489eb191e4d3674da2",15.160839160839162],[12607,"b6e812fb734298a0f75583805395ce9081d510a72c65c41cd6c7705757a737ad",9.917710196779964],[18178,"b6fa9f36b1fe4e94795eb35e9b19497700beeca757741976b6ea1e07003ac338",9.317957166392093],[14955,"6d93f5339d3f793f03cc557992a4b0e94884371d9e20e2feef29f5f2b9f09b7f",10.052724077328646],[5776,"afa68eacbbae474d9538fbfddc0ba7339a3c3330c212a3c14e963f7cfe7097da",9.917710196779964],[6272,"1419c62d85e2be76d0ccfd1a27f27e8071528169b07d2097a93debfd686b45d7",9.917710196779964],[14479,"b56cec42c82bbe0b3fd4842859517dbc31abb3d36efebec7db3902589374a689",9.317957166392093],[3639,"2c272abbd80a37d5b1834f6b40c43e6d98d5b99de90a47fbea9d6f153cd202e8",9.317957166392093],[16246,"9e63274fb2cd9f672dc2cda47163d3c8a3c3c5a6f5a23f1e92f06bddc5608962",9.317957166392093],[217,"b63251fd4a5e8a69c900545149ec5004eb53c3b38b199ae78fb91ce41bf084fe",9.917710196779964],[7427,"655079f2ef243a9fa8e6fb31f7aa34ec85c2435eb0c74ded9a84f508e81036cf",9.917710196779964],[787,"39b113981a88fa7bc0b7adfdba429054520f63c3e66559235665a222e83c98fa",9.917710196779964],[10439,"1c8f7523241f3562bf576d951a39612ba3b9e9f7170ad9a70a4d2f9180eb82bb",9.917710196779964],[13055,"48b0f0e61de3c496433c42f35dcc811164b7a4f99ab7121fbcd4e8c6b31c40aa",9.917710196779964],[4199,"14238a272098c18c83dff610b1becb98096ba55c6f326a6b49da920429846ce4",9.917710196779964],[18978,"8fe93c41c81ab63a15f550e54f377059617fa702b7e56e19fc105f2895ba4d21",9.317957166392093],[4256,"1ddd236188312e1f680bd133ff9c22251cd12c315dca3fb36cee0eca591918e4",9.917710196779964],[17440,"2c317558c48d0bf3b1d5d866e93260229eb1c9c74f3517c7dacdf3378a94e648",9.317957166392093],[2950,"217077f1942a9e5fd4921eedb81e5eacb8576dd11648fc4266331555a0a2a9ec",9.917710196779964],[12048,"9d580aa4e35138ad2b1da945689ae15bc111f155a3af0210afb1354c032fffb0",9.917710196779964],[14593,"3ec62e15da7f17a33981e3ca5af07349f743a0be0d3a3a396fa49810eeef3e87",26.138053097345132],[15550,"7e066ad62a1c1c548606b322959522a586e11e9a47afe659102d230066eace72",9.317957166392093],[7269,"24b3e00d57edca510c5f2f6c98b25a9aaa1c425b7a5714a3dfc41b85839837d0",9.917710196779964],[822,"b6275e81a5c5e6dcff0a3c7c637ae3b02cdadc35b0b4efb26fde8892895561fa",9.917710196779964],[15504,"7c1ab777e3792835a361688651c897cbdaf4e5d42fdcc95d547eda3535810774",10.014641288433381],[17244,"d0e4fa8bac4847c0d882b8a31fe2d004b56cda39a16083f96bdee04fae7b0e4d",9.317957166392093],[1060,"4203ceeedef3ca104e90a6e6af93bab737ad392219b6dcf5502c784d1966dcf8",9.917710196779964],[19531,"6b22844e57fd20be08d0efe0d848fa12523af5ed6c028ff2490c46f8e53c630d",9.317957166392093],[8,"4e99399c49579134575b2f359a2e03a445d63a53a06244c686b9ac617ec6f7ff",9.317957166392093],[19608,"e0044796c6c5e7e448ec32f14db50ca8c7c4fa964c410c88db54fca4bafa9209",9.317957166392093],[16792,"4a23d1ea16f737e7df9fb3f66f586f37ceac833b7b0140efd96b455876c47656",10.052724077328646],[12411,"d27529057462201348f5d29a156b5c992508ff77134eab95f222a78966ff8bae",9.917710196779964],[7911,"a3028a5c608e6ea93da717dddc41a3ccf9511e22cc5993d9095e530ae7d22acc",9.917710196779964],[7322,"b64cee660894fd5f40398c0ac4db19b86c806e3798358602d1917d5e6275edcf",9.917710196779964],[6281,"90826cdca0d5804ba596c7e468bd518125c6b7e098efd5b45ba13e4f747c32d7",9.917710196779964],[9893,"34052d841257c3ddb59f59af041ad205eb46c2d5ed517166f9eaf4976f32fabe",9.917710196779964],[18186,"cde95cfd93fa13e45f686f51200825b6e2e798d216d280dca9fc6c04a7008e38",9.317957166392093],[18256,"ab9a19f8dd985222fde696c2a498c0f4890777eaa2049bdd4b8f4e4c6ad1e636",9.317957166392093],[15091,"39cd19f6c16fe1037d8942fa627c6c5d50807a24ee25313681d78c120b58e27c",9.317957166392093],[48,"c3eb56ec08bb5d7e7497c6e560252eefd6b124b44ec2390a07f11805dc8aaaff",9.917710196779964],[9027,"ec8874a60d7f385b718841518c10beac55d7cc0d66704d234305ff2f30ae9dc4",9.917710196779964],[5326,"69d933bc0b5aedd1e829e71128b928c88cfecde25d655278e2b76e41a51745dd",9.917710196779964],[9614,"f12faa1ba7ecd4c1cdceaf9bffbe0c089533f030b25bfaeffdbfa06080dfefc0",9.917710196779964],[3946,"b8cd268ad367bb02d546514e5922527962aa7011a9b739a32245eec32bee04e6",9.917710196779964],[5842,"4c781cf326a8c49ceefefe631d123a875fb656506e65c4385776fbf6364f0dda",9.917710196779964],[15207,"9a5255f7272c6b2aac92a9a06d8f5725dac0002036745d717b277284bbc25e7a",9.317957166392093],[799,"84a1c5978403b148f472393e02c5cd73203492d3b5b90e649b84423d846e8afa",9.317957166392093],[9747,"97079818230c0358db06969e1240a3b5f2bdaa8b25cfd02f8cb8e12fe0fe04c0",9.917710196779964],[4246,"67e3fa695c1b1f64ca1c82f6927b957832e42cdf3d4a4cb93182be7d6f3f24e4",9.644381223328592],[14118,"7669a50d7c079ebfa1a545cb99ee6e38bf5504903d328723739c24aa1e142c92",9.317957166392093],[19849,"15721b2ce3cd5139696fccfd907be1dbcc90747c0e1e8147d2e1ed5bb800dc00",9.317957166392093],[407,"02afe3454fd7ff2858b45b23930d44e33d00dc5a33d594da76fcd108582b4cfd",9.917710196779964],[18512,"d8e424f1e02b1cebdb889b7d0c0409436b6c4331acb2e70da780638d468c3331",9.317957166392093],[2603,"52a98e024225d7c47e8314857e5c5517ab45327b3b6524282ad95083ce3121ef",9.317957166392093],[5540,"03600c53fdebecddd52ca93073f3583e2c87b2a658a39774108e06e6ecf5fadb",9.917710196779964],[10151,"5c046270e717ec0b4308f145f8c3e6d362a09ac0c96f9ab9303dc465cde462bd",9.317957166392093],[19061,"4c3307ae46bff5d45bf92ad3369624436d2cafd1a63deec3133c34fc3dd23e1e",9.317957166392093],[5772,"4dbc4cb4310171eb9a657287222bfac458f4239213602267db9b88c0ab839fda",9.917710196779964],[6244,"5e2568932bcd1c5f2c26731eb90d7b9ba77797e3d25e4ce5f5a5b67bc3c86fd7",9.917710196779964],[12930,"856a77da0a7a794ec5346b34f711e2b1a04a25d0b330c02336ac4d04d7db08ab",9.917710196779964],[11135,"986d8b4101613410c2fb6437e4f079b8793623690f7d4c3326e4dd761b510fb7",9.917710196779964],[16240,"a3c9f20784c8583ab5e6550352f50f79c2607ba5f41c97a76909be608c51ba62",9.317957166392093],[7638,"e504f13fed84633e27ce318b785c422b55331b8ce8630ed32eba3972a2b0f5cd",9.917710196779964],[15574,"538c53258c07c1fd8ad8499000fd51fa53f80b9412f61bd2e0a5f52778761a72",9.317957166392093],[5975,"89e21b2b8af97a7b0e47718adeaf6aa086deb502cc8e7369f91f3229476d3fd9",9.917710196779964],[2597,"42e02c91467688ac6009739fae24a4dac47d566c52dc1bdeb3a9724bfeac2def",9.317957166392093],[3151,"a94be5e06ca36a59b0586ca5b60e4c1493ec9cb0787a04f3e35cb5a8575757eb",17.083197389885807],[10599,"43092d449795de292a6f77362f14dfef91bf5f48baa8cc12065c93cef096a6ba",9.317957166392093],[1830,"de33ae51d7ce80e75162031957c87ef0eed78a5cca07e8070248b85799c00df4",9.317957166392093],[16382,"a54ef41cb619c86f73803fcdeadb6e510f42becb8a42cc31b6e364faf270725f",9.317957166392093],[5241,"a1306a66c57bd444155815b8021da91ccdb972932e12eb0ab0fb619daafbbadd",9.317957166392093],[16434,"10630858b02dfa0408d4772680c07b70683a03be605aa768a95278338000715e",10.052724077328646],[16245,"f2ad784afa9ace957e504724bd5b6c6261f2bff3c3dd6f04bfa7e543d7ff8e62",9.317957166392093],[603,"3dd2f91770a44321d3e89f8fe2ce8aa3397618f829b4aa253dbffd3ed81ee8fb",9.317957166392093],[2390,"a5ff20bbdf34988022a5519d0f2601ce1f8c9560f7f051cdba596d8798d386f0",9.917710196779964],[5766,"3f25c1e7eef5dba9f5e78b8867ef5dee88dbfe400a0cbeb7d9fd9401577faeda",9.917710196779964],[1297,"f3b09ab9b480b175e527dc783990be07b8d155d9281a1129d1268a2e67e066f7",9.317957166392093],[15696,"29462896fc51140146b390f1ff68e7562544a6749f1431996db366f96dc4976f",9.317957166392093],[8324,"0177376812dd4a0c59fc8072c097e2a732f2c93f13e4b6a175c9699639a527c9",9.917710196779964],[2440,"1999e4c4ca6850be0099c95d91afa1291ac4c4c024af6604f2276f0be86a39f0",9.317957166392093],[4797,"d0ca02d6592759381168249675f6e537e529ab8135120619155fa286717962e0",9.917710196779964],[9234,"3ea3ba63506b97dc95586f25948fd666090e1765e26af41ccec95532a27d34c3",9.317957166392093],[9776,"5437377fe325c807f00bc3f710adf185b5adc33532f31e1973537c8f7ff7d2bf",9.317957166392093],[10972,"c19d4c00aa88157186135988cb50347a560430841f9394095c74e7ef3ed833b8",9.917710196779964],[17037,"def23152923870f9f4723f4a803dbad89a57bc9b6f3c1fc974f9195d3a383551",9.317957166392093],[5227,"6f9c613ee661a03ca45e9768b4fa6e23103584a005dc807f8de8fdddb8e4cfdd",9.917710196779964],[14476,"6fa795feaa7e3eddb66b620cf07767b4b0347e4a0fdec44af2a701c2effdb589",9.317957166392093],[11863,"505d4516b364317e0968a09b7e2bba721e9be538bd7c62910996050ec1f349b2",9.917710196779964],[5398,"24ff428a71081c570ec0d3eaa9715e7a79532dc6710604e8d86234212554d0dc",9.917710196779964],[13750,"752de2ff3776225e521f41837242766e6f4962878235c2dc5bf24f52e9c0719a",9.647446457990116],[8120,"dff4bf0451dfe585686f07a7a8af9415fac7fc369eefcc5ae5fa9ae874909eca",9.317957166392093],[7020,"825367e80e3a8378b426c657a14047a7f2da37cfa9bdc3948082c74b7480ded1",9.917710196779964],[17746,"3f261cd45e6d7bf2f017f3f32bf3fda8f38f9706df766c3aab5a21797da23942",9.317957166392093],[16737,"72f2b044fe30910edfd45bd99102cdb5168b15335846d38a7be4e307a8d89d57",28.12785388127854],[4069,"ff08b7d1ca9f65c80e898908674caa87c8c375b94b2351fa7b4f849f53ac4ae5",9.317957166392093],[11162,"72f34083ec851b0bbf21aca6fe5a706d21258c3943d8166cca8d0c5a4542ebb6",9.917710196779964],[10465,"6948e5f6665f3ba6a8d8f1db994c324534cc51bdcd70346b55af28f1236e54bb",9.917710196779964],[18600,"4fd8933ebded308d62a0d107d81da91e7a5e09d478c1730fbfcba8a11a0cac2e",9.317957166392093],[4651,"8dbd0b76a4419f4e7f5215800e07511b380661f01c7be77f42a9019427ba49e1",9.917710196779964],[18514,"1e5fb40c505b3454b7729843d023b386ebeb043d7841642c97455d6ea9932b31",9.317957166392093],[15046,"7e8fd4f4e294242820de429e128e00691e0b68a698ac4393e8777bcf6ee9a67d",9.317957166392093],[5317,"942a291850570238671fb8ab30f68078b839c5392c5456508b05fba415bf4ddd",29.418848167539267],[15679,"3c4c73c75b4c9b67050e8534ef6ed0482048f9ac5955e43cda6cf6e85a9ece6f",9.317957166392093],[15642,"0a2d31f780d9549c0598ae76dbd182b784967a7e82b500c5acae0575c74c7f70",9.317957166392093],[2678,"83ffffbc079ab28a36e8f48bff50f60fede37afb9967cd8dbe9614f9dde1a7ee",9.317957166392093],[16843,"03ebd5fb4f442037ff6294ba5c1e47b5dceeaff6393c737a93d889697b076755",9.317957166392093],[15152,"e1b15b14546daecf4838667e84d09f81e78e243b3c33caff58ff6f44ae92827b",9.778611632270168],[18257,"20428e516301ae5df49f918eebbe0b9a1be78d4fae72dc99ad74f6650906e336",9.647446457990116],[13819,"060a6b9db9c7a5f568259a3f76e8ad8a369e210fe3a405bb096225b4571d1f99",10.052724077328646],[11411,"087db838795d8e6faa4cc3808e40d98be44cb22683e0e95116f7a2a64ca44cb5",9.917710196779964],[8975,"3d5e0c5e659d1f8a5eccbca7e9ef64bb94ebd112a5c518bb2358f2ad4d8efac4",9.647446457990116],[1252,"34265106827c67ddd8d26a6d7c1dacba7cd184617d541c83f2246d2c0196a6f7",9.917710196779964],[97,"a5c7aebba9003774bebaca12d602d6893ba6eb23b3061bb355ee7137a4c264ff",9.317957166392093],[14594,"2745a2c6a6d2ad12266f860fe8c02d0e0c381a47a69b1582a9feb35567de3d87",9.317957166392093],[17716,"0fef4342e1d7f527a2c442724bf3690f13c30b9875e16b400cd0b09945b2e842",9.317957166392093],[16353,"d5a622c77fe969b4b41b9198abbff88810c33b3504be1d8d4ef394911fac0460",9.647446457990116],[1916,"908577a501c026c1ea7bce3360665066e9e72bc1bdae08138f293141f42792f3",9.917710196779964],[19752,"f7c189931b1c64d99c4160a4489a8168e0ab7dc6b69a7854220fd72444d1ab04",9.317957166392093],[2336,"8fea2c92b1897ccd94ceae7714334692a63fe94c9db91eb463d0498cf191d2f0",9.317957166392093],[16729,"5d62e7629c05a79c3244f495245b9fb2a8140c214ca38d6c93d51e46ad3dce57",9.317957166392093],[253,"cfea838c58f9d6bece8336cdce6e20dceb41a489631871ae8a731f56fe4e4afe",12.01332839689004],[17580,"0d407a2dc07744d25d3c1c1190fdc5716056c274d3d3a05d992ea9966489b345",9.317957166392093],[1243,"8b421790f864cc2b0d3ebf29f0399602a5187a4b2ae98d4752ec544f4a27bbf7",9.917710196779964],[17887,"7c2bfbad000e21dee39f19c0e72db0825c690ccc54d71328e002599d68d1803f",15.91459074733096],[18798,"1a1b5614fa6b7a55568354f67bb781a10aab02be4124addaa25c61fc73adef26",9.424083769633508],[13478,"6531b7298884f5f6bc9f6f8ed352d41f2d6345ebc1e23adc5458297961845ba0",45.2017937219731],[5937,"13dad142a11ca5a9bc25acb3f7af5d8820efde9bd68cb371bafed79d75ba75d9",9.917710196779964],[2860,"4d320e5deb9e80e9e0612d2b00aed8083d55befeb2847001568514efc10d57ed",9.917710196779964],[8337,"78d8a1f4a8bdfe541e56bd4990773276908e1d13405c97585eb15e628ce516c9",15],[15120,"b31456e6d1f5d272d7161a1dfd203317b7b88db9719e3fa41e0b271096ec4a7c",15.073170731707316],[17662,"548e934fbeee4a66690deb2022039acd1eed147e60e38d3408d88fc944c1e543",26.105882352941176],[13162,"82c05d774c0da7b3fda77cd916fe7c807fc990cc166845d9f18becdc35c6c6a7",9.317957166392093],[17275,"7d87c70dc1d5d77cc0157ed2a4b80b90596344fb4451aff2540f8991c509b44c",10.014641288433381],[17919,"63683df0a9b15b4f76a411f3c88b39eb43be8ba0e0ddf5fc7c15d2e30278ee3e",9.317957166392093],[9807,"e78a9d220129fb64c4ffc7b65262a3b60190150bdd368e2a2c57d3b3ac3397bf",9.917710196779964],[16260,"22ffc352053564d679a749a1cacbcea099792b1bbed73f847bfbed4cffd62762",9.317957166392093],[3513,"55aa7c87f3f86b88ed31d64aff95fff8fc2b538acdc925b3b202781d7895e8e8",9.917710196779964],[8170,"7b52197394486cc1da35ba0985c9d9d987df2bd6f187c7a0527c6b2b34392dca",9.917710196779964],[15159,"b992dee1055f7c3d1527301c5163247a02b23a7445ec55e86c6b11f62e86507b",9.317957166392093],[17967,"75a3b115707833ff18c7386335fa445e3c3f5b9f3457669f463b2bb63b3dca3d",9.317957166392093],[12810,"2363e6daa3808f593b8423f8affa7aedeedb54b0de882418374859f2fb22dfab",9.917710196779964],[4765,"3857cb5ef0ee5c629aae9b57b7165cc7c9e98cc29bf98a658556d8ebfa9d8ee0",9.317957166392093],[10506,"1e82fbb6a372786070c4bb19463be09a746c27b100be3e22f9d22057aea927bb",9.917710196779964],[4611,"5a6a696f6ee93cc2078c0d35f4380f0f1ffdf14d666b5c82f299d24428b08ce1",9.917710196779964],[19480,"2159034f5df0179706b228dee1c8aea5f67004d094d143f6468ad26fbadb220f",10.052724077328646],[19370,"1bc40f14f6edcc19e6e56d0474519c03ee034b64002db99cee518c911cb12313",9.317957166392093],[8673,"80faea79656d3d2a4269180cab9a8683392cd7b749f89f8f304aa5a32b21d9c6",9.917710196779964],[15499,"92fb5bee1b4b3ac7125783756b01c9280aa4f98a65c353351ebfd11ac9f91f74",24.738730365275583],[18936,"905378fe932b359b46744788b16bb44c286ddfa4d3e722ad0fd3cdd812e47722",9.647446457990116],[1610,"41ba0ab263e3f79c1489d63a8517d19ed7de734a0907dc04669814b84cb082f5",9.917710196779964],[4681,"941a8cf576b81576d1cff9bb93516bcd7b455a273a307b3cbe4c6d6ca6ba1ae1",9.917710196779964],[9084,"a70d69b64b3ad058f3402535d6720550d0d5a4c1de376e014b34b73ffbd840c4",9.917710196779964],[10940,"aeeed99e6e5fb0608de77e2464fd85ae3700ee6c86ac1f7d781f031531dc71b8",9.917710196779964],[4052,"65ccd3af4d9350ec089317ee35403c69e640890d7158e36fc01cfe29e7026be5",9.917710196779964],[4459,"c2b64714b1fd4b4858fbadf8fd494a346d54f4ad3be8cb5566def4b854dda9e2",9.917710196779964],[19503,"ee71d79af30fb006bf649f203366f2b18e1b7d5e9ce241c18a8845db6450450e",37.65675057208238],[6845,"b6b7d33e11185d8fb7397c02550f90a222b21cd84003d3b70afe452b7a11ffd2",41.333333333333336],[13855,"f86929b9f0577864147b847c4d66e01ac8e04f04c7d5aa6287861eda5ee74c98",9.317957166392093],[13619,"e0292aca958b0d41ae695db8eee17cf8b6245de6e10fee32723662f88d3ef39c",10.052724077328646],[10551,"c53fee3880233b1aa4952fbb99b7a6f5564d0b39c202c488847dddf371c2edba",9.317957166392093],[13948,"422152c8222046a6e5beedeeae1fa61102c452fdaa2d4d36de0aabb37532f995",10.052724077328646],[13644,"53012cf34dea884f8a7035de9ffee52d5fc59a1072c7c58bca2bbf0b90cc569c",9.317957166392093],[17764,"a0da3397aded8c62f74af54d6e67d82e3c96ea7b219e0d919115d06b17c5f441",9.317957166392093],[11573,"97237c8c02edc1af9b9e10b2f8001d711512ad525140908b2d4b1a686ccd19b4",9.917710196779964],[12142,"26a18e8b3295f2dd8db3cb32fb78e738d51b0531296b27462c4d5f009f6464b0",9.917710196779964],[2540,"351a971a87126dee740fc0c41a6dc4149272f699e541fe50a9451d995a8592ef",9.917710196779964],[16779,"784defdbae33e74b67791067ddd4ff97b54bb7173c323e55349011428513e356",9.317957166392093],[2330,"953aafa14e41a0f8abeeb8ffdf8933f1df3cf22564f9ad827d4900fc0fa9d9f0",9.317957166392093],[4377,"c07f30bfdf8f1db0368ff3da993b4a5fbe2eb6d3427036ad7e7dc777802739e3",9.917710196779964],[5841,"7914e86a43351ab33a901c92dc08d2fafc94c32be4fc75e8d181bf3ecacd0eda",9.917710196779964],[14967,"78993ba38b78c585dfe230a41aa25256faf374b695be887540c3a216e56a397f",9.647446457990116],[9845,"3317c829bc766b5fb6b52d62a8021cd23dba9d6e243f8c59434c590644f950bf",9.917710196779964],[10691,"e48bc0105f0961c7a56ea46f3e04243998107c6c9390babda8b265f7ecfe11ba",9.317957166392093],[5664,"c29658b70149af0e28b2cdadff760f710bb9fdb1e1eb0baa397c0df988da3bdb",9.917710196779964],[4766,"0fde5660b5399cc4df027ab774a0f71494a6c3303bdede2acfd8882e8c2c8de0",9.917710196779964],[16559,"a7b31606dd20d247df275db7f84ba5b8e9072ff7099342bebe11efd4ebabed5b",9.317957166392093],[15307,"98fcb0b650c22c9e04df5fc397201945728383477271e760f01386a033423c78",9.317957166392093],[9741,"3f117a1819b939fcdee1beda822400b6d93dd27a764bcde4a66d5dd411e70ac0",9.917710196779964],[5788,"531ecc5dc1664300d94968d079d01ac2d3e33980f71cac42b1dafb66d42a7dda",9.317957166392093],[12186,"97ee488afb3724569e9d80d5aff864638d69f7caa2d6517f39f1d8fb900927b0",10.052724077328646],[7616,"0255c2d04530993864ff525d39ed32dc4a619db87c4ded85095f94ee88ee1cce",9.317957166392093],[19710,"101e53f19d4f13d04021f95e49423c15900b4fd440b3812d2068826ed1746906",9.317957166392093],[5503,"09ec4330ac25a77541b74e17270e4860a0945fed6d20ac402116156ed35235dc",9.917710196779964],[13549,"8d52032fbc5a8f2bdecba205a00a04bf60f2bdb41d56b8e288e7c8188b04c79e",9.317957166392093],[17446,"f9ac2ec1948afc0aaa9e523ac477b10b4cfb9292bb192e655b4c1fcd6dabba48",9.317957166392093],[17472,"e232277d44bc2dc4f54ad05a374dabf11960e75067b839624ccc1c796a604448",9.317957166392093],[17012,"f6ca157137330899b0d77c131257fcd71475eb5fda5135a48f5cddaae2a1c551",31.800453514739228],[19458,"2b0c064d3486de300213be75aabd63d3211825c9892d577e2ee44181c5e4a70f",9.317957166392093],[6454,"a562b20e16627af596995f9e52fcbe3b2294100ae726cad654006b2fff5cdfd5",9.917710196779964],[16477,"137484810da163fb46cdcc325d09667a93f8f035d31da52c21e321dfea7cc15d",9.317957166392093],[11846,"5420f0bdc5d31476283d08a9ce1739a5df0480313bc20c40abdef10a60d46cb2",9.917710196779964],[17055,"8aace0e984d8d3cf70827ef1b845e940d45fd77f0986c024ef00151b64aff750",9.647446457990116],[13184,"8a68d5ea3b679039d9311a6eeaf446bbbcda4606d731287d42e1a4f41a7854a7",10.052724077328646],[14483,"bf18b4b067e6787f9e90d33fab012d542f7698d581f1214a0dfb81a058a89889",15.953890489913544],[6731,"ae52fcab817e64127ba5b4375a2f4a1bfd7c2e90d0319207bcccb1214751bbd3",9.317957166392093],[9834,"3a73d200682beed22833e0356174ee4bae98590e1ef9df384b83e4609f3a65bf",9.917710196779964],[18445,"2cbcd252b9187a7e28e0bf30adaf755824b3ae8127c358a2ab9c879dd1d2c632",9.317957166392093],[10079,"59d3cf924c635309af6568dc9dceb4dfa3df6edbb5b49204177465687946d5bd",9.917710196779964],[8390,"6cc945db2a8154053a22d2e82e111089cfb79331660b5d6e5453b8eb2e49afc8",9.917710196779964],[2544,"4e49ad1a61a84ea3158ad7daf49a9f8594b7a2ebd94e8adbdd06905c2a678fef",9.917710196779964],[16848,"551f338bba3f8b6674128de318d41c82b39fddbe785dae7971afe7ca96b84c55",15.105633802816902],[9204,"3be1558080c038baf457be3ad6783b61c5f267b505285ad42cf07ac1acef66c3",9.917710196779964],[6388,"ede448456e58b94f4ac40affd859226612e6a37ae030ce221aa9e9445ed266d6",9.917710196779964],[17561,"24b0493a74df0c286f3c4eeca6d24629d2e4cc678977f80e9ea4268fcaf55546",9.317957166392093],[9360,"1cf3dcaaea7ea4bc45a6ec5cf25df5ae5aabe399317c9d7b8b028e3a41c381c2",9.917710196779964],[6191,"4727db8684ff19bfeb4abe3288466cdb0b3ac202875c5992da0f3c4b5898d5d7",9.317957166392093],[17067,"75780b0bc1a20e78749c1b05d7eed4aa3c3432e54c80995b2688af381a85c750",9.317957166392093],[16407,"6a234f13aed9fa863e8b54be770abe78e487e0f0fae32e7171974b1c2267fe5e",9.317957166392093],[14204,"9f881656868771b96ab25cb1d29699e6069157a6bb43a21189e1dc7ba8be1e90",9.317957166392093],[6841,"841b5f1ec9f315f9f9b17a310e1d7f5c5ebbbb0f59b14d870ce70b3a71b401d3",9.917710196779964],[537,"7d2abee7616027ca8643ff010246c9c335596e56b38507c3bcabfacdd0f45cfc",9.917710196779964],[15322,"cd6886fb6224d6c6a19bad194d1861e50ab59ad4912069004d96555b246be577",9.317957166392093],[13780,"c34564ec6a9e5d1c4bdca70c81c6aeb6acea657695d7195a6a247e12336aba99",9.317957166392093],[2232,"e097d6e8a350fdb4e520819644ba6f778585b64ba609f69d926dc9b35df552f1",9.317957166392093],[8245,"46fcb79732f1989d63478a36e2b1281a83241d16967ba4d73770c092d570abc9",9.917710196779964],[2532,"335503c97efa736199dc093ccc10cd4148190688d3eb7594d0e54d4749c99bef",9.917710196779964],[7706,"13fd1b13524c0adaf57c03d978da1492a9991d59dead601af71d76f43da280cd",9.917710196779964],[17258,"f74f36ccd8f5930cd60beceec52e7d60d2f680c7b0e85afe32f55d14f646ed4c",9.317957166392093],[16761,"66b1d5d4502d77f42cb0e8034c3c021f31a13241a3ee7e095265d6db21212f57",9.317957166392093],[11627,"86df77f8b35d3117dbdaa624b508a099fe527d7a0c2a675f36170d18b02bbab3",9.317957166392093],[12770,"6b0b54652672b595a8e09aff5cffff1a8fbed87647219548c8eb711e01c31dac",9.917710196779964],[8574,"b8a41cfc2e75c70f7b565bebe4cae6b5a3c9356134be82c87de075dd1ba297c7",9.917710196779964],[7687,"a7a1e522978a9c55dc5c3cb5fd6bae4b99a90aa97d441600ccadd7d16603a4cd",9.917710196779964],[3238,"479f728e83fcd088c6a9e646201add5b44bfc2dbbcb799b1d88c857099d8c0ea",9.317957166392093],[15487,"d8abdebffc668225f3e32eb4999414d469e97f91cce726467d04a4fbeb9b6474",9.317957166392093],[15936,"9bbe832e766ba11bbf2611b63572d57bc359069dce5e5fb06b203a2e76fb4b6a",9.317957166392093],[1647,"36896432e68f93f11ff7efbda543cbdd5b30c41e980924fa679631c2004149f5",9.917710196779964],[9837,"3e9af804dae0375f456169c588a9f3276e2439a5801f1ca4a8fbb32d1d7b5fbf",9.317957166392093],[7104,"20eb140eb7a3deeb374dbc09276c3d1510489b94a97f41cf1958529adf2c4cd1",9.917710196779964],[17932,"b9e1518a90d072ee512f365b089520f0f5ab7929285888b20c9692c48123a63e",9.317957166392093],[4388,"82ed75831e22fbf0fa210773308f079a9cdf506d0e1841e3642cc18e7df024e3",9.917710196779964],[11779,"27f772e408519f648aaf03886f70c53211f88fe64e404b29b5a60b2b6ff3d8b2",9.917710196779964],[15588,"d47e3d625eed351b07b37751f1dd8aae3f7d0e1da152d2db1bed2a1c12578f71",9.317957166392093],[18239,"749c7476ec13294278fe194e46ce0ef06f8f0e57493655709910352687302b37",9.511868533171029],[16500,"c3259b5a5fc51c77dcb7335a2e82772a138a52070c1fcd8cf701e4afb6eb355d",9.317957166392093],[6011,"1487a6b51501e81afff46879a4b158eea2a5580931d4ce1949e88fd9287301d9",9.317957166392093],[12218,"a47c10f7c1896ccc4e7c3cb6e5a39a9810e5d0b0b11e5c631423d7783844f4af",9.917710196779964],[1832,"9c4a1f5ed9ea2f59ede05f8760dd83f123acb8dfc2b3bbde736b6ed62d3c0bf4",9.917710196779964],[10227,"4b35438421dddf20743b92ccb52b3f6e5ea03619f0610f771d87209d041ccdbc",9.317957166392093],[2819,"74a971ae8e4e1c9c2085adc117bb01a8d55ed89c74e1cba318748b6a515e8bed",9.917710196779964],[1869,"5a0977cf2a6e313e69b82f38c631369d2693a68068c4fda1adee66e43a30cff3",100.53475935828877],[6869,"d1730084d62360062b96345b8f9c2b0a252666dd6c3bc8daf176452a54e4d0d2",9.317957166392093],[9092,"5b5b6b4d7bbcb899cb350d3a02dcebad05ae29ec0549fc242618bd28d36e37c4",9.917710196779964],[12912,"a241fa3ddfb71f9e42441fc67c7600e4e01b72cc6701d736c369dbf5aecf3bab",9.917710196779964],[714,"39a7a38ada799380776f9fd564048561698b49cdb71e68c8393a3494c6e219fb",9.317957166392093],[3983,"8d47cc8acbf8359f2fb9c531fa2275a9845b644eea28ca6a22d6b33b134fd2e5",9.917710196779964],[8539,"0478bb7c280b559358ca5aac2aa63c736af817bb3676ba326f2699d01d90c9c7",9.917710196779964],[419,"0451d9977bf0807b886657f43c69b3b025f623941b5b15dcc72ef607daab41fd",9.917710196779964],[7417,"1391e7442e172fe81c2d886e54078def4c9c261679815a8d447df314fe7348cf",9.917710196779964],[6330,"0412a24523327aaee4946af8296d668f7902a27eba89c6501458a1b21e27c8d6",9.917710196779964],[1028,"f80a5e4aba4c1a25f97a79824776c261d05b4d06bf29ade7037acb75afb514f9",9.917710196779964],[1116,"98ddfbba9629d24b7f1e3a54961155af68380a734a5afc7256b3b7b3ce3b7cf8",9.917710196779964],[12292,"d6093a6e92f6e8e9f06c324c6cda25d1f2348ccc4577b912321454cd32a14baf",9.317957166392093],[8152,"eb6564422de6880e2dc772f225361e0b9084643058b97442eb2c71b8651c55ca",9.317957166392093],[363,"f7cd2f31a1c5e39603f58472088dc449c631f9b6345b42091da0aaea6d19aafd",9.917710196779964],[18167,"79da6577fd58e113bc99a83f4868c5f3f5846832ad873aec84eee14662510039",9.773123909249565],[4716,"bf420f3b531d8d85af923bfc2faa3bd6faa34f62255576c2e7c209fa9f28f1e0",9.317957166392093],[13563,"286cffece22c137fb2cca1e0ff3b0b5aa62466ec010af77095073fc86e506e9e",40.609756097560975],[7905,"610847c6e7a12d728b742a77099fafb6f5110ddd630593d4756a09fb587433cc",9.317957166392093],[12849,"4600184510cd9954b61b99d67d7418e4e04211e1c488c6b38ee794ad083596ab",9.917710196779964],[18636,"fd95a851a6572271ecb578edd00170983e4d9ce51a7af416be65603dab31522d",9.317957166392093],[3088,"9e109d1f9ec643cf0954a6c5969903d310646726eff1c32b9782c041da91bbeb",9.917710196779964],[17485,"39d4d88b445ae26b532fe1581ac9bd68c514ed5d879ad33a392b166817cde747",9.497392881432782],[129,"1f9f42e780848e65b81d5f9c70bd0b11f18f09f476168f0735a50f81641220ff",9.917710196779964],[11324,"054734c4ed5252148c15af4c6f306b0415025bf46b1a6d1851c345ccd4fdd7b5",9.917710196779964],[10531,"1f4adc18b9c0193fe9ee1bb52b8e8ec3adbdebc35f70f72ab0801f6b2df0feba",9.317957166392093],[9388,"9f9a1c5e3da2401979d65bee695cc81f8ebbf6956b00bb5198fecd77436c59c2",9.917710196779964],[12501,"16c03a20a6b4f1e9b09df47eeb23d5802f18913c3ea500216853ce427b8ef3ad",9.917710196779964],[12231,"de32dc0b3fa860e69165496a9c55ffaadd3b1e5e40f620118b8ec55ea5bdceaf",9.317957166392093],[3780,"ecdff2951bf53f4f08e289a323ae7e0cdaff786ace48056fc52ec819799315e7",9.917710196779964],[3113,"dea111b8d2c9fe1eb66ba80db5e71a8591a4044f3a318f411dbd6cbb79c691eb",37.93594306049822],[18685,"769cc76f70a3ddd8f6a90889e3d5bafe055ad73b1beb2b1226c9a5435327f02a",9.317957166392093],[12894,"82145767933220718cd8d9d9094f3f28b59adc438f80b9815da8ba45ecdd54ab",9.917710196779964],[5120,"072c452600e7ff3877d7128219ccb497ac53f67f2dd37dfd836899a6662479de",9.317957166392093],[7408,"64d7f6a522cb7b78f92b38f61f031b5194ec16ce495de6bd4964af0d0f6e5dcf",9.917710196779964],[1174,"63556aac61ef4f972d4631f43d678621165e15cfeba850043e11cf1a059128f8",9.917710196779964],[7928,"053a15681c24dc1bab31682b0b0df831d79d9606a708817e7382184fe97d0bcc",9.917710196779964],[19400,"54b516fac54b1c05ae791ad7fa9b7afb2eeaeda623d0b77f4fdfb49bb8188511",9.647446457990116],[1447,"81173206f68f7fe62eeddb39627f197b20284505a218e6ca687294d134af87f6",9.917710196779964],[17616,"c318f60684aca08723c102ae497958b4f0577e0a139f03346086e0a6bb2de544",9.317957166392093],[10629,"a3671cd325cfe8125784b49862483b193f9983160bd0ea4991fd6d20105582ba",9.917710196779964],[15148,"392ff073b454dde1aa1856c2d097957e1698c8ae00fabe32afd121995b14907b",9.317957166392093],[14869,"74489dc09c796dd400cc14a896d7a70e4021c3d52b3e8c33594b4469de966181",9.317957166392093],[13618,"48708a9109cc395d8d5a7bc75c4ff498346f58c67617d4eb8d47141db743ff9c",9.317957166392093],[7848,"f42edb24d02c73d4e813f5a5f67953f4ba69d3f2b57190dd906b36f7b33d83cc",9.917710196779964],[16795,"49b05afd94cf6c4d657b05a68862d4269d540cdf4d475a9443079a60fad76956",9.317957166392093],[14712,"37ab75e882bf99e6ba46fdd9fb8048ccbf93e2f01c4a18cadbf6f669404ca184",9.317957166392093],[2507,"d3bd5be8dcb5c093d8b67d8842250112784f56d32865d59e69ae8aa4145bccef",9.647058823529411],[9660,"89a0940356036894a5ba9874b74cf14ea2f621308bb9373609fbc8b5bc5fa5c0",9.917710196779964],[9953,"715c3737245075224a5722ee051be6c3765381ab55ab83f8f2a36c95d41f9cbe",9.917710196779964],[3742,"c1212488e67e8edbc67ffa9c93743d44ded65cb4fffe62c21de9b22fd6f84be7",9.917710196779964],[13528,"abe4850b8bbb4d83b7619c05c904270384700a4f2de0198ee2176cfd7516399f",10.052724077328646],[15266,"d9aa38a9b5a9c776b9de4ec74a1004f6b3656f318baa2b0d92a536a8b4db0e79",9.317957166392093],[1171,"7b952a2538fb1ed97b1512ec2736a82a85704575621330f776d0a00fd96b29f8",9.917710196779964],[13019,"46eb6a9455346064a8c766153243c7f0e762c62c8f4a7fa76036b30e118374aa",9.917710196779964],[2379,"70b86ef7c577a74c5a32878c200fabd86ca335b115e3cc8c2db296e0936593f0",9.917710196779964],[4646,"0e6e3d87be4539b88522db5e0f5f0201e5e7e0938dc50566d4d1c382751f58e1",9.917710196779964],[1604,"f65d58b0eb54d7b30ee9bc262992c25b5b50395be2ea98ef0ff1353b3bba87f5",9.917710196779964],[12236,"39145495ca3321692e608253dfd7fc379bffea5e764c24bca4118eae8e13c2af",9.917710196779964],[3553,"fc185605480e9e50331cb9c899e7efbda30f20438f0d0ef6a15338a21ed490e8",9.917710196779964],[9865,"f4f2fb881093e9e1e91a528951e15ab1c464d8ea13641056b25008048bf623bf",9.917710196779964],[4232,"bc952624cf1e6085c5a6afc6a7dae57e0bf1088aa1a994b48024e566e15332e4",9.317957166392093],[18134,"d5caef96b51d9fafd2f9ca4f1720f3bb2155e59200f3a04d1e5224e760be163a",10.028818443804035],[17624,"88ebc44fb79b77fe43d4f3ca1958866ca54d9509c940ef40ec2acfa3c675bc44",9.317957166392093],[18635,"08fb9e758360c1531282a753d07ab91b9b70b39e5a265e7de4c866115d2f612d",9.317957166392093],[17346,"ed11f2626bee01baa6e1146690542f1c9292cdc2ea72668328fb50f83144f34a",9.317957166392093],[7077,"2eeee2bff483821a858cbdd2696c963dc3bc81dd7420efbd2981164c82cf7cd1",9.917710196779964],[6438,"7d4f47860588ca4bb1568d8d8a35dca968e7aff12035dd3e2016639ed7abfed5",9.317957166392093],[138,"9f68f3e78ffd42d1b904dbcb214c18d59fb8593f7c7d2f46ef14eb23f68313ff",9.917710196779964],[14694,"0cc028b63862f51b786d1e701baff8383797b116c40800afac6855e17a2ff284",9.317957166392093],[14969,"bdebd3c7adb592c39866940bdc2472bde70caec99f227bf78143280c824c357f",39.13879003558719],[11525,"8527c1bcd9a99ce009142a86d600d99cb1f56963f7c636d900a6f73920785cb4",9.917710196779964],[18397,"372601da88157ae5896176a3a2c5fab352f97c7dc42a0d179a93bd6c02867833",9.317957166392093],[16278,"0733cbe37aa301c9b337fe058622cd531f0ae3a9ec2985e0872988f86d47a161",9.317957166392093],[8781,"e96c4c9f32803df6b6e5e142bb8f171a6ef95effc37368c0c8c3421c0d192ec6",9.917710196779964],[8135,"5b34ab16db7ffdf44455c590d794724fc77eaa7a0d74354f081be444e2ea7aca",9.917710196779964],[12348,"396f092f8b13ed72629be64bd4d42b2c7cdcae48fd846c4606c9efe05a9be7ae",9.917710196779964],[2690,"a0a00d294679ff12a0807cc99995708b54233308380c5f9d9dca476bf17c87ee",9.917710196779964],[11307,"e807a8873b7be64b5069b257e181886220417ba358b275b5336cc84779cef7b5",9.317957166392093],[6741,"efb44a726d7e5a4d9a6d1aec13e957cbf5c0e23c916c01d4208a5d789f0ba6d3",9.917710196779964],[13308,"621e6787d84217c847534d9012f7ff390d1d92d6141ce1afaf76841e00a071a4",9.317957166392093],[73,"aaa52ef16f836262b5eca14d21b2980bc0cfb3e2d9ccbc943dac5128d1e883ff",9.317957166392093],[2864,"d10c6849e9e809299d562f89864fc5fc4cd9a5f312223774eab3aaa3df4454ed",9.917710196779964],[3458,"ee17c3b697d1756f1ab0c1e636ea97e7d117d15a5b43f3edb423a2be278d53e9",180.42959427207637],[17572,"63b0317137e92d26f3e4aedc3527ac94f5cd241ded0a1c9af3af85184eecd945",9.317957166392093],[11599,"3579e99a5f315479c8201616295862a3be334405e87893114f04c2229636e6b3",9.317957166392093],[131,"789fa42e118e528f6a2811a81d32289500fc21f247e670532c412f1bd91a1fff",9.917710196779964],[4674,"eecaedcde9a065c1b453286b079e3ae8e344f2dd9c1e9d860c6b956a192b28e1",9.917710196779964],[6249,"0dc55bdb058c94a1e22d277561b1c156b109c2a125e38e0d7aa528d2720065d7",9.317957166392093],[13206,"6e32cb4e0e6f13f618a54d30e911affc74aec6daeea76d78915205a85374caa6",9.317957166392093],[16047,"96b441d3df366bbb497fa816ea4ed0c4e6c08e992990036f52370ac96f5a7f67",9.317957166392093],[17119,"e22b14497a06551e1ccf211ced1f59d8a4dffbbb1097d4d051f98fcf914a954f",9.317957166392093],[99,"1ef3e759ba8c888a4b2b531aa5fd99b65003922d1f5fb09671b2211e631f63ff",9.917710196779964],[16816,"b03b0e5ea0e585bd8b105d03bab982ce5cf12097754cadbed7cd7386347bea55",9.317957166392093],[1403,"d7bc13355f0c21f690511afec5f9fa799d2d7dd790e137712131271521b2ccf6",9.317957166392093],[11942,"d953f3888494b9accd208e35ef6da00da0d57c71aac7bbbe2598b755b3bfb4b1",9.317957166392093],[8334,"6009285556727755ef993b7658ebaf5e989bdc56d07b8c7e417e7815a0dd19c9",9.917710196779964],[8242,"e4c29e1047c6b0b91c2efa3eaf82da57b584a15e71c3d79c8ef947166dd4aec9",9.461024498886415],[19172,"72cb5eac99d1589dbbdd1782cad2d61539f10f595330175b213ad809891eae19",9.317957166392093],[9141,"a28c3df92f7b67a78d87e8f34516f8e2912cdbe007ea6db0b9977cba6dffdbc3",9.317957166392093],[10376,"06dce2e1cfc89257e3a83f31b18c4223fab828cb1729b73a14b41a63448cf1bb",9.917710196779964],[6653,"5f2f703f3c25df41b6fd8110c014ba84293fe76d98fdcc962f92f214799649d4",9.317957166392093],[19698,"25d64245394da7fbff7b11256b0c1ad52611d7c880c23db11a3007616ad4df06",10.052724077328646],[2801,"9dc9bc4230a8de4ba1bbcb95f9a922c669dc060e757e5eafff98626c80f4b2ed",9.917710196779964],[5237,"c20709d1abdd9a5fbe0aa8edf2ccefab074267ab4797777a94dd5386cb33c4dd",9.317957166392093],[2632,"b090f6b749de7d8df54bae0245fa99cd196f6c188d3d59b58ef5c9ce3f2ef9ee",9.917710196779964],[3640,"a33500a94bfcd977716716897b0bf1b205109b2796d8c2317c13edc3102201e8",9.917710196779964],[12944,"a0bf78abb441595227f53cf280c9b718d4086df8ba07362993394877054bf9aa",9.917710196779964],[3121,"4664c5fd37e19780a2a6145bd36a40967034bd8a2a6419532ab12dfb959587eb",9.317957166392093],[8571,"c0ed81b85c47d1eb5abd97ba61be19d1f0f7f81da7d3be27f40057560f689cc7",9.917710196779964],[5246,"fc4e10a97b988e514c6c286494b3d7a9cb2b5da137ee3e07a267623d89ccb5dd",9.917710196779964],[2283,"32602e2702fb7b930ed6cbd96cdf84e468a1bd3cae907c538f07ccdc73eb19f1",9.917710196779964],[11786,"8012aa777ada2f3d0c0368bf75ee54fc918509a3cfac303feaeae767e0becbb2",9.917710196779964],[19205,"275409eaa7f9fa0852ac0211260aed5f54e31e3c91e93b6e4d388d08084c7c18",10.052724077328646],[16611,"e0474821e4673f9661f591004023648185ebd6154cb8f8c1f800fbf860d59e5a",9.317957166392093],[16717,"4b6e2450673fe9548800edc7222ac42216a19b3a4bf030723130879c875a3058",9.317957166392093],[9745,"89fc91d21be2f1af820d161a6f7d6bac20cc5f5b4cecb9722ccf625d078407c0",9.317957166392093],[8714,"d43e021639c65628001b2c86709daa7acca2069d4b5b2598d10187492e4599c6",9.317957166392093],[14377,"ded788b4571b40a4495b1f595da2cbb5dbee10990c31379639e30204fd4fcd8b",9.317957166392093],[10228,"ce4538ea4dc4dac5252d4a07196328efd1ab01f7e0967ece6ca27d73b011cdbc",9.917710196779964],[14460,"f7ac55b6fabf04d6b5009c25667bfde98f75aa14fdf89bcf214e3ed52e4c0f8a",9.317957166392093],[2994,"7e1e9c1e03c4a7a86598feb6e632eadbb74d57bb422a3a43925cfa8866ff53ec",9.917710196779964],[12203,"4c12ab25783520269db7dc085854936e83201d6930838087759ce2c7522010b0",9.917710196779964],[5198,"ba6f9ba7d50c6cf6844b076b0c43edc9d30f196182231cdeb143cffb6817fedd",9.917710196779964],[1175,"2d8a287596f15eb2152b8bfc9fefa805475131951e4670cb012d8bf7ba8f26f8",9.917710196779964],[10248,"1eaf890c28d05ec46e92fbcc8ec872a80e87fde0f0cfe06458fbe0d5edf8b7bc",9.917710196779964],[7021,"f68a8028e6e3c5eedc8a41d5fb545fb442fd64116a673c69545fa0e7d45bded1",9.917710196779964],[17826,"a66b775fe3f6297276339984963cc8ac9e685edef57bb2b26cd05e8aad86c740",9.317957166392093],[2120,"409917ee47f529232f8a3eb63999ce9174a849e506b58f5e2ebd698cab831df2",9.917710196779964],[1546,"f2f0d4d15292ec56c8a69566e1202951ac862be3ecd5bb8a7b0ce4cac178dbf5",9.917710196779964],[17103,"303f457435cdf7a3b77305df0f25d08e4e3b64452b009655927e02e7243ce04f",9.317957166392093],[18644,"4eb5c4ddfd9af8beaffe5b1ff02d4ad869f7eb349f61aff624f8068a40b5082d",9.647446457990116],[17937,"627ea6f21486383f7a6fc9272210278ad51d543b7394e2fa1a52b68bad9f833e",9.317957166392093],[19013,"b5d74a48f2370f5dcee6ab19942b31501a17bbb002bda857a9e2341f4b330820",9.317957166392093],[4091,"dee4b280bb1955b6390b7c0c4f91d3cefd2fe95a6aa2634e400cdfe049fc21e5",9.917710196779964],[17597,"874d25a167eff0428dc6cb5aafb36ec893da385682c8a61aa04a7080efe53b45",9.317957166392093],[12035,"ffd0155c90b81bdb8fc24c81ece2522eee88dffca754424d8e343f933c3d0fb1",9.917710196779964],[4710,"116ae33881be8e5b68a181c6ea5dca30036b2fd71d37049207d024a824b2f4e0",9.317957166392093],[2859,"d53d71f81162c24f4125130178b77002965f72f7ff1d0ee6d738018bdc7a57ed",9.317957166392093],[18996,"429d04dfe563e1e29a953b492f81a956f0d25a25a1df6945f83ca7ad3184af20",9.317957166392093],[6484,"c7bda718248041c28bb49dc57e4873466a05ac5d01b82a60b423ba89e4ca94d5",9.917710196779964],[15733,"09daf3727da642c7f6131d2f0330b74d53b4f4c4224c16e2dbb3db3168a9d86e",9.317957166392093],[13298,"68628f8a07d3aef0a395f883b2459e504f4bec735e1f953b804ebdbfd95e8fa4",30.12912482065997],[17689,"145d62d612517aff21e8977ce0b0b1d41c566eff0c43d934dfd911ff25f46743",28.146596858638745],[18044,"f3709b52f7b3681b658d31cb5910ffa002ccbe09d223d15b68c25b59ae46643c",9.317957166392093],[13953,"8e27b1b922b273711a0a889ad683e0de3605c37cb8fc138e30f952c48d8de995",10],[15348,"46ad6b48c009448a533f31884b24ff76b2e012354e19de1c16a3a160881e6477",9.647446457990116],[8430,"77da40a049ce6a443b224bc8e71afd2c84ca7f46728d0ea77a596c3d2f9371c8",9.317957166392093],[6396,"a96d0e660c5a7d27d7b3e827e2c32a013a643137348305aeb4e1c66d2c335ed6",9.917710196779964],[7151,"169b3969153e4d251cd1e32ca17700b2b90218a492dc47f7e68da919d6b804d1",9.917710196779964],[14274,"c9317b077517c1cc9abacf8a4b77c353a5ebcec61f78065608d89e6c90ce788e",9.317957166392093],[14956,"c613f4fee64830e8c62612d299ca67cf65da43be2a7517b1fa3c287255e3947f",9.317957166392093],[10631,"9b96f07d74141cbbc6f596fde9665d4b1b2602973e859b53f7aa22e853077fba",9.917710196779964],[15831,"cfd8140eee071498dd71b3a96b3fb5696ebc3ff301bb3ee6423152a92892b36c",9.317957166392093],[10231,"72431268ff1d94c7e01e8d46c6a7e4dd052f8dc69f34843154b2a9516e0fc8bc",9.917710196779964],[14918,"d737d7a71adbd423526cee672ba40b368fc09b8afa9f104a00b690b457569480",9.317957166392093],[17482,"82b0d6447d85731ead9f9c48e6e76fbbca88ed314dffbd9fd9c280d6d7b90a48",9.317957166392093],[219,"e6190a5bf8b102a12e44d83d1260064f6c2dd2d1e502a0568f25fefb162f84fe",9.317957166392093],[740,"4b32269f24ab903be013e304b19aee34d6a32a3bf1de97f02d7425938bb5f7fa",9.317957166392093],[8434,"26fdb3058453a1f05b743142b2e0635a73d2f7ad848bb6538540b3da07e16dc8",9.497630331753555],[5156,"cebebec16ef1ea958d3e2c0f8c27a192116bf6eb629ef7ab25c7f5752c043fde",9.317957166392093],[4654,"b989bc84868d309c4bc74c695bdc2af455859bdd0fd304280a4cc011758c46e1",9.917710196779964],[18851,"9ae5f384f0376b2865b4f5b48a2e39a663d681676764449f6b4c5c3b93c50a25",9.317957166392093],[1632,"b0c4173e1e4fe06442328916fdf9295e2e7641e2d595f6db6ce24d00f68d68f5",9.917710196779964],[18854,"62e9e29658004658069d4fcb81ac7ddb9321ca273268078a78419252b382f724",10.052724077328646],[8303,"bab95f4adc52ba485d499e13077103013c3369fadf88667577f36157b4c64dc9",9.917710196779964],[4172,"6c05ae6c6da64c3a8011ef21f6fa9e68baea53e18beb5c066ad99c0efb509fe4",9.917710196779964],[10553,"d9370b5a2440785777fdf68c1c732b2e0a1b96cdfee811e722245f9e9e14eaba",9.917710196779964],[17188,"85f5687270de9681fcccf00812515524c1733935dfa25bc50c0b7b4ae1b8004e",9.317957166392093],[15076,"648934534c3aa38703dd59f790c8e96ff28b5f68d5468e1f213ffc6490851f7d",9.317957166392093],[1309,"c09310cb58ac445c0c05fd7ce1ea12a1ed6a65e6cf897bf2da28caae4d5d56f7",9.917710196779964],[8807,"a1dcf90b60c2b3c1bd2eaa7a4979b5235abaad94c76718e26deebca06f3d09c6",9.917710196779964],[10559,"baf99733c0a75405671e1e0e4bf6e2579166373efa90532018615444218edeba",9.317957166392093],[9727,"9d120f2734a397d9ef028a0b3a6876b2d1bdf0548e158a53dc47b880991b24c0",9.317957166392093],[6466,"27463a4e7fbbf7c86c1432889fbcf0a7244d35794de9663eec4a0ab512cbb2d5",39.267563527653216],[5312,"d87618955c0e0de043d0ad92fac58f1e0dc71c6f25695ea89473f82e16bf50dd",9.917710196779964],[6311,"df35478bf23744852e075e5e32959da402a76433c7cf5b062d806c087b00eed6",9.917710196779964],[15352,"72aaae7cd1a189d68dcc3a62455472251c5149d23bbb3f7e40b4233a286b5877",9.317957166392093],[16138,"552cab56cf778c88aa205ade9bf1ea47db436db02c20d7a44d301074359a4165",9.317957166392093],[5657,"d7ba76637d397f7480794b6cf7834f604e6e3104fc429635055c1b9a3c4e48db",9.917710196779964],[5918,"c9e5d0cc631b9fa7afb671bf93832f4c5fca9dddad35bf513ca0932c478096d9",9.917710196779964],[872,"055386460beb97de3a704f505edfa6f265af84fe28977e148d4a85c419aa13fa",9.317957166392093],[14481,"3b6399f4e3c0219d986f454678cc7928d938947f1f33a74d655ea1587b819989",9.317957166392093],[16897,"ab6bc0261b12e02e0cfdcee0bf165d13466c95c070b52ee7195245f0f4bc3f54",9.317957166392093],[12958,"a4dea4a11b0ae65ad4b2094a95ae36daf15594a0a545e38064edf60443ddd8aa",9.917710196779964],[7182,"7a54d278aa2adff4a5a36813cee2180e7438eb0e327c2196d27024895280cfd0",9.917710196779964],[15726,"0d3c308e09666dfacff9664340a9e5efc559f71cff86d7c574badb1e6b0bf86e",9.317957166392093],[10549,"3689da6ca5ace959006d6662026e8bbe01ea8959b0b30ad900edfcb32f64eeba",9.917710196779964],[8480,"c92f9b9b3cc56bb38e48b2675e892c5bb58d082eaf79ea97e9dd1204b5b524c8",9.917710196779964],[14544,"1ab78b1cbeb79f2309176cb5795452ebab103ae3061bd37a4284b0b490004288",10],[5850,"1e92998d5ba53e17670df40c48390c0447234e09ceee8cfe966e3c641b87fbd9",9.917710196779964],[14736,"e5c8548146e72f060c664a193c53c2a2fd935f37d1f22f04fc21ba476b432884",9.317957166392093],[17070,"98c9ed9b11ed89baa43307e66f7f90c2efc836e60fa453a0cc57fe26733ca150",9.317957166392093],[2270,"5554a99e45424b8770c8a9e31e5b390402b71b42cb44d205265ed7e117fa25f1",9.917710196779964],[16885,"9eda1ee49be9ae56e18ec0032271655d9a08bcf99fe914fd75653b804dfc8654",9.317957166392093],[4331,"e59fbe0cbf12c7922107f7cdf2d97e0da0c33713dd695343e711b6a3c3698ee3",9.917710196779964],[17635,"ef431272ebf3d960d508006690a11e986972fa3b113922bc673a4d4f740a9044",9.317957166392093],[4607,"7a87f630181cdc966d57f50882f14b474adf2073ddcdd265ad219a31b7b496e1",9.917710196779964],[9429,"884afe5b48dc2008cba684763e83376d5766d05978299f315b593d8947a428c2",9.317957166392093],[9375,"062c53b1dd8e25613cf66bb4de30afc4bdd0d5d73701ea5bb52d61917baa65c2",9.917710196779964],[9194,"7ce1ec98f32e918c875f2a1ac88f24e97fa175895073bc6429b022304c457fc3",9.361256544502618],[7621,"4e4b6510147b45a67cb33402e2cf420e09f08890f17000738ed2e656c35d17ce",9.317957166392093],[19135,"f719d75fd9246d964b11adc447ef2e0d8e74fee5c45c3f4604f4e3a7a9ebfc1a",25.970625262274442],[15544,"1e0251e17cbe477793c28e89f52e96c30e15eff752a2615ddf354373f7ae1c73",9.317957166392093],[7181,"a8d4a2389e4e0520c76feb3e4fa66e966ecb74abca973aa700a6bf32a45fd0d0",9.917710196779964],[15761,"a3364986b8c15adc0b5b889dacb5e0deba08fcf9a90910656ce8969aa7f6306e",9.317957166392093],[3993,"3f0ff6ea9c18cf42fa4122f7e366d24e6edde9242ee8d02feec8c3ea9becc3e5",9.917710196779964],[14773,"d9c390ec8c3e962a51f9feb5e84e6b04a7f02b3356ff5167b1cfffcb21a76b83",9.317957166392093],[7901,"1352be193b013b7f8bb00012830a1ea93010f938d1369e921cad9c2b18ae39cc",9.917710196779964],[1007,"3f97eccbcbc5eb1469436145b0f8c8c67af9bf99977bac86864ac8d3b15227f9",9.917710196779964],[10125,"d84cdad7c2e5b4e19e6b7e2eb56a81f482e3800173f5fa4df47ce1e635da87bd",9.317957166392093],[11932,"1eba03746f472c471741552fd2aca9e5c52f3e1cc7c0bdd636b518ddfa48ccb1",9.317957166392093],[15014,"cb341b5d459fd28a55c6f7b73a3bcae41b39a3c7134f8d65506de3e7fb90137e",9.317957166392093],[3093,"d5df1b08db3491337d2e8ae6cad47dccc06349fe492c314eaa7d25292b70afeb",9.317957166392093],[9397,"db9a8e6a33fa29c5acbf160130129420691f280754d9edfc8588313b7bc449c2",9.917710196779964],[46,"8185615cf27f81fa7a84785723b9c2239bb917643342ca22a3fd572825f9b5ff",9.917710196779964],[9806,"59924a298eb5b7fe1376e5a5978b20026b4941871ae4f20cd84c664aeba097bf",9.317957166392093],[15535,"bedd723cc95b13b14471ef11ec34fcb5474be439059349306d7e7b37be414073",9.317957166392093],[15672,"2b4ce0d90c5a032436be4aabb4063c4b39ed0bf6219a8a16c394d9dc8642f46f",9.317957166392093],[3101,"3d34ce590158543cdc113640dcc54d898ccc7c4fc4770e5f978a944f5e40a3eb",9.917710196779964],[1791,"d4ac81858b1d377120f07588c8b837d6c3ba62517c22c73799d4a58fc2734bf4",9.917710196779964],[4640,"cb79182871a0c30c8782d2ae7359958a4d73d3a096b2161767857e4616ff5ee1",9.917710196779964],[18174,"1dec715f31c90d737b7b00d4849b382886b30f9b47a9aad0def8c32007f6cf38",9.317957166392093],[4809,"bbd45a694a40ca5d9bd645f8926f4c359ecf0c968809ac2c3bc1caa11e3d59e0",9.917710196779964],[3748,"67e17a462953fc6d30c8a93a146068663f8ed2625937eaac25c706bdba3645e7",9.317957166392093],[14475,"2040d8ea3dabb6785b991ccd46efc9a8d66f00413e0842e4155b17337ea2c089",9.317957166392093],[8496,"8ad4bcf8390b0cc711282614773c34afce4b777a0d33f67e7381ac24f92509c8",9.917710196779964],[15259,"aef55c3bfe1214d6fe14970c81e5e198f8e11b4ef40fc2699ba04b84c5223f79",9.647446457990116],[13463,"9f31af719beae11041ae012de56abe6b1a2f556b585e5df795f95bbd79fac8a0",9.317957166392093],[19229,"afcf09acdb7e7d96087c00f40c61b1756ca364df60e9101ddb45321b5067b417",31.05169340463458],[10023,"e384b97c84d9950cc835a3084cb7c87124c238b1e6e33dd286b63f71149f32be",9.917710196779964],[10276,"c715a4056930e0b29548c6355af7294062dff91f18079e75fc775d72a4dd8cbc",9.917710196779964],[10093,"1676463fb6c3dbfcddfba1a088f7dd1725e4982ec04e563f7c2e7764a1c3c3bd",9.917710196779964],[9396,"810d799b32ae71d9ff484a6369cc8038ac01be16a55f37eb96217df9507a4ac2",9.917710196779964],[14416,"2bb53aa600055cefa62d8a3e375acdd1496d5546ddad7ede07bd69ebda511c8b",9.317957166392093],[2537,"1d3b0ed510c8b77006da72494d0c78b2d5a243834c03c5b5d66ee0391b4f95ef",9.917710196779964],[7852,"3ea7753b1c44bfcdad2494cfdfe3b60b7fda1d7d95a394473dca22fc04d27fcc",9.317957166392093],[2124,"9bd062c65c4ebb2c91b0a7874710465c3595dfebbb4780c1dd6edbe78a5218f2",9.647446457990116],[9594,"bca56d96951ea374ff98368aa7515a7dc028c6a1d0a3b632d222b29403e109c1",9.917710196779964],[840,"ab3b116a04262091a2e7d9fc894576756e60d5f73f22a1a97e0e2adcdd3b4bfa",9.317957166392093],[2989,"7b516c051f31e48426e8ce45ba8210a2148f53c5d35d14f57b4459a16b1e5bec",9.497326203208557],[10423,"2baf1d6ba7729728102b1e37b2a0ce240e3d4216ff842b3878c70a5b9fffa9bb",15.003322259136212],[2862,"c09381361c2f168ec7537781c0c0d93b84ce9cfb963a7d3ed3ed8790b70556ed",9.917710196779964],[13864,"83e20a4217faa0ea56c10ae76e9bf0376f800d291a593adf8da2433b30e21198",9.317957166392093],[15108,"e5b62ce87077dd9b9adcf36161892692a61af132a1b7317c788f804e9896657c",9.317957166392093],[6003,"8d1c7628613f58da5972e427fe7e40463286e5dd495f562afb8d587626d20cd9",9.647446457990116],[14082,"6aa8adce108a6fa94ed1115efb4afb50ac0df6204e818125a16887c257d50193",9.317957166392093],[17974,"8341fb3992532effc12b0f66522291be5dab6889f3c844c8350013f6d387b73d",9.317957166392093],[4044,"f3dba52407b15d454d9b7f4b71cde4114267a149780b097615c0532c5d7176e5",9.317957166392093],[17750,"4e2a03e94bc3ba5ce79894655bca0a6be11c56b8eee3d1dbedfe6d4c2a123242",9.317957166392093],[10764,"f44dcf740e1c5e54de530fa8789c7e11eb9125adb591ae6dd79aca68d1ad92b9",9.917710196779964],[16741,"290851b214bdd55c256e5b64cdc8e893b5f810ef936460293490af3e31929657",9.317957166392093],[14439,"572bcdd13b5e4628926f6a50359fd4995accff31d2c090487f0d7ebe09637c8a",9.647446457990116],[18498,"9fea8cf6eeefd9e1be9c2874a52d92471f838b46e708cab4eda67f88284c7831",16.187895212285458],[18290,"b93517317cc24c52f7227393dd4a25ad7b3df24d2efdf83248421b64f8080036",9.317957166392093],[13264,"3413ddf56769403ddc7b1c6a6235d97d125625ea276daa663a0c31a395fd5ba5",9.317957166392093],[17407,"ce24715e898283d08772b82a3eb920ad8efb67eadbd340b36f54b7c95ac3ab49",10.052724077328646],[8229,"f514b01038fc6e15f46cb06367904d31cf63c5091b701a13b358584b5fe2bec9",9.917710196779964],[2611,"61701ed13b0eb4dbf33a603fabd6c1fb3057972b3bad4fdb98f8933e462d19ef",10.052724077328646],[7776,"542c88bf496cc9acc51af7f26a8d627b4cc5225cbd7cb740031102e656a4f6cc",9.917710196779964],[7172,"36ddc0adc3ab1d31cabaee49a10f0040a4e760517647d6e25a449ea876cbe1d0",9.317957166392093],[16973,"a7073e94a6740c989e4e996592700100e686bc5d892eb3285a167a32516c9952",9.317957166392093],[2053,"f84bcd7d11d36af32a135faa880cfeaa361a6d8ef9f2f905ffcef3d6760b97f2",9.917710196779964],[14574,"8a4029f57bc5286fdf41850236b36fd6bcbacf6f49bdf2cb42d6b65f50479987",19.58108108108108],[11229,"0e2080e5b2d4aae7264a5a7894a1354d9cc283c56be6a12882da7850e74e82b6",9.917710196779964],[13729,"fb1490bea14a7b88e1f9592371a7ad9a0777b0f17812c1ed0d024f3b4fdfd89a",9.317957166392093],[15035,"a70714acc07a832b5d1f50f0da1a5de4cc8d25471b861fa35dc9e3181bc9c27d",10.02710027100271],[8711,"79c389bc110b2eee26dd8306f3cd6af568466345be6a670e756a63a445d39ec6",9.917710196779964],[4812,"692bf0570056af1e7c80c0c117baef6e616b18f6a42a20389faf0ac841e556e0",9.917710196779964],[3081,"3449b7e5765aac249cb6ee69f7568cf0ff2eb37924712dcc4b5b8c287016c3eb",9.917710196779964],[17496,"8e7094ec5ab37ae628f2da71a5c5066704917a504fb543faf91e3751d557a947",9.317957166392093],[9442,"572585867ad598a1e08f2edee3ddad5ba7f04087db06029356d7b89e3c5d13c2",9.917710196779964],[14565,"b38d75de94701ae799c2135470818fe60c56721017ed11a4ebacdaf3feb0ce87",9.317957166392093],[1329,"299af93bec9a258773363fba433558c0dce490074332103cafed2dda7c6b3cf7",9.317957166392093],[7029,"69ab0807e164027c2b7bb5a6bcede3393d76ac058f8a31479af0ea296869d5d1",9.317957166392093],[17074,"34d1570412f55890964647f243f8674708fe70ecc6093352ac4f2274b21b7550",9.317957166392093],[3939,"56ad7fd64498a6734117b80326a5129713a3a4bcb29de88d4732900f16eb13e6",9.917710196779964],[12402,"7c88d08fac5d1282d64cef96deb8a31fe8f003c8f837b50fb41331049baa97ae",9.317957166392093],[3129,"2b9a4a7e5641fbeb1b724c73b9938d10fb13c74f7c60af6c4901b976b37e78eb",9.317957166392093],[19191,"e062cf81d5106d07a8481842c25d459f769987b11acf8f3cb90defb43cc8ef18",25],[5339,"4d64a546498bc9c3be430410c7cbfa9d1b5824434b90825837802a9c930e32dd",9.917710196779964],[13152,"c446f0eef13cb95358205ab5e75307638032963ff3eebe6918d64b6fb1b5eea7",9.317957166392093],[9877,"dc8e9b83e51c63a2575b752a9083d38f49bd38cb8b00a95aeea13f2c90f517bf",9.917710196779964],[6131,"f71f0842f03ac36e27960171d5ae2ed520b2ed7c89c3d9fc5d7fd34f89ff40d8",9.917710196779964],[8461,"c964a10661b0fa15f4ab4188f628d6e52035998cbfb3b98bbe988fdd44d140c8",9.917710196779964],[4347,"d9923050fcfd21ce8ad6b553e825eccb409200ea6d0f308ef12a59d0cda16ee3",9.917710196779964],[15783,"c58d9298da87b99a2acba180b17257791d986338268413a1d4216d006b58a16d",9.317957166392093],[16640,"addb083e7466e4aa24dc17a87094c56370dcd3bce2633c6d8eb9cba4fed8055a",9.317957166392093],[13149,"1399416e23a2b9eabe392311a8ac0b02431d0470ba823e0b83173791c93608a8",9.317957166392093],[3395,"215b7d765273750f2ad042570acc6df2f1d753d57a24e940d11eb02a16f7b2e9",9.917710196779964],[1475,"a4df7ade694d6adade2b1902a8c8979534988acc41ac6543ccc722de100e4ef6",9.317957166392093],[14139,"5ed26308fa27b48ad4202b451b6a5d54df0a33b72f6a2a1c32051afa2122c091",9.317957166392093],[16365,"140795d2e9bb78a6db87e62b31d6a607879d354f735401e43a71cd49d0acbe5f",35.4976],[16380,"d727ce4b747e723b37fcd9509e2685cf607ad4dde6d63c81e3282ddcfc9c7d5f",10.028818443804035],[3455,"b6faced2b5726f6906dcd82f2411d48eb76f45f5a46ba44f60789a50c40057e9",9.917710196779964],[16910,"4340155f0b3f9c51af31203bc94137cfd7dc2da8ec6108e50f621a57a430db53",9.317957166392093],[17375,"d366a926d3b74bb901418781106cace03ca686e0bd2485d748496bfff69d574a",9.317957166392093],[114,"a399552954edd888d92158a6bb245eb7c1b4afc5f16002907ce3c0581a484cff",9.317957166392093],[1510,"d428236d39a8f1ae61bb9142b9037c018eff66d9a8e9e71931baa220ff6e0df6",9.917710196779964],[14068,"1c8614fd377942a2ef10a0fa2a51c571ac4ad7cef05bdf69f9f7187562f44c93",18.08372093023256],[17148,"745662d9c32a853cefe0a7ae9baf39b38b46984837090ac608ae291d13cc214f",9.317957166392093],[3996,"a2e12ba330c414e2a2b721b6070ce20e270b3dc95909a9835d534f9338b4c2e5",15.072463768115941],[18429,"177462cfb2baab35c6afc55079de79a12ec3b6d4ffda56c5b55ce9888f320833",10.016260162601625],[1005,"e4641d03b68d1c8cf80193cc94daa3ca9314e3dfe63d99d968a0902eee6930f9",9.917710196779964],[4054,"2fc9b998b25d5b7255ab252f6f634c0c0bad7f4efa45252f65d5789b490767e5",9.917710196779964],[10146,"7d193095bb85a4ee916558b6926cb6815805f5cafb798aac632230101f4b69bd",9.917710196779964],[18276,"917ef266bf732b0950f3042d3e9e137d8e96d1bc513a65db584a7ae2430e4f36",9.317957166392093],[4102,"27df2e2c2c7ab44ba5182d18fd7dc8911cc5a78b4beb42c4650b7f87492e0fe5",9.917710196779964],[2327,"bea80db34d27a38ca3583be75886ffa477128998ffe627067534a256b20ae1f0",9.917710196779964],[18479,"3eeefb5f097eb99faf934d97456295bddd97a771f1a2cb9733733dc53f5af431",9.317957166392093],[12064,"17788d3f77e38292e94a67b17d5ad43093588acc49c3c9db8cfed712a887e5b0",9.917710196779964],[18984,"3644b34230f5715d89021b4a9694715207cdc1ca3afae826646a75d3d72d0f21",20.056338028169016],[2577,"82fad86c5895409dcb73260ace9c32769c2dd6e0eac92492e0af25bfd8cc56ef",10.081996434937611],[1277,"ce5cb718b0ecac7940835bdabd81bc5f322a46e0e1103941286428ab3a8a84f7",9.666266506602641],[6402,"c8bb066d0ad766ebfa08b4e450441e2a2bf83404c2768020373b6b7a76e456d6",9.917710196779964],[5845,"6663721711936c9dcde56f80020c74071d90f89f3e510ccb4f16d694f5d807da",9.917710196779964],[2680,"67fc49c656a168f1118ee7a009c022046542a8266b23ce83e432faee22e5a1ee",9.917710196779964],[5450,"48c273ddbb5df0efec3f521471b366de93409d25f0f29fd223217191b77d7adc",9.917710196779964],[17047,"2151a2972c019757636e82091bae88a8b65d7497c384a8f4b19f4ca886822051",9.317957166392093],[4624,"89f7c346981be4b1433863885b797a9825e7e134e9ebeac5008fb5a2672e77e1",37.28146453089245],[2193,"afbaa20127f9e636b317e2f3fe974605af913fddb041b541620a3cc6708a9af1",9.917710196779964],[9086,"b359963c24bb025e9b184c203c7fae809f4af459981e484de1bea3e0b8043ec4",9.917710196779964],[13536,"d3f43c672e73074510f51230378c9d0d9bbccaad3dd855e2e54e788d236c0e9f",9.317957166392093],[1233,"9e94a0560887b834f8f40a506b0e2728961aad3ff28b2898dbeb7f0d0341ccf7",9.317957166392093],[1115,"045e2a3590fb407b143d359b4daf5e7f67e42d74b1953fa7b6334f2ca8217df8",9.917710196779964],[15970,"6f96657e2e9ea3e4087fe67ab0242370e77d783147bcda2caa33d47e61e96269",15.94306049822064],[19394,"a957b0b7bed8d858c66f39affa7750cb369c951604546b47e5ffd243bd930412",9.317957166392093],[6838,"588e3627f17840076088133d999aa4d66a8b24a3bb48ef7fcdf47c53231204d3",9.917710196779964],[18744,"9f85ee19a86ea205b5d568f8c586dd8e6ea3a6bca411e968a0677006868ee028",22.115183246073297],[14542,"0c6397d02af1b86c0c41b7a28dcc0636118521d7665d79a96338cddd81934c88",9.317957166392093],[18078,"b58310e7c78faa96fc6c32798dbcaffa07aa707f20bb0ba9a3f6894437f7923b",9.317957166392093],[13527,"a069f0727dcfdf97891d6b94a5ab608317cdd88f005faad84068f4fa59b03a9f",10.052724077328646],[18077,"3a853042af3ad17e93df2a23eedc716fdfe18f2ed69fb031a84db94a80c0953b",9.317957166392093],[10926,"d74d44fd1d3f7b72b5acdb5308da6465a21bf583ea0db2f7ce4a42431f0286b8",9.917710196779964],[13358,"1fb181d8d3f6c1c086e58f60134a09778adc9e26fd8a72ee52a628e487a54ca3",9.317957166392093],[2424,"fc9fb727a3d908e2f04f20aef23dc96d4f0add1e1481d1920709c590ace953f0",39.407407407407405],[10596,"fe08e3807436525e5f6734a1ef507907d23943e8d8b3b3212800edbcf012a8ba",9.917710196779964],[3918,"06e856d5767445681d87d87d260d9f1ca9233d69153aa4748cc962ee6ab83ae6",9.917710196779964],[3206,"1801a1c804c57c7248c5382127ada609ea7a067186858ef556486166c8eaffea",9.917710196779964],[260,"c15e2e673ab222145b53a7a6f4f8df19c37e3cb7c7ea5c0bb8e143dcf4f634fe",9.917710196779964],[8237,"944836f7b8aa34cdeb746d505b8ad5a58d699fa1e298e9a8f5ca09f63dcbb6c9",9.317957166392093],[18234,"669f7e84cc999f812e9555a088d2c52a24029c171d1d0edb2e2ec925fbb54937",9.317957166392093],[11044,"45816969d52e4a0a13e469e2bd883b0f66b83aa6e03c0ef920578fd259b3bdb7",9.317957166392093],[14467,"dce3b889edb0c9c3617e722433aad432869448503d787af4a941caa4ece5f389",9.317957166392093],[5621,"752c948352ed6898edf5db1bc0daade2cef842371f19e6acb3a8693d286a89db",9.317957166392093],[9581,"b1b28bc98d1f9ad6449ad2d2272c1b0f32c93f0d27ace5191e4da4a1bd9920c1",9.917710196779964],[15416,"fb1036514644598c9c6c5d4d002387e4789a7432296ca699c3594bee65b5fc75",9.317957166392093],[4127,"f907cd0fbcb70c2c48b395cdb6e91713f1cc501b1d205b703df978b95a9adee4",9.917710196779964],[10683,"a72aab15c2cb6a9570cb7facfc219cede8fa3c1d2f2c2e7fea88b4844eab26ba",9.917710196779964],[17369,"9b9738a7d630ed0eac152c0a4e4954913d4436ae6aa429f0edc526494888844a",9.317957166392093],[4857,"d24ea8e3b20cf3f459f1f8ae96136cf488c78cab27518351dd8f0d19ca3916e0",9.917710196779964],[18068,"4a9ac44dc970c5002dfd03dd31e4460d611f9b26b08a8e7ee6da201d266cc63b",9.317957166392093],[10252,"3bfb0e2b3ef14ed02baaa85f9f56fd11d422706611c0acd9f0b87ea0dc62b3bc",9.917710196779964],[4672,"61ee3214bc347af543062f1288f9c6e0df4037596d7564ff333798902fb929e1",10.014641288433381],[11018,"cdad750c55c95ee1543c5c698364df43bf5fe16cd403ef51f94a0dc4a5b0e4b7",9.317957166392093],[18639,"58763f7a6fa8e330b253c4536bb0ac14b27c4af0acacaa773f1efc8df95b422d",9.317957166392093],[1139,"9960713adabc882860fa9cae722e6cecdb687247ad7f264b6c3c444395ca5ef8",10],[14200,"9832311537a4ad0425f2f06ae0b820539edd906726c21e9e7013f407a5753d90",9.317957166392093],[11607,"84a0662e0d3cca7e21b7965d836cb965357b10d8cd1f5a36f94c86ca30dfe0b3",9.317957166392093],[2185,"6fb072e8539af8700005a8f03131a478155efd5c1d6bf608d49f252759eea7f1",9.917710196779964],[4442,"2b2fbec05f0c7bf9e07212b2b8b7ce41355936ef7dd81f7fdcda46f4daf0cbe2",9.917710196779964],[16487,"73defa731ac4f4b7700ae9853dd9b7d1673a4ab284ad87a18335ba130d4e845d",9.317957166392093],[10547,"207a3de1a17416279d7cba2079fb338ca5701659d710d06ce5e7c09f1709efba",9.917710196779964],[2975,"ab5f236aa78cb8626e727322c66be73dffde92cdf51f6d46f0d21646f2d975ec",9.917710196779964],[445,"e547d3a211e5f0e2458b029494bb219ee7ae405bb2064e57db1d9379304116fd",9.917710196779964],[9978,"a8229926ac47484fa45f6e7448849e0de06469b3e9c9d19cbed8a934cb5774be",9.317957166392093],[7655,"2d4e94db305ce434fe19f8b6b555eef594eeef29f36ef07e5e493a7c3deddacd",26.647686832740213],[13325,"a99446296c32f018ea727b64b45aad1099c65d14ffae4680ece93be6698123a4",9.647446457990116],[8388,"0bc31de8de9fec5365c3067fbf1d07fdea90ddf112903b4b181443301055b2c8",9.917710196779964],[10678,"1cb1f7fa1c0bcc2ac56c24376372b0f711654f55b26aa59231aa9072d4782fba",9.317957166392093],[13999,"168d41c7c490021722dd13fbf11bb0ee0df5a54f33788b81e2d56df79750f094",27.110012360939432],[7252,"2f0b803cf240a9d2a39b835f1aef03b26b6841a09c562406f22e413098625dd0",9.917710196779964],[13603,"08b6e94d13c85ade0299c5c0aadf9bc8346e9647cdc4216248a8eeb6c190569d",10.052724077328646],[4746,"9740f318c36f5f514dcade4c556d736c9292df248f2e5f1b92292373a5a0a9e0",19.771836007130126],[6211,"663b4c7d815abf5457ee9e31b92367299e149d0dadb1dc9f2c1c1a71819aacd7",9.917710196779964],[4562,"019b10e31d0c68481b7626771f1ed9b8338a44dbf29dfc210d3cc44bc048e7e1",9.317957166392093],[16625,"59bbee8a1df3add4e0501ca1fdb59d5761855a2662dc66f3e33335b7d65b4e5a",19.22902494331066],[3231,"88eca3f37df3edad49034c9738e13cc8a7784d32c6c3b74023396541ede2d2ea",9.917710196779964],[19519,"dc4cae556a68de69af00669ce5c5982bae768dfed6be756f0713746e65c8c90d",25.401769911504424],[191,"05188361e9fa94dd6581f71ef5bddf235ff288885cba31b6b9c5f4171d40bcfe",9.917710196779964],[13895,"913d102d419a04acf821fd8cabd4bef2568eba31677d55b8fdcef897fcd12497",25.848594087959626],[18418,"7a55df3df86d4c2212fc4993ed34d7239a79bcb994c9d63128d35227597a2d33",9.317957166392093],[13875,"bc3d709961fbcc06c43a4d2f5fd136f7b3a163e0382172b7e5ccda1adf5abe97",9.317957166392093],[5180,"d9dbbd602fc659e73b1fcad8d859b0865905d1b07b002c141d90ec3279ea15de",9.317957166392093],[17390,"6a4a1f9a22bad14838e30b120fd37693b18367812baed3e8216ab9fe75dff549",9.317957166392093],[6055,"05f6fd30bdd0854212fc5ac95405bf9b250494746b1960e993b0ec123a42bdd8",89.28571428571429],[548,"cd44b095fefe554694773c882618cbf65fee75505f19a3de8ee9b5ab4a0d4cfc",9.917710196779964],[16229,"41599e86778aea91396831a0aa37ad75186118c9b0c410ea457d9b5405ef1363",9.317957166392093],[3004,"34cb8bb49ba1bcee08481cf7f8de7f323cac06afc953c8cb777f55fb88e940ec",9.917710196779964],[16963,"9e2dcbba89dcddc81fae4f4cbe6e4823f62e50290ce7c1d73cfdcaae20efdc52",9.317957166392093],[11609,"cc7816d16c0529594964ece4ff55d8fc1f39af93f9bad7c4696d633a7ecfd8b3",9.917710196779964],[201,"34937abc3824df71fd392fb990ed2bbacb23281f975d3fdcbff3de9d5413a5fe",9.917710196779964],[4593,"06a9e4f5fcd76fdb0469a60f8476346ea44be003c0f7c592ed00c1928dcfa4e1",9.917710196779964],[16685,"fbf244515fa8ed1faa534bdd7716886fff2306341ef88428bcd72d51646cea58",9.317957166392093],[5014,"f5b9271067ed1724d6acaeee6e01d8e762188db79f97a28f154db53e03d712df",9.917710196779964],[1772,"d07b58f15302ba329fbcc7bc75b76bb3a03c2e9316d5d0d363e5e00dad5672f4",9.317957166392093],[8723,"56ab04b460531e264bcb47d8324bf28653269fc0ec5c7d74b552004ac6ea8cc6",9.917710196779964],[4732,"6014446934e84ba5c4861ecb4aa7c5d25f4f11183e268cf128584b0cba57cbe0",9.317957166392093],[6681,"b70545ed3df2796d572c95d3ef52df09c191ae4ed30a33bfbd229e6a3c4117d4",9.317957166392093],[6282,"45156529a3c80c1b11411121089c8b8a9fb635e6691f290cf1a93767dc1430d7",9.917710196779964],[10512,"ab4d8639326ba449fd757ea1827c74b46e9124f5a8144fb870755d5c368f19bb",9.917710196779964],[1793,"bdb44b121d5ad5c3f6d8cf7455a2446e8d3a66202737ee9bd57380f8177b47f4",9.917710196779964],[2351,"e5da18d40af1d01ba15d0876376deea865714219d8c684ee53b5afba5deabbf0",9.917710196779964],[14417,"8fe2a6d4c8edf4475eb94ee5c5633c0cc7dc1c9322bc3d7e6b625c9834e5108b",23.243856332703213],[9905,"ad5ca940fac8f034cb6130bb81d6c882a601aa3fd0e97a657d24b070f84aeabe",9.917710196779964],[13768,"ad12a527c331b259105e902c0d8846d4c01c0767abca18054bfdb66f60f4049a",10.053097345132743],[6052,"1f6a937c58ef9cc87f16ccd4d4cbbaf8aed420d63904b8bbab207a22ad07bfd8",9.917710196779964],[19493,"5236ca665425fc82368134ed445f9cfb48d02f63f1af5210d8d3272d6b4f890e",9.317957166392093],[1332,"2267ee29272f68359fa8848220e6de3879042680037525cbdceb5491089832f7",9.917710196779964],[10936,"b33c7a648dbdc87e237acae32bb537d4b1d684d43eb5d951ed48bac70c4d78b8",9.647446457990116],[14198,"0674f2e58ff346c7ce8c2ee3b2ea7b25febf159457e602162a555935cced4790",9.317957166392093],[3613,"3b5f4cf6410f52207fca976e9010f4140f557046ea92f8528323faa7cb6626e8",9.917710196779964],[13368,"f230d4821cbfab70629a32d253f12347c30d31fa353bd4f68996cd1f8ecd1ea3",9.317957166392093],[12661,"a10b393f3e43968103b94f70f0854799cf25b6527be89a902ef837b26816dbac",9.317957166392093],[15403,"ca4b6e3ae6c838c0f444d321febd06c597b70d08dc10f34c3c8930ffd4ab4276",14.958448753462603],[19378,"7f8ea2c819e2a3ac437dfd46886c1f05e383629a45286b509ebac4cb009ba912",40.649180327868855],[4278,"222f73474a65299865cc2771a1918b4625182077bcf7040c8bb8ba650ae0e9e3",9.917710196779964],[4606,"d258b3db10660d639ae4e9350d6467ff62ffc7f4177f09c01c800381b1b896e1",9.917710196779964],[13128,"013ab9f2be0d5808148e00ee3fba0c7b29a791e7e255b6a7fe5cdb684cbe6ea8",9.317957166392093],[10410,"2d3ab1739969de82d9db711ffae793401139cbe86a7ac2802991700e089dbbbb",9.917710196779964],[18906,"13be81db9519b30fd7a5b0b6e4eb00b59bdb06418cb24a8d2f459965e8cc2223",9.317957166392093],[2790,"f2dc4bdc403665167be5a6d5ba440f62b263833d0960e51f16e8643d48d9cbed",9.917710196779964],[4584,"a68e313b0ed5cb9960c15d90aab0901ec7a44eb8a8656d5ccb30b021f36fb5e1",9.917710196779964],[2982,"4b1fb4f0e1869e5c44b663760c1695d8bd8007b8496abf6e14383baf489164ec",9.917710196779964],[3451,"1c114dd82c533105302d033aaace89fff76291ff4dc1d738ac0de0ed55fd5be9",9.917710196779964],[2012,"aa3199dd5a6c7ee496d493efc4002c8364da18e015f54d7d45d8f2835264f1f2",9.317957166392093],[18188,"4f91293ffdff1f31145e6c2e304e3024442e0081b2801171baa7127589297f38",25.88235294117647],[9932,"17b0ec69d37d1b16c5d8a60f7a127d65d6a0c45e529e38c7a9c013f4e6cdc3be",9.917710196779964],[852,"e7cd60c25a365622a4d864dc26e742384bfcfd60f817f89623d37c3557ee3afa",9.917710196779964],[4303,"0503f7138627fbd540563e34c732c4430f5c8ec81f6ded11bbf267f48891b7e3",9.917710196779964],[2447,"8fec21801a18d49b15a1d418baf4491bb624c58278e26fcdd8326c5081b634f0",9.917710196779964],[873,"5ed9dff1950cf3abfc1fedd1ad20fd1c01bce4a70fd4db3bebc62515382712fa",9.317957166392093],[188,"bea5901e909391978c16fb83af1ad8349140bb96ca9b59da89bf8c0bb607c2fe",9.917710196779964],[13538,"68499523552fdfa8d156cf755412a4d130c57ab7cdd8ea70ed346dd5fdba049f",9.317957166392093],[14490,"2f0f67c8d1f5ff5e13cc9504f41c6c331d04b6dec88ec078ea55de9370e36d89",9.317957166392093],[18700,"32818d22cfd638a1f72ce9ebf15426080220981b30b1f4c3e875a326c57a552a",9.317957166392093],[16155,"99ad172933f8b998cf4c1217d2ae88510cdc8ba692e113eb16a3ce3879a5f364",9.317957166392093],[5876,"c1c87e528d108273ae66e7dc2d908b1c98d5f78e27d219ed9675310d1566d3d9",9.917710196779964],[7718,"b97e2fc47cb09aa6569e4016c80ae8f5c9f604a0d9843a4ad3275b8931ad67cd",9.917710196779964],[13403,"05d2579a023d8eb0ae4bf16b08dc9ca5c3e0bb3bb73ba7ead8bf53a84bd930a2",31.20366132723112],[12575,"8a0791fa4b08588c8548c48210b9fcfb2e9180e41397c7b58b2cbb1a5a456aad",9.917710196779964],[3527,"58410d5da22b2223a200f2ea4451fc8e390de43c3b54c0abad6abb8302abc5e8",9.917710196779964],[9169,"9ec853efdbd09721f5246abd9051b33f279cabbd8a9693d5977f378fe54db7c3",9.917710196779964],[11322,"ea9c50dc8b7e03a3b6e8b1fbd48210a02b479929a6b6fd3360684de2ddb0d9b5",9.917710196779964],[10222,"ef370063e863529b334dad20ce368970568d70aab7d1747a6abfa20d8da0d1bc",9.917710196779964],[11851,"47f2f7f86152aeed1cfa1580fae103bdecbb31548cd28d2c7609a7aa09475cb2",9.647446457990116],[7331,"8c027e75ea75f6b50b64365657279570e73f69bed5ed8ef857c3d0161489d8cf",9.917710196779964],[4854,"9541f190bebdd6f36b3e454a90d3459dcb1bd788c0a4128eca220086a0f41ee0",9.917710196779964],[1212,"6c81f7767bb1c6a5467e9d188e3a8562f1b3b3b907e81be636500c0575cff0f7",9.917710196779964],[13843,"18e01078cd0aa55feef22ca7cd5ac0f8790d3bc56dd8a8e9e87dd26f258e7998",9.317957166392093],[10736,"34b20bb063d3d4ea2486c1ab1f90016f1d155e9cf8bc1b5cb953ac513fc0c3b9",9.917710196779964],[116,"b8297ac9cc7e8a5418af8d0f39b2d010294afcbff2d3d664bde2afb442e647ff",9.917710196779964],[1722,"08cb2c2f470fae4bd7aa5e3a573159d5bedd79d1828fcb80851801cc15d3c7f4",9.917710196779964],[6458,"34bcbce99c93370cf7c98477c2dbd0285eb237587e437aba66b784f01c5ad4d5",10.052724077328646],[18254,"058bc6cc5f81ce2fcd25b7f47e17e09a042a499542c05967acd992126b04fa36",17.101659751037346],[2292,"010e98975c560c9e941cbd6af9fce82c18b9985f46e150064d8004a328fc0cf1",9.917710196779964],[8641,"23ef4044431e75dfabcfe96d07f1952754e27b85866a0f2e2b6b170c12ce26c7",9.317957166392093],[1552,"1f2a1943902d99bf2db0946b04200d14b7b62f4d745e1ae90748037112cdd2f5",9.917710196779964],[18343,"0d01cfe471c2686e081c2a20195f8d33d2f110314cb681314d6021f3ff65ec34",9.317957166392093],[11568,"0f7da2506316bdbf9a70855cc38ce72a09211e9423db49ed22e009796a0423b4",9.917710196779964],[6973,"6fc29d8da95f20a44b24bc7af785741514a26fb77bce845c6b95ae8bd65c26d2",9.917710196779964],[3544,"eac8a54bf136fd09a2268bf480014d01802e76ca218bfc7d95108309c2cea2e8",9.917710196779964],[3518,"a8197a8a66a7600e01a0979a2fccc8e5c7baa0cdc9f7b62db3eb8c9baa1adfe8",9.917710196779964],[13054,"3daa1d06586f46c7e364e2d60c882a6a03077025881240a119f41c0ccd8e40aa",9.917710196779964],[4966,"c33440d77ad7639f802e4a266540db6e1480cdcbdd33e17f3fce3598aa6369df",10.052724077328646],[13609,"1e0bb3f8db6f80363bb2c616c22685201b9be6ac85ae573deb4c9c360792429d",9.647446457990116],[9383,"3118b5903ecbfbfb90216a80462ba2e5b2b46574462c83abf8b46a948c5a5dc2",9.917710196779964],[13531,"eda02cebfb10f5e258ed55438b6f6ad5d909b2d874be9ab89e987ba37421309f",10.040705563093622],[1873,"1294710ed8408400d227535cd2b3faa3824647ba8c4e7a717be274ac0ae0cbf3",9.917710196779964],[14935,"bc6f1d2121e078f93f263c06f565e4f3addf4ed0cde448caf5f5ea569ae01a80",9.317957166392093],[11651,"3bf9d5c1bbb72c3ec682b8106890ab101ee4439701a2860285718382d4369ab3",9.317957166392093],[15468,"c8c20aa1d1e5bb255fdf9bd8005afa9d5bbd38598e06d38436ca8a528c18d274",9.317957166392093],[18030,"277b54fbe3e69e39354d39f8c2fa123654cd8f081fc156f561cfda60aec7b93c",9.317957166392093],[11641,"700eedf92a567f58460b8832496e8c15b78789659724740aff5da1992fe0a9b3",9.917710196779964],[4533,"3da3226e0d4db487286e8913bf1e9735daa76ca238b679aa58efa162d30f25e2",9.317957166392093],[12706,"a92fab7f33cb9e8eb0b6d31e47e6622b7bc91724534141aeae3df79db8d990ac",10.052724077328646],[13497,"d84a2d65b5ae66bbe19b7684dd947f1f3d2c0fd2467fa45557a5af4aebdcda9f",9.317957166392093],[10174,"5eafd0da3d554cce80f5bbc5c476eb78f98ce2126a374f85b90481a934be37bd",9.917710196779964],[19693,"3a6f7ba806d28038c448494a98266cdff77b1644f96509b875b8177affe00c07",9.317957166392093],[15934,"69ba569e1fc62a889ecf256f28fae5d762b91c7e02906f08db893d325f46536a",9.317957166392093],[13751,"e84845592cbd07a357aafba30f819cd18d300088fc12924df87562673fa76d9a",9.317957166392093],[13504,"58f7ceddc53fcaab1d713ef2d27e37565b36d0676b69a1bae8872a8df608ba9f",9.647446457990116],[2725,"5a7f3d59c9f5ab66fce060c4daec0eedc22e133e81ea7ffe165371b7bf8a3fee",9.917710196779964],[8917,"51379a33f756353ebf14e9fe50b1719637feb9b3e2dcbd0dea84d0736ff35cc5",9.917710196779964],[381,"df441ddcd0738b2d16a42c0c01f4af9293b498b168fc8751bbb52dbb83987bfd",9.917710196779964],[10607,"8760e7577350f28cb9926be02ec346bedbaba5a196ed6896da93ffe034ca9cba",9.917710196779964],[11899,"db0dc8bbf1adf2b07c93244e96934475ef12b3511a326f9be8580c8565290ab2",9.317957166392093],[3185,"ac873a0c72152ba357e5488d26704b5d9b78d4d3aa6bcd1117ec8c73c39e1deb",9.917710196779964],[18209,"d4f2b080c9d5f2973b10ed1137b081fbcd9995a2d8b03cbb9412e00b0f0dda37",9.317957166392093],[1464,"707bcce287e9614fc84e9c25f8bf84cc6c7a2d60a2674b172929946fcbf266f6",9.917710196779964],[5417,"f170844e838f00f86f1bd1d251f9bf626d61159e480f20d457f30dac7acbb2dc",9.917710196779964],[7974,"fa80e943fd72e3fe0734e40b480e4e9f4ec24f5bb8cfa5f61d5ac51d9c22b3cb",9.917710196779964],[14133,"8769a5aada17b59f1b9541a5759973988e08317f03b1d5319664b32538d4dc91",9.317957166392093],[7838,"88c15d7248b3a3bf5f6f18dcd6a5be70db05edb87d5aa13d770539e0a6f38fcc",9.917710196779964],[1815,"8a4abf4fe13aae0f899c451b59e0e333b0d1473f6ff10daf2e82f598106e23f4",9.917710196779964],[10294,"4b19444aa6435705f18f24ceffb8338b2b9461f8de29527c43acfab270a267bc",28.14867256637168],[13681,"65d38dd3fb8469001d030a9cd732f0284e00ccaca4ed9f2ee25eab92ad279a9b",9.647446457990116],[2648,"e5f67924ce9cf506f685fd8210e2ebdc5ffd91c0cecb98d32f4d45db57cddaee",9.917710196779964],[11946,"a939979088d5a614973977a3545f5e5465e618d5261c163e081c944d1195adb1",9.917710196779964],[7203,"f00bdae4de115fee637993a8fe24703f4fc591e39b16776d9004104ddf8fb2d0",9.917710196779964],[18227,"00ba7dfc59be97fa30c92d7e18f9519ba9bd62545267a4e49903be8398ee6f37",9.317957166392093],[1942,"a61bbc4400ad666cd2093bdf77412b858bf3d258754fc7f35886488792e16cf3",9.317957166392093],[15004,"5aa7bc9b4d01d0d1798218a20701608cf307667f6db2f9b6fa94e64284304a7e",26.138053097345132],[5413,"78c6537e3d33cadcebd99a37145ed5ed6bf0751ee04a191145a5fb08df39bddc",26.09252669039146],[19112,"2271e21e72edd60707ecd33f320645b131aa26506e62304b05cae8e2839ad51b",9.647446457990116],[10097,"dd329076738d7f8f3eaa877ed5d2d2161189abd3dbc488bcbafa955e2806bbbd",9.917710196779964],[5906,"3ba2ad5454357e8265ffb860e3e1a3a6942c8e4f8fdd461e76e6471585a5a6d9",9.917710196779964],[12698,"a2aab79971e1d741c6e5b83e217ee88321e4b3ee83d18f633ac1a542581c99ac",9.917710196779964],[18699,"55d8b166f763e6e559dee29b546d3ca30e8c469afadede2966eaa8da6e09592a",9.317957166392093],[15551,"c1728a3ae91d07185aa97df81051a0a1d13e17745158f4f43323fce369d2cc72",9.317957166392093],[14110,"c6ad70374976106bdb3979c39fa505e3e3c9a90bc097f729f82d3430752d5692",9.317957166392093],[11391,"440bac90f8a1d3fcb008226feb2edd54217b528543e5a0f6c8030d855d3f68b5",9.917710196779964],[12008,"f0ab353da635060e6cfd2991745cc1aacd9a64074dadba62f4590bee643145b1",9.917710196779964],[8450,"edb5fdbd342a6ed739df1633c20feb782b1ba1281d8af091142ad6a8984f52c8",9.317957166392093],[7386,"78253f57df9b453fea3a828e22a90912e4f386388f4b2e4a932ae5d54d9a80cf",9.317957166392093],[5230,"1e0e631e205d4fcdf3ea3a9aa523f1e670e94ed3726d058269789c9cf6bbcddd",9.917710196779964],[18867,"a21a758f6c5b87abcdf1ee51f91c88779f6d513b1538fe3cbf976d7ea90a7b24",10.052724077328646],[18619,"839f83940796565c0fef8c484a7c38178b43b047d35414f6f75c8aa69b2e302e",10.052724077328646],[17600,"f7680d053aa0f85ef4e47c20f54c2c08689b9c7981e85b53c7b404ec52db0d45",9.317957166392093],[14136,"53976f6906b8d9df7d24a7582720bdb1c30f37c454b7fb27c55935600fb1c491",9.317957166392093],[13431,"fe21dc233a6c9c52642beb51e3364fcfc4168a76bb312be5154149006836cda1",9.317957166392093],[341,"e060cd25a48ef8a59ce553b3bb1edf1ef80d6e29f71445163276152ab938c2fd",9.317957166392093],[17408,"500f51d255ff26309745a1ad633bea3a5f01b6ffae7321d84bac94a7f1baa349",9.711670480549198],[12264,"4bbebe2bcf1dfd4b86e71fbe93eb5d2ef510ad8990434ff9fe3e8135d8fd96af",9.647446457990116],[15986,"4d6a19f60b01647d883ce0a485bdc21e7b24ad0b313228b6c759c0105e28b968",9.317957166392093],[13979,"a3b96ec2f5acba4e56056c06da773c36e0bf4bf9500b70c2196775f08ab86f95",9.317957166392093],[6426,"df301c6c66718eeb4e0a689b42f0374eeea6eb27e0c9eeef0adc565a38ab18d6",9.317957166392093],[18001,"760f63e648547d04c26faa84576524eafca6f0c5a973cf1f7319aa4fe706403d",28.90391459074733],[17650,"72c5770c6d46ee91b97d6a2c2023445fae81e36d27e6177b476a583c29bb3c44",9.647446457990116],[10910,"958164799a6d80ed1420f79e63955ccaaa6f93071a86dfa7b05ec3cdbed69cb8",9.917710196779964],[7082,"37588e76407448ad2503d0df10f47d2ccb1f19fe441e945ef41042badf6472d1",9.317957166392093],[2568,"33118e7f496d4b4f06499fc01422babb000f3663c8c8d00a7825f0ff7f2971ef",9.917710196779964],[1341,"d49ed5dcf18c0dd863fe9b3b115290afd2ce29afe6c1963ddf7b5c5f1c0a23f7",9.317957166392093],[9327,"a8ce4ded15c72d5e08cb6309991fe3f71f761190acee6dff94a32947772fb9c2",9.917710196779964],[5805,"ad3acdaaa788c42ee26239f213950fd57f0bbb802673f15a1d181ceb0d1860da",9.917710196779964],[5372,"de62d03159c229dadd900d93244e8c51e5c41596ee31b612207b6d77e86907dd",9.917710196779964],[9894,"feb8654bc32164399465b89377d3b7c84513cad37eea23f6657c585465d8f6be",9.917710196779964],[7299,"7ee6ba41fbe64299709bc28e48a091a69da0d77a17d5c1fd4702ce8b384215d0",9.917710196779964],[3278,"459213ea5e6758d23d8ea87c1721e195dea05c3f2202536187604876b8b88aea",9.917710196779964],[8464,"d34b032d76dcf8f29b5a7ad1baf9a36ac174add700bab0fbd11a31d948a43dc8",9.917710196779964],[4203,"07b9b87af585acead0013c0b0ab71f8a665a71ab5e9047a5065e3a8e8fbe66e4",9.917710196779964],[4064,"62c4e1e977bca274b9e3dcfab98e428037512b3a6eaa7aaa2347d18d805757e5",9.917710196779964],[4241,"8fa0b973d508c79187c30dba2bbcf981eb1aff7ecb70a85d177c38097df72be4",9.917710196779964],[18468,"60c93972eba0e3c49f90faf90570712e08fb4da0c6948e5d65260a7c9ec43f32",9.647446457990116],[18785,"eddab60421cb60ed285bd60ed8bca761cb6075c8252259aa3dab17dcc3ee9127",9.317957166392093],[10163,"1fba6ace2c561660fa73c6189db36486c08139c5666e50a74bdf164d834c51bd",9.917710196779964],[5531,"ef896a057df4fbb899e711959bfbff4c0cee468c29ffbcdf7298a50b8e6307dc",9.917710196779964],[4967,"f36fe351d56e0aa6702ad9b13db13005877e41adadc75e1e5910850f0a9f68df",9.917710196779964],[15337,"d2d381da792616c0d6fbb080e551fb2bb656a3c61fa56211ffcf0bc71e87a377",9.317957166392093],[12590,"1e42c55cde41f5db19dce1a904a8d722e51c0975de11053384f051f6552450ad",9.317957166392093],[240,"df721ed8033bdbc393829f2313efb2f0f36d9aec3142b3e4f9c9239cee3c5efe",9.917710196779964],[11565,"48a6e1292b16f6032c6085f6d8bbcc9486e17aea825547e2d1209c8735e925b4",9.317957166392093],[3479,"6d12804f40236d9fb61de9f58d86bafd7d623cf126499ef88fe9dcd36d2930e9",9.917710196779964],[4946,"a63eb7ddbc57a72b94c5d6f7cb95e8d4985e8ce1f22d704ae48553e67f5b8edf",9.917710196779964],[19275,"bb821a837a17e44de9462eea6e35275949fd0d9ccc4b1a27710b5d5d559ecb15",9.317957166392093],[12108,"2caf7067333f6f08f8462c538cc61bf10781fa8c32c09ee65cab78fca08babb0",9.917710196779964],[14291,"3c8a5e22582bb3f63617cfdf52bdab90ca5990d7b54424033904e2ca218de68d",9.647446457990116],[3560,"22300449a27841a80f24e9c7a91158e32109b8972166f92986cbe1de120b88e8",9.317957166392093],[14205,"e2a4f17269a3775c4e6da275611717ed983bec73952f9c10648ac0cea1c21a90",9.317957166392093],[1878,"80290a1657061fd9be3e8b72d8d11844b22e1f0a5e515d267bac9133d2fdc6f3",9.917710196779964],[2171,"6be34dcc7e56e4738324e797259b7dd292f96a42a92f1dea2ea5aa25a765c9f1",9.917710196779964],[17054,"1794a7ed7ec8218ae132ec677bfbc1b8147f3d8a2181b8000ac1d5cfeb990651",28.19047619047619],[5247,"53b99ac07bcd995c8afa7e3207a0a77ee65d183ee4c3b6359093a9750393b5dd",9.917710196779964],[7418,"ae895aaf9c52b6b36a3b4b8f1746b7025a8acbeb5ceacd86633fb9f5dc9546cf",9.917710196779964],[2983,"0ed5a9ea72e04e4081aa3dcca2546e3cbde250bd45ca506d483705253b4d64ec",9.917710196779964],[3068,"3ecfa634830eaaa78178631b73e01e71b7e9587d8fbbe10557ece8020f18e0eb",9.917710196779964],[11148,"b2d7c0c7d5a2cf332ae3c3895334bf42476134d0c16b6e706cb8153c8209f8b6",9.917710196779964],[6561,"600251967ed9c376e1977dcae757d1d9ce8af7ead564cc33fdbee3700f78f1d4",9.917710196779964],[59,"211855bb4cf3a238901a3656e2d98546bafe1fa1f6a3676f892e24837cb495ff",9.647446457990116],[6139,"43ea698d8edb2fdf214657b00cea3c39352f70e13f2a7637f095b401e8f937d8",9.917710196779964],[6106,"65fbd3e6a8b8e8d2e6abf48518e2d639682c56274312d36f1596e70d40fd64d8",9.317957166392093],[16941,"bb9549382977dd2ee9a2a46e1431edbd3a7b3c58d3028b3c985f872be0874e53",10.052724077328646],[1532,"f538c529eeafae2265b86cd8811bdd4452214294ee0fb76d67c7723a30c0ecf5",9.917710196779964],[18539,"fd85cb6ade62fad91b971138b0af016eb84e197d2416f0ecf8e2e7600a17bb30",9.317957166392093],[13459,"1b52581bcc85635dd53666af9e81f30ca785f256c6306e5adfa298f06c21daa0",9.497326203208557],[18047,"6f2bb26a4ebb0c3a912d7533cd37672df0d8b6ddb02aa7efaa444a290a1a613c",94.5903890160183],[15805,"c9cb79232ddd16c3739da9738c3d62bdcae42f77bd4f2c020b64b82524b5456d",9.317957166392093],[10587,"855436dc1f6cd5e36541a0f4dab0e4b2f6cef84032bbd68db6f66e60a83eb5ba",9.317957166392093],[9453,"73b3b3c621fb9845d9f48eae17b45d753d84b6687c30948ba2f0469e3d60ffc1",9.917710196779964],[13002,"159c77a7d08165f51186b73118f318f162c82887c5cd333514158d4461fb96aa",9.917710196779964],[6148,"72f48e53b6146a88ae2c015086b1005e736dea301b4ef4f428ad7483b92726d8",23.12041884816754],[12795,"3e13c7e94c2a7b90ed2fa526352883048e210b938ecbc02ba4ab9d088288f1ab",9.917710196779964],[1055,"827d2db41c50bd8402942da7a8177c268804d2050eb6a28fce52c8b4593ce5f8",9.317957166392093],[13330,"76e9ca671cbcdc552d33223cb6ad21db6dd162283959027d45788246416c0ea4",9.317957166392093],[8458,"d8db85c57b1207d9c3435f1eee717239eb778ef2b10e7ae202d008a34f5344c8",9.917710196779964],[7491,"e3efa43b8595b4838411ec95bdc50bba010f47bb972468080c13a576ba4ec8ce",9.917710196779964],[11777,"dcf5599795fb4a53e733e4c237d32dd55ff32134c69807639536856e5994dab2",9.317957166392093],[1391,"a7cec88ba1631607e410d2201a4755df884b63744913fccb54e6dc985076d5f6",9.917710196779964],[13588,"d503df3bfdaad499cd8258832f088e31df7ac1069199effbcbe1aadcf0e9c29d",9.317957166392093],[6081,"b35156c623387720270f95f1c591bae6d9e392c33c7ca3dae8fd18799e1b80d8",10.052724077328646],[11407,"0afbf0cda799f6e541f0816a37e426024bf7541025554b1f4590bc5d3c084fb5",9.317957166392093],[17198,"741df8055f7185d1064b469cc7e4339c6d5efdb3be5a8fe1dccba52192d6c84d",9.317957166392093],[4529,"ec15cd4a0e989af030f08b009a901af190c9b89a51bbbda8bcdc632fb3ef29e2",10.045662100456621],[18666,"22ff301152e319c7f8f6e6cd47c092531e31073c8801932d7fc3e7caf36c032c",9.741496598639456],[281,"6924380c929e0dbc53dcb5746748c5805b3f16fe3e8694dbb13cdf98ed1211fe",9.317957166392093],[17640,"15e6371087e5684c14a65f80f516e2b0351de3013cf4e860b19bdf41b5f66144",27.159763313609467],[13719,"260a5d6852d32f6054d22e2502a3b3037a26ab6bf925259cffb2ac12a8d0f79a",9.317957166392093],[3965,"ba5e5b948b0d1fafed474c6171f00ed5609a95485d2cfb37256a83026b61f4e5",9.917710196779964],[10296,"19ce5b335684e7efe1ccf2d390d231d06e2ac9841b89b7a4da26c527734f65bc",9.917710196779964],[8545,"8dcc133750eef368064f303087ec6b77801675957727207f9b1b9d59767ac3c7",28.098939929328623],[15877,"6561edd6c4554a8faee430862febfd53ae50e732dac04222ad47c0dfe199786b",9.317957166392093],[19766,"459caec44c2742219dae70a481a0c104d5f1afebb64ac3c7e2351bb2c3c5dd03",9.317957166392093],[15789,"5d53bc41c0e2e2920051f19205f95a6cd879c565b4bf4eefae4033a29d1c8c6d",9.317957166392093],[6463,"27f7366192f59bf9014fc2748377a831bcbecfc4e455daafc02edb9989abbbd5",9.917710196779964],[1564,"c8e50f9be1c6da5f8da32ac447ff7cea14c1f6ebe38e6122992b35b08c52baf5",9.317957166392093],[939,"53270d6be8a7e8e0d516f8e5c2dfa715eef4678372ef2b806c1dc92f7e6891f9",9.917710196779964],[16031,"9d401655eff3d7e883c5add5c78931fed58d7cdc5582fa8688f110e8949ee467",9.317957166392093],[1029,"99e09dee667867d7d7fdb7f2076cc0ffb7a1ad05d1258a48118455a008aa12f9",9.917710196779964],[14257,"494b7a0daaca5ebc77c5fcb7650bd643646d2166ff1054bde80becd04830b18e",9.317957166392093],[19673,"ab878dcdce1ad5b7d10b48a2a96ab68210597b7137e29d1b7984a2cf0d457607",9.317957166392093],[8645,"3e91a7c5f520394d33911455f7b9d46d2d1ee88afa6c608499756840954117c7",9.917710196779964],[2475,"ba44cc12e7cc55e7a3acaf8d5c2a5a8d73dab0d52b8a47d69f76ab69e57a08f0",9.917710196779964],[1860,"14ad8ed51b363a2aa289b1dc5a5ec0c2ebcef3f3acde6254d1b55b30c2f5def3",9.317957166392093],[17636,"20e01545e0ccc3670f076848d12cf6317acad53a572f1123152dfa29971c7f44",9.317957166392093],[5055,"023d0e5000b6e78790ce8e59dbd6f7651ddc15c090256b83b7b55e78887ccede",9.917710196779964],[12741,"53e4d9c6801858c0c9c40ea1abf67d8eeebfbb1158b96f00ea36a50b3bb14eac",9.917710196779964],[7459,"9ed734ea24f5160cbff68ae3b858f80cd8ad0ee3a05a34bd62585813c20806cf",9.917710196779964],[17730,"75996a0c327bf9733b369f0d7e6c25028d7c34b4083c10109b07afe06e3da142",9.317957166392093],[10128,"c523dc14dddc959adbadd089d3f7f409eb0926368c909d90c86c0435141f81bd",9.317957166392093],[10041,"558ae41e11486eb7697ad1ff358eabd2ad6afdc424adfda553844dd9672a16be",9.917710196779964],[4422,"bb07241e5a56e40dca71f68a9d9bc674b29729b5ced057410d3e5536ef3cf2e2",9.917710196779964],[12789,"dcacdea5e6a02572caf749582543da6f4f3fe82169268082ee62ca9c7acef8ab",9.917710196779964],[9221,"9e41cf5af6b876ecb89cd136f3758586603882c293072afeb18d8701e55156c3",9.317957166392093],[13942,"26226b7252a0d7b05e185e649be11d390d83b10d6a3fa3245b5fc5962d722996",9.317957166392093],[703,"71f1f66afd8441dcc9b9b9acf3a58ce24010ed063dcdcee674f3e83ea7f639fb",9.647446457990116],[12144,"06381f0809a09538838f2a76776d89d84803d86945f23da5339da76605e063b0",9.317957166392093],[4346,"5c41dd2d685fa943fe2491ef4319e217d574cdc92fba98f5367beb58c9436fe3",9.917710196779964],[17053,"7d81f929e9897b2e5348b24597bb733c1efe189971f23510e983120d15760a51",46.3458110516934],[16195,"0d7a7f86c7e0c9a7896b2bec0a74c5a4ed9fe506cf2ac0954e973ec171c81a64",9.317957166392093],[15888,"db2430484956c8da0a911b666517dc4693fb23a944ad5b926d9a0ae8acc13b6b",28.066193853427897],[10903,"2d3d5735d04d39827e5b3c987a5b48e0dfa5dc2d6a421c22423809043f7aaab8",9.317957166392093],[1205,"dfc44c1bf45997e8252fede19caeaa3905619eda46b9ce0388963e0fc3dafbf7",9.917710196779964],[14329,"41f29489e3d3e835e7aadf5fd49fecbcbce612094f142cf790e72c74b7d5bc8c",9.317957166392093],[14793,"7c0f36ec2037ff6247485afc8fb5f933c85f9f9637090f54d6742cbcacaf1783",9.317957166392093],[733,"9481fbe1d1325f939eec7513f282c9a6dda982d6026b71df90a00b7d378502fb",9.917710196779964],[17886,"1fa6dd243cf2383279ff1d8b8fa22217231848c40bfe03768273dd09677b873f",9.647446457990116],[5408,"302254fd077a25cc1ae15e1d634e94816134110cb5b409045ae94d7d473fc0dc",9.317957166392093],[8832,"8e86066e6aeb3f8dd73eac45c2ad7d7dfe7a9d971f2299583c3f08d9d1f0e7c5",9.647446457990116],[11228,"ccb5a5f769de81490baff7ccb8f65cfd4df0a39f56e6d97670f78164e91285b6",9.917710196779964],[15137,"5499a8a738d01438a1e058701da936f1b6390350f548b967fcd5d414c66de87b",34.44839857651245],[13555,"4bda618d6b6e881d746f8d8868729a98a0a257da14aec4a8d628d70e94c7a59e",9.317957166392093],[19252,"e5972aa14c0966b9f1ce67c5f4e811d9b2de7687cb7271366f5f444e536e7a16",9.317957166392093],[2631,"2835ca8d3b98de2a0ba8f71eac0832a7af16b5e4ba1441b7de7c4ded0534fbee",9.917710196779964],[10358,"8564d964f091786a4662232be046d3bfbd4bc34fd4800877dde14a56bc4803bc",9.917710196779964],[4644,"2c5d2038a2f03d3b0fdd90dea28d630dd085f68084b1c65cb21d96deb52559e1",9.917710196779964],[3562,"ac18f8fb6fa53e94a3d84dd8faca1d214bda4a0d058782b4eae85251299885e8",9.917710196779964],[19653,"6ef769bed1da4637e6f74a5ae1b04d864cec0274ef519cfd1839cabbdd8f0d08",9.317957166392093],[6967,"3d2d3d4fd103c06720f6e80df5e424c59300f268954280ac1fb00172bb082fd2",9.917710196779964],[15051,"3476cf95cbc4d4b7baabd1c711c3ca5312d7c6640001a204e81f2bb75bf07f7d",9.317957166392093],[19538,"64c6947011f46622d169f492563de90094f07c314aa324604b961ae311342f0d",20.060913705583758],[6214,"d6d4e9d55ea66660022a73d36b4d57eb4ef765bc96a8c022e6be16999c8ba9d7",10.044213263979193],[15034,"e52fdb9abf66d31621af65d7c8618d7d2cd0cf6f5424b5b1b1f0060c0d67c37d",9.317957166392093],[2589,"261feefbce573f22170ba92ec1604b50a499dda7bc758c71a33cb80be0e238ef",9.317957166392093],[10881,"3220ef96b53192796dea2b7b6909fd963d3083208a695aa2fc52652f9c46c3b8",9.917710196779964],[1421,"2de9927e195cc7c463d20d4ef8d3f9ab2622db2d9cde514bc39c1cd487f5b4f6",9.317957166392093],[11848,"d6eee8b8ae3e7fbd576c89691fa45a1feee8ffa46570c3fea1b814325f4f61b2",9.917710196779964],[9428,"e043dfe10f1b859feecead5913e2b0a329019f8bbf51a60b06552b7f79152ac2",9.917710196779964],[6138,"a9bebe5b2a164768fa7c3e0849f7bb7b18773f9f4af826bdb2593ae6bd0f3bd8",9.917710196779964],[5597,"b568c8353dc5448846e702c19d3e8b2a0d1d4c6890a729ad1fe7bc226e55a5db",9.917710196779964],[7775,"6484bf236daf89d38b999a07756a655384776459a2b001a2f04e63c29b31f8cc",9.917710196779964],[8611,"88650a589f057cc544a4b1a9d0b1bd048c26f0d19fe36d318020793217755ac7",9.317957166392093],[12132,"d7955ef0ea6627950dfcd3bb43e2ea5a7170c03bc2b69b74873f27378c9b7bb0",9.917710196779964],[2986,"12e144dcc913457505f1394dda09c0feb377bf25356a6c7f1e94af9c08075dec",9.317957166392093],[2148,"0d922fa25d680a3fb1f498797de5304e522aa24b52f8b7b0781d52f8ea6aebf1",9.917710196779964],[3622,"3a21351368676ef95b0078b94599da4ac59519b7671f07109ebbc217361c19e8",9.917710196779964],[13985,"1145edf3929bf9d45df8d7926459c5673bc93e402ac9732b07d417bbb1694595",9.317957166392093],[3007,"21fd65dacca0321b9161979164b4d991c65d0d98cd44a97bc9f54f8cb3673fec",9.917710196779964],[1721,"318756293c16378a62586374795061927f2ba0dfac8f425caf688d884047c9f4",9.317957166392093],[19691,"ff0bb751a4cb23e15344f6dbf6cd5650cc24209a7a0140c738244f6ac8831307",9.647446457990116],[18753,"d55d4a2e92e3c870e4a9999ba32ef6e4434238417e39bd52bc4bf09cb84d7328",26.15481832543444],[6015,"60f7222ddba443cb9f5d2de012f2296071a8ae06392347f2c04214bc27faf6d8",9.917710196779964],[6114,"989faa0bcfdd83eba03902117ff908dd96c3c17d10e0e853b3d2fee51fb753d8",9.917710196779964],[13331,"5096f946964ccf8c286f0fb0f900a9ec04c224c141456706e5491f356dba06a4",9.317957166392093],[14114,"be36b9810f98d86ec07985c4b780c9a687f8849c5487f926c2847fb1fbaa3d92",10.052724077328646],[5229,"b8b988d1f06eb1c89e136e3aee74865c46d582a44d48076a450b2fecfeb5cedd",9.917710196779964],[11945,"f8f81d67afa4646f4d490ecb09b46658b28f84f6261fa47806957d7af1feaeb1",9.917710196779964],[3611,"e57880e9749ac6f82f80d8baa739e3dca3d80fb251ad6c2217d14845b42a27e8",9.917710196779964],[16051,"4770866b8bd8fd3ea1f11d6e6c955843fcd037746ec694d44670b33c822f6167",9.317957166392093],[8524,"18dde83c55af7b1416d7b1b4e9c2afd6a7ebb7dd8214669b235864e2021addc7",9.917710196779964],[13124,"9477265d651f4df944c29f0135ca32473c774b221fe54bed1444a42ca9957ca8",9.317957166392093],[15064,"21513f5f4609fee77fa36af1dc4fb5f4320c5b503db423756f26d450f542527d",9.317957166392093],[6294,"3b16e434e9acd99846ed898cb85f428e154ccc369ab2678a8e5fb3f072a714d7",9.917710196779964],[4292,"9f5de699c19f0c8c83ed861e7c975c095f3b71280843853a398216582346d2e3",9.917710196779964],[2082,"38a2e4bea00d3776d5c9dfb7bf85ff64a51b7e9c01f996424f597c6fec0c5bf2",9.317957166392093],[11384,"465d8873621897d0771c3ff0e2fe9f424d28fee07dced5c89d0781e3cc787cb5",9.317957166392093],[9051,"f91882430900493a7ecaaf6933f65c2da12716565258b9bb14a2920dbe0473c4",9.917710196779964],[11176,"f4e195dc2d0a295443a6e8e23bd89003cfba62763b7c0b8446cd0e7adc44d3b6",9.317957166392093],[9306,"81b9ed61d243968b234c9e1356338327bd4361fc0db14a71d37aceb51608cec2",9.917710196779964],[16501,"6e58ecdea3431b39930ee8fff8859f27718dd90547c492123330e94fd1d1335d",9.317957166392093],[10269,"098a41e6a200bc2415d7fdb05eeeaab711048665e2e4f9299076aa67e92a9bbc",77.00444444444445],[5015,"870924cc5bd9b536540f069ccf10f2a9bc0949156bd6d082da06c499e6fe10df",9.917710196779964],[18934,"351f49c115013dabfaddf099876eb9066102fd37bf311c02837912c745bc7a22",9.647446457990116],[9464,"c110f85ce1a8548edfaca6886522bf3b8974076fa32ae426a0543df27321f2c1",9.917710196779964],[15280,"d9d1e5a2a39b7e315d212e4cfe8265bd92c139dd857f32e64ea391aad5fec878",9.317957166392093],[19311,"490cbec90dedf9cdb34648acc8a04d41658ba56e170a21253c633f0afbe79714",9.326968973747016],[18058,"1f478ee0804a69ec434c6a4cbd52d06edd71f60467c70064ac10afc5103f093c",9.317957166392093],[12477,"2a3b87b8aa7fe6f0d7a185deabacdab1f14306a751bf4ce3721ffecf28f512ae",9.317957166392093],[12745,"20b5f0dc8cb8e64b580b4d18b6aec5a0b91f7122edd82e33c6c1a1e903b345ac",9.917710196779964],[5514,"47364a9dcceac9f12056433a964080514aa12912015b846225b30b564f5726dc",9.317957166392093],[16199,"c7ef6dd4b6f4b22795ef8ca87f61af997fca145764f69d986d4fa181e1870664",9.317957166392093],[12536,"aaac08afecb59cbce554cc7473bdefa8cf641fec78be1e809f508320b36eb1ad",9.917710196779964],[15980,"17291ccfb4cd8d4da1259f3de269cbfa207cbd241d1e9a137a2137ba4a13f368",10.052724077328646],[9612,"56269a16b69bbc82047148609ce092e16c07f683f73763a56fe44ba41ffcf9c0",9.917710196779964],[8182,"881104aa0b886be4e96fceb9e4f6733a248458b4e8f82b57ba8924a9aae119ca",9.917710196779964],[8176,"5b92684cd31713603e3b3c28fcc4e70c854bc42f67c9aac96f1772c7fc7322ca",9.79605826906598],[4683,"65e688b3a4b476c52ab49dc80aa136ca92c8b533572aed62d26fefd3be8c1ae1",35.87081339712919],[4293,"3f800b63b50876bd191ab13bfee55ba6aabb55c6f851d73a8a55bea26a69d0e3",9.917710196779964],[11715,"4ebff8bd62987495a97939cbe23f2a7ed19c575437a51cfe33da11ddfd0537b3",9.917710196779964],[10292,"3adbb6a278d94dd1f259cb60f489e8383708dcb51abbdfbce903c28218806abc",9.917710196779964],[8904,"8b19c2a069513dc377d29b4b7901b99edee666d8ea82cc61a34e917527496ec5",9.917710196779964],[8774,"ecfa03e8b18eb9a4005a46f9c871d60bef9072be23f9496167b78fbb00af38c6",9.317957166392093],[13967,"a0019c6d9d6ba97af564e8eec77b93a82c6f12afd070cdc810aa0cd59b0aa595",9.317957166392093],[17045,"726b0554e8948cde80016dc84965d53a84106fc3162c049f7118481287e72351",9.317957166392093],[3245,"5df191684c1118c11c0b108e43d4e416d84c5de7e1d87eab944fe5950c70b3ea",9.317957166392093],[15770,"43bf73aba2d0bb56708d02781a729eaff2aec95583202329ddd77c388e8cf26d",9.317957166392093],[7611,"7f364ed8a45789e0fec285952bc9c6a442fa7a2a96b3a9c9cc0c85a5d6f224ce",9.317957166392093],[16112,"ea3adb24a64cc6fadc85064f56948d2bbeaf7d769ee31b6140d84f0754a6bc65",9.317957166392093],[8354,"5f142497f5d33b091c27496e447b7077cf154038732d33e351a5aed14b63f5c8",9.917710196779964],[5377,"6f5f79c5d162f1155d62a50766cd7bf225cf7533721ffbf66e6ee2b685d1f7dc",9.917710196779964],[18788,"98813b4ee05c5d89dcf52542b14485e34f3855b6e3133515ff2b077b341e6227",46.35240274599543],[11694,"a3e75d018236edcdfdba9a63c0a8851263f5825564aa446873de60882ec853b3",9.917710196779964],[16426,"739268371c11db363d651b8e1561dcd0f448aec70292fe790ea335efce84985e",10.052724077328646],[13065,"c672b5fb8c8ca1fe77136c303772d5331642d886b189b8251ad86ab3b3b733aa",9.917710196779964],[15926,"66e2d790a96e3a3c83fa9c04cd4d9974c83afda67d238ecd74c471b3af7c946a",39.87185354691076],[12651,"09684e667a0ecbd578a9175fe0a41683ecb9ef3feffd2ee537ff47dad838ecac",9.647446457990116],[2651,"b196ec3ca65c0dc4873e539e009d9191061d2570ff1dfd4ff3544d7983bcd8ee",9.917710196779964],[12165,"de3fc865b579e331bdcd762e43729cb5d736b945798f32a420b49b19751144b0",9.917710196779964],[6422,"cbca671a74460dc97c0f790a84deb0792f2d20c719b65774cf76416a99a926d6",9.917710196779964],[1179,"7d3ad4f6230035a33664c638f7cc0ba96599245412c5688c329f5e1c0a3d22f8",9.917710196779964],[6735,"d590fbdc0aef8329253bec6ffaf8d9913f3fb15d9a4845a4db8ee10dceeab6d3",9.917710196779964],[15129,"a2d442f4eeaceec6dd570336d8d186674885086b8bb2016dc234866a5347217c",9.317957166392093],[10190,"b480f2830483943a17a068c5ccc91f924e03bae62fa71b260acd0399815e13bd",9.917710196779964],[4081,"984bcfd7a289116933ddbbd891bc6c2390a5b2cc7c168f2216058c0d2d382ee5",9.317957166392093],[17484,"f07993f4f7c10a72bf51c7b13963b44090580d37a978f6801ef4d5b169abea47",9.317957166392093],[15655,"fb5ed024fd61d3f5382041764a7e2abecd92e83cb4b58ca58f73c55d48dc3b70",9.317957166392093],[15358,"7ec032748cf1fbc850bb0bcb98f1179a4fb7e8bee10018290f1e1c7c0ea14077",10],[7873,"bbfb6ba48e219c817a4efd352adf1a06cdb34c2392e94fa4cc59a05e04886dcc",9.917710196779964],[1822,"6a885fa1f0ad5db222138b61f8f732d30b1159039789710e8c1fea9f326c1af4",9.917710196779964],[2562,"b4281e00c3da35330dd9d31f774da355db6af68d49f286c6409fbbe7d33a7eef",9.317957166392093],[14236,"1a2ac5018d3c19f6556fb5aab7ac914cccfb973a19ce4287b781cf90157e4f8f",89.3869625520111],[16241,"be1e4e48717741c8b3ae8429d38a311400b5f4e7dc7242ab6419995cba8ab862",208.46715328467153],[12502,"7a3e6b72a0114c6a907edc2ed7844da73cac935e1431f391b6f7901ac189efad",9.917710196779964],[11761,"ae3fd53ef3d05647904977ad4a889aa2939f4336aa3ba55f32d4e334a472eab2",9.317957166392093],[18918,"b03857979fe2df53f6cacbb1d3723f87a68b89e2480b405525253ed4432ad722",16.948421862971518],[7028,"9b920927bf7b0aa0cc0104da712c24e7bb7e971c17c52e79fb6acce4a54dd6d1",9.917710196779964],[413,"79e461cfd2c3f69fc8ff6aca0b4a869d08f9cc971402af431463c491612348fd",9.917710196779964],[11697,"66ddd1f7f680782462507c6be573f22a7f2e487bc5a3af60cc76b01bb89852b3",9.917710196779964],[17189,"76c45482d7e2f02a149693670698473d4f2e3121e13d67b204e6fa3cac33004e",9.317957166392093],[7929,"b2b0b56fc11516903326a1bfebfaa0fd09d89e4e7f85e7274e76b4edd7920acc",9.917710196779964],[10457,"7fd9924c4c47d1eeb66db2a6598dd154518ff795e5eb8061443d99124bee61bb",9.917710196779964],[13304,"7268e98b5d751bce043b8b905416da3e4a5f2bd7dd77f44ef3d64007770d7ca4",9.317957166392093],[12233,"5fbb41ba5074ae42080ac7bd6b7cca238b943e9aeda54506a78076339404ccaf",9.917710196779964],[7831,"74d972126d22c28f62ee199c6d091eaf4496127eb777c6116bcf9be39cc995cc",9.917710196779964],[10034,"40fee768caaba3a38913edf5909889e3df1d3f63b2037bc6c47574c2017b1abe",10.052724077328646],[19845,"db6c33be9e5195d4a7b8cbae5ccbec9f8ed6787059ce22f23259d75d5e9ff600",9.812893843916626],[7194,"5e229f25afee2b9ee62ddf9bba3c67e76ff279e6c4128acee4bca4ae7c75c1d0",9.917710196779964],[7290,"849e137bbb22fcf3bb98e32572fa729cfd38ae9db60496be00f3604b53ff23d0",9.917710196779964],[17914,"db026d70e6e4e2dfd54c4990ffaa34febcc0feecb716e16152870700f79a073f",9.317957166392093],[5008,"08b90e6120d7801cb42ea142051af29dd6790658bc32c30b4b5277328ffa1cdf",9.917710196779964],[18110,"7562a39fffcd050507321358b3e316c39b29aa01197fac5a6e82c52b8b37b23a",9.317957166392093],[8068,"08f5ce9eaa00d6459f74867ac02e17baf8b15896faac055e04b3c2d18445fbca",9.317957166392093],[16579,"928b6681ad099e1965548d7f2e4f7fabe768edbfb805bf5205ceb70ea2617a5b",9.317957166392093],[9926,"c8b0706f02fe10d090c5bec1118e5813ffa33562e1c5790c611a3546650cccbe",9.917710196779964],[15261,"d174d8cc14162d1399bf2221eefe72c4e092156fbb7e821b0ee2fcc9c4373a79",9.317957166392093],[18490,"2a9ae8c3da06039a2341e5253a45e8c1d3d1080ff952cef73992f3ab25d49531",9.317957166392093],[10899,"3f130c244468d866405c2ac7930345a1246cdf331f9d120479da7164be24afb8",9.917710196779964],[16622,"137c3995d6b78354f905882fa9b2801c472d3bdeaf60c7c40dd402779541675a",9.647446457990116],[2653,"ba7ed7365192a6b0fdc8a6bc75d61e6c90292bfdd945ed6a20185b1a70a3d6ee",9.917710196779964],[2216,"ca1bafeb300bcb92703feb5633ae05d6ae91f6f049a5d1d5be85a05d7adc66f1",37.11246200607903],[19027,"44e180f9aa64c4269befb155d64d2ae7c1090e91893919374479c2badb35ae1f",29.01511203751954],[9980,"8c8c4d77533c61546c4fe9715bc837f7de8bb8ad6268514048ff3b0f81cb73be",37.25170068027211],[5169,"656a51fd53376dd914c518fc79211a1b03c6df62f5adee9cd62c6eec3fa429de",9.917710196779964],[10615,"d359bdf8070700476a0381633939140df34ca4509671e762b20df018b1bd94ba",9.917710196779964],[15728,"8bd3789973af033751c36d3f5811ab197fad28b9462ccf560c26cbffc826f76e",9.647446457990116],[7191,"9de323bd76d79098a2bf7e3b6c15d3a2d466c11e5e3239ccda82b45e6731c2d0",9.917710196779964],[18880,"1148526d1408afdbf58cb425f89ff835461c864dd9eb753626850f7233952924",9.647446457990116],[13348,"67c30e2b7953e45990bf8a742175fea978eeeda4d49632bf657b527a3b548aa3",9.317957166392093],[14994,"4df399c64ba846ea25df87421755892dcae366002dcfe63a29c40d0201cfa97e",9.582887700534759],[12639,"fd09602db66513dd154e1f5dff1ad06c910cbce2ea1477bc6cb6bb850c2d00ad",9.317957166392093],[6100,"cae4b6c9d0a3a7e361ea1b424edb9b6596cc412f857df3be14af03ab4dcb6ad8",9.317957166392093],[4124,"b27a18d793923abfd2cf48c3a416c325cead0ff05204096b2df46f142a69e3e4",9.917710196779964],[8350,"e38d8855813c657a090542718321c62a8a48883a84db40c924c123d347cd01c9",9.317957166392093],[10703,"10ed7c9636f0fdb9664f07214649470934392a99c30022041a75f5e18fb6f9b9",9.317957166392093],[3014,"2c6c2b67e9db14506398d474d5e11b8417b8469008fbde9abc3d3e9f401433ec",9.917710196779964],[17105,"3d3351f1fba983113c243268457d00cdcb6b89b0924c89ea70c00f535e6bd74f",9.317957166392093],[9752,"0015abc667db9c515df832617a7a33867d45b37e02a53d7031059f128f9900c0",9.917710196779964],[11753,"ecbf7a6d5873f1caf24087d3eade4d51c70b68c282832505a7563771e973fab2",9.917710196779964],[11526,"c3a5fa4eebdb6621ae26d8dfcceac5aeebf6a240d627d127995c8be60d6c5cb4",9.917710196779964],[7095,"8b885f68b4d0ec56c39aa9ec6571c3912d7045abc57d97761a3347c4e74a5ed1",9.317957166392093],[11103,"5877bece0527e1b7e1dda54bdeb97cd888c13eaaef45206160e4adec3ce538b7",9.917710196779964],[1959,"004d9c5cd0942a81d1dd11c211829166e4a56e2a760e92a9b78af1fcb2204cf3",9.917710196779964],[10185,"c6c3bb0a4b17441ea973b4851bf035bb5fe6019f0db462872dcd64806a461fbd",9.917710196779964],[18980,"65016a50fe98c986603cbdbc990e8029387f9d4a20db6c7ec3b5eb8e3f7c2121",9.317957166392093],[16710,"4b8cbc1cc674c46d65fe5d5dff38d0302013f10a22809e72274fc9b76e8a5458",18.326315789473686],[9875,"8074baae3adac5e79d9333ff0e1210e67450a0c5455526cc64313c92b87018bf",9.317957166392093],[4004,"b9cf340a926fd9b2406f3cd548a8594b110da81e60f22bf82aa18b97cfc9b2e5",9.317957166392093],[19455,"065f7d36fa43edb9ac8f19400a4ebd123bb81d8ad315f544e2814825bfbfc40f",9.317957166392093],[13743,"eddb0e44b24c0bcb656cc7cbad1e6afa83141ded97c7e5c03cbac2d803aa929a",9.317957166392093],[947,"fabb7efef5239eafa6c4f72ee99e736e0950ec13168b20d92a905a51c08b84f9",9.917710196779964],[1709,"8e220ae4da687d375c7e25a3f647fa58d71adae92d55e8a24a0f6b6a1154dbf4",9.317957166392093],[8907,"22755d9f284dac28fe0b7de5a013f141bada997ac0948be0f731a6b95fbd68c5",9.317957166392093],[15619,"1f57ccbbdc5d96a0d7007946cb8eab5dde7e6822019efdd9dc43630cc9e4fb70",9.317957166392093],[4570,"3bddf1a848a35e010fb0f6b216cdea0ab2d58b00a061ab2ae99799245c44dbe1",9.647446457990116],[16774,"23502863e59a25c6be97e6e78838a88dadcbbcd86e87930e9200ce7ddc6cf656",9.317957166392093],[19041,"dec337fff18b7ecb449c776b6aff46a79abd6c4fced8f339eee1f3aed4272d1f",9.317957166392093],[1395,"2d4839dae940b63b88dc5e49423eb78ed2083db14a1845eb07890462f2e0d1f6",9.917710196779964],[6312,"0985173441e5ba6c10c64dcecad14e34f844bc8af3d29f12de4074a77558ecd6",9.917710196779964],[16314,"a41c7067e839aa2ef19be4e5bb0ce44665b9ec0ca652a986acaabd0a9514c160",9.317957166392093],[2836,"46171bfc928b8e783e8f346fd4b63961f464e2d114bab0773bf919d7c2226eed",9.317957166392093],[14399,"e8e5240a23f564d63d87022a66604cceae3b6f7e06a89d60c20a0efa4e2a4b8b",9.317957166392093],[9022,"de8ed349752d6082b79b31bfb1fdc5f78c1908ee71ba1865d5345d59ec7fa1c4",9.917710196779964],[17154,"6509e0fd8999989865a4345d919a70d3a2b44fdb7ff2cb2be9b5baed2c20fc4e",9.317957166392093],[17003,"e8e678b6a528169491435f5c1c3bd63d71232cc88ac36ead432e9dd24c95f351",15.94306049822064],[17742,"101c51a08d9ed0f89302bf0aa67c1cf937a97473926743c36ad807a202615b42",9.304433497536946],[7306,"14026b75d3f0414e6c8a0685091c3423922b71f7c183ff1f3876d16e75ec06d0",9.917710196779964],[13238,"8465a7d56661f4daca60b24cba25a85e63b761c0559f8c426a92b79697c723a6",9.317957166392093],[12263,"2232721cfbfd51040506b2b5873955ba1ffe10ed96c14f8aed4a83bb9a8d9aaf",9.917710196779964],[3852,"fa6e2e572734f745463e5b3dfc6145ca6e84d41a8346cd84cf263f667542b1e6",9.946524064171124],[8101,"15524e52a86a50b8675237bcefb6dd99e1defed95ac48e1927c2c00efe5dc2ca",9.917710196779964],[16401,"adc6d53c231d0a9ad1f823e062b5c01613d3c8f38b2a1cd46be66ab3234b185f",27.661631419939578],[9150,"d3f17e55307e24f9f02eab2589777178f2a97423ff4d08f3bc2c00cf5e60d0c3",9.917710196779964],[8226,"12069e7cd3128c16dc6e564f5d4d70aa21a4083758cd189fa4d2cf2942aec3c9",9.917710196779964],[11441,"c82a05c6d8d286f8a9b09ad6f519c16ffdb4a6eaea2f032c2a7c579f5cf700b5",9.917710196779964],[459,"21bd2cbf87e972b412892992df365f713cf197ace5981e16f292e13b789bf3fc",9.917710196779964],[18769,"786dce6cf90349c9d95e400489afad1d7709d5bc6468d0550c058cd0af380c28",9.317957166392093],[10994,"aa6cfa7adad3ff7a2899d73dbc9ecc7d35a5bbebed2734b7939f79ae1a5906b8",9.917710196779964],[13230,"339910b11bdd9e127b39dca9520aa418f1bd213ffe37d675ea4c9a702a3054a6",9.533923303834808],[15651,"cf3ef866c5303f683e250394ada57ab165c050cb1287de1e5d367ed104244d70",9.317957166392093],[15312,"1d00614b1b4120074b3fbf7f91dcd16025feb9cb142bcd75d38e84102b491978",9.317957166392093],[2113,"1648d438bb66a46a1d3879dbc7bef17ad07a9ba8369455c5ad7528ce857e24f2",9.917710196779964],[13886,"c9821335fbd52dce74ee3d11de073eb815306d1502ae669ede8e9e59c4314b97",10.052724077328646],[8861,"6b9d2c77fcd2737c1c0c0791cb525f6295b8333fc2bf07977fdb58fdac29b5c5",9.317957166392093],[13572,"597e1d85a7e0f60d3c470575d4d4a4a54caf88a2b0d70070eb3b473db4db2c9e",9.647446457990116],[5281,"ea382c83b548a9aad87385d055e80d0065e5a1a239468d4b181869cfc80286dd",9.917710196779964],[916,"e3aa99db8e2d3cb249ef90493f26ecde18fc27f19b44d944b500d7df7210b6f9",9.317957166392093],[8693,"e94554f3eca794c1465b62424650a32a30d365790744a1c5c6e308d1143bbbc6",9.317957166392093],[5286,"47a4f8687dfe5072d991c0084cd27c2c84c6b5a2c02d1b7cc05061aed0fd7add",9.917710196779964],[7761,"4e915720d980ed123081ed6443f30d871579e73dd162e23da4fa3316d75010cd",9.917710196779964],[952,"ae3894b7f704213fb36a97f33167b074fa1ebae9b9e7b1f5ee5e3fa2c0d87bf9",9.647446457990116],[11522,"a7f2adbbd9802e4e4505795fc8607b9fb3a9458bcaff56fae1949c477a8f61b4",9.917710196779964],[9763,"a6a167f6eda6a050bc187b0bb79e570df54b11cb2402399ed750f9e080c8e8bf",9.917710196779964],[4160,"a83f9f9b72fe9e0ee69addc490e426824f6d2da9d74165d6c430b29c7156aae4",9.917710196779964],[6558,"87b8d67d5c23fd5d1e0536fd5dc0aa1075393f937362ae379590dff05a58fad4",9.917710196779964],[11664,"ce70169f7cd42d24b919dc42cee6d2be80d32a56e5201f52b7b73ac23bbd7eb3",9.917710196779964],[14094,"be87559fbf0f9d98c8847e155b7a8bd80f9aa50510f7f917b142acbc9f5eb792",9.317957166392093],[11461,"c736b28fab93e4dd4cb74b98af5fc83d49ff1db93d10726d166e656de705dbb4",9.317957166392093],[14269,"8e0d3c2a5fe10c6043005feb63bf7308d19d28012996d572419613944a938c8e",9.317957166392093],[7216,"e05bc6336c9128c11c32fa82d098b3693ec2d5b4eefe52d8e7775742910393d0",9.917710196779964],[6932,"2f7bc9a0e1df40b3cd10e1dac4363eafaf8b4289c8f4d0c3ff775a20e14c6cd2",9.917710196779964],[7782,"b098f85e6b1bf343c9e0cbfbf76440267d80e4812eddc4d2296184d7597aedcc",9.917710196779964],[17470,"bdcaacb2ad131e4e9490c2aba6d2f5c08d959da352173cce12a38e5cc19f4c48",9.317957166392093],[14589,"8eeb43223affab0055e80b87d31de6573048b39bc3b7ca1204f67e63a56d5987",9.317957166392093],[4343,"b275a069d85c8aa3e6b676da4f4afd0bd9bc665fc26c9f6d0aeb1c6844fc74e3",9.917710196779964],[17469,"6d11ac86f60fb4633fc3aded1772e83bccc4c89e9e4cafe48ecc66f53f395048",9.647446457990116],[3588,"7f741375189e040a3c95f6a0fcb594196c6ec3e04ca91c9a30b0dd6c666162e8",9.917710196779964],[13032,"2bfa45bc65b6b6c02a6ad603d8d4fca15fc5a97943937b7a958ef52aadf163aa",9.917710196779964],[10029,"e46e3232586997556b5c87fb9dc5469929bada7066207b934e174eba472323be",9.917710196779964],[18927,"09c6f2e3f29ec1c5b8b7c240cf55b457283363d3fac3bae8ffa4a72567a09f22",10.052724077328646],[6008,"705e960630a5483cdd627fad397c5f56178496330dec890ad13a789b58ed07d9",9.917710196779964],[7240,"b0048b4d9938827b35ea6e273444f34118596352f96516a091d25b11222871d0",9.317957166392093],[3409,"ea93cb0a2d565dc35d96f16de59bc6345a81d689b86f4c4337a124153a339ce9",9.317957166392093],[7942,"a23361ada2f0380adf9f74d729a31e27f3f2a2acb1907ae139f0eb94bf9cefcb",9.917710196779964],[12697,"a71cda6f0851e5abfefcd6a02587434886d359fce3ea52dc9f074d8b125d99ac",9.917710196779964],[19195,"7fdd4f9d2c9438714e8666caa165105b562f82f2ae18be15cd6872201579c918",9.317957166392093],[4856,"ed4242adff0351c30e225b59e1355b59224b51f06441ba93b12822f5ca1b18e0",10.052724077328646],[19088,"7f00672b4a4ef67a8a14178c227ed70cbec93918e9b54a4012cbd67437e1101d",9.317957166392093],[5747,"61200217afb4674f535d894c2d1c61f79638971bf24025fab63d3ad60e4eccda",9.917710196779964],[18713,"c0285c836f4146362ac80f94af2033ef3373102a39431401adc8d89f2dc0cb29",9.317957166392093],[9992,"c4c5f55d1302e01b1450d62d253a92e5d40f58b5fde10b50007a509b0a0761be",9.917710196779964],[14283,"c65cbc9a0dd1bf53245b5cd9c3eaa53ef159134a3901d627d158b77924790c8e",9.317957166392093],[13324,"eb484640d16940ff6c395ab77eb9066ef6b4668a13c67f62c8eaf396923e26a4",9.317957166392093],[17202,"981152b1a119045950c64a5744d76aaf414a20ed555db7d83fa9c8a569fdbc4d",9.317957166392093],[4327,"986f276801ffc0e467ba0534d6a2fc14423088cee9bdbeaf0c8566ecc7b597e3",9.917710196779964],[10275,"211e5fe4b01c013899adf573bd0cdc350d36b259d74b9c7f35de512cdbe18dbc",9.317957166392093],[9395,"9a9d4fab8ce315f25257c31d0dd7882df4e88c2bac38c06f38d83fe6b0dd4ec2",9.917710196779964],[9158,"a0151b2327e9a2ffbc166608561be374280d310c3d1a7798260810e97a8ec6c3",9.917710196779964],[15073,"1ad00bb1683fffdb003eb8076d3ecbb6e0c7bbbcb9821298b12329305231297d",9.317957166392093],[7635,"0934f0ea300035b6fc18256bfa9968c38c0075ee02c409cdea6ce4c5727cfbcd",9.917710196779964],[5659,"b67742effe1373d5b123a70ef6ebde01b599574950c799d45d5f901ebb8144db",9.917710196779964],[16940,"602ba5e611edc8d9e146644f49635e30394b53914edaa4839d316d226e055153",10.052724077328646],[13922,"43fda0a977a5ca3d71e2ddfa6729142f48b4d982b7ab06c35a33643548847c96",9.647446457990116],[12251,"68eb5b66465445117a8b28d73486335f7c2c2b1e24971a825f08ce2e4715b1af",20.03647416413374],[15554,"6a908c23769b26bed7d616caf3743dbd0c8553164089261b816cae6fbc87c072",9.647446457990116],[929,"c4f3550beb3ecdbc22d3b9365943f0d3d121cfb2614514f8f4a98fd3e19da4f9",9.317957166392093],[15134,"2e76a5661878dc5bc72774836c216563a4d21ca57bda5baaece3d3c40943f97b",9.317957166392093],[11913,"368e90d28144500d64090db8b0f03bb0e9a18dfacad73e741e51d4ebdf29e9b1",9.917710196779964],[12589,"f92366c6943ffad7a1a31d2bb38ee778a14f3cc6ea7b45e782480abd3cc055ad",9.917710196779964],[3123,"a0010392bc3b534452410650251b604754ecba25fa7cdf9e0269d16eafc383eb",9.917710196779964],[8355,"ab836dfeb967fe68c5dc67a67708e71022ebf59d0e7469952495a0464738f0c8",9.317957166392093],[3273,"bc94290ec2ed444aa17b99dc5d34299d5f34db4179df0c612106240cc30490ea",15.944153577661432],[9040,"886609a20a53dc35d614d6a317ffabece53b4db73bffbb0125d7f2e6d9c884c4",9.917710196779964],[7971,"98a03bf91436d1d162fcddaeb2aa712e028ecdb0fe3187d4397db94bb7c5b9cb",9.917710196779964],[16200,"45da3d59a2b4c715760929d386ca65f4ac368358f239084c5ebc14e7dba5f963",9.317957166392093],[18288,"64821a2015fe71bbdce655c5665ce1711067a1fad76b4606b5b2da0c71060636",38.17040358744394],[13163,"5fa26e79796c39288f8e4bc896d9a73f09f78048031ca6efc979ee3c91b1c0a7",26.115555555555556],[13091,"34353a5915453275f5c87e367e391ce5a666d6be60fbfae5842932ed3d4dafa9",9.317957166392093],[18258,"700259341f157b319ba3422835a2d19e0d4bd4df2c7a0183a8e1b270c4b6dc36",9.647446457990116],[1133,"9f181198539c1980a63829b71e5ea69d94ac15dc7128c6f08f60c84fc91564f8",9.917710196779964],[11111,"d0729fb408b9223e16de15ca6501ec015a2b264483caee65be548a3d3ae432b7",9.917710196779964],[9254,"6a786257792eb9f1df22ff98badfeabf5b6a3a2d589cb14e2c09411cd1091ac3",36.273972602739725],[10534,"bd3c21b7beca90d5f36bde2902fa3c765317e1628123f17ca40e5ba9b3bdfaba",9.917710196779964],[18526,"a47b0b13df8a8687584ff69fcd8c2a4c7b387b4f3e386eb967992e3f0908f030",9.317957166392093],[12524,"f004cfd5b669a7cd78e427a206d9f69e6b8440a513cd20d5cb60e75f270dcaad",9.917710196779964],[2877,"24192a3550c2b3263d24b7a1f56ffd483da381d189fffa2c927e5ef6fb3342ed",9.917710196779964],[8778,"cf57449e1f983ee170f59729748a8fd842f6cbab196d8cd0f28c3b0d2d7931c6",9.917710196779964],[10373,"ae80d9ac9fe495181c9c201aa22015689ffd359741d1a84996cb7414f522f2bb",9.317957166392093],[18339,"7af186e20fba479917ed4dbee7cead30140cdf86b17f7ef7f9035cd3a20d1535",28.846975088967973],[14631,"4050dd70ad534add5200bb1d9ecefa5bdf6fe6fe9e25c4233deda67475c75a86",9.317957166392093],[3001,"9653fcbe8f719bb1a2c3d44a59f60a4f231270101a203e20338a245db6f544ec",9.917710196779964],[19018,"742af5094edcd20cd662aa2fd3bd04d2cf3baa6b851195a71ed654852b7ee51f",9.647446457990116],[4540,"a3e720aa2b5df9ffe59462ee552ce849db0124a8ac39b17618bd1aa8aaea18e2",9.917710196779964],[1228,"df18816390dc38317b7f7a72ce9abb560c56e33ad672bde67e0275eb66e8d7f7",9.917710196779964],[8218,"7761ed8881cc1edbbdf9bbc0402c4da74bfa835f341e1fd0ffbf459e82d8d9c9",9.917710196779964],[11551,"f86eca8babf67b5d38a2fe8f632769dbcf29fe284789b94920daeab040903db4",9.917710196779964],[18223,"aade368443c8864b1f512fe35371b867b8d9d5ed243cf9de60bca1009c4d8d37",9.317957166392093],[7805,"935236a570210d6c498036377b61f2b6232c16a9788aeb388b9955e23018c1cc",38.61187214611872],[10110,"9466cf9257652ca53a63243203a8337acefcc2eab805791b975a37b69c8a9fbd",9.917710196779964],[16972,"58195242d11b5a8842b83b0e3a6f0d4a828c87ea1d1a8a500972671bb926a852",9.317957166392093],[18365,"1e664d17e8f2b3cee3315a7d0859181b91497607aeaeb261c01be4a9de975734",9.317957166392093],[2029,"bdfb75e641acfbeeb71aab20a89c898a0f9272157ec9430e3bd0793e4ac0c2f2",9.917710196779964],[11805,"093c6c2206a061bd9d1cdaf72cee0fa7952885c924ec0482e7461a8e48a0acb2",9.917710196779964],[14965,"1ff6032c81fe0b360de13eb0b57f542ebfb4811c91861130a7e362fa26983e7f",10.052724077328646],[1685,"f78fc7e4a840b40da6872f73af9923ddd44fb9e6360483961b302bcaa02705f5",9.917710196779964],[19544,"16e266a3cfda86d3c4589e57f079c3d19b942254914580c4944cc92f2fdcf20c",11.301587301587302],[14294,"27c2f79a91c62f98da2d36191a89e57fe96b62174856c03a7ca37251a6c7c68d",9.317957166392093],[1398,"09918d00081888d5dbc27ef7dc027553dd12822f2932d57b18376acb1180d0f6",9.317957166392093],[2122,"8d95f46dd684d3075f14f365c7f0a529288e5f72ddc9c3a05dcbfd69472d1cf2",42.66202696824706],[13407,"9ca10c4b861544606205800824f770bc408f0263d9eb4fb9e5dfb72a2d122ca2",28.02659574468085],[9899,"0600d11ddb65f5b8d8b17399b3fe8e7961dd109b8531d4a7b5cb2966b982eebe",9.917710196779964],[4707,"762e394a9ebd6c8d49547e861a91172d2841700af6c3c14bc02e6af5f3cbf6e0",9.317957166392093],[15660,"39622d3a2d0b63eff550ac8baf81de0f8f73294b5990792ba80f316705e22770",9.317957166392093],[13888,"f92a10ae1bca8803ae9b321299a56181fb4057611c07d8239bbd645399484897",9.317957166392093],[4139,"5da71f89bdad35e5f4886c3f3c5f3096c623f82c9c9e06ad2b1e55769061cde4",9.917710196779964],[10450,"422397694858d1d6a19ae6fe8320c80be448f5f51773811f5bbfaabd78ba6abb",9.917710196779964],[16310,"ac882944eb4b2e1c29809371292d8bc5c9fd1929679ec4bf603c5431aa90cb60",9.317957166392093],[7593,"316d62a1ff0811758372acfe9545f7b771c1b0d039f01d0149e62e607f5a37ce",9.917710196779964],[2788,"22a8d9e669047100ec7204b1d253d59afdcc99c7bdc46e1a078d7da4153bd3ed",9.917710196779964],[16584,"7bbab92f2afc869cd7e62a24c21c4e25404d026e413431f28a0bcb101dfa685b",9.317957166392093],[17953,"73edc8116a92a8941a61188cf39031fd5f58581f4b6d8990709332ebd362303e",9.317957166392093],[2716,"9f69b33d47bc3a2a61bb23feba81c835a9f02e65ce4eaba50b42e8770d0855ee",9.917710196779964],[18055,"21cd27935f72c645022a27b7b072a86d6ec79eaa3dec67ea906e612d3fb8203c",9.647446457990116],[10062,"1766e9108589ae3d7dfaf008eabba3734a43948f0c265219f253a810e4dbfabd",9.917710196779964],[10103,"fdede337d80533b8b5f691531f5d94a841a4cc3b73879b7b9d1e05142269adbd",9.917710196779964],[2387,"3a90ddba4e934b800557911fa213453698cb18260f163a6ca03472d88d9188f0",9.317957166392093],[3002,"a7a981730f0d52f1133f6718f51c7feed3a98e502256bbd0c76f3595903243ec",9.917710196779964],[14984,"5bd96255dd5b7f5d1a5bf28e9e68f473209800c71757b2a3ec3d745fbf96db7e",19],[18664,"b1699b44c8eaf7be054b562b34db92e9af5ac2e73e7f4b6ec28ace6dbf9c232c",16.01426024955437],[10422,"b96602426424af07b187c7fceedc4744ece468d666c720784f4edc2f8f9cabbb",9.917710196779964],[18682,"dc78ea0f453bbc30c502f4fe8fd14c031987d5de4586580c620390b1c8231c2b",16.032654938484534],[17998,"423ffd53e7a655821ef46061f31c57be3e6b9a0c5534526ed233fdd028ee443d",9.317957166392093],[5259,"ae446e0edf7ec75e7f3ef5dae34dc21147a943063c0206e8d042143322a19edd",9.917710196779964],[16539,"06ece69c3491ee8c317158c6cee645314db7f5aa734b55faa13ccd5abe55575c",9.317957166392093],[19005,"5b062587c66dc7151c3ba2e35204985a07bb2a059b665b492f140a7a88b46b20",9.647446457990116],[5152,"d292855394ffa28896e2648ed4726a2a12ed12de15c863fc7ba26843343648de",9.317957166392093],[12585,"3d14a9c788b4e545b0a9b4d8d7bfa01988866e645caa29b46bc01fdabf1a5dad",9.317957166392093],[16852,"46bdafcdf95e982078e159ac679abadcdd3be674946c731dd15783da84c63a55",9.317957166392093],[391,"6c5b9c0df15aa3bf616fd65bf50766eed7587e637a229c1ebcd0ab0f7c736afd",9.917710196779964],[12328,"201ce839b2d60e69f8d1c3b14c58b638bd366f13b79728a8e2067f9748b10aaf",9.917710196779964],[7915,"54b871a0a61ee9cc1d95956cc1e127da0bff45c035343b40789ffd87dcc01fcc",9.917710196779964],[17514,"a513f70268ee9d58ae48313839ca5c1539d936bb55deb448083214ff07d93647",26.118721461187214],[17556,"2fc6afcac5c0e3780ddcbe0c7ebfe50c3d39d2c513bd0eaf9c1c5f3465d95e46",20.13605442176871],[16879,"53f9ced6c5bed2828e53e686d42868af9e53e4e662a456fc3a7c7caeaabfa654",9.317957166392093],[4036,"18cf8bdf3f69f8763518b387ba2d7929ecb675e199e1e70d8cc8b8f000a086e5",50.623885918003566],[14249,"01cbcc2718193dd6fb869c97571ee2e9b1566fe8e673a1f5d016230e4428f98e",23.105022831050228],[487,"7a34ea865444a8f44222cd35ae071a002b1f6748be2a0e51708d4db39940bcfc",9.317957166392093],[4634,"a964fe07f603df1f9a6f0b9d4006793564009aa65d427f8ac24037750af668e1",9.917710196779964],[11991,"a4870727f1885034505113497dc2019ba9ec7f3af8f2f61ad53d0f24147d61b1",9.917710196779964],[2460,"db73ed0a054a120cbc1762a04d65e3cbe0bd4342cdc0b11ba87c73e0a50f20f0",9.917710196779964],[17169,"173f9377ffe0439796566553337ab67ee4cfab4052b9901c47afd80250c37a4e",9.317957166392093],[9733,"c2937893f8f41635c18752b94c129e3922da15fa8769bb9654ec12e61e5215c0",9.317957166392093],[15999,"7d2ed0e2718f191c2aa5ac6e226fe1dfc2b6bf8a9a118771af68b31482e68868",9.317957166392093],[2452,"b2f9264b6bbac914c48a4cc712760b3ed9e46b330c8a54a1d2889c43f7b830f0",9.917710196779964],[2273,"6619b2bcde844cc8e4ebdf7c095d5bc56b8e0854e310f368277f28ad429b24f1",9.917710196779964],[19692,"a0c93d2e6b78fd8e4a8ffa5d7263683f691997161edb6d10b9d2b0af95e60f07",26.138053097345132],[18679,"c930273004d825c05cd83748017d28962561889af1c9ba02dab94744c55b402b",10.052724077328646],[17286,"ef9d8cd4e07f12c40b4c530a4fafcbd043e22620fa88c2d9849dda465964794c",9.317957166392093],[19742,"b8a71335f702f69cd3aa4df0ec4508e2434e6a9d26c6f64f3458bc464e984a05",34.049886621315196],[4298,"c8f19a4c2e9262857d0a855b327caec5ab6bc56a60302ebcf833b767523ec7e3",9.917710196779964],[6937,"ce2bf9ac5f56d46d504cfa0d163ed4e6ad119d9103e4694390109ed3672166d2",9.917710196779964],[850,"a73a5b2daeab302ca62a7942c0a3c838d2512f49d87a59ffc8a812b9d5a03cfa",9.917710196779964],[11916,"ef6d9e289e460ca3bc4ccddc8332ff9e1feaec6d932c9dc6f13dc005a137e7b1",9.917710196779964],[16411,"4b07a4abb713f051dc9d44bdb624720cbb386b13978fff703a542552a943e85e",9.317957166392093],[8225,"f5a1b4272f7d5342baad698d0ee3b9c85e0b7447940b82172351687ad65bc4c9",9.317957166392093],[10045,"bb79d543b9c18acd1d23f87dba1c8a8cb5918af24f267531576c819090e813be",9.317957166392093],[7309,"bd769f218fb26f2dbcd073cf00b5d1fe08e56b0741d47d171f30a9643ca902d0",9.917710196779964],[13278,"dc3418ca234cbd950a915e1cd341a139f005fd6b31dc0512bec2bf1f55cd0fa5",9.317957166392093],[10545,"0fea3faf20ecdd235041c8db4a25ab27d4772e3d3d47d99a45153ecaab40f1ba",9.917710196779964],[18108,"db9f038c16530a1347c7827fa7ae038c92845399d96a6b5c116d6232a626bd3a",10.052724077328646],[18355,"b88b875035a7fcb40534c603aa6809d328f95b114373996c10a0d693560ca534",9.317957166392093],[19127,"bbd37ad5c30a9247abdc94c170b898358a15819367533afac29b32e612083e1b",9.317957166392093],[8466,"83c89a710a003545f4d9c6f43e6a43d41eefac9136d8a00b861d642443763dc8",9.917710196779964],[2455,"0899d640a3760fe0c950aa2a069cb404537c83bed2a849cb28b205718d4d2af0",9.917710196779964],[2350,"3cd95899401a36a97edeb5e7998a6feb52314d9f4b4b4268f42be2312a40bcf0",9.317957166392093],[16035,"b8cfa32fcc1d425599fd6bd4dc0715d914bc539d1c8210b50133a519f983b267",26.84149855907781],[5201,"f325336c6651519c238e33470f2e8818b83ec93a2492e57391ed7faa6f81fbdd",26.225312934631432],[374,"51679a6236ea227e0d904313e8fcf990866c75da34833a8767b27de6381689fd",9.917710196779964],[326,"a4ccf3cee6358561a12849d9269ebe8e984e26c834e0a50c73861f0658e4d9fd",9.917710196779964],[18049,"ee5875b495cc860109d072219e1bad77c89fe278574cbe970dafa50742c2533c",27.77810097652192],[5269,"401ac6370783b550a89702cec8a8238b67b7fedb3985c5d8da06a4b6d2bf93dd",29.861946902654868],[15704,"3d9faa7f9a128b86c2cfccc1ddcad1ec5a648dc0e515b53649ab69ed46a76f6f",9.317957166392093],[1219,"39aff51a224a75374e6059cc31744ee021ed90ce6091421c55083523cb7ce3f7",40.121580547112465],[14464,"ee21f1b94282180923b9a1ddbca1b63bad082800f5ada6e56b1ee86e2f97fe89",9.317957166392093],[12799,"575300db3ee864911308d1820fcbc7f49aa623f3e4a06c7533aca6defee5edab",9.917710196779964],[7401,"6dd9a031dfc644f9e1d3504f15ab5b159ff7c18030ee10a74165948d951d6bcf",9.917710196779964],[11323,"ccc0eb716b7f4a6a2f13e9e71e5dbe6d8da09654ccc656846eadfe1b8503d8b5",9.917710196779964],[9505,"ddf4b2b4be0faab9691d3856e06b2955d78704bf6db7bbed7d3a09191c5eacc1",9.917710196779964],[8587,"11e74094b710b3528eb7ff7eef0fcb46ccd81d809a3088557a2a56cffb7683c7",9.917710196779964],[3044,"a7a11b2520561db94644f481d684ab274b9b35864931175b9f4da289705f06ec",9.917710196779964],[8624,"eae6c66d9cc92d2198703670c368b1b4d0754e30d95a3c9c0fee3e799e6d46c7",9.317957166392093],[2709,"a21e9f6ac657a38038b895610774fe07abb865774ade7f7310d3cea82d1066ee",9.317957166392093],[14830,"b398ac22cdad8ade1dae8a30d7c1f422f16020361ecb20dc1a92156491744682",9.317957166392093],[15643,"9d7c5a4eb38905e39012b77ed4a99beebb8455f04e5c2457234eee5591f07670",9.317957166392093],[15856,"823f11231f3befcc81b3070670dbd15ca172304aa685110f73cc5dae1a2e026c",9.317957166392093],[12170,"b6fdd785d1e10ea7819b7757d099ce2b8bdd43e493fccab82545ae112f643eb0",9.317957166392093],[3707,"270c251518419e8f99d0cf085c248ee07d0349a34d4afdf3d14dd9c5248c8be7",9.317957166392093],[3615,"0b8fb9da3d1636e41be321afece69cca7dcc79b96c87cd63e41642f699b922e8",9.317957166392093],[11104,"621b3f4890a0a1cdc3c0fc2982a43a860a0637ae45436b9f219ccb6713d137b7",9.917710196779964],[4802,"f9f2289c5cdc585062fd27deb00e0728c39a2ba6f91518e92d6ddf62d96460e0",9.917710196779964],[6678,"dfcdea732db44283ed74afbe00a920aebed082bf27e7239cf56782b4f72722d4",9.917710196779964],[18715,"76c1bb37bae1e9345253ca03f5ab8a55ca2b5d895fcd9468ebfcf5de0843c229",9.317957166392093],[1795,"eefe9b9cdf89cd62b009007bd8be3a080afe053e9c55812909e8e2ecebcd45f4",9.917710196779964],[17993,"d0bf4e841ac737f107b424fb533f2661419e9fcdb950bb6182f08da2b6265d3d",9.317957166392093],[19664,"04ed5894b576fdf2d31108787f095cfd02324d16248372ea40cc4aa50d2bb207",9.647446457990116],[6723,"9d8337252a0cc537ee08cf8b217a3d859154796d39cb8b6d4fe19f07cececbd3",9.917710196779964],[8622,"fe94f2d3b8075c3636b5716b127ceee50ee1252dea054b3489594aa5038e4ac7",9.917710196779964],[17758,"f2021e4481688fa22cab08e07d055373aa06e04b8fa4a59bdaa5911c20f70742",9.317957166392093],[19362,"78cf7dcb4555f1724e571acb25a31976a983f6301ba222d022491b984a314513",9.647446457990116],[4456,"e1e4461b95f05ebdbc77525e166c0929a600defc421ad8ae261871b08f8ab0e2",9.917710196779964],[5202,"17411de2f23e24b98e58f90b5cc9f3d74dfbc89355705fd3d2c809c89ea8fadd",9.317957166392093],[6863,"bba74b3c001951ba71f1a9ec2c64b18842d1d75680e1da2eb5acef451cade1d2",15.055079559363525],[14767,"bb1aa5f3c08d9d1d856aa7f44a5805f64f29a8a98fad269ac96656cca65b9483",9.317957166392093],[16062,"822ab528d28b4c7c3fbaaff3e35b861db4969baa7dbbf498b65d1cb482a12367",9.317957166392093],[10366,"1280ab95ba2e4a62c487a72910ed4f9a022e47f55b35619a0332155b8bf3f6bb",9.917710196779964],[1630,"9ff7e79736bc04008021ad7160cbbb87e3faa4ae7caf1c97f3a4f39cc12d6bf5",9.917710196779964],[18153,"0eaecd414de92bc1ba8b139b48fb4ef7aad491a3baf3b375b9eca2c216b54339",9.992962702322309],[8890,"6e96e496e1f5d62fd80c768168329d0c44600da0345899f621e4f2e380157bc5",9.917710196779964],[2757,"4654b009031cfe00c3ec1fc77e4ab1a35d2792e190a1fef820cf7d9da31e0fee",12.56637168141593],[18118,"31e5c23b73bb93e6ea3a97a8c8fd5126d1526f84cada13d7724d39ca4dc2803a",9.317957166392093],[8262,"8fc8b92b055fefc07d6c007841e59e137e5f9a5cfad5aa02fa11a59a48fa97c9",9.917710196779964],[12667,"30b330c8376918f8abd3d3f04e459498ab8cd68baf29edc1310c1bfc92f0d0ac",9.917710196779964],[5394,"937fb564b5af7d4696d433bef616d7db02ed51be56f01a2cba890b28a70bdbdc",9.917710196779964],[4839,"d70d3591ac9a987a7dd28456840faa0084fd26824509b3eaecefa147ccfa32e0",9.317957166392093],[8538,"008d57af25a3ff18330ee3b35585a1e2609ffac229fa3c0d2af368fb83cacac7",9.317957166392093],[10352,"88b11b30d96489b0fae5bdfe0658eb68374e24fe563e4bfc0c43986a603407bc",9.917710196779964],[9813,"9d430fae4bca1524258b305a66f3fbe0f63989171ba72c6717aa80f462918dbf",9.917710196779964],[12632,"71781cded1cb549021cdd826f220c5f81c381519a930644b6ad664de115110ad",9.917710196779964],[12329,"5a1bd521145b19ac586bed2cf2e67ec8db8761c5f7849ae52eaafa0b72700aaf",9.917710196779964],[3504,"39175c530fe509d4154b7b9312294862cfb26b155274424f8a28cf16a2e5f6e8",9.917710196779964],[2408,"32295e0e2d661770cbaf510498b31f7a4ebda0c2d8b4015a36eb11c95eb369f0",9.917710196779964],[14669,"bcfd4004ef9764915c8338c329b97da967169b8dc69bcb8321d16764645f7585",16.056140350877193],[1452,"54fc8dfb5b2939685c4fc033fb7281d76707e20db27351d3f2176969bf017ff6",9.317957166392093],[197,"5d14f52d6766c88d607f49a5c9653b159c741fcd940a7ab8b035520b539aabfe",9.917710196779964],[12699,"fe584ace14fb0883e82aeaee100ec9c17c2f89e6f1a01bec313816d2ab1899ac",9.917710196779964],[11693,"c29e7c6fc9246b1689f96bc1cc9edd1627fa1e1582f057360b17001a3bed53b3",9.917710196779964],[15563,"b54b49752dea1191351aa488a4a367d1b49cb7c0550b42cb795d0b6b878e7b72",9.317957166392093],[12786,"1acf86b3f4cfb51d5bbab8cdec668f1ae3486ed91a845158009f435da788ffab",9.917710196779964],[12515,"13c012a936dabee97a6d55046aa216ccb725639c80c1412c283a86eaa8bed9ad",9.917710196779964],[743,"cd323f25f43fc56d8be4f3a77e1acc8232754e52be1cbcec235207fdb3bbf3fa",9.917710196779964],[3154,"d45485ffc6eec5b7e724b4330afc20a7f40fff7a1c9267b84adcb6b299b855eb",9.917710196779964],[1537,"fb82db80566efcf385b4fd2eaba8185e7f352509ad451b028ce19d2b7f7ee8f5",10.052724077328646],[9098,"a4b9134c0cb7f9c418e1935808a03c136b5f985afae3a4e176a74faa639d2bc4",9.317957166392093],[17727,"242f0d7a7be9f7e7dcb13c1deddaac97d2df74eff2a261d2538d0ac48f38ab42",9.317957166392093],[7912,"04417d77acece6ef96af008349c7256cc8a0a768697976547c7a34e997a929cc",9.472566371681417],[13557,"8c4547077d3068d05d77b364f8e5eb06e45c092870439c3941898236d41d969e",9.317957166392093],[19461,"3c300c070ccb8bc64490c660df2f4213b18af6b0936fe8b17efe689d32199d0f",40.69230769230769],[11214,"496adc308a5eaddea8f8c3aab32bdc06714ed65493550003656b032de95a9bb6",9.917710196779964],[15598,"1f9892032e6ff9475dd444d142cc9d0a20f8b8eaec10c508cc60e8da74276871",9.317957166392093],[15630,"4599a4e0cdf1a9acddf97f1e384ce66c4293806bd56b874f10fa9ae28875b870",9.317957166392093],[10838,"e9512f5f78e31c45dedde66c50a16d2bf264f633ef62baeceb149fa3e3cd10b9",9.917710196779964],[15962,"67cd92c146837c101d5e374df6c49a0d8e2690190b851584d645a462d8e48d69",28.075743913435527],[13216,"91573f087ab0a75bf77baec218d8ac913a0900c7d795003d005030a085df89a6",9.647446457990116],[15314,"1355513f9cad3e96a4390fed74e61250e6baccb4fdd5e3818f3ab521815b0678",9.317957166392093],[12463,"b0394ef33216dcc18ea8f91c86d8e0cd5ca3be870d163c87b363a71f895639ae",9.370116971970868],[16435,"76a26748724a2c66369d0dc75f810f402fecf552264987e94b412becf6566b5e",9.317957166392093],[8109,"a550ee9bbd901f99b54ed57e3e22d35bd4af32dbb27b88a2eff779af327bb2ca",9.917710196779964],[1033,"576ebfe2fe2635ee6fd7fb0b48f5d7bd8a3693a5f88be74150e95117e04710f9",9.917710196779964],[1797,"21e8fd5884d88e30e6ee8e069b9c2d0781d8fe2bc82a9c3fa6c768308e2145f4",9.917710196779964],[15211,"0baffcadf0882a1d29301bfe933b73d7c732bdf746c02f3f7ceb0a53822a477a",9.317957166392093],[5245,"9e4f75d1bb7e214ad1b55b26e23bcbe7c93148091ae69c1f4d76264228f8b6dd",9.917710196779964],[15333,"cdc5369e64ef2e5671573d51a970fdbce5c24ceb4de657c6fe678e85b76db677",9.317957166392093],[3076,"cbef01b43fa902f43fb115d7ddb19c447ee5c70baf1800f20c4875eb85c8cdeb",9.917710196779964],[8301,"cc2f03ad17bfd97e5e49d3a112035a35946c7af8baf1fa9596c183464b1455c9",9.917710196779964],[15078,"a6797f902ac436d8c21b7456dfc0b88e4010de30c2bec7655684b698ff201a7d",9.317957166392093],[18843,"a1bf30e3ebb3e487ee4178400c22cdf9e5d67acc247547dab13ea7eedb8a4325",10.052724077328646],[7389,"f89512f1d944a43b24ddc70bfeedb46fc2c0840049af128406c2dc50f9d37ecf",9.647446457990116],[11726,"2a4a84fb2a728cbc1d74ccb8f1027a282414c3c74b17984afcf625ac2e9c1db3",9.917710196779964],[19794,"b9a95c6e8c0fb5dc367d44d36fb76f89cfdf0a314b55f9a2ee8cc2e837cdab02",16.035634743875278],[1624,"9be0be5940c774e9da0992dbcfc7bfa8109d1b889b96bd3e9f5316ba51c46ff5",9.317957166392093],[5063,"5b7f7233f5562ddf5c9d54b0fb44f6140cf5d99758ab7948a072a08ccc2ec6de",9.317957166392093],[17987,"e664f1019d103bd1e925b009e128d2c34284971a4afd3c16d2ec220ddc5a6f3d",9.317957166392093],[1019,"f1242b211ab7cc9636202a11a15d7790c71db90e2de1bdd0057803e7f2421bf9",28.097560975609756],[9475,"5440d94e0613e0b045b9e7f87313a63467e57f413d20f8d570451bfffe74ddc1",9.917710196779964],[1833,"df81c224899893eb0bd312ecca03c0ec97105e9d297542f836ce5b6afbd60af4",10],[12426,"4e9e560146899dd59a0f622a7f8fb95ad4bdb4e31153f312acff3186d30969ae",9.917710196779964],[6683,"8c3d9645d5c539bd61e581a8a214f595b3c68764c785fe35b83c9beaf62515d4",10.052724077328646],[237,"fdbe03da3cd41e3ad678aaf36522722dfce469049bf9ed5063962ac264e763fe",9.917710196779964],[15820,"e74f247a06381010fae7297036974f42df36a116da09467ac844b02e6516f96c",9.317957166392093],[14367,"311f44f7ecefe8dac5ac2dce4a7dd9fff1e0453c56883d1bc7f3240a90b6148c",9.317957166392093],[17946,"64e7e5126bc06d8850bc92ceff757a5c28c8637730867ce864cf80eaefbb503e",9.317957166392093],[5587,"c3e9097ee97fc4f4d2d84df6cc6f7893433ed70327fb46b3478e4f9219e1b2db",9.917710196779964],[10241,"235ae7cd2e9e59ad7396af4ced41d638b7cf66d3c73a2487a4d83aaf014ac0bc",9.917710196779964],[9841,"73aead6a685a8ae07b14b3fff106469ad4c07ec95973d96708868fe9e6095abf",9.647446457990116],[18665,"122ebbfe5ae06d0f7ebbb0b990f83dae08a115c7d1856e117d4ba68bbe051f2c",9.317957166392093],[11459,"f597f8855ed484e8a6605385adb12ac7cf770bc2a66f30619c56695edfa0ddb4",9.917710196779964],[1531,"5b79ab7ff6e62c19f8fb298c0d6d9c0ee6c9d0c0912657a63eaa7a85440eedf5",9.917710196779964],[12581,"78cfa954973d92d3039fa5bf8607ecbcea0aa52abc6c7857bdcecf01e67b63ad",30.567441860465117],[9642,"cb0cf74f9b1cf1b819fcea9f79d740a03d016eeb55028435a6f103a3f47fc0c0",9.317957166392093],[1353,"6b3f3b5e0abb4fbc06e137191dbb124ee72a17b9b69c821bc2f8a232406f09f7",9.317957166392093],[4794,"e611f7cf2e11430b57e110fa3676affeaa6aa4fd73b1566d7fddbf2d40036de0",9.317957166392093],[18168,"99bddb73ec365acfe822b5df70d6451ce58dee98dd478363d4729a307d35fd38",9.317957166392093],[14739,"85b5d913cfcd4895b92135bb9608cae3554178131b60af37b0f32abc5c5b1684",9.317957166392093],[5207,"820018a29472c942d92da3bda1b0d6068b1486a4fe84230a4b87b5b598e0f0dd",9.917710196779964],[7855,"5e6986461314425cff595fbdda2857ecbb0ebd1d942967bfdb738ab4a2657dcc",9.917710196779964],[11571,"88eef07ddf508104dfa8f54ffbb980305283c3c9b5e076fbe849363cc94d20b4",9.317957166392093],[14949,"a0c7f496e365e61f31ee92ab2ed74945804742ee1b8a0935540190696e53c77f",10.052724077328646],[8541,"05b0f4637d2b01e00921bb535779aaa9d5f798a23170ccc000b2070088d8c8c7",9.647446457990116],[4521,"832e0b790e90f9cef079a6d30977c087fa535ef26016a5c3e66e7515f74037e2",9.917710196779964],[2162,"844a5fe024a10ad14053e2a56f3ddd9837ff94ef2984641449cbd62bb74dd6f1",9.917710196779964],[6039,"e985dc650284a7bf52b12d852464291d96f7fc5532945768f28213494298d1d8",9.917710196779964],[905,"80c61fad99f821e3c32f1243c5194931a69b91d835e4d980318cf42e07edccf9",9.317957166392093],[1048,"fefc838b667dfaa725496b1e171719ccaf89a820d5f3dd8efce699f79e76f5f8",9.917710196779964],[17565,"1df144f619a5eb0ccdb04045081860c2cc86ae501181b147d7c3de6bef0a1046",19.226908150064684],[5223,"b39c7dd1783de439b3b7ac72d8d6c54350a95c77128d591ac1d586fe3b79d6dd",9.917710196779964],[12904,"a72390c4cf1fab2ffc6d8a64014d995222b2316bb146b14535876f9d37034aab",9.917710196779964],[19366,"77af857a9eaa60eadda903515fa34c3575ee467775bf6b014069189e4b093313",32.058931860036836],[1678,"1134117449baa0b59df01660e1786ecf17b8619a418ecd14a7abaee113a60cf5",9.917710196779964],[2948,"e97826fbaa3d8ab5f3848518a4a36ef22994c4f5096e0e1e0d4bf076b494b5ec",9.917710196779964],[12707,"d9470259224e4b32dd6e7d42c70eb534a88dabed23e84ee2fc943e1fd3a98fac",9.353846153846154],[3468,"7bc2ce5223c242fdd9a3e10e2ecbd908601cd1041c40ac22667fb0b0aa6f42e9",9.317957166392093],[2713,"577d84814b9084d65572a1913b09ae7f3330ce5aba71dfb2a9c658114a8d5aee",9.317957166392093],[14494,"d3bd48342a265e9c4af4a7a663e7a7e8851b0a9eccd856494c10953c02b36489",9.317957166392093],[17412,"811427aeea844a24fab8b5e53cd8ddaf7ebb86c108f154e883296cc626dd9049",9.317957166392093],[19289,"05167ddd8b6ebad16d64fbfd67a538833b5688e771979344bfffdcc4e3622615",9.317957166392093],[6009,"f99ed943d8b4d079a1b0bf794c7bccc5bcb67a3e7763e45300318e6b304c06d9",9.917710196779964],[5543,"5cda579bf2bb34bd8b39a095320ed618b4031ef8a5104fd7194d8f5d259ef7db",9.917710196779964],[5871,"04c337f2b07d44e8eb72bde9d80b4aee18e2b98a22e18a913e1b6a500ad3dbd9",9.917710196779964],[19020,"7eebf6f7bea56920e7c3350829e8027ba4a2d78088e33e9c9d3cda584262d71f",9.317957166392093],[329,"8b24369d214763f093c9a79f5473f2ca2472bbb3476391dc80e5a6e75afad4fd",9.917710196779964],[16064,"09af3ee30c0a3c1d7218a233aec44242a3d90a13604d025e17e0483078b71467",9.317957166392093],[18338,"265325355207731267b8c7b1cba0f59015e9d84519b799b2bc1511fac31e1f35",9.317957166392093],[2037,"8691a47348966b85fbb7d7fa3edd9a778701c3f5a08de9274ae6e0430392bcf2",9.317957166392093],[3470,"bd85e94ffd900b038baeb80dc877ca731d776fa4acaaab3d8b466627b2c53be9",9.317957166392093],[2793,"68d7ae6edafb43e6fd57cab71fd2b799dbb997731969d92c32e20d221350c5ed",9.383886255924171],[15710,"5bf06cf53e9ece4c8cf7fc5e168bc21986f90a411dfb372dd91480dc8c003f6f",10.052724077328646],[10797,"3ee7204ff14ccc85b5fc280f616fc0364bf0a419ef751458c885b4d3e56d4db9",9.917710196779964],[5565,"04ba01e2df0b68ae0702d42986381e4565e5149d028608211d8abef70ca9d7db",9.917710196779964],[345,"d96d068c1b3b8d4e8ef5439f0dae575e4548f63b9967ffc96ecfca8d8b22c1fd",9.917710196779964],[17868,"6b6f738a737fea449d029a04b1afb126e29290df01ec792bf6e1e6e89e0dcf3f",9.317957166392093],[10178,"448239c7f1a842bee43029a8184a7fcce1a1646f5b60a828b57a448bc8ba2bbd",9.917710196779964],[10836,"f525b78a002cc78433cbc8e72ccbb18d2b5f6c7de67762bd1d9ac491c60d15b9",9.917710196779964],[15978,"a136ea276cb17effa73849787a2399d359d14649948e541c263502b83850ff68",10.905335628227194],[2069,"b7c9c4e2722971cdd5c3668f8b4882f05de48ca43e19930e54fc29dddc6372f2",9.917710196779964],[8825,"2dcecdc241f4b3575feec169a005114c85564b3362f5c4f1f33b702ef755f0c5",9.647446457990116],[7571,"656eab778e43975118289cda580eb7a0e345d08960b5a9a7045ba51a286c5ece",9.917710196779964],[4466,"5206e8c4493f567365fe6d7b245bde2bd943bc517ad7c2289c58466dd97da3e2",9.917710196779964],[6355,"6817d0ceb7da651283099c70a8ffef95d0deb2cf436b59218feed14db2cfa7d6",9.317957166392093],[12408,"a87a02ba1a7ac48504a7f1f789147a16ae1e98453b9ce44d8ce63e3ab60e90ae",9.917710196779964],[12735,"e596dad56aae70ec86cd5ff8aba9d04190d3a7b48a9a70aea9e61117b2d858ac",9.917710196779964],[7301,"0bfc48cc1db1b13cadd39c6edd376724d4633178c9b092b158e2e0a3576611d0",9.917710196779964],[10483,"3a36fedb3cb2744d46c77e2935091c83b64420aa46504a443a7e2ed1e27a42bb",9.317957166392093],[17335,"d59b58b2f7e76259bdb3eaab95c3eb6f05d28fc71fc4a444f93d3ffe4bcc334b",9.317957166392093],[9514,"f9814a9e63849617dcf4b063208269ba7cf221bfffc45109c026cd8d02589cc1",9.917710196779964],[8444,"552149d43906d2ffaab0855e7bf426a3d2427cc29627dbd0498d5326b4b658c8",9.917710196779964],[10345,"da8ee2ad2892e3b780bf4c16a2679ad7f8f426af8e1451ece7883d19d0940fbc",9.917710196779964],[6796,"471bb91761d30d0ae93bcc19733bbac209b63e776e5473c3c5c1e6ea833f4ad3",9.317957166392093],[8420,"cd7de1139838ab1c4b4246a19f05c6d5601fb05c4fdb9edbdb8c7a8967327fc8",9.917710196779964],[7374,"41b3ed7be5929349d4d9ac6477bd818e0e12648a6d0c13f033bcce1e1add8fcf",9.317957166392093],[17802,"e1a56d21113ee81a199dbca7f31eacaa4e4355738a11be80f0ae8c801b393a41",10.052724077328646],[13844,"bf92f562673861bf71cbb31e59a3786d6afe8233e5bf0c1cbf7d852777937898",9.647446457990116],[14803,"a59a074dec936f813b226e817fffb6726fe9799436f091c28af42aa24017cd82",10.052724077328646],[15146,"8fa1d06ba5e2ecc3b4443768ff58e54474bc8767ac611dcaf55156f04ff1987b",9.317957166392093],[9685,"e777cc9f1c7e324d2d6c54498cde796731dfea77b9bd0914455ab436efd27bc0",9.917710196779964],[9029,"4c374a1a1af34b708a91a6e9a92c0278d005ee4aa2762a9e027c0fb761cb9cc4",9.917710196779964],[12592,"0e781e67a2630c13507e127e350e17c28520522c24d735c1147e8f5eba7c4fad",9.917710196779964],[8223,"f698a6f90bb3396e15270579d9bc6662d37c31e920c200a2ee66a358d5aec8c9",9.917710196779964],[9484,"525d2188421cd3aaacbe4adc16648ed5a62e4f4a05969c2ea211dbaecb33cac1",9.917710196779964],[15422,"fb61835c3a508b6c1a6d75116ffa72d2d4b2b20dbb66543d516abf02dddee175",9.317957166392093],[14247,"59e6b9b0b9e06d111ea48ec4b6abf361e3d2e312eec6854fc37524ef0b6c028f",9.317957166392093],[2338,"c020530ddb40623b47743cd123c30019afca0e0dfc589a75f5ec5a958a5bccf0",9.917710196779964],[18866,"0389aeb7a7b3b8846441f3d08cdba18aecc3ad67d8670244ea58f9e6be917b24",9.647446457990116],[2758,"cc57b14046e43d33e696df856acbcd98a34dd9f794de6a86e7af473d68e90dee",9.917710196779964],[4530,"15a0fb81525b1410d3ef9af3a1b38e2d4dc5e4f48feeee034b466427f27329e2",9.917710196779964],[18070,"8efae9a65fea3c62e4a38b4ba9c397bfbefcbdf63bcb621a134b4cd9f57ab13b",9.317957166392093],[15442,"7fc2ca88b4c049bbc104c64ad07c72c42ff4fab3eb2dad1fd81db6ad01ee5475",9.317957166392093],[4062,"0371ab0ea723e19f8f66649eb9c15efe79bf4b66ea53bdb7ae1e78129c3958e5",9.917710196779964],[3309,"5cd57b15a308151b22f66445a9a3b799ea5f74aa5f483afd69600fa1e17c53ea",9.917710196779964],[4526,"137139d1cd9f7f6ec36aea61568e6de4b0cf17fcd086f5f8c316f5cf07922fe2",9.317957166392093],[15184,"fd165e1967ded50fbddfb73d9ae343148b9d68fa2f3e9c728440074a01e8dd7a",9.317957166392093],[685,"f69abe5be723e7c3b9d8e52ff59dd8e58966c545b0a5d4ce0b78c2d0479057fb",9.317957166392093],[19522,"f31c2c38d39f694feec5bc68f884bbfb3ba543c532fe6dc409dde426e5b5b10d",27.132412672623882],[8139,"a00ca218e971cabd3d191f930aff50836d14f983fc2070885b9d2cc231b272ca",9.917710196779964],[10143,"619ce6d98f6af17e5981ea466caefe2d33ffa88559017c2d69553b40eba26abd",9.917710196779964],[9104,"ae08e67ce4e9b3c5603895d62613bcd1d5078ef8b881c6229fc80099cbb727c4",9.917710196779964],[41,"4b59e0e8e05d8b57aa1a727aa3d3d65e9b76b4bbc658fc859cd00b500c85bfff",9.917710196779964],[17084,"0372da510a944cc40de2c5b9a950b12412f796fb1ec4d00502705d2163d03d50",9.647446457990116],[15020,"4634d7e726cb2d499fe9e3c2597237a94857f7e392c07f27d9540f61413bf47d",9.317957166392093],[1032,"66304378385b69d2a4905ef932060bb9160d0d4fc77416d9b3ac0f8f9e2d11f9",9.917710196779964],[19331,"bdee7f00abcc98186792d520805e9c525cefa7fa5bc96a568d9d88189ea92714",10.052724077328646],[12041,"23ff15c57a40cfb17dfebfb22ff445d8039ab994feeac8cf5d95fd468e140cb1",9.917710196779964],[11824,"4e7dc85586f980db597d778d4c27aa0a9d705e621d477c2ccca22c03d47a8eb2",9.917710196779964],[331,"65a6fd00bccabf5aaee94de747a98a4e445d6f380c6b23668c1de5759586d1fd",18.755148741418765],[19404,"13f9206abb2b5d05cabfd614eaccf30e7ec9b73b337b65f5a53050cda11b5311",9.317957166392093],[715,"556efc32fb663a16c30f9ba6aad2683bc28505d74539e5e6e39f0beabbcf19fb",9.317957166392093],[6938,"3798b106fbd07b06900237c99d4d08036a57fae8e95af16f3d1182743d1066d2",9.917710196779964],[2797,"2361721b7790a961752f4bce8e95df614b3891c48ada86ab1259337b4321b6ed",9.317957166392093],[12999,"4c10083bc099e8459e8701932db349047b79f6fc449ad0e6c9bdfab3bf3a98aa",9.917710196779964],[19613,"6a4bfa43ee1ea9de3d234a047ba6c9d6357ad850ca3c2b17276a6392073b6509",9.317957166392093],[16115,"7cabc1c54afb7914b40b847d452f2f5bf3a26f3406b702285c31dca8b8d2ab65",9.317957166392093],[2308,"c9e5f9cd12384d889e58652b9b4d91f0b0aedbb8cc9d29fc2bd32235e782faf0",9.917710196779964],[19724,"8555e3284a46cc5e691ac66cef8071138f6d8b8c6a5f8a79bf1b2fcf077ce405",17.97583081570997],[17711,"e577c6f731355609c50a4a3786cf264656c35dd680419611338c76dcd4470543",9.317957166392093],[10834,"b444fcf95110e85f9b10afe69eaf283acf9b29ae5d23a6207ae320977f4219b9",9.917710196779964],[11142,"2b9d58c45cfb1398a99af0018ffb93f7aedc9116156ca15769e296ccb93002b7",10.052724077328646],[13983,"8952e3d80d3dd239b80773d08c4f61f51d706abca2199028f9f46bbdcf5a4c95",19.066666666666666],[18303,"e1c2af88c28972a34c8eb9ff11792e108eafe8d69648f1e5dce728c29bdcc535",9.317957166392093],[14620,"bd55324397324af8977d74d60a17310e7a5b98a63b835203a1ea2829b5d48f86",10.052724077328646],[18084,"ad3e61fc3828e9e1ef284d4a9ee85d0ef64da92306ffa447ee8919faab2c733b",27.24890829694323],[555,"41e1332076963d5429492f4b148d6633384df9b4829d0bd503664f17fc913dfc",22.279646017699115],[11462,"7cdbb2adf92ae190731325b429e11e6300b7cca2f5b0069b7ab0a8b013aad5b4",9.917710196779964],[5666,"ef1fa5f341e10dfc4af92f40c53f5400a48cb0ce066f51052efe0f94262939db",9.647446457990116],[9951,"a4dfb6c14b8e3498dc3616aac40a0a1858d781157d3238ee0eac8dbec1bb9cbe",9.917710196779964],[10014,"cad142604d95278b11abba979e645fb433e21bfffc3315329ec24422edf13cbe",9.917710196779964],[558,"b2d4bb2854d40f7e3994489d9b43fcf94415881bcd2d87e6988fac777ea73cfc",9.472566371681417],[12466,"13b5751e204e0f14c21c17c3f517426930581cf50ea80d8c2703f15b63a934ae",9.917710196779964],[18235,"5fb4b9c8c334cf6fa8bd1f088d40a5fb2b85a0543f7cace4bb035fc9fa7d4537",101.59267734553775],[14828,"82c0bdcc99b262ef1f2a194f9c481f3993717d051f5f20793161811f750e5082",9.765429648739829],[155,"f274aeab300857d022d86f6a930107c2635c886c3fa16d4df623695ede7df2fe",9.917710196779964],[5222,"9ae605cba56df16a386929de95257a1a16f784fb3c445e57cf679f5f5cd4d6dd",9.917710196779964],[9386,"5b561a7fe837eed2c9415f8f8829fc95946e40abc053557cbe6117ac27175ac2",9.917710196779964],[17808,"630f53078d60bcf6e388836850e67a34f2fa49a7c1728c3181263de78b7a1341",9.317957166392093],[9836,"8ceab2c842c9fa7a090db232a6ee2d11a269cb6693a30649f69ac5e046ce5fbf",9.917710196779964],[2702,"9dc6ed54a79838eec159e1080a1b5eadf7801bf0d42e0ee82b63f8e5c1d373ee",9.917710196779964],[8112,"ad737803d4e57f099e1ac26cab10a673631ad2c443e69b7d60d34308f05cb0ca",9.397642257991386],[16170,"2814a2134b1b4e4df89b417689898730b3bcf77487ba47b5eb48bcfd2a4c8f64",9.317957166392093],[14255,"4cdd3f0bcb6fa38b73042727099dcf7366e9315a4f8e67fdc06b504b92ded88e",9.317957166392093],[2478,"9c3d8723e768c3a12062c2f914ab5463d061d6c3c23fc7cc05d00f1497e802f0",9.917710196779964],[11760,"7e271c0a3557416db5a371c04ac1cb3875e04fd05b61dd1c60fcd6be9382ebb2",9.917710196779964],[10431,"c5508de72e1ee76dd1126a4c20ea13d8e0e857abb2faba34527be712d9aa9abb",9.917710196779964],[8989,"2c83d119b633484dd2f9cb3e8b7cb4e25388399ed251ac36e993e6a224f1d3c4",9.917710196779964],[8567,"03711e6cc58ed8f5f219b737e1c8e119cf538faa42b78c6dbe6eb3adfc19a2c7",9.917710196779964],[19743,"d4e797520e0f17657e9b67658b146f85f61ac86c31af85c08539e72b546c2005",10.053097345132743],[18846,"5c964faf0df27a9824d4317caadd128e82658c0e4c08e56371f4627581a92225",9.317957166392093],[2166,"293d7848e931052064a1d9b98c652af03111b6888e0019a7120d914483afcdf1",9.917710196779964],[19414,"0877b5e1c1625be1f5bd2ba5cc939b22a2585bb51e07346bab3bca272cce0411",27.87830687830688],[19749,"d2e891473fe3cd87290129a0c9bc47f6ea12e60a718d31817eb169583f37d104",9.317957166392093],[4868,"a220940d7cdd6445112314acce696001735ba3e4c541137fbc424ae04a5d05e0",9.917710196779964],[10572,"81efd8b77a369809650ba1e745700d2ab4fa2009cadab809b3b5fadb8040c5ba",9.917710196779964],[2183,"a8e9013645cff6d00ef785bf133f94ddef5d2a0367d410dc3a7d438d1352a9f1",9.917710196779964],[2618,"9fbdd81e5a092b66fa2bbb6b0c40ff46dbba19803b34e2ca390b39a56adb0fef",9.917710196779964],[15769,"30fa03c8cbf4a28b47d39938897d53ad0bfa6ccf9e42e5898d8c05e05706fb6d",9.317957166392093],[12380,"583f6c688e90bdb047d42c600038dbc531b63e10f29b2a87d7ca14b0ea5dc3ae",9.317957166392093],[1479,"5bf4149a6e6e0ddd1416b24aba425cb4e73c2d063b084d689d6a6bbe4fdb46f6",9.917710196779964],[18079,"e6b8a33e6c853ec8c49f5fcb919ad65a95a6a28da28337e0b35bfe38229d863b",9.317957166392093],[16933,"925c72a2a2b5283d9b66c80817e19821b269e6a6c902805021d619269e006e53",9.317957166392093],[16537,"77c66be4c95f7750c298bdccc2d4daa67d5d28bdc45f7e29a8d5008774d35b5c",9.317957166392093],[18743,"25d0f64fed800c3589872cbdf0118d8559777864725bccc74f446190b0a9e528",9.647446457990116],[11024,"a615a45d4d80c53df03cb2a27da1d9d5ebf7f817d8f394bf2ab1637daceddcb7",9.917710196779964],[1469,"dbefb80edda3b3a3e5f5390a9ecff40c709c40a7a886c1e7d1c075efd7d75bf6",12.384341637010676],[14069,"b56e4607c55fa7ac8c58cdce4e998fc771d9f11b816522802583d352da444793",18.507462686567163],[9589,"22856f84d8052e6c27d1b51f6db2c358d0a27717c0ea59f6c21fdcf256dc0fc1",9.317957166392093],[2,"b5d918327ac276a2fec83a20562bc36aec5fa7f83e00959d6018bd6b32acfcff",9.917710196779964],[5100,"e624275dffa9685b065bc32ab90d601b2e286820650b0530e8348e125a0193de",25.829596412556054],[8600,"aa4e892806e056cffc5e10f8aa607dd9870cec7eef7e0e76be1f40c566556ec7",9.917710196779964],[10166,"762caff1be3a025214c47d273527077035a6a13b2a12613c07c05d89f8034ebd",9.917710196779964],[1131,"20c38db12d73db226538aed9f628223311843a7c96a8e304301af072c2a566f8",9.917710196779964],[14995,"0281465eb7b3f2899f77d7e8f6f1c9e566fa1a642ba532e16b19b180c07b987e",9.647446457990116],[1629,"a8a5b16a2950dc0f04c0854f3ff00c18644841e3af9d8ebca5704ff26db16bf5",9.917710196779964],[4811,"76aeecf4986b9a757ba1d800b354fe7975d6641a424318dbf6911313b30057e0",9.317957166392093],[13908,"2bc103eddd21361719880a9a7b88ca2b1d4d249434987cd1c547cd1c6fcbdf96",9.317957166392093],[11891,"9088a201578d863b92571babbffc19e82395a974df3ecced5e435694ffca11b2",28.09964412811388],[3672,"0dbea09f94d13a08c0dc69041d240a4a545a194c776ab9bb8def6b53f45ec8e7",9.917710196779964],[4339,"be346fa4a24c72acb7c1b9bc390ca15efd28a936e46de88659c4b06745ca7fe3",9.317957166392093],[11840,"e142e889dffe3e57ec196004386c9080bbe6ed053853e77875a789eabc8b77b2",9.317957166392093],[17551,"cec116a2d34fd4fc224ef9974fc03f4aa7824f18389fc440ec02f4eb31fd6d46",9.317957166392093],[19393,"cd47b9976398bedfb413ecea2cc107e9037bab3fe36e380fa4cedf0234d70812",10.052724077328646],[5931,"ca8c574463ec33af3ee851f15ed6ebbde8c1b089b676565e1552468511f37ed9",9.917710196779964],[9543,"6747ff970762beccf2c51ef56cc74354193e5360e1b9c8f165f77ca23e3270c1",26.13903743315508],[1914,"986cfe02b18aae691c75f87a6829e9548eb1c1cd6d7cbb192566e7beea2393f3",9.317957166392093],[10565,"e9e5b3e2aaa295e3dfc985aa24d713117670eef54aed0a178050c3ef33a2caba",9.917710196779964],[4516,"d3467c433dcb071f98abef0a8016f6f6fe1eefa1ffe9ca29b2e158791b2140e2",9.917710196779964],[6591,"e57e100c4d5d995d37ecedf25110f38333cf03f3a444eec54766400b5e28b5d4",9.917710196779964],[11277,"ed657c98d142bc033274ca9fa49d0ed944ab0b28e4dd768193e9bf7a832c2fb6",9.917710196779964],[13083,"3d3ee49c7f95f1814dbc528b53b10d3cca8e244983d23dc8b175f5a4f35ed2a9",28.19221967963387],[5060,"26228200ff377dbcaefab29a812e95ff7b57e6b6eacd02a14ccbd8cc12d6c7de",9.917710196779964],[15657,"f1c8a2b416be3edf54fb2fdcd88d2267cf423c0a48353a1697a10940b7c83070",9.317957166392093],[10254,"444c8a6a99dd035c05a9499c62bbc8d62dc58025b709b51f0b041d73fe0dabbc",9.917710196779964],[16569,"7a6fd220236da9bf696001044c4b3fd4557371832e0be3cb8e5f56d3a42dc45b",9.317957166392093],[6199,"7ad797a5d34419fcd4f61f75ea72d99204be2e67a6fc4766bbfdd02c9c3dbed7",9.317957166392093],[9233,"a193f4a12a7b3006aee96f8c00b5ade77a2f653cae8a5838d5ea6477a31e37c3",9.917710196779964],[15197,"496e34001b5a49efe2b5f15b83793fed2423027d311296ac9415e1674a51907a",9.317957166392093],[6788,"43a52dfc6cb570491c6c9bc1d5b5515e7b13ebb91f18d35f265acdd41b445fd3",9.917710196779964],[8932,"6f242483efd382baccafd36fc31acc5ea21f768112a33194e4f6719f9a164dc5",9.917710196779964],[3097,"254fdb2bb9e25d87bec3b220e6a164260837e0c4226b15a9499d845af5a0a9eb",9.317957166392093],[14741,"2e5bada5a05a8a3fd30c3c892f7efa5b11ba37d5713e9f115a939b46a7991084",9.317957166392093],[14167,"77dbf4fc97bd283728c24b72315fce8485c86dc3f6850afed8f3639f42331b91",9.317957166392093],[11138,"800c5e7f83de0fa36e079922d14e43c6f58ac9cb41b6121281d7cbb3c6e807b7",9.317957166392093],[17015,"93edb65286c709324241c2247c388f5f62cac0317409be8a70f8ee78c33dba51",9.317957166392093],[17010,"0b30645287c1c5fc501ff5862a55b964ce8b428ffee686970560f348ae5bda51",9.317957166392093],[4404,"8f153031c8fc991cbce529a8ea74f091b70e5e304b2937930d19b60472e70be3",9.317957166392093],[15896,"6b5226d5d94a95b0443f9fb3d7de2121b5255f346870313c642260288da7176b",9.317957166392093],[13196,"813541b4d43beb95ac0507cb8350e669d4827cf666e9d1d1c0b67f0823fefba6",9.317957166392093],[3787,"d583f9c14572832abed2f714569b5f845b0868d2b39bced7f86385da583608e7",9.917710196779964],[4862,"9111706982945c20fbc5ff23996c141ed70f64e83038b9d48aabcb689ce310e0",9.917710196779964],[2962,"ffde93a56fc94b915b667e2e6f7692cd5a863ead94a29d8783af31d6cddb91ec",9.317957166392093],[12732,"61e123853d3c16d7ba136fe7b2df474775e9103849f5f5e3e8bd725385b462ac",24.233128834355828],[15170,"0a3543673537e3c617e5cfdf7d60a8649b162387b290b13049234e6b18bd1e7b",9.317957166392093],[1877,"8e6e9db1f64d60c109308e82d84e343d2579cade06ed70d593416b78dc1dc7f3",9.917710196779964],[9624,"19eb755642d2e2c1f7225405aeb855a2042e05aeaf141155f31b39fe6002e3c0",9.917710196779964],[5406,"f6c5511dd307a8d199fee36f84e5a4f97bd7b9ea539d2b1fa8383b240550c3dc",9.917710196779964],[532,"addc4fc529d65c1bf85ab8168fa8fd7928ddc8b5287d9fe1c1f0a93e030671fc",9.917710196779964],[10577,"9c4e09b15910e4df05e296ba8857be5ece1d79d86ae0c9ad910685f8331dc1ba",9.917710196779964],[12133,"8cc568e0e6ceafea9a7c7235443f91f3ec0ec7b4ec7007599d8408ec12797bb0",9.917710196779964],[13143,"0af6f5b3eaeb15fd4d557d434f16c2af2643ecdc5aa2bbff2d3ee585a3af18a8",10.052724077328646],[10374,"37d034cf9e6193a53c1dd769f86a906f65ca6a05012e160aac3cf9b533e5f1bb",9.647446457990116],[11747,"d7c43ebf453c8165d2419d1618058813e42d77b5e7b612d5e0de15692d0307b3",9.917710196779964],[4013,"d93c73f4c2b99708c1c03da9eef6768634868f6591c0dc75257e5ad28e82a9e5",9.917710196779964],[11636,"ec7132cd53607bc99b5e1d692381e2c54e7ef6b8d6f9c3c8eb4818663707acb3",9.917710196779964],[1614,"d2243272de6d91d5481706d28c8d95e32e213497f1e168f2c4527103f5157ef5",9.917710196779964],[1265,"b3cb02bc4ff629a974e2b4afed6dbbcb2207cbbc00565e56cc2d4d3179c392f7",9.917710196779964],[927,"b3265d23dbe8dac7432fc9d0ff8164421c9f72b9ff4e92d6e09c278fecf4a6f9",9.917710196779964],[18329,"4ce0db75fa1d2e95620b3b333505fd5f17bbf0c4df25ad0c9fc1964fa0f14b35",9.317957166392093],[14719,"1871e29576e98b57611bac44f8aa645e41c17e3a779e46e476be818325a88f84",9.668934240362812],[13375,"83840aa8fb024be05979350356f127b77f1d5543afc8ddebb925b844c02deaa2",9.317957166392093],[11408,"9168ac53c89d8c0752fa18bfb92a5b718ca76ea1674987eed8c9d3ca76f34eb5",9.317957166392093],[8013,"ae4f4621bcec2e66d5d86eb6765284e690fc4b5c03a6241b61817189746976cb",9.917710196779964],[3729,"604fa200a48a24d99f67b49b7befc5364ef239c54190033430d8ebb006006ae7",10.052724077328646],[1077,"a43f121b100ff61ab88e57c5e59b4d3992241e6aa33f7f8b120f78a51b2fbef8",9.917710196779964],[14302,"2e4e8753660b4e99c6995ddaee1ae4159998f9f71935e36cbcbf13395b16798d",16.9757700696125],[5165,"d680e6ada490dea494ef3e454a42dc1f8ffe408d38602a6bae6c8bca427d2ede",9.917710196779964],[2315,"50e446a45acdd1b2a820cc8ccaa1f7c58126b4a458bc8e1062d53e855253eff0",9.917710196779964],[14933,"cd22ba9cd615c72768fbd0f515c01b40db813ced704fecc2756e294ec96c2280",9.317957166392093],[10131,"9fe2f57fff7aba97570f8ec01d297f46624efcb99a79d7617746301b7d187fbd",34.64961530463714],[12640,"89d25fa8d46d4fffd49a908c4ea7a492bb96bb3eb76a0f37ec85cc30393dffac",9.917710196779964],[5270,"0fd9d969c7ae0ef748be6c38f5f9db7f7ef1da1f6dce7227f9cc63549b8993dd",9.917710196779964],[13299,"893c82a6e99cdb5e30339009ebe467feb437b9cfc55f47c826a53e98284a8fa4",9.317957166392093],[13885,"b0b9fac7af9cc3e81639ffed1225aa95d8b1baee57eef3c19a747aa7f4b24c97",9.317957166392093],[17153,"96a9175dc754994f4e20661ccf804986b0136cd522a1db3a918eb937ae6e0b4f",9.317957166392093],[8536,"7458684b86a22933f9033ba7fc9269ea7e13175ab520eee6a6db2e5ba7bacdc7",9.917710196779964],[16219,"8ff2be0cdcb971154735ee60c2c4e3287adbc8b54853f5ed5ba80296c6c36263",26.923076923076923],[349,"fa17ea6d5ff5bacce3bbea27d00567b16d25d89d7dee50f9907373e709b8b9fd",9.317957166392093],[8428,"3b55bc9fbcee324c414e3db57a3d25a971aa51abe0dbac9447d22f5e40a671c8",9.917710196779964],[4896,"8070caf6369f6d7df6ae6c2d0a650a2924ae8a502685715224bb3d3f4b18e0df",9.917710196779964],[14215,"4acc01f0a24a0a6ae6a468661c00192c4a0274ea7624e176ff3f1ad6d44bbe8f",9.317957166392093],[7644,"170cb44c57fb999982f5197a6a146b4a6d751c2f983e2ddee207d23dd394eccd",9.917710196779964],[12987,"cc2c16011467c77721349e120d4bf3c8d6de5ea80ce4362a36ad48e18795afaa",9.917710196779964],[8332,"f5a8b2e2404bb57f0d6396e4cc39097afb028df66fadf04c2dbb211219461dc9",9.917710196779964],[11921,"925ec6c962a8a427d0ef1f833259d56b4164c9e49e1b15b52dca95012dfcdfb1",9.917710196779964],[3769,"c25ce952dd2d4cf9e0dcbf1eb56a779c44afd6eeed31330790273858986826e7",9.917710196779964],[12847,"1825b90417ee8fcab7195d8277c11cb0d66493ff4338048aa1e9931af4719dab",9.917710196779964],[8490,"8d51fd06b6c057a39f8b3bceb4df4d1b014de57e6e32ce5d6d1a6c4add0e12c8",9.917710196779964],[17247,"984218169f2969756a6cf61c2062ced9ea6b59ba23160e296f0fd8dd723d074d",9.317957166392093],[418,"e496a067c17f0bcc77fb163c757f0828f235a1fc17e67f869a1f02b7819f42fd",9.917710196779964],[10193,"6f0569e2741c473b79f25b4f1f909e474cfe643b163f441ada5e7cc505e20abd",9.317957166392093],[4669,"738b4d4aed7b6867522327d858ddcbaf1b74a1533a50c1b7498841563cc22fe1",19],[7948,"b5d82a74d34303909bda5b2d4d9d212698b8433ef7dbdf6aca1fad4ec6eae0cb",9.317957166392093],[5123,"e1340144c0ab944b088dd4e6d39eafc2b801d27d981b4c0f1e6eb3e0350976de",9.917710196779964],[16554,"a213f05b2f82596536f0ce85c249ad66ce616832274fe912acdd2348f860f65b",9.317957166392093],[2026,"90f99c8dd6689a2b1f48132d294e22d7805bc908081530e482dd2e44fbe3c8f2",9.917710196779964],[6537,"f39b4463aabe935245f5a29b0c75573cd324b7fa82b9efb819678b4fb87924d5",9.317957166392093],[9197,"11313dcec0e166be5449706222b7197ca64fc4d8e24bee422c78fdd8708e73c3",9.917710196779964],[11567,"1c3a4b76fdd0c45c22290248de988737427e65de1bc3e6872bbf17fa5d9223b4",9.917710196779964],[6948,"ea6787d452251c4f9577584e30b27037da619d5f4b09be1c6d02899068e344d2",9.917710196779964],[14509,"f7aa3a7ddbd9276f81b59e33a2581d7d5b6ac43822fd037d10c46ded74dcf488",15.943362831858407],[11638,"988aac316546c283a2177e2797198817662c9a66b7b47bb09e165e8e3a25abb3",9.917710196779964],[12619,"e03f3e0f184baf120dbfa7b891baa9bfd89ac512498063e97583914a1a5d25ad",9.917710196779964],[11480,"2bad778533adf0c3dce9ee7df35033ad6a607944ffcbf7341c5294bb5510a7b4",9.917710196779964],[280,"c90f18eaad9a96cbf3e01254faebc19275bb5551dbcf6a21083ed1dda36712fe",9.317957166392093],[15029,"be19dc491fd1997b3d2913caa9aa412c5733ea212638c64206ddcd026548d67d",15.003322259136212],[1425,"61df7353eca9529b2030a0585d6a3bedecaa6cc8c78ebcff838b963ef20dadf6",9.917710196779964],[1073,"c986d00fca23056ce63a6643ce47ee98a5fd88b163820c943c03e9558689c1f8",9.317957166392093],[14514,"5d08feffbff32a03f17586411a5f977d0d98d49aba1efc180864d7564457d988",9.317957166392093],[1070,"498cb92988b75eaa8c219181e2fd03a896910883e664e51c8df18953b90ec5f8",9.917710196779964],[7265,"a2b9864680abf6b3a18b9a90ac925a3da6c6df048150727481e9228a95e63bd0",9.917710196779964],[13772,"3c9d1ab1670af24c8b6990b1446415204b88a7273944a8315e728285d611e699",9.317957166392093],[2255,"a917580624e38cb76fd1f1849b1f9e49516dadd3d96cc22336899fef39bc39f1",9.317957166392093],[8910,"8ddd18a1f319887a0dddcca622a738e4a46704e09acdfb1e7292285cd3a262c5",9.917710196779964],[10727,"f59b1f265bd343a3963492165a9ff5a244a877560f0369217a4ca2041ac1d1b9",9.917710196779964],[15081,"3a524275b9401eb508c7bdf3abe4c4dc0275faef8b819dfd14dbf7799641007d",9.317957166392093],[7156,"c465d9e6b41e8205160a15630bf08d95776957c41fee2eaaa12f04456c50f9d0",9.917710196779964],[17654,"56d5fd6d8d2e9d0c6ded1d06936077380d746fe34ebafda407b5be47d2272044",9.647446457990116],[11642,"309f9df46154a37ff4dd4d42ca216e096421a9aebd0343824aebc9993bbea8b3",9.917710196779964],[11560,"a272ee04fffb0e917dcbb597884087f40810515b245088aa241fcd5a64b42fb4",9.917710196779964],[5855,"27da6f4ef8194a8158743221ebd68b136cac8c4071f9fca75ff73bcb4745f8d9",9.917710196779964],[5095,"1509fbfaf17e6da8d8882df71ebbcf80d80f0b0c71024eb385a1ba457e789dde",9.317957166392093],[10100,"f7cf50567680025925330077db58972b1343cfe037efbd77154fcb9cae6fafbd",9.917710196779964],[3818,"b6cb35a898adf5e241fd357a460a656ace7373d21f8b5eab679c3cb943cedde6",9.917710196779964],[7399,"2779e7ef2d1256f7831a58143dc41a58a16650037af025e0220c476c01216ecf",9.917710196779964],[2604,"71526ae6747e519facdf8bc27d29b8c004a6493008b01b7e415dec37cdb120ef",9.917710196779964],[9161,"3b7caadac3b088e05030236d64e3db56b99c3b0330bcdd39b14137f18601c5c3",9.917710196779964],[4261,"5aa3a60da908dcb7035a22f74020532a923d4854f7b2af3e3c2064e748ef06e4",9.917710196779964],[12785,"dea2758dc60495b9dc4731a2fddf8e859316bef8f2fb8900b4c7249282cf00ac",9.917710196779964],[17557,"1c954a2909ba93949d26974596dd555cf2a5f00f64ae8cfab4d80db379d75c46",26.09252669039146],[17061,"aac218aea5672edeef7c8c66fb9f527be62b7eb6825b7cdc3206427047dcd350",9.317957166392093],[140,"061e59215e3964dc24c3e395c66059cc97fd8400adab62ebf2e11f49c42610ff",9.917710196779964],[6387,"470a1b6b4aecb2312cf7db38819f1df99e50c239eb366bbe26be7c2440dd66d6",9.317957166392093],[10300,"2d6fbccbf22f626852e283b5f40d4a08954fd9c8fb4f392b5045d5b0c71360bc",9.317957166392093],[16805,"a7653a5529e6a4a7076cf49c5fe020a0daa88268f770ea61b60fb7bdbdb92356",9.317957166392093],[15758,"d110315835b0974336e7f0d2a79e96a317bdf1b8574898f0bfd9af5e89463a6e",19.085972850678733],[12160,"fe9776c7fdb0c5bfb33aeab85f32542284fd5f3b51032be8cb5bfbdce4c749b0",9.917710196779964],[8656,"a623cbb27c0d191ebe50f59535ee8ec720d81a5597d9312a7ee9c2274428fec6",9.317957166392093],[14679,"e224d27699ae3205236f3a1874070ce3755d651452739f398b46ef9ac5824285",9.317957166392093],[12172,"7963549da0b124c6012bec71dc87dd5db7325510de95345d88a5eb2374183cb0",9.917710196779964],[2800,"aebf7fb3ef8be5ee92f410f7253983d54078ee247845901459ea45d30326b3ed",9.917710196779964],[13221,"b8126bdfdb0cb165063e6bffbec1bc725484ebba77617a70c3893c51f69e81a6",10.052724077328646],[14024,"e12912ed4b8bbb69583b1fa87df862440e7e2b9ac39c2b137a5f8d25b2953994",19],[3700,"ad3ddd61b5d538826f5c538e16f13c1fe8502e705ac593723117d958484497e7",9.917710196779964],[16043,"7c4c374e8759fe63e6d9f564143f4c1fedee690ff764cb6e6799f69a33d08867",9.317957166392093],[15634,"52bc7eafef05137bb0a24c80410f342269fbec913042c76454c14f55cbefaa70",9.317957166392093],[1820,"3b4800b64b1a46878bbe7756d53ebf236eec61badc99f89bb31feae8518b1cf4",9.917710196779964],[16457,"f6c525ecb495e380ec0e76906958f4c85c4c9bb97d8deb0bf72140d44e1f185e",9.820170109356015],[19269,"4b670afe437a79988e6a5cb135686fb1bfd00dff136ea4b891d59057c7f1e915",9.317957166392093],[4099,"c24a699518957a33767914d5800a4375081720bf432cae9cdc40d0b4b9d212e5",9.917710196779964],[3361,"a8d9a96318472b80e6cfa7df277b5b7cbd75f795c7115b9d7deb40343b94f5e9",9.317957166392093],[15022,"011f42c7b882b404d94a32a76e4c5dd7e3c999fed65ce6109a7e667ac8a3f17d",9.317957166392093],[2017,"81ce965c42f747830dd16d52a2ba37da4e328f6e09d26fabb4a5d60ca3eee6f2",9.917710196779964],[6005,"7c563c8e2bd3b138023cb5c86b9da7d75dd5e45e7f5dd368046f21fdc9270bd9",9.917710196779964],[16986,"8a810963985a4c99cc5d9467c65191b82129f5b480125ecf8f7e64ea339f5b52",9.317957166392093],[17447,"cc6f590c25132d205efffd6fa65cfcb40fd01425a73b3976cc2ba7d4ca9eb748",9.317957166392093],[14517,"bba9aff9bad50e785d912f1b1b3c296d66e6570d2d53384314df0b6698c6cd88",9.317957166392093],[6302,"c3b2f0e634a8055821b52a2d6ffc50d8bb4269067a020e2378137fe3951b02d7",9.917710196779964],[19273,"def506b254aa9f22b0d03dcaecc74b07f6aae8ddadec71487e59448d96e5de15",10.052724077328646],[5524,"00d70f354da99809b92aaa40afb4679786683f2233b1ad9eecb6c0bd820015dc",9.917710196779964],[11912,"4bd5f2bbd8ea1dc10a934aa42ed3cd5baffac83144ea4c7867c9b769dc8ee9b1",9.917710196779964],[121,"2f0a5c6c32d6bf0c760b13798fd4112a86fe18c2ac522c8289133fab7cf13dff",9.917710196779964],[3434,"873185d2d1ebb0db65d9f8bbc68a8d0609ab2f1367729037ebedf76c2c4b76e9",9.317957166392093],[4216,"2c4da5b811613011b6697df1a72a62cd802881975d554fe6cf73e610ade359e4",9.917710196779964],[10432,"a26d6ca4f8a7841f721b2c08ee9fb7963d92896de004b2d0f93227a3242c97bb",9.917710196779964],[16785,"e84fddc332e1904f0cf36b577456e7721de52500aa1b9aace552d45f3007b556",25.8908072795147],[17740,"090ed875af48b5c90cc03ab7336b81818143ab1a32c12ca2062369e2ff7b6742",9.317957166392093],[10502,"47ccfc0b0dc1c2ddbd44703ace87f115a5cb00544d33c01dfb3c08f49ca728bb",9.917710196779964],[16950,"aae2bd316408703e2b13f868b883165bf5d3bc6796abad99539d8e232a802953",9.317957166392093],[1062,"9089ee923a6329ff2b810dde7cf518e63c3775f613d6be385909a0e1b62dd9f8",9.917710196779964],[2496,"5fcf73269bf1677546ba87902c67fc0a3a1ac022b713fc4d7c839da2b2b6e0ef",9.317957166392093],[11042,"18b7b838262bdfd4b9304870a10d1f28d3e53fa9a76c0211554092cfef6cc7b7",19.216494845360824],[11811,"2a2f98c3f1b24dd395867312b8f4ccd8c038a3f884183921e032f2ff49eaa4b2",9.917710196779964],[9111,"f7907d51a0e42ca3ab77668988c000d157a90564b19c2e6b5790b1d7766211c4",9.917710196779964],[4543,"9a387e8583e8af9f740a71d190cd7a126718067c9f34f6900d76ef2f263914e2",9.917710196779964],[7328,"b1901d4c6117ad38600934dab2ee7f24416d59c722543692a5746aa61988e2cf",9.917710196779964],[2091,"bdd9f7d3f5edd77e70704bdf77f0d82ef7389115bfa3a217bff1e43f889c4af2",9.917710196779964],[5797,"ed2a14ca00747bf2eef9c035f0b6952289d68c188761a3fb90a2de232c1573da",9.917710196779964],[8102,"97612dbfa2608f4bba88a049f91e94cbc59b55554e224ec8985ff6f5edc2c0ca",9.917710196779964],[14853,"1465f9cdc92466310b0b35ac60f82d00b139b6165342f5fd2e4c72bc7b42c481",9.317957166392093],[1281,"088cd77dbc0d0e354cf5379b533cf9def9f1847a203793ec0f664a9371f47cf7",9.917710196779964],[1317,"de2028a7879813772a0962274d74df964ab95992c013e208b708069135024ff7",9.317957166392093],[1809,"8eff2c6f143069dc51bc11715eeaa7704c11aa769507ec8f574920a24c202cf4",9.317957166392093],[6420,"be1ba68e18a573d63b02c90e33278e7417afafe94a89e372bd131333da612bd6",9.317957166392093],[18045,"53e5589b2e147ebce98b5ba72b1510351ce0987c60e6032f9550976297e4633c",10.052724077328646],[8255,"d172bc2182a761b7a2c3e76b17f80d3607a70b9fa866c36a3d3717abfadaa1c9",10.052724077328646],[3623,"04d6f14b3b030681d247bafcba605d0d5f97cbca0bbe208e29215b9829ae15e8",9.917710196779964],[17278,"cee56887688b72eb11fa7faf75f7c9115a904e692814d94ee26fb707a295ac4c",15.055079559363525],[16492,"01774b80d403b2da44096dc24db7fe863065a021f3b7cd28cfa257e34293645d",9.317957166392093],[2826,"fa4d64fe33bff994ce5f84c91d3ffffa40a5b773ff2b486286cb6839d03186ed",9.317957166392093],[562,"5f6f345f667f6b47970b7cb900fed35405c17c16cb90ec3fa0cc7524461c32fc",9.317957166392093],[3508,"defa3a5a541974f632c90be47ce100eea5a63b4ece2e3c1d129c8aced5a6efe8",9.917710196779964],[3853,"10c2712cef40c959669fff15c4ef586682ae9124f4de8ecd3b95c03158b6b0e6",9.917710196779964],[3865,"92d8140d8b7565fcd4b02ca8c1fc6149b1cb28e45373adc45ff566779dd894e6",9.917710196779964],[10957,"0421aaae4dc580a73e224c298ed63dc35d057d0e8dabe50573e629c0fce94db8",9.917710196779964],[3410,"c888ce29e576455e68f19eaea56436f380eca52bf9ddd9c849985376ca0d9ce9",9.917710196779964],[5488,"32932f038f8f5fa3a741b864a3e9967500ccd2336e2357fbb25402524f574adc",9.917710196779964],[3693,"dff1703549aa3317aa136b2a9fcad7476537cffdd997a68339a992c47238a1e7",9.917710196779964],[8290,"1cb0d28ec3d63dcf7022dfd8664f89d4219435117d7b82f2d27be43ea17961c9",9.917710196779964],[13010,"a2a17529cd73d623e9f912f938d7e8f802e99a808b471998f28e1cb8655e87aa",9.917710196779964],[15232,"27ce6ab49b4a8fb9534f561b5ca5048138230cb01ea09cf0024faa9d66eccf79",9.317957166392093],[3678,"a55543f18ee37a2d32a342c5b834a6932ba9c673787b30f6d6734581cb11c0e7",9.647446457990116],[9956,"82e3bc4a460324443c65fbd08d93b5963902155e98e27ceda09eea315fcc94be",23.069486404833835],[12690,"2d60bd9931f69faefa2f6f295ae585880849031d3b431b9cef37715fce90a6ac",9.917710196779964],[3657,"899fd9003630a0a59ac79c217d55299ecfae298207f513cb1191928eb700e2e7",9.917710196779964],[9641,"0abff76e016c4354ea0dba8a2e8c252b7a52ec6e3c2cdccd377d7c539fcac4c0",9.917710196779964],[2816,"caccac0f53157b540b4bbd76915ac3cb6ff1ca9af0503c14758f30b9e2e692ed",9.917710196779964],[18275,"cdeb3082a52d646d485df8994683a6bd1b8549ab16b573ecafed0a85af1f5b36",10.052724077328646],[3462,"54e06cebc6e8484600fbc10325aabb89c1449ba385bb0ec87a23798c278249e9",9.917710196779964],[18649,"a637b50d29557a5314b02c21de6f6260616ea52de7d4a9f865ae2417cef8a82c",9.317957166392093],[16742,"1fa8b2c5a5c379750d4ff645581cd672dfd19f20353f3925c161827169fd9257",9.317957166392093],[3568,"82536316e8ac716a7c3d48e569161884bf911da3b143c74cd496465ce4937be8",9.917710196779964],[17310,"d3de979ca27be86ee4d2aa367bc2b6e8788cb06f3746a762ee082dab54cfbc4b",9.317957166392093],[5812,"cd6524e8dcf3d8fb1528354f60bd0595f3108291493ae1bd9dc3f402a99b50da",9.917710196779964],[18388,"fd08568b77bdecebb819c6a45f4221b54288a29e7193f86828e894ea7955a733",10.052724077328646],[2479,"faa8b0f692548f4fa74caea983974e009fde1a68a1c3cf0eefeffb5bc27302f0",9.917710196779964],[15161,"ad6b65723ede373005af4e51bff98a006d46289602fb31fdebc9042a94073d7b",10.014641288433381],[8561,"410725232b28ab820741f56a4406237d9c8f3496859dd12a2398d44d3944a8c7",9.317957166392093],[6662,"6102f462c2b4f51861142b3911a50a75bd91e225ff560db6e30cb983b3873ad4",9.917710196779964],[1253,"e9f760511ba4b8f2a5a028780fd931e97ce94c7f9a036f2e8b6fde44bf0da5f7",9.317957166392093],[15743,"ed7299349fdb15ad8dcc883a79ae282f007c0f1ee23de8652a038ca19f07836e",9.317957166392093],[8738,"e8706c8c7681dbf391ebbe8c691ae3fd4695dec84f70eec7c13501e2972078c6",9.917710196779964],[18876,"86f71f6c70cea6ce0cc39b730eb94e2c9bede6d187720292f1c4e9d836da3824",12.033930254476909],[10509,"daf51d2e52ea7ced2df4da5a10052169e4960764ddfa639eb92ca1d39a261ebb",9.917710196779964],[7268,"f1556b3b7160d793e3a23e3ddaf9b48b071107c35ad12014c22ebea4ec1039d0",9.917710196779964],[16656,"64fc7829846b883e3cd114a216f6a763ca5af7ad5248eac2d262125000328d59",9.317957166392093],[7999,"5875a67c493dd67aa6f927a721a6d2070a4b9767d8c6e70c8fc75df52d2386cb",9.917710196779964],[10636,"adf2a6e13b9ff37b1bd7f7169c8503f8e0175270d21d431b0731f27d65dd72ba",9.917710196779964],[10006,"712c97c1e81b5d6dd7c9b1ed2b49b4d5155b137e1c649d39862b2f0708474dbe",9.317957166392093],[18825,"d02978b73581423cbad9954c58d527f8760580b79e53ad2a28640dcc6461f425",9.317957166392093],[8686,"9c1a78aea70199b1ae9fbf3e8b604e7e0344f176b9f5ad7de10a92b9d5c7c2c6",9.917710196779964],[12372,"bca9af736ba5c0a2a983bbd1aaff79667ae649981f5545f0b7829f5c68caceae",9.917710196779964],[19067,"354ec7ed720420da7f86b1afba28761dfa5508ab116de3faeb48aaade84a171e",30.989547038327526],[10201,"7191f375eef40fbadf631396fcd1b0e30477efb5ab55527cbc0951f473ea03bd",9.917710196779964],[5604,"1c1a0125f879be1a28128566bcef3beb5c1bb57e5491f90bbc40c65920999edb",9.917710196779964],[17959,"391e9d339abc386d4748f3b91a4f1c65194c7667219410403dd7ec50bf0df23d",9.647446457990116],[1972,"82197a86d3bd72dd1cf47730a2387a576f71ad9a9fce50ee9fbc34a4314c31f3",9.317957166392093],[16922,"9efe82a18ec3c05503ff31e8af97f646a419f3acc7f95ba7fdb66c1f1014b953",9.317957166392093],[10514,"e489e28dcc7bf80929c0d1852344cfedf92c5864a2f117535d113c0ad1f917bb",9.917710196779964],[9466,"5ad34ef10a8502940be09b9dd4bb9882aa9a3e52252e91c8c79c99965e3febc1",9.317957166392093],[633,"e53ec6828c4122d9f966d496b75ced906cb9b6b1c2e6af7d949315032058b2fb",16.057761732851986],[18631,"e83270dd204f64693119595fcfc472d038e8b22f7c1a4492c5a5e59d4a03842d",9.647446457990116],[7657,"2333f959f45187f0cc2c5a662f9d15691b568b4e6640dd29f8ef5f7abc41dacd",9.317957166392093],[8099,"ac2fac98cb69fce63c4116e6de8c5c18c370533debb89ff820a5e5fe42fac5ca",9.917710196779964],[3038,"9aa1d12f5c23fed249a1db8d0c5d8be31d5c27b8073d9ed66181ca4a061610ec",9.917710196779964],[10578,"346bae9220f7f9e06a7eaf64199dee9fc6c1a7fcaee51d8f3a75cbcf1e19c1ba",9.917710196779964],[15925,"23dae448b36c7ecce5efc324b91faad0abd4ee8d87d6ab86de0797c115ab946a",9.317957166392093],[12127,"cdd13e35b86af45afb3350d31a39313ba9207ebf8aae61429a6e1027162481b0",9.917710196779964],[4014,"5c8e5a069e31697a2b67f86cf0c66e7d203a4ff0d68612b33808139e7df6a6e5",9.917710196779964],[14001,"3bb44db87f4bc7138b7098d6466810fb5a7d3215b4d90ea4b23a324bfed5e294",27.853658536585368],[12465,"26721165764213c15e248974ab14d034fc4bb3a6b594c95491e53901047135ae",9.317957166392093],[581,"efa8bb45e8ddec4f35f280b03d1b663efb2299724f600f9ef4d69ef5a1a909fc",9.317957166392093],[13805,"4e902291d37a6dc9b0613ea32b719b995b1320558f56f209ac49b0b739144299",9.317957166392093],[7804,"eb178bd7d8688095b22468e4bd5dd6fa41933020116da5593fb3b63772c8c1cc",9.917710196779964],[4958,"dc122dfc254501986eb7a7d1694549f064ac66f3fd1662e884d981c939e47fdf",9.917710196779964],[7518,"baa922c9fe0a95325a7478800e48b128c0b4161b4ed3c93615946035992daace",9.917710196779964],[9433,"2a93695275602a2bcb3f31c21a9c00f112f92184628bad208da20a3fe39724c2",9.917710196779964],[4567,"067f3706825f8606032fbedaf96cd1c328def12cb7c676a42ea0c8e1e9eddee1",9.317957166392093],[17882,"5e3e8a5b6d56d94aeb79ad32034c433491fc6c067019216b17b4520aafd0a83f",10.052724077328646],[3441,"686ac97578f99776b683a60e2cd60b455677044df5d352f9888241ebb8466de9",9.317957166392093],[15583,"abdfc47939df067725eb758a1ac79d624a9d770460c564ab6497ca608550bf71",9.317957166392093],[10479,"41f4d1ab40ff75cec9ef6d5b3e73476df41c030dbc710ccddf2efccca75f45bb",9.917710196779964],[18676,"0910837ed4c63f098befa3abdad98a4b64f0e6dc3ef70a34603f793664fa7f2b",9.317957166392093],[18784,"d2e6a18414f6bd07dc5183e1c4d049f80e7abe77ffb44bde04a41aa75af19c27",9.317957166392093],[6361,"6442c5f9ebb5b048788b89d788d56b0c4284df93e91a57aea1bfa14333919cd6",9.917710196779964],[1575,"cff529d52471c0b3334798052af873b4d65c83e662b6da58f2dad5a424abacf5",9.917710196779964],[7906,"6b633348ea897097e82a8e7ac5819350daffa58596d38ea02f040228761f33cc",18.116630669546435],[15141,"1f12425ab8f6faf6274460113515bf8d1bf51cadf7ca068348da8ba45572b57b",9.317957166392093],[19271,"ed55ddffaadc79169fc94d2c09993f199140ef516f1c21aaf0065939b056e715",28.848056537102472],[1990,"9dceb3579a8b352d0865e49eb78e1e516a0fa3932311171a12b8b7d4a54811f3",9.917710196779964],[11711,"665784b7bbd5f4611fe49c1d8e57c7c5f733441b3891f595ee1a1f75f9143bb3",9.917710196779964],[9838,"a38b3bf9c373da0c00f0695a53d15190e0b8a6d6607881fa4976dc66b2345fbf",9.917710196779964],[15174,"fed8ccec80294c7c93a79b352bbf10a188892e67841116809601d10ef709057b",9.317957166392093],[12840,"3ee08112ab7622cd66f341cfa08b28153cc68d37ca3a825a2920fe5a472db0ab",9.917710196779964],[12695,"d778e6ffb55f45b7d42258b3f3299de7bc4d8cac3ce8a59c995ea72097659fac",9.917710196779964],[18166,"c266a2727d31550ef84c88a64661e9691154fde0c9ba35e4a363036b34b20a39",9.317957166392093],[11874,"ab270229a919e15eaf64580bb767ae3d5619d20406b1270c9123579c4b053eb2",9.917710196779964],[9775,"917b35e08292e298cf668b8669d5f69941d5fdae142e8b932d804d261325d3bf",9.317957166392093],[11713,"192757cd44da2a15d8f5bfa3c1517ce8e4ebb913f710b8746a957de093e639b3",9.917710196779964],[1480,"8899d7f560988acf6e3d23e198e6165213b6c89b91c6c6f1ceb39db55bfa44f6",9.917710196779964],[3401,"1013ae015141e660cd55fc5a9a0982ef306dfbbdbb278b9db8f300577e76ade9",9.917710196779964],[11217,"428f0cbaaf26ac33605b42438ebd60df32c0cfcbf6227249ef01f3a7d2c397b6",9.917710196779964],[19854,"d7ac3f21bb6f475203c4b9cb071f3de5172a37b0def103efc8af1ea2e2c1ad00",9.317957166392093],[7479,"95d6c90ae4e64de11ebd6da7fc6ec4cd3cbfe3018da187e50b113ccf3d95d7ce",9.317957166392093],[8046,"4f3fa6e599b87ccd28f078b36e6dafb067dffa2d72fa10ce41ca9d79e66839cb",9.917710196779964],[6751,"a05590140c1bca73e3a600d60ab0bc2209490ea4ad1a90fa2398599d71d994d3",9.917710196779964],[17089,"cbe42cf11e6006c51c37adf7c41cec4fa2a7dcde25faca2215f817a442fc1650",9.317957166392093],[17362,"42cf5d5489cee06798aa704f457c8d13754fe200d79e5367f5a41b7157f9934a",9.317957166392093],[11532,"7457155d188411df6127eadedde409b38302929956bebd031ca532ea50ff56b4",9.917710196779964],[4126,"c52e9eaeca3c70f545619a96d3364eb0ecd9ad34994ecac3733683e74fa5e0e4",9.917710196779964],[18331,"818381f0cf410b146c819d5499b425e2a02527f646582801a47b559060a73e35",9.317957166392093],[16760,"8da5dd4397ebefb3dbbe2b0d107eef3dffad16a0ca893ac3f63670816f383b57",9.317957166392093],[16289,"6ee6ebbd50e5d4a0fc27f7f128d7d715d5ca8d5c2adb53a9c51f9d2a4ba46561",9.647446457990116],[13560,"ebf8d0afd35f9e5a2da4e21c3db6bf5a220b9161583c06a82d4803d8870c799e",9.317957166392093],[9284,"4c7d6b070f3816ae1ac0545e72eafcb5095d4b5b463d754577b5c5714393eac2",9.917710196779964],[6058,"1144dddfd2d83a7cbd3697dbd336e6ebe442877d80b309badaee79b5c379b8d8",9.317957166392093],[15215,"79429a0372e5e0776903b54df834caf54349969821c91d754a468fa66ffa2e7a",9.317957166392093],[13046,"6c6a81e7554f7e443944de5337e4f25a2800882d4a9dcbd778a08bfd4b494aaa",9.917710196779964],[4316,"fe7fc42768e730482f02855d499241ec00c381d7947fc788a141fbd62307a6e3",9.317957166392093],[14798,"66fbd76745c109f33d14545ebd075731884643d1930c3dadf81e9b165bd4f982",9.317957166392093],[12403,"6de4d0e83a374df9ccffc08ebc05c69e04e025cf4de0bbf5260b8644728b97ae",9.917710196779964],[6763,"cb0b85cdb400b5df7ca78265600950c5f787637c248cb631f9a7d04d18ab82d3",9.917710196779964],[13418,"2334b0561d236a27d8615a9f0a3eb64eeb0a2c2eebdfaf384e4398f6738104a2",27.130168453292494],[3104,"8bb5742dc916da0bf9a62501d65d012d68578fee2bbf96e9300adf4740dca0eb",9.917710196779964],[16803,"1a6c9ee91b1db592d0e701fb7b91aa5d51e154bdef864afad4377aca98f52d56",9.317957166392093],[19582,"0a48a964a80f125c1a4a3dad0fc98f739f754fc9e84698be50243b2d7c12ee0a",26.40963855421687],[7018,"679db1fd2ae4d50bd9a533d6c659cb3ba441383c659fc118361e4f52f36de1d1",9.917710196779964],[3180,"a11f42a10c4864f9a76d8ac6ab225ec404119408a2d640c01e8b3bd605d325eb",9.917710196779964],[18670,"c7e734e940678a443b62c1a526d523e250e32419ebb077e3cd73446b4a99cc2b",9.317957166392093],[10147,"26194655c320761c19df8f4bbdf725ef90c36f330a4ec78d0eb7bd654ab067bd",9.917710196779964],[19121,"f52e7163f65d116b8782c43011edb4afeddfcbc8bd8a6073de8332289d008a1b",31.03846153846154],[414,"efdbdc33a881cafd209846ee8178792c4cc2448ac29861232a9407691c2546fd",9.917710196779964],[3226,"1b741b2bf7f8492f5606ea0ff3f368d246a21712771b12390adc00bdaff7e3ea",9.317957166392093],[12572,"d9aef47c7a2a8dc8931d54c1ff68f5feab71d1e808ec5bb14232f0bdc26170ad",9.917710196779964],[5644,"c19b39e638310b5032ad39c25c144dbad64d9a6f813685f5689edafe71415ddb",9.917710196779964],[6230,"15aad7700f66919b6477b9c43ec307992ee6f967d1f8d05aaef8b883b1638bd7",9.917710196779964],[10708,"790e1222df0f5267d475404b32d1ad67f935b5a2853aa1f16a4e373dd896f7b9",9.917710196779964],[4257,"19d68606dc9149a864d725f4bc606dc9e7f761dada27964a1c7bf1b14f6b11e4",9.917710196779964],[8267,"25aae0714d98ee60815d73ac4e0b7d440eee9eeb481b2af6335b12e31d3085c9",9.317957166392093],[17081,"793c33159a1e7c762fc10822e4c672e0fa69bab070ff8e704de15bb304004650",9.317957166392093],[3702,"57b14edef077f2b8e852f76a3e9cd7e4fec5513e10ad62b3691b8d91a40d95e7",9.917710196779964],[15777,"b19580c9adfe69bdee0f720230f5f09d111e0154137e116b23e29c080333c36d",9.317957166392093],[2917,"d81b0f6346bc240fbd4bd9a5d180bcc418a936402e85e3d13b4201c17031f8ec",9.317957166392093],[10220,"b052670f37fe56f2335ec3b865240f222b78b5ba418aa9399b0155345bc9d5bc",9.917710196779964],[7069,"f4680d93ced41d09cdea615ae2d453fedf2252127e9c5da19b7b0eb7f98084d1",9.917710196779964],[19415,"0304a30c17fca7277fb34b76aa870dd5438478ef604a2a388adb8a79362bec10",9.317957166392093],[15382,"894644fa2846744cb9ebf8abda51e6ec1991eda3eee1adfcfccd3039a1b0c076",9.317957166392093],[10581,"b06f0533dcc8fe9800964dca23fa3fbcc7eda4ac80781858b80fc1319ac5bdba",9.917710196779964],[12481,"69e44a6ca05ebd473f560b2c91bf853f1f21c0fb9ef5a3f116eb822d6ffa0aae",9.917710196779964],[13899,"f9f12381fc751a59966c1e590526def4f9b91e4d55ec821daaac7385b4f50b97",16.05925925925926],[7120,"4e67f5bef3f6b18ddb43c0dc62548b49757f7b5a775dd112d38ee8796f0f33d1",9.917710196779964],[18314,"a8891a2308c31d5211bf3f574036bee1aff06a5b2b1deaf2b3daab77af938f35",9.317957166392093],[15826,"6d232391efbc7c87029b081b6b3a985f1de9f090621fb746a4c739f98095e36c",9.317957166392093],[691,"f8f07a3aa2d1d7c53049ca9013ef7366b15711d108d0b99faf4dafc8d6674ffb",9.917710196779964],[7051,"5ebf4a8657517f1a351369c45f927434ce4ba69b923bcfd318da2522d185a8d1",9.917710196779964],[15596,"fe44fca9dc76c1f8388ed2ab71ef8099e3ec61a88516099d5ec37827f7126f71",9.338112305854242],[205,"e30d66f526128f41f8c4795e22e7c659520b7c14961f34a82e583fda065d97fe",9.917710196779964],[18688,"a332091a6c71e2f5f5863fcb3398da57c502f8140b8630d77de5a7764afbc42a",9.317957166392093],[1856,"0e7355edb11d14db95e72a94f170efe200b0563ea0abdaddceff7344155ae7f3",9.917710196779964],[137,"dfa9adc930375fc7266e29042bb184084f13eabbe0cb616b6c698f1ba2d813ff",9.917710196779964],[17022,"fd030806df3162bcc32355ed910b4e07c27b65beddbb7264d04c475dd8a77e51",9.317957166392093],[5727,"28c6d3dd4bd20765101887ff74d58861e4fe3b5dd54eeb5946caa017e1f9e4da",9.917710196779964],[18302,"0cbb77ee7250670d65469758a531b859320cac96c5f05754c02a7439ec13c735",27.908045977011493],[5310,"c7b5b3ddf2d43bd98c269afa85690340200ee1993b072b7099f7a67a948352dd",9.917710196779964],[3031,"bcdfd87b2597518e31f2865ca13b818734d2df27598e69269b76d2df284319ec",9.917710196779964],[16976,"ab7a22981d2a6dc892094044f63922ad66baf592095d8b289f75fca4286e9552",9.317957166392093],[1065,"34562174736635004826bbc252fd51ee6f7e6705c636109d03644974eaefd4f8",9.917710196779964],[10188,"30f6a1c56d9bc4c8d1a8a8b5538adc604cd39ac043a8d25fb8766eb8a83e19bd",9.917710196779964],[18940,"1556b64986e502110af77111720cc2c20c0ec84e4a844d741574d6d5a1ec6b22",9.317957166392093],[371,"d6dfeb80683b213d4adae9a69b9ec6b8bd614686db37f8ad133e43271c5098fd",9.917710196779964],[6383,"af4c9051baa10c71fd79f61f5797042eb73faefd0e34852066abcb003ee16bd6",9.917710196779964],[15102,"a894bf6d4b158f25e594106f96623bc9e7eee59b82f775864ec982cd722f947c",24.252991452991452],[14727,"577a300a3fd9ac66593a6d23ed0ea7dd40c8f80af8c4be713b938714723f6684",9.317957166392093],[17238,"a22d109cae20309a1e6a8077d1c9d1f96775f8d5d44d6429d060109ff6c6194d",9.317957166392093],[19759,"e1f3e38aaf25edd7dbb9f7baa8412a90a16f5196f73e0d1d461762979e3f4104",9.317957166392093],[6902,"c00dcfb6a49ed3be60994b9631a04b62ed1bc8ce8609b1e14785cfff8ecc9bd2",36.883553421368546],[15246,"181334adb4a3ffd9bc59ec98217ba56e52cb8aefe20dfc1c939c5b7f64768579",10.022779043280183],[15670,"7381b75046a4d47e0ec758de8432656dafa0fcaed6784992099fbdd436f90570",9.317957166392093],[9525,"dbc93ecb0c5dbfe2acf2701a8524eca0f3f2ee62d3030135988efebea4c989c1",9.917710196779964],[5734,"ac18e0c1420b7cf03f2251d8a7f604d41cbdfae58e607bad3aee89cf8d0ddbda",9.917710196779964],[1286,"71b9b173a1fc2faf53317c5073044319a2ca4bf956a50dd11860205213cc74f7",9.917710196779964],[14839,"88dcbd25760be6cf38e5769dd88242ab714f413e4d1f2669a705226598c92e82",9.317957166392093],[2668,"9466411dc3d66e6d7936295f226ab1927dd942c766b019ca0ad3adb595fcb5ee",9.917710196779964],[17048,"a9e4fc1ee74923e40eacf9aa56dce28d3a681da7835d33d2f5ed4b6a3c8a1f51",9.317957166392093],[6610,"3370fc3032363357c6adbf847ee853329586b047cc942303eab916bea91893d4",9.917710196779964],[14847,"58262343adf007a85fe7f7c05eff41d2302c4b6219555a5d75328ca64764fc81",9.317957166392093],[6031,"a83190ffa507a4c6066bced30c7693828630391fdb5160bc4e2cf8118fe1dad8",9.317957166392093],[11822,"10efcbdd82f1a1c6537faa6c83432c74248ff5fb65c4a9b83951b7dee8e590b2",9.917710196779964],[10194,"323e690fff39fb64e9d93fdcfd7db636e35d42266ba2fa76b825ff03f5360abd",9.917710196779964],[2179,"677076452383c4f93b97965a6dce4653c0b456ed6398349fba35e49ed534b0f1",9.917710196779964],[12923,"6458ae9afb7f6f76d5553bd8d543521887485baacdc8725b4f3a9b89a2b725ab",9.917710196779964],[15861,"30cb31dfc72d62ef0d79cde6c19252ef18e2ff11987410ac98585644ca55ef6b",9.317957166392093],[4077,"3be80e675486c6b43a7d0a244c5f26eebcb066fabf66f172bd94a358a2bd35e5",9.917710196779964],[14577,"d591011b8198da8aa7302f0a4e1508e9c5766ab3e2c9db520f343e60b4678787",9.647446457990116],[6833,"573c71a8e6763ea49b6d0216a61a92aae0b8b71e8c069a0064905988fb2e08d3",9.917710196779964],[12870,"81d4735c759f392fc0a8c18b2010aa0d6d9663756b097206cff0dacfea0471ab",9.917710196779964],[2642,"11c6c76936bca3ec97f4723c5f29adfb600665e710bea6c96319010ee576e3ee",9.917710196779964],[1903,"aac0b5f5d48c79e087b9630538de9ac2c301af697ce1555e7cb6a441d60c9bf3",9.917710196779964],[10288,"ce8f3345196527cfc02db6a6f378d3e7e335f8ba0a6253e5130e0921d67d74bc",9.917710196779964],[4949,"01da9631778e8853468b0cd2e172e65f0f35861d192f321078024fd42fcf89df",9.317957166392093],[12608,"0a1cff5fd7395ad49a75bcd470cfd5497daf9400c68c1ab24891cfa3c68c36ad",9.917710196779964],[16926,"65a092c6a49e4ea97629daa0fce44b9a36ebca0f66da0162cd563a71f68dac53",9.472566371681417],[1771,"02f2ab737e4f382f04ba44e720e49ef22341e55239ec7ba4d9881b9281c576f4",9.917710196779964],[19526,"e39f23357e765b01207b746364e2cbdd63944acb06fb980181aefc3afe2ba60d",9.317957166392093],[14471,"11a6cf35de0d2e09949706a13ca13789f7c37a6988fac8705cb81b1927a0db89",9.317957166392093],[9717,"9a5c2fdcc2c5d6074848bd3ec1a0c3cad90268a7047ed7b9d367770102763bc0",9.917710196779964],[2675,"c9d46e6895e446b419971f15c9ced7de72ccf36022d92e270ab5380db8b4abee",9.917710196779964],[5962,"910f7542ff055432d7d4b4665e57c1255c1a8cff2bd6ffaec2fc400d338855d9",9.917710196779964],[15092,"cecf55bff0fa9bbb8c9e93d7915c54610da63b28d14f456ac7cee6c25cf5dd7c",9.317957166392093],[14433,"d6860de158ca02830672b27e390eb34745eb10838be3f3a545a1fdd304a7a48a",9.317957166392093],[4477,"645fb60229e6c984346ccb7e13159cf783e6bb24a6470cb0851a89276a648ee2",9.917710196779964],[15739,"c80c326da600340a02e5a11c6d439a4137dc929d4307e6ec38da3ac60c39a46e",9.317957166392093],[17051,"330abe5f4b6abb58b05c743bed29a0167da96b003e1b55d617bffc5b3eba1151",9.647446457990116],[3621,"13bbe120f23431e8c5877846010c65903f80c988fb484b9915a773eef69019e8",9.317957166392093],[15786,"fbd24ba6a238828c9d4cd292fbcd3379fa7a98306ccc2910fbdb1068cac6966d",25.30812854442344],[3017,"eaac34206bb74e3f80b8ca12e45d80d84e21c656b99ba404b3bca8d8c63e29ec",9.317957166392093],[6288,"4984b12477fed73d648f5b772272fa92bb70b09936934506a55a2f38a9af25d7",9.917710196779964],[7979,"00cec4b92ff17eae2ec35cbb39d6b5fac04b540a7ab231cb38aa372f1b18accb",9.917710196779964],[2256,"ad8e086cd4dc355211362fafba55771dce7f9574e790c0233a448438833038f1",9.917710196779964],[5782,"748315b3aac3fead60d1d9801057e0cfb39a842dc1c20ed6e82cb33b566c8bda",9.317957166392093],[907,"7ed861247e465f2815e87c94e95cfcc8c93a88915a9c7dc34cc7f3db3682c8f9",9.513513513513514],[16724,"9e0bd2fff8e716c2ccd69f876eacdc172974a2facc01ec3db237fc922fbef957",14.188034188034187],[11939,"00e35212eda0896524e46beb07332b5f35ccf6692dbb8f8423d4cd2ac9ecb6b1",9.917710196779964],[13742,"2447e8676f2273562a04886048347d2785b588943273e94bc2f0d3298c589b9a",29.28798185941043],[776,"163da14380670d726480d6ad5b71581db0ebfd33561d2f52fe26abe8914db5fa",9.917710196779964],[15791,"aadd8a59c8614dd67c1554f1ce4907fbbe3c7c671f8b5f46f636db3deca7806d",9.317957166392093],[6362,"5b231526ad818214b6a2b4ddb0d638401dd49609e74823e6d96bd3bcd7239bd6",9.917710196779964],[15107,"5105f9e1b7f4d4068889393615580106b6d8c67a205a7137d2b850f2888f6b7c",9.317957166392093],[6380,"8ab8134326ab8925a3cbe0b9b71c4984944413ab91d723fce226d7837b2871d6",9.917710196779964],[10554,"86f3c527e703cc8edc4af94ffb71095356198635be79af14b63d4efbe1b1e7ba",9.917710196779964],[19349,"4a63130b53abb5814aa8dab81084c5a9400e0ee4f02690874523868ac23d9613",9.317957166392093],[19801,"407fe8b0b8a9602f3af3f2c625feb4ce05d3115579dfa58a052d8ba0edda6f02",9.317957166392093],[13086,"86083a349fb1833c0b5194b458c5abe56f1f752fa107e1787143aa6de4b5cca9",9.317957166392093],[13648,"75a84ddaa7241147372e3c358c2bbad60af1f7540afb1250b78ff96011d8409c",9.317957166392093],[383,"cacf610d55cc6ed54c779453aa6e372e27ca479e0cea5d5e73ca4fe6557978fd",9.317957166392093],[16839,"7d603d42d9c0fe6ecb7329bcc2f343f3c6ab788f4a58e776128965d77d0c8255",9.317957166392093],[2416,"e75285f7e8f877c9b4455fc9d0815403e266b4bec3879d126933a30cfa115cf0",9.917710196779964],[13516,"e55b0fbaadc68eb47e5857ec553049ac2c5ab318f217fcb0aac413c5d83c739f",9.317957166392093],[9218,"68fe0cc13bcc2833c62c48762bafa8cfa36157d8f8f63109caa2d0b1469f5ac3",9.917710196779964],[11234,"020ac9f9b0418937d0942fb8a96411a85b8b2eea9d826c11582e8610e5d274b6",16],[8858,"dd9dd8a440b685328a13673a0c7a18eeb7e2a4f4d9888bd2c0c0d83362cebac5",9.917710196779964],[302,"cb373cd384f218827a1863ca72be70c65d5dbaf3032998537af54a330a03f1fd",19.19290174170227],[9825,"a4c78ee3e65b419e77a0283187c4bbb8ebda948555b7f02101a1f9d3397478bf",9.917710196779964],[5859,"1e7197e7a00e5eb08133ed691dffb4718277553d45ed373423784240bfd0e6d9",9.917710196779964],[6269,"3e6eb41f940c74d1c5d987f139902da65cdfcfd1b925eaac6cbd71e9a37a4ad7",9.917710196779964],[6491,"8e9247072be2476813560f5ac82fb46fe8460b06eceeee3e33bdf3b9b29e8cd5",9.917710196779964],[17800,"221ff7db0581c08cebfc095337cfa8133630b8dabc82e7f01c9b473446194a41",9.317957166392093],[1931,"1f407f1b86f349370bfc19f3de03f41cc051d5c5ed73152a7821d35cc64e7af3",9.917710196779964],[11067,"6063b4bd8c2ed3876200354744d8228a3478d9d384a8750d525370689eba88b7",9.317957166392093],[4393,"a285ddd0e56fc80b0b05092df14458c9acf92cb85da0fb2fcae02649a38420e3",9.917710196779964],[5884,"70eb93d2359c26856b71dd93b860272e58b9a2055a9bf1181221accc7c37c5d9",9.917710196779964],[1141,"9598b1685f513411dde48b97b63045d860ea81c008253fe932cb212649745df8",9.917710196779964],[14296,"a6c4f7c551efc51b64c88e1f9f403cac28c96f407b699ee9f99b6a27f46fb98d",9.317957166392093],[5838,"e58787442bd88415c225a867a1c636ae08783183d9fae55e915e42e536ee16da",9.917710196779964],[11386,"3256d179354767700efcd5e1470b1d3e626c3a9ec350e1fdcc51cff6f02b79b5",9.917710196779964],[8023,"953a38053764e2b8d81f07ef003bc40033a51ecc538cd03c452649c2f2b568cb",9.917710196779964],[8815,"0c17f78f38f5e47d649a8cdfaec2c7e8c1db7eb3401169e00f9d56fed7ed02c6",9.917710196779964],[11025,"3cdf23626784eb63e9e3763d9502f39dcde7d01ef1c5c0ed98347c0275eadcb7",9.917710196779964],[19540,"fed77dfc26915c96341720cb5f83f871da89a80868513828d5ea28ece1661d0d",26.138053097345132],[19175,"ab717d466f8b932633ebbb767d982b383507d627e46531cfc2d92f8f50cc8c19",9.317957166392093],[8834,"469a5443e3e1d6905a8a07ae9cb1cbee24b09be4bf894239285340ed741de6c5",9.317957166392093],[8030,"bf52fbb6c8a7e7c268225eb230f269f4571b3684e5bff73ada81e37244ab5ecb",23.844036697247706],[18207,"b093cceca63aa7f7199ad6f67765dfe19acd8b8fb581e3b755c28d344b87e237",9.317957166392093],[4410,"c0ef4b0f493b92ce60874a960aefcb5512a3ff722ac31e58cc7e17cc02f604e3",9.917710196779964],[1338,"418399b703a1825ebc9d9096c1eadc79a8b2f987532201405b709bfff46128f7",9.917710196779964],[15345,"aacca0b012c6fc638711b0bbe9132ede2ee14b44d0f1318ef868d862da9c7277",9.317957166392093],[5348,"0a37f25fce4e4a9750cd61c56d7f9e60c390019bcb2b174da26db9a9e8f828dd",9.917710196779964],[3985,"e78c679b11df1eda5156a778dd2dabb6497476c2c606b72d105d56e7b336cce5",9.917710196779964],[12510,"e4363f5283afb3ea52b721e61cc187a3fc6111ae457642b740642e5c12ebe8ad",9.317957166392093],[15426,"7db6de9a0df41022c599233893bd978f70df6d33d9426b4012d24730d755bc75",9.317957166392093],[18830,"ee9379381ee1179e07ae9ef35a586fe3fff12cd7e0a9877b36766db581bfad25",9.317957166392093],[5219,"28a39e6ae74dea1489afdfc5e4f64e5c0cf5e0efd3d94dc936e7647961e0dadd",9.917710196779964],[16053,"9a30c9b1d531ee8111c6ccfd873f276f3c3f835ab64fc29501da4838541a5367",26.09252669039146],[8329,"0920eb6475439c4cef3252b20d342de49bc308b46ca755440d48a9acd89821c9",9.917710196779964],[17082,"fb0a301fe628e701295ea35ec5f3c0d92ace8377c2e5ff74cc76cf9412054450",9.317957166392093],[4631,"a34ec385b1f551a3749779aaeb2ce775e779b4137041b7d1f4771fbd93ec6ee1",9.917710196779964],[5652,"608af9705365616ec3d855822b8d925484c89d92a4cf0beb149cd6818e904fdb",9.917710196779964],[18892,"1c55db5c8a57383bdb6c1e8f51aac3ef322850f83bdd44feaada51b0b75ab323",9.647446457990116],[14815,"88b99db57bc6a7625be2ff89bcab464d052e8c50776ffe7cdcdb7e7c27827b82",9.317957166392093],[5388,"6884a90ca8ee185c635bcf0eb7b342262d078882f53a70ed129099bb03ede3dc",9.917710196779964],[4964,"fd677277c65351f806121f27ec668678c735eedae10524be26001be49a866fdf",9.317957166392093],[12702,"b71c92732ec5b265083540253512ae68d54ca3443cda49b6e43c946eafbb95ac",9.917710196779964],[10713,"7f9edb9416c287ba279dd77c78e8e1b1b8057a705b39aa75951f5e0c8c3aefb9",9.917710196779964],[5265,"da51a9ab0c0901b8abdd111d28c5bfa1e3bfee3aa6b3f9c05a233cc5178a97dd",9.917710196779964],[14927,"d903b23d40d0d1bc15188a10d04d82aeae5c1b1afd388ca4e5a18af25ee85d80",9.317957166392093],[8454,"47194bf54b18a924aaad7c0f22c7bc2dc72d67535e31aa0e249375c122aa4ec8",9.917710196779964],[13996,"77e6a03cf638527b4ea0d1559147367ef95f343ae10724676048e9e274d71295",9.317957166392093],[12919,"bd8b70f3a7d9e14ca975d26e5b2ed011bf931e089d5cabfc450ac320f90c34ab",9.917710196779964],[19682,"e18bb373685ef477cecf226f9ff314b33c61dc5313c308407e7b6622dda34a07",20.71301247771836],[5743,"d411279bd5a72197e48b55693ada6b793e6492e23a55c55a5702c77dcc83d1da",9.917710196779964],[17025,"8274341725b065d022dd84ebc5b855948c8e5bc7150ee95a6a24570b3bda6d51",9.317957166392093],[4286,"4cfea907d98ef4bba6b64435e6ea344bdb31595c7201a5152703c7beeb95dbe3",9.917710196779964],[2426,"a94ae7e21c48face50a62a7f86c1e19e8d02305601fd651acf817f656bdf4af0",9.917710196779964],[11539,"fe8fbd6c3c190e33193fbbd625bf40cd7e048cf5895cacb2f9a9b79e587e4bb4",9.317957166392093],[610,"aca8d315b2307938957eb35af75876bcb9318d1e30f3478bda9d149c89e9defb",9.917710196779964],[12214,"5c7aaf76ed041ff7b7530b383d7f01aabcb6d3c29324a09c4ed363774cfa00b0",9.917710196779964],[9208,"b3efd5b8dfa08033c86bb9ad3febcd69453e2be27ad70b0a419356ccb3e364c3",9.917710196779964],[10516,"db42ede91cc8eccc2679d4c079487ce35ca521441557a795115f818e9c8717bb",9.917710196779964],[2555,"e69e10ed5bbd6f934ee84afb5996989247392a0644e119a4cac1b66f9bc181ef",9.917710196779964],[2033,"22099dcab2f0537c55e5092b180cef4e32c0e4f6e7abd008b9d25cba1fb2bff2",9.317957166392093],[19336,"4782099ef92e675bc51260e809140ab7d202933857a7f94bc5e35a324d150314",9.317957166392093],[19267,"6fbdb8a7abe1ba6598bbc43b61be7b2657b5f76bf021e50618ce4bb5819b1216",9.647446457990116],[16025,"f48eaddf0e019def8f043568dff6656610dd1f942122472b5a2de5ebca2df967",9.317957166392093],[10372,"414e402151132eaf99e934310744042373f6fd7456407f4576e4c2027783f2bb",9.917710196779964],[8512,"944b9a08b9b3f7da4d7c15dd060bba0ba5efba23de78b29472718c50a26bfbc7",9.317957166392093],[12787,"7dbce90a791389b23576c9e22068bbe85c7bb0edb61bf5cc7e4662a11104feab",9.917710196779964],[19120,"e1d2dd06305c1ada415ff4e22214d15e38a315f4cf494d93b06186e3fe2c961b",9.647446457990116],[15914,"f191c24710777b9d8380dd3192ac906cccd7ce45467e77380f95a44f2eb9c36a",9.469939523301317],[9954,"5528cac65e799229d2c6e94a5b0645e2f9a5717acc21796598c5465c44e89bbe",9.647446457990116],[279,"a7d8ac79eee38a0fcd614987210266df03cabb922059da43866a1ae1fcf012fe",9.647446457990116],[14273,"11a90d5169422f270ee8197f9b4c546025d2eb75b9b2bd67d0c4d94de2207c8e",9.317957166392093],[16983,"057c14adb514a818953c869a57867f38ff2fe62a64528c1f6e9b08a8ec857452",9.317957166392093],[16644,"9158143d39f80a42a4e9b701b43ea4f5045f91a13144ff05bf5028681bf6e959",9.317957166392093],[13667,"c65d5ed873717b2757b5b0124e336fd504d7e4462a27533a14acd3c8b7c4f19b",9.317957166392093],[3325,"c29dccf3c67ce78cacccfc35774e0fbfb5689c349f897e08276a332e597836ea",9.917710196779964],[10061,"72cce8eca378ded76a8f15e16f97b2df86fa7d0f4bd5c01a7a57013695a1fcbd",9.317957166392093],[15984,"50582eca80c368518877a00b5190fe9961f6b0bbaed430c609b0555c3f28e168",9.647446457990116],[410,"7f0d27adc44a31ccbf93bfc2954626055760b1f37c1bb990b946933bf6a84afd",9.917710196779964],[13685,"c1135754a9bb6dce543da6318f36016407c0f99d03c4908f1e23d1108ac5839b",9.317957166392093],[5461,"d1caab0308a2cac0bcf20f4c790be5a2e96a2892ea2dbb5dc9a5bd854a826edc",9.917710196779964],[11702,"f01d59332f2111e846e8a640cfd71fdc5544cf3e58d063fe6e0d71b3fdb54eb3",9.917710196779964],[8934,"21dbf84c5b9e24747faf8fbc9f9d4c6859f0ce1a809bd5cacae340af078f48c5",9.917710196779964],[15872,"51cbcd51f330ef9b648ef57af30dec446f76e573d22becc4df50103ec8cf9c6b",9.317957166392093],[13379,"8b901f5c4b7c5f9f3eb7a74aaf1a058b499e353b52f03a40d12b061d03f8c6a2",9.317957166392093],[1328,"038ac382c367d0b53e10065c2c7a7126a2f9dd0ef24a2125f15e584b4c173ef7",9.917710196779964],[15982,"7cd0d192f612f7cc73317676657c0b9201191509f2c2ede261a5e4d7a9b9ee68",9.317957166392093],[8424,"f0ed7c7bed76a55ee4ccfd1ae10e54419aad086dbc4390e72974b5d62bb278c8",9.917710196779964],[1996,"e86ee161a0bd4be827dbbbf81c76086305b47844b2ba2e2dfa3bc5ccac5f0df3",9.317957166392093],[18023,"54512e7538487780ba3a1becc1728ea40f9d9f0b008982180d4c9caee227d63c",9.317957166392093],[2345,"2685ef7936cc79b8e6ce5db735780dea414b3fd856a97b44008fc06ba28ec4f0",9.917710196779964],[11341,"892d4247442280f088f293b85b940c3cc758d20d76ba72d7a19fbd53c2a6b3b5",9.317957166392093],[10150,"8fac34cc894d9495de9799024453d89e4ec92603598bca5ed559fb73817c63bd",9.917710196779964],[15435,"b6ffedae9f5c2b80db80872d39f6dbd1dd0b1dd0f9b8735fdd7f797ab2046e75",9.647446457990116],[13421,"9908516966d1e90eaa927e643739b8c461d3e8629f488f6da8681f46d6acf1a1",9.317957166392093],[3915,"b2aefd7b97f3ba45e80ee6eb02966735ac55737da00bd5a77a88926557f83ee6",9.917710196779964],[2614,"26191af3357a7e33fc337e4a41af6828f9d201c940e9f3ce0bbf35c3e7c310ef",9.917710196779964],[8375,"1a3252e4b8634c966e255a7870e67b449435d5da673bde019f74b6f8261dcdc8",9.917710196779964],[5633,"80d9009a2723b9c1928e6a1abf611daa83756e9c1b3b99056df7d0b6bc4570db",9.317957166392093],[5730,"b96252f78827d01965bfc6ae1845692cb777d0deedf4172470ea3d63c103e2da",9.317957166392093],[19369,"bf8163271c1e766461cb11e73712e9804acde37c286d950bba29f78e5f792513",9.317957166392093],[10427,"582a9f3e8c50929facccea9c43a9eba98d8ee05045300f80a2c9fac3a6f4a0bb",9.917710196779964],[15734,"7551a6d1f649b9886a1b0c47c0eae7feecef41fecd0960a9e608db417453cf6e",9.317957166392093],[19650,"919718001a4e513893e040073a40f58e165b05f9ef3794ebdd44fef8b43a1c08",9.317957166392093],[9133,"e17f96c12ecdb8c27225a4ee0925cdcd46a565b7f7b516bf79113b28a31ee5c3",9.917710196779964],[1946,"d4d4924eef9e47f5d971197572e6ebd0c272e8b400be9372321935cb969b5cf3",9.917710196779964],[2304,"7770000eaeb3d1949d1bbea0cfb9ad7074bc0fecf086d70f93fad9d77f4601f1",9.317957166392093],[6834,"0f7ef4fae7d05b460500ea6ddc0508d7f00551b8a788211c9b40909fdaed07d3",9.917710196779964],[2253,"715e773c68a9e6c7725575b944662a7dfbc3b72c4c75439db718e007d5683af1",9.917710196779964],[18905,"81d33aa4a0347b8e3462d2f5594d9e6f9da73a04e28ee5e406584e362e614f23",27.853658536585368],[11240,"2703dcf3342e9afab18abc69efcd13ff71b6beb0cfc782d913caa9d613c06bb6",9.317957166392093],[17187,"ee33833d598b677b865fdb07fc7b61e643aca900ccb776699d9e2fc122c00a4e",9.317957166392093],[19306,"4cdc538ec086b80244fac9aefaa528e5df43a4773836b6a09a2cf0368669cb14",9.317957166392093],[646,"c723459e69d1f5408823df30bda5c04e128c71f80c9f9d7b11a70c4f46a59dfb",9.917710196779964],[1517,"c28e2d40b4a515f99b3aeedbb197fddfffcf786aba13324d00d4929b2babfef5",9.917710196779964],[11470,"925b4069e14a8ef877d2d9bdc5f8112cf196835d097d42ab4642ec2e16bec0b4",9.917710196779964],[11227,"7ee3420ad1fc85ca0d7ca3c47c9f1ee1400111d0db65cde4ff2eb7ef207c86b6",9.917710196779964],[3008,"dff95a446e2ad6358f2dc1bf7cc0c8ac1661eeda67c110f9749a53abd6433fec",9.917710196779964],[18387,"c5e6f0ff499daa102a8731bed3ff91eeabbd1aefd705f7c70defef142c91b033",9.317957166392093],[6459,"f4bd5540335a4f56c0577cc2c6950cc5fea2609f42cb69a288252a83ec2bd4d5",9.917710196779964],[16645,"ce1d9defa1604c1c1a1d065cdf66888431383a79a386a6ffc3b2cb490658e159",9.317957166392093],[15534,"3457e70d43cd3c1ee13cac2091882a8e36085f472fc794d01465c6538f4b4173",9.317957166392093],[12286,"35072f72d05f4ce1be5e21d5ff08ce4bacd9e391d005949b45d37b14b93859af",9.917710196779964],[8938,"e5c4b62ce8eb388f0a4b44161924d87ecbd433270c0893733546ff8bf35642c5",9.917710196779964],[18296,"1401075d2f936a9498d1e9f1291a02d4a0e399380cd0375a9e75848b1467e535",9.317957166392093],[19124,"1e9ac67d040dc1684b23732f40c43ece008ecd862a92e1d6131ffbf87b4e521b",26.877828054298643],[7605,"b73febb42bcf2d3fb9ffe40642a3734bae586fc483377e646a6bf9ecb0872bce",9.917710196779964],[1457,"54f338c8aa73f72aa97cf89e6080ba2aa1f5e56af11abc08cc5fbcccd51672f6",9.917710196779964],[15663,"399c4ce493fb06cfa94c31791f9ea2a7439b1c802156a94b3ae4753d7aa11d70",10.052724077328646],[247,"e3b0abe916c2ed086864863a285a195f43547c61e1218bba5b101f67520c53fe",15.947454844006568],[7123,"11b1addafcfeca5cdbf23ed8da71628e3ead1206b1fdfcef4a23b3d9340330d1",9.917710196779964],[17193,"ad7000530ce974b13cfde5399fd2438a599feef5c8d51cc8e1f4f2c3e6bddb4d",9.317957166392093],[14334,"dd683ca78aad50aeea91796507ee88d98008403e7a26f010189565133c6b9b8c",9.317957166392093],[4742,"275d05609f8d89bde8156278b8b7a5dc2db2b30a28b2e30fedc5ff6898a9afe0",9.917710196779964],[12276,"58db0d63df9625f8f8712ac541b9ebd97330c7316ab2250e22e25b920e2670af",9.57544757033248],[13150,"ac2cfb494f351fc21f565a8a761271e090b6a26c301e9ed4c30d7e57908605a8",9.317957166392093],[5493,"9f21315a607deaaa28cd968cb0b933ffe09cfad2f7d94118657577b875d342dc",9.917710196779964],[6771,"7129cbb4199114d63e6917b7263890e64881f45361145a227ab27e8628d278d3",9.317957166392093],[5322,"8ea435ba2af1771ed50dc754f669ac09adebf563d26439ae344470b1a5e948dd",9.917710196779964],[6020,"cad88438966df41985a727a920e042da7cab1ce1ea79d577e7fe7eb96cecf1d8",9.317957166392093],[11153,"a135000a097b375436320eb1e87373ee28c6215d60586b62a030b2807a8bf2b6",9.917710196779964],[12003,"ba53bc892e89e20e0ccaa6a431eaa8110c9ec7a36761ff9df5293465ef6a4bb1",9.917710196779964],[6581,"a082b0604d78314ee1189a78559fe32456e516cae2524dc302c1e7fedf97c7d4",9.917710196779964],[6301,"eca94b1e8b431649b5af5848718b55e9a746ec5ed82e0e2c60b49f00bf6202d7",9.917710196779964],[2541,"79732c0fd7ebf9b1ab0f317fc5eb5c94c2017ebdc47eae1913b64db7565e92ef",9.917710196779964],[19101,"8344328bbbb43676c390433dca9723b26d6ad9e7b125d547786328122cf6b41c",10.052724077328646],[747,"ad232304aec13b955ef6720fb29962ac90d143a19c614cb5aa9ceddd2a6debfa",9.917710196779964],[10281,"27b42b2c51f2fb2b20490fa0c47584afcf443f0847a54dfee0bb7047b4a085bc",9.917710196779964],[10979,"dbf981486d4855bd497214bd0078da457d9eed7823b1410bc26aa23a36622db8",9.917710196779964],[15326,"a87119c3c00a220c1800b48adf6428f67d8e0a3a8e85b0b67a5159603a50d477",19.12388250319285],[13930,"27204f6531d4969fc8535e3564c6d95ea4820a599d2c45a9bd08bd25df2b5896",9.317957166392093],[6566,"b8d89f34d319792b28f132643e1b66f650876ec78f6c5fb346ae489c9f08edd4",9.917710196779964],[2481,"3e8daf6bbd7d9ba4927f614b136c1068db789406dc55e50afbea921f42dffaef",9.317957166392093],[19422,"9b68404cbfcd753e66e04f6bcea89a6bd730eaff8d7a1ff7c3d1b0374f3dbe10",21.010526315789473],[9740,"c964c77ce81a61883b7a3aba2713ce058eb683a2ed9186a8d08e4410c9ef0bc0",9.917710196779964],[13217,"425e42bdafe206fdc19cda3c06be5ed1f6ef04e4db75d94af0d2f2cb840888a6",9.773123909249565],[12498,"4a9a4e00ea0a3f83435c5ab939211ffb2d2fbb910e1288a48f8ad1b67155f8ad",9.917710196779964],[14658,"d9412fe06ccf7c43f3bcecc0cf24adf11f4cb46d3c448de721ed5a89def0bb85",9.317957166392093],[5771,"8ea2dccbc2bd9d2c63e8a5a85e7321d520d10f00748f9ab412c8c4a2634da8da",9.917710196779964],[10619,"cb1d123ef2e3710f82c45f3e0ae7a2ba4b1d4bec2157ebbabbbe97c5a58990ba",9.317957166392093],[6481,"311b82c6b4c0b52f6edaaf2b3c40a349206865c4965351d4acb3a1f0966a99d5",9.917710196779964],[12215,"5911a7732715f5885406a00b68c9d5a003e1bc30cf74b2673a5e6ea0ccd8ffaf",9.917710196779964],[14049,"c41d3eb136cea7c812784399129a2ccc6752b1b689a32ce25dd554d20c54b593",10.052724077328646],[13022,"c2923ea50fe3fac6ae43505750baf70f59b331443b4b5243d909b16988fe6eaa",9.917710196779964],[17723,"cf0218f63ee145b34e55309229f0eaa632ac54e5ac508decd6886f31dcdcbb42",9.317957166392093],[2229,"9cd2d30c59b92c8b2ff3a507db26132d7d7bca8f3954008d23e86004ed2c59f1",9.917710196779964],[7462,"78ae6b9f65b79368f06c698bd533a159a31202aefa86967e8b5f4e63daf6ffce",9.317957166392093],[12110,"5d512e88b8061f5e3aef8668292fed618efc05844d61fc24edea832dd5eca9b0",9.917710196779964],[13898,"fac603f224d1e9a6e6ee86c8825c89bd2db9846a7cc49c2170be2f9fd6fa1197",9.317957166392093],[7672,"2a187a849a6d3674efd962a972904771481b5f227818c0d49a48ac0fed2ec7cd",9.317957166392093],[5399,"ff754fd1fa00b450a02e542de365c208cf21c74f03726b3d6918cde3db4fd0dc",9.317957166392093],[9289,"bb16bacfaf8bc0d34275b35e3259f7a4afc1f539411b9202322dc09784bee2c2",9.317957166392093],[5012,"904611231992fc1752caed2d582e272a7d33506122652f84c995b062f89f16df",9.917710196779964],[13613,"8a27310ffd7d6c686b19ca8b4d66861b541b12121ac6336e64a3b9efbf47179d",9.317957166392093],[2136,"468b3e76106b4009abe18fe1f1d9c731aa89dc990c662de8da26dbdf97e903f2",9.917710196779964],[16174,"0220d80da33b4cb5baa224821ec563b36bb45f7da5028a78645b8e0d73b18364",9.317957166392093],[5710,"d4901aaf423e2fc5c857778a4dfbb77ad01b5b2d391f22811ed0753dfdce01db",9.317957166392093],[9291,"ebaccbbd316a28796f80a77752f76f01b9a20c0b8d24ea00b4305d1dee93e0c2",9.317957166392093],[6840,"6b8d29eb4cee998e7672fde032c510717c3c47cc9a16fef39628df5dd3f902d3",9.917710196779964],[11222,"8e1bdfb7dc7d03cffc072c7b06cb4e61b4b4e57f713506d34b69a255fadc92b6",9.917710196779964],[10817,"60797b340728d55032d17ba55e44b8a06bb311a8977115dcaf9509be238230b9",9.917710196779964],[1556,"5987aa3294614087b73035785a246c92b8c1fc055bdf99a69338c99e900bcaf5",9.917710196779964],[7430,"01282d78c0ecc31cf70af0b5692789bdffe9fe315007b5516470f48b7f1130cf",9.917710196779964],[18010,"c1001c19692650daa61ebf4fbac615b29ebdce4b83ab128e3c3b6bbb7225053d",9.317957166392093],[2827,"980cde889bebf007449a151baebfc2b26c4b1611a42de40578cbd86def7884ed",9.917710196779964],[14107,"de1ea13af91fc4cf57b068e706f206b109c7dbfd5c099387d0d70df4b3cb6692",25.311942959001783],[15561,"a1fa2a389e5f35af2dba5a627e179e08371106f79fb77866aa3d1bdff1d48372",9.317957166392093],[16381,"807d92084b06de0ece1734edb75898dd2d317352aa311b7cb94b92df5e817c5f",18.269956458635704],[757,"62655582b82aa747ca57df3c3fc529ce598eba9c3a99706362e18d328c3ad3fa",9.917710196779964],[10880,"3ab365fef393d6f550aac2ac7d5c10bfac0311d3377bca79dd00a6cc3936c4b8",9.917710196779964],[17086,"65336a7ea01fbadb433e505a3c818d2f215ebdc8673f5793f62a1e59b4cc2150",40.253485424588085],[10425,"1434d8fb6e93975b8685cb2196698e452e723f96bb02927a23e9ca7e3267a6bb",9.917710196779964],[3337,"44f17495694db98f49d83e8ed98efdf3cfcf5597db6836e1032a8c202cbf16ea",9.917710196779964],[2322,"c66c67d0be974c14309fc4047c613478b0709b2d4040c4acf1112b0cbf61e9f0",9.917710196779964],[3293,"2d001fe1dfe7b0a84c6954c468a94de99ee1a71658e1d53ed760bd6e948470ea",9.917710196779964],[6914,"18290925ec5a53a1b9aa962f376a000d718630e77fb076386870fdba39c37cd2",9.917710196779964],[6857,"39c3ece130110dd8ad116a0d906ec75e39fee8911abf87bff82c95b38ea9f3d2",9.917710196779964],[7059,"fdda8ba422694d33cbaec2448ec8d1c2cc7ef3832336e335e7597692e2d49ad1",9.917710196779964],[17458,"f4fdeb2c63786e644b90812f64bb610f5569f8b743a0db8cec5ce1de6ade9f48",9.317957166392093],[10272,"559da3b02b8fe93c466dbf58716ed7553a8d6fb21bfb3d69f864ca170f9292bc",9.917710196779964],[2313,"4cb12d8b0d80ff4f1d0d955dfbb6706d54d3a293c453617b6a15f5bd6d92f3f0",9.317957166392093],[17365,"8101509a9d595905928f4cfd88590a09d367ced0590e54b02484934ecd848b4a",9.317957166392093],[1894,"1923eb374ce46aab83cce65ce588585955d689b98780daaedf2bcb71cbcca3f3",9.917710196779964],[8476,"fa603647ccfbb80b77b27cc29b8d8c0ad5600e29bb2b5828011cc00394fc2ac8",9.917710196779964],[5331,"be8226688d990aa0ce7513977d715aeda43ab03cecd4515b4ef2bd4794f53cdd",9.317957166392093],[4239,"f1d1878f2c13d312ad30e0a261337f0a200fd2b72b810841da1a422cec742fe4",9.917710196779964],[8962,"e2f78259932960c8fb6b9bc3c5e9b799e5da936f3f1dd3fd3d19f681f4bf0dc5",9.917710196779964],[17220,"2736d1869880c9aab6e46d5e224d7432a72d9358b54f569fef1431dc8606844d",10.052724077328646],[9367,"25d5f8819ff87fedc2e5ecaf04400cf8194cf7602c42ad41a6facb34d76070c2",9.917710196779964],[13249,"bf1576b144f8a8456ca93f75d130a11f2190bb1bcb3d90806a7faa8b6e8bd1a5",9.317957166392093],[12855,"2f49c6df7029de44a40a872f9b41c840e5970c3f0ca5b9622953402936f788ab",9.317957166392093],[3040,"7dce1efa5cc055e736ae50e257bf457aa47433c3410115263bcc87c114950dec",9.917710196779964],[11304,"4f6cced5b860b01d37f93c09094a26f034000a6cd9cef51c91ba2190da99fcb5",9.317957166392093],[14170,"a978a558d22da0c460957b9d92354d1a82cd88dcb55c00b9e46ad2eaece10d91",28.149732620320854],[13680,"58b5331dc6fca224dde3d47c4084ef05b33a071fcc514bc77130649535b7a89b",9.317957166392093],[7743,"c4063a70c251ba868803282f4c1815e9c617386189e46b25ecab9ed461b031cd",9.917710196779964],[13874,"f26fc37928433a4bd7ec87127e744827a968be29c2f6ae23c40bdb9a37cfbf97",10.052724077328646],[1471,"6db74732c6842664c11353bc3edf73f803b156ec3841cc16b3e9ad468c7557f6",9.917710196779964],[4859,"a431ed1c9e5d6da2eea8bce22f29e7cf267d9770941064a3f1ad864f8aff14e0",9.917710196779964],[5476,"0b698e4277481b2a5d6d0993f06d7c774ec991e02f95eb21f1b87724c8f35cdc",9.917710196779964],[14537,"0c1ed4ad999f3aa0c093ae16227a0c5d7eefd58c0036978861deafcf56308088",27.902268760907504],[11255,"b375d9a2c322aa16217955dd1914ca676e37c4e2cd7252e7f3a03d38867a50b6",9.917710196779964],[951,"19e12738eb01a5561c0cbae583002a3552aa9e1271cf91b59046cd93daf97bf9",9.917710196779964],[12529,"9d2c158bc8aac26912b9154b9974f8c137d51b1de93c1d0bd93f08d49dd4baad",9.917710196779964],[13489,"ed52f41ea809db177fa505c4124b440c25d8e3efa4171fde0f7a179183c71da0",9.333333333333334],[18752,"fc993fa6c6a80cae89b3ecdc88ad39898dfe55dab8250cecc5c1f02e6ab57d28",9.317957166392093],[6014,"31b57cf1fa5c23497d8e2c155e836d079ac06622d44cfcf813e20f557794fbd8",9.917710196779964],[7461,"d929df5203ad494d0ce66f0332dbf1f1881caebdd1ee47b233e895168c8601cf",9.917710196779964],[17517,"0cd1bb615e506a347a43677a9b4bb9bd8e67fea7714110d03a9fef03b2be2c47",9.317957166392093],[12821,"fe9d72f97e0ee8f24651b618b92ba9fbdd395514e8dd9bd15a0ab017e8fed3ab",9.317957166392093],[17510,"72dd497c4505f5339b8849834ca0d2c7511b6ecab4e48f9e27cfade7709c4547",9.317957166392093],[12319,"0e8efc1a6aabdd9962ee799ec075511e21fa8136be8106656e3c1787093015af",9.317957166392093],[3843,"3048f835612500e076f11ae68daa0c96bb5f352dc21bc89a0df58ea31dd7c4e6",9.917710196779964],[13565,"d905ebcd88e991b66f22f3b3eb88a006ab9fe22de04d054760e847527222689e",9.317957166392093],[15773,"a5c5d9b9adac9d4e2d2897b87277928b700b3f183e91dc910b7f3384a3fce36d",9.647446457990116],[449,"1f2933fb5f2e98a5dc579159fdc4648a1b1d67d6e1b2c086a47fd97b72b512fd",9.917710196779964],[8979,"35195502859aca6a999c0d21b1c4bf2fd86cc50b5206822ad9a974b0fcbef2c4",9.917710196779964],[19183,"291850ecacf736bb74f178388e9c314516d0d6be72fbf50ac3e2011a9d413819",9.317957166392093],[11005,"052d5d3646675c5b2e66c1da5fc432f7f49c7440a3cb2a842864169e85c4f3b7",9.917710196779964],[5125,"d2ae03870b99a21d6488e30f8546e065d2618cf35783ab05f9d79370633375de",9.917710196779964],[11872,"fa40ff8f17f2b15878eda17b2cbf1dda8dde2db89a02be979ae6b498eec73fb2",9.917710196779964],[2501,"d54a0e60c3044452d6a8749c25438c9508e386fea6151f594a5e327019b2d8ef",9.917710196779964],[16272,"4b3ec3365cc926d0a5f91c91ac03c68f65b4eb6bf802a45f7de89d4246eebc61",9.317957166392093],[16628,"c5a765ab80aa1a636a3152e6ddc5d17058739a735a604e160ff4c765f688345a",9.317957166392093],[14885,"55ebbad856c8d5d29e81f836782853838489056febee91c62aa14e5d41fd0b81",9.317957166392093],[4860,"72eee508f4e3035de2976aed663582f83672548b8ed67254064d7cd9fe2714e0",9.917710196779964],[19775,"9a2cc5d1197eb3539329a9a6ce4dfa252ace93fed970c8d51f54eed558ec9a03",9.317957166392093],[11970,"c9474eb3457154f7c77aafc2bd23529dace528815172f17b95ae9b8c552982b1",9.317957166392093],[19777,"69d09f55c3b2be00e8dd493468b60fc8079257fbd0d6c156fef009a1d9759203",26.721621621621622],[9078,"39013938674cc495e3c4c0f6c1e43df2e2ca73afcbb0286a16f4c6747a9048c4",9.917710196779964],[17352,"3f7b775e6dfd6a17368944a3e4078c73725d0eacfc8cedb81e83be9185edd24a",9.317957166392093],[196,"82f39f74a443d624bba734dd18be1cd8c6f9caf16a00278a28f3f6b3370cb0fe",9.647446457990116],[5548,"a4b945ec837d1aecac68eb7830af925247b7eb45be01bbb1e460b4192ce2f4db",23.404871626069784],[13897,"c454030eb65e66b97196bd6931bb7ae5fe0f490cdaf4151e61badfbec79c1597",9.317957166392093],[19296,"ebe12990fcde3268b68260079952c80a25859c60d5cb159860665c94bc0afd14",25.309734513274336],[2291,"d2a97628e873a33b4d53a44b1ea207e35b63c5cb88a9d310f9e931486bee0df1",9.917710196779964],[4010,"18e77accb3461032ba1831a3aad7a5dc39eefb0d9020925293e522d982a2ace5",9.917710196779964],[9781,"d2b6a8f9b00ba0f0956fa71cc628a4f4e15e82ab65a422db51648b06618dcdbf",9.917710196779964],[17114,"8fc18fdb2f0012fd6bfdf6a2212544f7dc3bce7135b6e3055f55d7d47a57ad4f",9.317957166392093],[15500,"27122708ac6861d8a0bc4c034af3533e536d392534be5c1d4aa3b2a18ac51d74",9.317957166392093],[10359,"dcfc12953ba81237999d96a05aa9e6b867af174d17315460f9a45b3bbdd302bc",9.917710196779964],[7522,"3316c2cf78a12a8f243100c6fa0e2e101a573115bd6946f835cd73c4caa7a2ce",9.917710196779964],[17578,"5bc9387058db940333a356663174a3df0b4ac56355689374e44ccb725831b545",9.317957166392093],[8148,"c102a90d253034d0d809c5b0565aba1601c0f82c8909fbb50d9fd116b03963ca",9.917710196779964],[8860,"6a07d8a28c085b9e3ed03cc3762ca7e4f9542390c3d8cf2db9a61c24647cb8c5",9.917710196779964],[14181,"b6b2b708702555c0540d9f223e2e0061035cf0ff7e31e4884126f84096c7d290",28.94830659536542],[8406,"bd21deeab7a88d5c174de6e21c39a1edbffa9d43d042eefc73229eeea65992c8",9.917710196779964],[16770,"817fb1075b4048388d11ccfb5b5bb90711d6b4cbda9a0f5539038762d4140257",9.317957166392093],[14425,"9178253201c74a1d5d425cfcc7fafaca0f59fa6865cf493ad64410db60b6c28a",15.003322259136212],[8147,"68b4bbea4906bc463197d4f11932c4437bed79298bb20e9a282de696f62c65ca",9.317957166392093],[12296,"8230cee045da4a03f97d59629c72154017ad623d77f78bcac4d6fe0a58b43baf",9.917710196779964],[6067,"be21b8cb4e192232d0bf06c6d1da46ec046cc308328df29bcea0826a9338a3d8",9.317957166392093],[1553,"f875e0c3c13f5fdf43299eabe3405afee06c11215d95a797723f6db8e7abd1f5",9.917710196779964],[17994,"2647bd174ec217c7c5498b7b9d6a661582ad59dc7396fa7951f85927fefc553d",26.09252669039146],[12208,"106016fc68c125838d57097196635659cd2b209a5cc968d0ebc5b3ccf1aa08b0",28.077562326869806],[2264,"b78c77106aa39fa97ee1c8cb6a62b591167de557703d4641789fc7d459812ff1",9.317957166392093],[7356,"9141fe4680be7e217881cbdd34dc616e6000596d34f920e42ddbb6ebe9a0aacf",9.317957166392093],[11508,"59f998b468a17b11c3058e8c3b51768ba08fa740a0515166ced68fca2d1a77b4",9.317957166392093],[16924,"7e8ef69be33d71d0c1739bf5b465a11585542fe3a5d6d688a77a8906e234b253",20.045351473922903],[16695,"50c8117dc2403c4a58b50749fc7a467b1428b056bc53dc69b96cc185014f9658",10.052724077328646],[5410,"9f4305401f570529058fe7e92afd4a3e57e4f7dc5de4bced2cad1823c907bfdc",9.917710196779964],[13733,"76654fe4bd2ae3c92b21e703dc5892ac4b6b0578c17125d43a8bbc68d3b1ca9a",9.647446457990116],[6049,"279938de8f387516f778928b7bc07fb63ac43f2b21fdd6908a9333efc8f6c2d8",9.917710196779964],[4431,"0cbe825c0a8cc88c507a4782cadb9ff2f39a872e41a2fb4189bcbeb1f1d1dde2",9.317957166392093],[6127,"d94475fa39f7e978e944f347d9601efc0940ea3299afd4dbe22cbe6fbed048d8",9.317957166392093],[4790,"8e835fc75b83d0b8a5c4b314eb83dfb0fcaa7e1e2d4f93c50be61abccda275e0",9.317957166392093],[14854,"e8cce755b9eb40e037dab31833731927b356636cba1204d4f90ccb336bd7bb81",18.96797153024911],[2173,"2d76bd6b771b9cf1089868a7335fca10ebf4dc08aa36263c60805a79c7cfc5f1",9.917710196779964],[17767,"74e09d84ff7d7fbf5882ea479c1f133bd600d195dfaf88dff98fc8bfde69ec41",11.232989690721649],[1126,"133ace57a10d7151b675424cd63b17928fe900be932d6ca6a58a1e4a58426cf8",9.317957166392093],[1682,"fadba451fc40edc52afe808802b578fb4c3736ecce1324c9a2e5b2ec6eff08f5",9.917710196779964],[13997,"4c29f5773922de9cd8613b89a9b7f24f6823c736e11622de8822cb8e35580b95",9.317957166392093],[17774,"105c3c004aaa96d2cd4eb171e313ef3ec441c401832dd8c94aa2602aa8c3d541",15.94306049822064],[8140,"3d5fedb5c84d49f6635303985c9266dccf4c7e55d250a99916b7d3b16e3670ca",9.917710196779964],[19835,"14672528f63649d7e1a0b7b1cec330422136bb68c52928c75f5fe0fd45845e01",25.83775918515824],[2602,"dd376f14741e9d562e95de446e8ff07820946bc791ee64179455260e0dd522ef",9.917710196779964],[3739,"63afd8f3a48e40013dc86e61f4a2cc82c9e4149eee343a49fa76109e995e52e7",9.917710196779964],[7560,"e7fbb06cf197f84ef91c4c2345b47d910ff10498c5f6e4ccbbef453c784573ce",9.917710196779964],[13440,"b4f5ba8557e66b66095d3712e254d6a8962987e7de183aa7215de9775cf066a1",9.647446457990116],[2110,"2857c290b172a1450f5be0e8f1e492028f4af9f4fd47b7fa3215ded34d0c29f2",9.917710196779964],[19265,"cb28b2b43889c5a8f467414a5c1b30376135a794d35521bb6c0a0c73721a1a16",16.083769633507853],[13307,"4b2ca9a516f4a925bd26c5e23b4167798d503c1cc77c328e0d4fc09fcdb671a4",9.317957166392093],[15325,"8780f393baae0eec52a0a2f25b4d2855c47ea5ca42f3df0fb2088f2242efd477",10.052724077328646],[14675,"42bb5ca9461ff0cdd9ccb88344aed9fd3ae1789c066c0987064ce9c05b715385",9.317957166392093],[5818,"38341d84d1aa969845c834804fba573e624985416891eb4592715e55e3ca44da",9.317957166392093],[6745,"522ac06fe0caff6f2125efad515489ad9cabe4f930108969a1af79285b289fd3",9.917710196779964],[13310,"8f72e60d29321c1ab05bf840941ad816f2ed6cbe65fae02ba2a062169af566a4",9.317957166392093],[16545,"324cbcc802a4ae116b95adc1f35bde8265708ad53e08b8b1cf31090fc243205c",9.317957166392093],[11834,"815325b3a830968bea0215199b7f8000cedb4ef76f7108ac52ee162613c382b2",9.917710196779964],[6942,"f9b29162099e47a5d0c659819f5151cc2f59d94d2334947019e386b6d97b5dd2",9.317957166392093],[1211,"cce7d268a5c7b732f3ff2d26ce71ef91a1fee5897468c3fb1ae55be74488f2f7",9.917710196779964],[12897,"edc9696e33179d0938998b0de640409936dbe48352439a46ea06ca2d557850ab",9.917710196779964],[944,"93f12969a3696a08ee8b8ae10c48e51d3cebc329966cc85652b547e87e0885f9",9.917710196779964],[4340,"af810855f289fd8b3716218ebf90fa9aee5a0e18ecb7e5b465a31b02db4d7ce3",9.917710196779964],[19333,"a7fb3c1021d46738c3513ff873fb09949badd446ffb21cba85367fb0ca7e1c14",9.317957166392093],[5460,"b541bb94fd142d87058838b659d3f40f5ce0e7b810c9be026d76f2897db86edc",9.917710196779964],[18344,"a3d2cfff1590d9d571be42fb33916549ecc1be4e8bddeb859edd454e6da6e834",9.317957166392093],[2493,"bfd730939de60a7f90e05ad6b398745bef20eafb2e325cc25a13f3d2004ae4ef",9.917710196779964],[13620,"d4493221b548a01a1e696f11936811b6323147639ea4ced1366357738572ea9c",9.317957166392093],[18760,"0c797156a765634cd7db0f4466fa00a9a7a2e40286d90343a8cdbabbed503b28",14.186291739894552],[19857,"91deb1ee1f6ee54192a5938d327dac07a589da5b59f201c52bdf5674549b8900",9.647446457990116],[847,"a2cfda6d20fae82600331c64c030ed2f6e6e88bd11ae04d66b3f34a8e8043ffa",9.917710196779964],[7694,"9cc36aa08b957f7956b0cf84660a9419d0bcea269de50a0637da96d81b0895cd",9.917710196779964],[19011,"8b6ac97b5a8d04041b8900fe7e8456ab64d816af85d26a9b10039286a8181920",10.052724077328646],[4739,"a866c4d136e478ae2141dbe89970873fa1ee10b26dd4e8977ad023a59deeb5e0",9.917710196779964],[4587,"3761b1f62d28aea02c6fe9884bbdc9199f5d551fba9e340dba22e8f8affbade1",37.53225806451613],[12100,"47dc7cc6066c402f5df376269ca5895cae0453a8a4e2520ec6b1f452092ab2b0",9.917710196779964],[3727,"337a9c71d702ab2661d2275cfa10988e51fe88f47f3e9ad0c8ccfdfae2096be7",9.917710196779964],[13836,"42d55dd948b488507beb3a4b31d87e27d02ad06052fb8a52cf3af3a02cc99398",9.317957166392093],[14703,"0296add2e88fad1be2ff57e691cd83358b126d13fce507fcebde1ce0285bd184",9.317957166392093],[2707,"8d2b753be8018c5232f806251d62a00ae1643edc65442c78c2dab87e424369ee",19.115384615384617],[15256,"eb093514f86344bc5f2329b2b3313188c90d131e93a6600aa9ffc93210a65679",9.647446457990116],[13821,"a87a2f2a815ae915a7860a0528b3cfa1f8136b46195dcddbb90dcd64f47f1499",9.317957166392093],[7450,"6d4ea0154e2eca8822b4a25ac1684802f0731925c6b7329c06f50a45a95d14cf",9.917710196779964],[16214,"a85f9a913bfbbb13b3629582a54adc9d7572affc5a6bb845c7426d77a1e98163",9.317957166392093],[13709,"96121b122847e8425cf7534a323305e9946da06e02add3c78d269b3b4aad2b9b",9.317957166392093],[14656,"8e56b78e6ecb821751891d2efb7a34602d8040e5872c5e3cb59efc9748f9ca85",9.317957166392093],[1735,"0929b24de5a5941029dab6ed2c6820f588915a18cc0d891ab9a67611aa88b0f4",9.317957166392093],[7777,"ac04ba3eb62f03e9f43a02ddb6d47ace4035e46f20c22c609f8fe7ff748cf5cc",9.917710196779964],[19694,"0b1ca223ab0a6accf03b8e714c0b28d8c531edbe01b265f7cbc51e1117ed0907",9.317957166392093],[13515,"6d0e9c39fbef73fba6ca3519696f31cf4bed644df518988fa805a9ae565b7c9f",9.317957166392093],[19239,"04f3ac7517657990d0e4d92c7793464d4df9128574ef4c4830b77b3f33544617",9.317957166392093],[3107,"bbc43bdc89d1c8b59a8574efd68c80f9456710ac5720df38e82319b2ee379ceb",9.917710196779964],[6759,"72422807cec578618fc39e3f96b84015e66330fd3e2cdebb2dc1c98e200385d3",9.917710196779964],[7011,"1514c13f44e021b3c1ce5753561aa01301436122e6fa3e6bf6352a68d434eed1",9.317957166392093],[19201,"be526d40a66c2dc6d43d87a18abff21e41a8f30b87e5bd6bb3dd8d946e998618",27.83273596176822],[14179,"69998ef6f94f5c5061a7cd9fc33afb77a0c0247b1794998f2d981274deffda90",9.317957166392093],[6512,"518a5fb3a52b47ebd7a65b6a3c20d230ab8deb8ba404240fbbe0591a600c54d5",9.317957166392093],[4922,"6c5702c9bf9461fc4653c384f411e1f1d80b2642f87b923d8b95d9d91da0b9df",9.917710196779964],[6071,"9be71d596a7f7ab41868ad89408abef7b6cb06aa7f16d92be5016a6062fd9bd8",27.933649289099527],[4455,"d56348a314fd28c726bbc7161747f0b732813d516dc648165621ead3b04fb2e2",9.917710196779964],[16462,"e84a8159ff055e345b03ed8546d21473faac3a4969b8f0361612064faaa4fc5d",9.317957166392093],[18705,"f171f6e8e98505b86167233968b2202281f7da49352f7ba2d3dad41400a0162a",9.317957166392093],[16870,"689afc3948d76f5acc80f1821ee3d5c85aeffe7d6b244bb5b12db88454f0ce54",9.317957166392093],[13513,"54710881ae7df911a1d64028f96c78c0c0a1a1a769a6ff1592322ae518b37e9f",9.317957166392093],[10157,"43b5a889f82bfd94fb8a444f0eb05d74850f7e04b987efca01a86bace7d15bbd",9.917710196779964],[1854,"fd2e66b83a06d3244cba19b957dd35e94d829df0dda8459bb0fe4d532c00ecf3",9.917710196779964],[9565,"0cdff27365ed649adf891ee65869b5818c1637fcef133b8bec1b7b2b285335c1",9.917710196779964],[5061,"b326f7382a57952b2c7d9d647aa0b9f93691a511da0ee05f02e47ae1b489c7de",9.317957166392093],[10489,"ba15d40cca543399d16a34c60fea581d9f5c574b7734450049e4b408bf2d37bb",9.917710196779964],[13159,"c565c2140dd9b90b0a635d5c59fab0bd045b9ec2404eba153f380bcd7bcad1a7",9.317957166392093],[3512,"7afab4e8164acc0ffd011c3dead26370e9bb08ecb35be0c8e050549102a8e8e8",9.917710196779964],[15331,"87bec09d36a30e3ffe4380cf82a90a88300054a024baef2615f006444988bd77",9.317957166392093],[2636,"667f2ce38d6d0850ea3e6275686acd4a63f28da781a36efd32ef73a9e4c0f0ee",9.317957166392093],[4482,"81f876af95eb6e5967e9590e9425329e2d901525b69c57633b92f446cecd86e2",9.917710196779964],[6379,"8b7d93cfe8288c7daef83beccecd0b9e943c0aeaef2786439c4e2a9b381374d6",9.917710196779964],[18811,"03d132751f94a3ecec8b12176482acb4d6e02867f02b2e0a3c610101e6415726",18.682835820895523],[448,"a3ec3584ea6a5e42dbad76b191721db24c850ca4560fa8ce2d413130e27c14fd",9.317957166392093],[2483,"3fbbde61688d426315b1784f4b15f9874f6ef51989bf6e0c6f7ad25143f9f3ef",9.917710196779964],[11310,"c207ff61777f268d932e2572f8ea390429092695ff63f63cf4ea5a8b8d99eeb5",9.917710196779964],[19563,"cf05d31bb33d404893371867388993614bfef2a2cf368e42ec9ac54404082f0c",9.317957166392093],[7815,"b1a6ea922d9301fbe854908a501d46d5d8110b3073e79d6ce068bfb211b4aacc",9.917710196779964],[6944,"6e731f2983d528d8afe547cf11b986747d875cfca8fee8ed66ce8beebec64ed2",9.917710196779964],[17873,"ad22e8b32a4cf61236bd4261bfef13e3ccbbf49aad131896b0f240865083bc3f",9.317957166392093],[4264,"90cb2d403460de933be1b6d592e7990a65b64cc216b5186ec7e3d0f72d8b04e4",9.917710196779964],[5510,"3a56ef4eb6e4e93645387f253dd180a4f5309d55a633b84e9b69b3bd0cce28dc",9.917710196779964],[14618,"a30e5832fe5a00a9241a86de563935b9435b50573ec01524b76b8bf51036af86",10.052724077328646],[10866,"b83f868c0994289f237f13505a6e6d915bfb31ce4a823e2903ea9fc11fc0d7b8",9.317957166392093],[19051,"a5d75250c65e5546d5597909dba97a9bc324733e64502de99a32c8fe32c6ac1e",9.317957166392093],[14270,"a1bc31a2f24c47e8be40707781bf0b9467c92324d42dc0a6b311d54e5fd0868e",35.906103286384976],[8347,"a6959ff6fb2775b5c156a924d14d90abb9b41577ac7563c7bb4211655f3d03c9",9.917710196779964],[12179,"0ec000ef8f2e21b05a0d8870e56dd23fc06033b5a4811c17d44ac8ec00e833b0",9.917710196779964],[11681,"f9f510151763da3fef0d9ff080c37c396ef7bb24664c1b7ff52b14d2ecb670b3",9.917710196779964],[10328,"320153cfe5d39ce20ebe31c4311b01811ae7fb532702904c1c7b2c860b7927bc",9.917710196779964],[18901,"7a2bef273049562da67bc5dd6c4c0c56ecfdc9da37072c29b468b808adc37923",9.317957166392093],[14714,"61080f9cc7c2140cc3d7f4656a5255ca1f425a20b2ee22707e6fe59b07f79d84",19.06236559139785],[6737,"fc5ee64d82c47044721f1bab3750d6a7b8fd9e82db2422ff65c443f6cf89aad3",9.917710196779964],[9082,"df254c412fb852890940fb20f08bc66a5389d05f165be8a7ad360355795343c4",9.917710196779964],[8756,"d01c3cce2ba6b2245f7736e0d463fa16b95127d2a84b81a14a8bfd3bd1c24cc6",9.317957166392093],[4383,"bc20b3272a6191f5b7f12cbc45b926c6f8888fc6f5e6aa85723584916e152ce3",9.917710196779964],[12185,"a1df420dc41d72a11e7464f4878d0ce2519953807bac9494a5751bccb60927b0",9.917710196779964],[17163,"31ff5d8781bdccb11d9ccf4fae2867846b466c2c32c4574b430eb76ef1b1a74e",19.101604278074866],[19397,"ace6b791cb4ad2ceb63d84febbb08f5167d06f6f6f41dc613dcaeb940d44dd11",34.88770053475936],[9185,"62d767e0390eda62e84307805b8dbaa75c353d75a1ea2a49ba3ba1cc783497c3",9.917710196779964],[2748,"517bb8536320b430f8ad9f2315abee1079c337abce335ea110677e7aebfd1dee",9.917710196779964],[7349,"525f41a65874d66804054efd6f9f14e98199d117c7a52e68e17af8014e76b5cf",9.917710196779964],[15481,"3133edafab20489a47d91bac9a91a29b82e65f62ed4744d67a5bd4ae67c38074",9.317957166392093],[15449,"dae85f8f503a98a65d6da42820926a4cc07eeb887cbc5679f621b072ca402275",14.864253393665159],[15915,"b481fb1d88d326d25866e96b04cf8eec43b259ed00b86ed648cb64d80bedc26a",9.647446457990116],[9949,"40df8492f0e2c4e64715271111625705af9a072872edfc013e4474d5fa4ca3be",9.917710196779964],[4123,"be937b69cb05d8b138d8c00dbb4b041f06d4f7228c431f4b52d144d0352ce9e4",9.917710196779964],[10500,"d641ba013aea7113e1b3e462cce0273f5305901ad0ba05e4f87a949a9d962bbb",9.917710196779964],[17918,"4066bd2a2cc6b52f87b6653febd553be5a3095b4b84fad7bf2a58268ebb7ee3e",9.317957166392093],[9435,"9b9a667a9d4b5334b5d8c276125ae2c40dfe215c69a85e13407955d2553f1bc2",9.917710196779964],[4867,"f864ab34931acac83eff8cde7c392ec4921a0865598ed325bdd34f3a4e1a07e0",9.317957166392093],[10779,"32958875459caa94cd832e55c6eb1bd4820b494a13811c750cd7fe3864f56cb9",20.202443280977313],[15013,"fc19383c5ad9ff1803cd082806b716c2b4eafb4496d749175d75e8117557157e",9.317957166392093],[12738,"2fd0900c022f1a23fe0c2fd04ee643dae812e42ab1959a2a36c2d503655a53ac",9.317957166392093],[11980,"75b2996dca3afe1c8132f891a60e9c3cbeccfd4073eeaecb119f4b27d46a6eb1",9.917710196779964],[9984,"3bd0ef6a040fad6a0e67c94a21631f7ed3a4378613f01968b5297b6e724e6dbe",9.317957166392093],[2160,"249f2285c70cf4030737ba1fce2faa93ac18b7d1540fe7ef447f0f5f0902d9f1",9.917710196779964],[12960,"21fc7fe90dfa9c8f788aa70aa0d17f918fe7378ea7a9992f543c646183a9d4aa",9.917710196779964],[17880,"a3d68753c8d7ad575d3bcb35c7bbfc7cfe4d47577aa4c84317c3ba085cbba93f",9.317957166392093],[13493,"e57a22721f410c387172c7813cd043662acfdd4c76637dd83c17b606b1d9f49f",9.317957166392093],[11183,"eeecc91ca2f80e55bec7c321aa0a4a119e215a9a9035af882873a12a82b7ceb6",9.317957166392093],[1426,"392344a363c373de03b965df52c4ca757000ab20222cad0212b3cd1848f1acf6",9.917710196779964],[8051,"e88d0556b8a6f5c04e86e5ffbdc84f077381672df3b5700238c0c2c1ecf526cb",9.917710196779964],[8207,"992627941427600846ede2205faef74efcccae7ffac1658fec0e4458f3c0edc9",9.917710196779964],[225,"dab03ebb56aefbfc04275853ec8689dc05e76c99420eab45a28d8013e44f79fe",9.917710196779964],[15372,"f5de5ff6d66c7e11b08ea18dccab476fdcd6ed450cdbcd5ae963896b0f23e676",9.317957166392093],[6770,"eaa6c26cfbaabe2bb67ba348eb27b715bcc75d6a1b390158c3bb6113debe79d3",9.917710196779964],[8389,"f8d02e4861ee875ce5f29b81db1691625569cdce06b8b520a3303d82112db2c8",9.917710196779964],[13702,"494cd5b9d6b65820f8dcfa3c2b283e2de8d5a2c0dd127db85fdf2a9cd264459b",9.647446457990116],[18267,"7d8f8801bae224deb52731aa510ec7c5fe496d750b2a6f50cf9d979cd63b9836",9.317957166392093],[19014,"2a4e96b0f786252b8ed17ac81231d51ccd816ce199dbf9fd8103af373b3bf71f",19.771836007130126],[2684,"7c5176f1b4a78b9a416b10e9d4b5e85a71b45c91587bd0f1a5fad645970594ee",9.917710196779964],[5874,"6679124b6864f00e228b5ab2d4f233fa8e91d379f92353b6a0e71857b4d0d4d9",9.917710196779964],[1042,"23a2e7e0bd05e6162909bbb0d6d35a86ed77b372571a946d06cc0f21dfe707f9",9.317957166392093],[19658,"938e328514830aee3ff75f1a734bd7ae2451c16a0170efdb9aefdabdf62bd807",9.647446457990116],[14227,"567d3112216fc86355e00a82a8ae19c17dc0025909f70bff601d01ab77657d8f",9.344947735191637],[18287,"6fa3eb5d5fe974daba40d9c561c859c97375c0952769d9ed47efb27ec43f1636",9.317957166392093],[19080,"77c663075017e3a61e7e7461bc9a25745d143a8b82a841be8b2deae9c09b901d",9.317957166392093],[13177,"2555e4e3e80c5382efe047c16a2c59283b56804646682468ab0c85b2634e6da7",9.647446457990116],[8173,"01f4973b0202fc25d426dc7b717d053f3cba99b9247bf1d1a726d72f751626ca",9.917710196779964],[8543,"66caae87c6f72deef39da80e38aab125614b7a7b588d9f7f16f2eabe559ec5c7",9.917710196779964],[13213,"7fc3da55a220c76c93c4ba71bbf05e2c6fdcdb7783b2c86011cfcf6b0d519aa6",9.317957166392093],[6190,"1f86aa94c9ededacd1aaf4374fdb2d68ae92ce03054ab033eebcab96f392d9d7",9.917710196779964],[7780,"ce125267529a7d40b04e94c2e9804b6b34860f8e3da9a1c896b565ff1cc9f1cc",9.317957166392093],[10600,"6046e1fa3f97ac4a8ef996e3a45cc17e59df0aff5eda01d24c2709d8da64a5ba",9.917710196779964],[7159,"35748792356132e294829af0ab28bead62f595bed1f3df753c12171f3678f6d0",9.917710196779964],[11409,"7ab4468a1c7202a360c3fb0886f4a61966ed9183468e42a4046aae25fc134eb5",9.317957166392093],[11738,"69c6df645abc814b8351bbd6d7c00d0861ecf005189dc892a3d229b9e3e213b3",9.317957166392093],[19869,"912a98f21c014026fcbbfc4ee098196b16b79986fbcb6b1036dd73ff3f6e3100",45.06926629040534],[7470,"1ddedd722bdfe02ca4a71f45a31b81e79985d6d727137ce2e40a7384606be2ce",9.917710196779964],[4744,"7fa16e5eface7fa5391e1b347d373a481562c97524066d6970c316831e07ade0",9.917710196779964],[2214,"59d468b07bf5d3038784e597a0b6429a4a70bac35a6e4bb00ab0b7b83e6b69f1",15.003322259136212],[19781,"0c3c67fa64c81d559535118b1a61cfbb3595913b03efa4a6adc7e0325a527103",9.317957166392093],[239,"47711202678bbd3f8e9874abdc61120a1a629e8e03455c6ef0d4a6440b5f62fe",9.917710196779964],[8980,"71392be8ac531504dd1845eaf694aaa4505010fe8cd3c7796701ab8e841cefc4",9.917710196779964],[13322,"b4b6b947b1a96564698f2c986dd1150848e21559db67a9f47e7217c6053231a4",40.766146993318486],[7732,"4ac3bdfad9876c7294543a9d83fe343e71d1e271fe6d4d73b5bdd7d5d98747cd",9.317957166392093],[9081,"75c18e0eb2af97ce7f2a03078cb0f997b0b0642799256cf5a381c2ff803744c4",9.647446457990116],[6462,"cf35f6a63275fbb198bbc54d96dff537dc23e04eac4fe20edab17adf0ab9bdd5",9.317957166392093],[10388,"c3e9d26f3d1990664f796e292f0820cd274b3d0b5f4e4e6a9996a317fb2ce1bb",9.917710196779964],[14441,"ba5b10c6aff5363ef2ae1a71a6dc4843cbd60e5b81c2291a9efd976ae2ef668a",9.317957166392093],[17495,"9de705908c55fdfafe64fe23338cb8d1b1b551d4809cc1829e806901bd68ad47",9.317957166392093],[10249,"71237102e8c9e9d8e372209215bb215247b8d7145ec1637bf1e71b2464fdb5bc",9.917710196779964],[3735,"db6cfac8d617fed661bc1ef7f62b39c90083529ea0dddebc80362cf29d4d5de7",9.917710196779964],[10124,"0e7b151463f8ec84045587e0f8f727d04b5b2b6d4f3c482de3e595e2305b89bd",9.917710196779964],[7691,"2f4547d4ca065774c31f8f64f02b5a402da015240806472f5ddcb173a7649bcd",9.917710196779964],[10802,"0ac91b5c376d04d48f15453445c64fa65cfb91758a99d01a8145b748b89a46b9",9.917710196779964],[14195,"ba493d1289cf7527aa9df12af2958e18ea86934b3357e60a9aeeb9b2964b5b90",9.317957166392093],[16267,"b923577feceae1da2803b39662c34267f31293f02ab0e793ce7e54976808ec61",9.317957166392093],[7510,"7ef595a6386c24af5d3f3874e5028681487b2277ee9eb0e7245f9fc8ed99b0ce",9.917710196779964],[11449,"5e1d1a8cb66309229e175a7d1d9aae6dc299ece30491e5bc80ab6df00414f3b4",9.917710196779964],[14127,"e24e2f727a69ddd126d2439d23dadb2928fb7f29fff484c94ce17a76aeccf291",9.647446457990116],[15865,"ba0d0023e78d814152791dac9e49c1164c60b53550b73951eb4c38d4dfc4c86b",9.317957166392093],[15026,"333db29b02612c52d2a7055a52952a8365077124f547b71a46fdb7b54a8ee67d",9.317957166392093],[13575,"8ae136da971a5dccffc249d0d25cdae8abe5c40bcae4af7f4d8430f3c7f5fe9d",9.317957166392093],[9342,"2a456c4d82f9d5abf031a16f33515d120beb602aa31d6d75957ea0a63c9ea0c2",10.052724077328646],[9295,"c3dac2a81c2e74baee913e96f374a930a38bd5eabd77e42f84967c1ee2e4dac2",9.917710196779964],[13835,"d9a4fdb7f951f7eab94086f22afc20c515ddd3c57fc61d82dc15d28351d49898",9.317957166392093],[11524,"a04d7ff1cb0eac899fc6255b7a7b32ca9c3e4f16912a049e116e357089ba5cb4",9.917710196779964],[13239,"0adfdca3814fe5d860adb23b264120729030c4678c230d799dbe28a058541ea6",9.647446457990116],[1764,"264b52c5bf52f222e1096e9da7ad5227af1906333ca6475d08f9cbadd17e82f4",9.317957166392093],[5035,"dba5fdaeb6d7d6d3afb9cce5738fe1242c5a31e94a91682d45572232104ef7de",9.917710196779964],[398,"b6a22141fc79160355331a3b0dd57f29090335643bf99ba4cdb45f60dad15bfd",9.917710196779964],[5721,"9d45d5407e96aee62071ebf9a5e28e6bd56d48726007ef3794b8b65136d3e8da",9.917710196779964],[10820,"2384db8c6a693c4d2c26d8a5eba94395051ca23a229080160a944ff851692cb9",9.917710196779964],[14366,"cd4246c9185eab57e981bef5e6f919586affb9da39fed9685db0639059601e8c",26.062052505966587],[12765,"a95301864fb45fac52459ad06fe33cdadd62eeac186851608cc2e158401521ac",9.917710196779964],[13571,"f47db26258cd7ccfa5344c788200db264ade28e2b8f027087d326ce43c412e9e",18.131907308377897],[133,"1cf614ff5b730b30e350909b7cf8e863683b17ef486b99ef9d35bd58e6611aff",9.917710196779964],[9705,"54807b240cdfda2661e2072d4501523b283b6180ade27b541feae4e5358555c0",9.917710196779964],[18968,"44f3949f54e2563bb9ecf4ae237bfe41c6c0ed37de3d4c16e16041c0306d9b21",25.40463458110517],[3124,"044fe18037607bdc86a2ca7a39bc4e9076023de57d1d2c5ed50a1b25e68383eb",9.917710196779964],[1349,"12c59014eee4fa265cae524aa5c0dc256c901ecf023058fb2ccb0415efdf13f7",9.317957166392093],[5340,"f8d76c0a00772de756662c5eda4fef6915bdd250ea41f6b8862f98c4528231dd",9.917710196779964],[5112,"89aebed3dae8466728ff5c169e070f46f8482fa55f672ccd97151eff320482de",9.917710196779964],[3498,"93fe86c7ada93ec9ce7b0bbc25532dd4190c598c6a4033d11a8ff2649d5800e9",9.917710196779964],[8022,"c15e2e9a208201819da5b64bffe7805f2355316cdaf780555755798ee2f66acb",9.917710196779964],[6827,"e5a61868aa7c216adb3d473ebedc1d7ea4872b650934b2dae38e3d97f99912d3",9.317957166392093],[15491,"f97f8afca9cfc6739fe1a00f84b02080afb63398b977e9e54f382de006ad4674",9.647446457990116],[5195,"96f5c2e08319288ac3cf0ca23be81dd6383d55ca42a7941bcc1cdef5ccf101de",9.917710196779964],[578,"8a2cac1363e3f1855fa94b316ea940ce2c629bcc782d439716a9a35b7a0d17fc",9.917710196779964],[6634,"744345b6cd53641276547468d7f7e3bb7c9283d7dba02df370b5a9e9019d70d4",9.317957166392093],[14210,"7ba459c51cea8a58228f177caf4815b8f7f2f681710fecc310bc646195c1fa8f",9.317957166392093],[9410,"168965697745db50fd01a9322db1ff63c53db4f146f16860de2cb4e857b13ec2",9.917710196779964],[6270,"27c0d6acd84268dd1b6c4a355b6f9a1bc1fb6e02768069494a9bc5f8afd448d7",9.917710196779964],[2871,"692adb0f64eddf33484fe5a3e7c22e91a12130297123f202f1494408eedb49ed",9.317957166392093],[19559,"9b25a3e85dee338b96f76b46a8272c0a1226e687d54fdf8976b807d275e04f0c",9.317957166392093],[10733,"2e25b4ca912a1b4d08d2f23907e741687980c1db5622e98025fb5aa55635c6b9",9.917710196779964],[6825,"00a863e55f33033b7333707962a19b4e96e42459cca4ff9972ca9d893b5119d3",9.917710196779964],[7826,"50402026963581995cbf5d9657d70d3e5a079ef61a4ccc3d6b80e3b352f099cc",9.917710196779964],[2378,"372380e6b68b7c6c063cdc79048db1c0c49b78e7fea883939601a5b0842895f0",9.917710196779964],[8069,"06c66054e8162b9c9c438c69384d2adde28e0a9cf417a3704ee7275f443bfaca",9.917710196779964],[18444,"06ed8efdb563844228ec0ddd01330ffcf85c87123a662dc188f879a0d623d132",10.052724077328646],[19170,"febaf8abf228666f3ea28ff83386ee8d824951ce6ba3d460f88e479d209dc019",9.317957166392093],[9255,"4a88372dbd0b9327c76badda255562251fe9d85a0293318c338c0578ab6219c3",9.317957166392093],[13116,"3411add606f1a509e24e8aae0e84af1d17a5ceb5d22b8de2f66a6daaf0d8b1a8",9.317957166392093],[1165,"b897bedf67809758edb161eabb739584def931ea0d9b1ab536e5dc8f8f122df8",9.917710196779964],[6287,"1b701d0df041b386c1ebed8a878de463de9818b16199fe0171ecf3f94b6a26d7",9.917710196779964],[3277,"12645b226da82f29e78e164f1585d95bc94bda30f3beea5d6b3ea1ffd7e98aea",9.917710196779964],[9687,"8cf49d82cf22a1bf1c8a66263219082b91b0db210cefdc24da7ce02c04117ac0",9.917710196779964],[15751,"aea881ad0f0695cfac796386a7afe5117ad64cb0411d6b21458a1b86e429576e",9.317957166392093],[2590,"e4968e2f145c3c80ac5f7a14228f99bfc5096b8a3ae18060c490cb8944f234ef",9.917710196779964],[8994,"a168a5efc6d4824d9811909207b279b2fca29ff6ca9887390bf868baa96ed0c4",9.917710196779964],[19152,"a8c11f69cbc1e31fb00b81af57a40aed247e2ae8ab9fec51ba8a860d09bb691a",9.317957166392093],[12711,"8b8d618ed131118ce462a76b2275ae6440b41a2444f2e6d056044285f24185ac",9.317957166392093],[1370,"c16bdc001e162b761f548d4d056a40db4b972b005ccb3615032aa7ed374cecf6",9.317957166392093],[2220,"00b11ee5c0b5948b1101dd671f2863b411b5b16f4c9b4d7e5dbf5984ef7762f1",9.917710196779964],[10904,"1b2573e7fa0bccfb066ed9e357cadaf4518e8964ef2323ffd31a0a0c17fba8b8",9.917710196779964],[4639,"315e6871fcb89a45dbf0ce14cb875b0a76f44b836d04d6a94365bdba5ceb60e1",9.917710196779964],[5557,"26ffce18a42151712bff53b77ba2b73498df9ba7b8b38a1947ca1718c478e4db",9.917710196779964],[7239,"457292947fa9a85a4f12953b504b6ee7d85bb0ac9780950b6346a08445fb71d0",9.917710196779964],[15846,"041cd6235efc7d7de20b12ba9bc3dc2225a2891db6387c804b15f63371b6566c",9.317957166392093],[855,"63c8b19f14a7cfc2c81359b99b6d7fe64daa09441f5523ebc18520e90d152efa",9.917710196779964],[19773,"2e4717b7eb3cf9c4675748f8b4743b1d6d70d7cb2718c7ddf4c38eb31e159f03",10.052724077328646],[13691,"e2fe8194daf5c20e5f83d3894ee40b09911705fe30c22651af8499c42e9e629b",9.317957166392093],[3077,"df41023b97c96bf4f379ea28249a93bc0eefc456afeedd479e36f6078bcccaeb",9.917710196779964],[1187,"a29f58fe2c8d7a46fe73dd81c1a638174c9a9cf32c293a27e35d6c8a413d17f8",9.917710196779964],[13567,"a27add9bf6fc935a0bab62150cea546b6ca99131c3258ccbdaaf674f3b55559e",9.423008849557522],[10662,"2f2d690fa80e11c0b7b9fefc5a9b5d47b3d9503ba3d8e71af7533500f52a47ba",9.917710196779964],[1818,"39020b939274f0aa31156c3209d3447097c69b9f18a2d06ad976fabcfe3421f4",9.917710196779964],[2429,"6be12faae188d6d662a19f9916386d82f8ca9023d5ff0b83212be58c2d2344f0",9.917710196779964],[17356,"732ce2bde75ecbe756ab24a7a71ccd3c9576503f6bf549dc57686c49aac8c44a",9.317957166392093],[7226,"148510041582218a7f02eee0cb3df3a2075d02853cc0fd70d9a386bdcae97fd0",9.917710196779964],[11132,"7a68c559d4ef561187bd7f1adcff526a1343adb2ed7a6e31971cf1c20ea219b7",9.917710196779964],[15302,"57eaf23323086064d6d5ed8e23b67bc30279d0120953cf048d0415c913e96178",9.317957166392093],[14353,"ccd0198de6ef7a246fc24702476350ca453f378bc164537539db8b9bd9424d8c",9.317957166392093],[13312,"e14570d94e7e7e7e8476670301bebd1062a5142808731a2d65828c31168b65a4",9.497326203208557],[8870,"c0956a6ed31ff083c1c010ffdff7769b5c307076420a154c36e7bc281c96a0c5",9.917710196779964],[2845,"651c86b885ac071021a3c4f8a00cbdd3b065b1c6ba20965ed5c2c3163cb462ed",9.317957166392093],[9523,"ff9e3eab702a9fa12a5b2fba30c2614f0133c938a0cf3aeaf562d38e98228bc1",9.917710196779964],[1013,"a8ea32aa5ba0ab9e9c6116af5c9d65b41516c179ad1b71d2737dc90c780b20f9",9.917710196779964],[2908,"8052df7e9d5b284537b7cb8b38c485709edfcd2e3e16aefa08293b71b5fe0ded",9.917710196779964],[1251,"e09a8e5d39994b6eb40c0462ad4a1048805e764537b68a2a4cd167eb570eabf7",9.917710196779964],[5064,"9dba29b5297a51991b4e2452fdfd78dc597c07e7a246de95dd9c819e4beebfde",22.26876090750436],[14422,"83f67fd9c4200d538485e5d846c6e2fef2d31616a289814c7b7e16f84be8cf8a",9.656716417910447],[11948,"acb5e120725750b554449fd2d69876eddaf642de85299c910fc70e62804ba8b1",34.92],[12245,"235d69859a7f6405674a13fcd8c39d8f4a4ecd6fbc59c541061dc88bb0dfb9af",9.917710196779964],[8823,"07f92ecabe4f2cdea43f57e397cc85cf0d7e583f4cc4ff07856018bf801cf2c5",9.917710196779964],[6714,"23054402e2f1218502cae97c9c2e7b1baf952fbdf6ee1ce60a016e5bd1bad6d3",9.917710196779964],[15482,"7c18689a4b02c39aea91c488c2be8c930e4ba9b89fd7cd6fb7e42081a7338074",15.073170731707316],[16667,"380e91a6fa518e1ce67d81cd8f6378ea7bd913c37d76e992a36ab87aa1365859",9.696644295302013],[9315,"c611e670568c53c6b0433cd7bc8111d4ba4b84e89451facec87054c6bd87c5c2",9.917710196779964],[8921,"5d7b847626f5bd0c45be6d13ff9752a742eed93d3a582002c878c8d75b7f59c5",9.647446457990116],[9430,"abb1b78af254f8696daa73acf91109314d9bb419dbdad60a3d54e8de05df27c2",9.917710196779964],[8467,"a31d43728e56b478b553d7daa7ff2f3c15b021be2ec6372463d87bd05b6238c8",9.317957166392093],[17021,"841c71c7a36bc4bf3229f394fe5ac687ca2aa824ae2555919d2a7d18e1e58b51",9.317957166392093],[3116,"820dbe1dac53ca77d3884c70fb5844057bcd84419aae1e60bdf5700714e58beb",9.917710196779964],[18838,"b33ce1a25cb924059fc4869c048f9069a0e343b0774780fe446264191c977225",10.052724077328646],[15682,"f4c6daadd70551c62d637d8d480909a595151acd1689caac39f2bd959db8c76f",9.317957166392093],[9917,"b75e8f10f6391fb7b6df0bfc8d986dd7563f0a44e8fb64a71873bd1c3371dfbe",9.917710196779964],[6548,"3f235fd02367ffc99f0b03f91a8ba2bfc3d311aa1130eb5d2da353b8690a0bd5",9.917710196779964],[2718,"ab67eb0d5955b0c9be38d21a666513124d8d77904c15760349da7499597552ee",9.317957166392093],[4805,"a7b4345361d2821a41c02649db52c2291f107c7eb1f747207c90a92d79ae5be0",9.917710196779964],[9810,"96b7920cb35c10ff0baa1c2c3c8a90e382fd3bd8180e1d7b4b58fecc859391bf",9.917710196779964],[493,"0d705b3328e2991324c65d23e4409434322d31bcf78c7bfe45556a699222b6fc",9.917710196779964],[17013,"7ed215d221c1bb3b92d27806f0d48499ac98e70d629bcec0e7a44e8eff0dc351",9.317957166392093],[5973,"835df2225988de994a6066756c409b95bdd0dd525144d79f05ceeff1e39748d9",9.917710196779964],[18233,"71b823e0d999478a9483f28c77b0843dca621727c7bf39a8b01b17984ff94d37",9.647446457990116],[544,"349ba8a0619b19b89f66e663dde667b6310b20fe547c4c089a32f2e2a7ba53fc",9.647446457990116],[15654,"5688de4b88a01edbd8f11026aefccc4fedc9b35ce0be19f7d41267bd60b94070",9.317957166392093],[11297,"65016ba39fc2c2d3e65fcd68203eaac003fda269628cf20d9b2d7a55f1f811b6",9.917710196779964],[5034,"21e654fff356f105b8f2eb4091d426d4c56eb39058412bddf40f6b1d5e66f9de",9.917710196779964],[3091,"040d9d2476d7129fe29afd05f0bb93b381003a70f99c76f5b97afd1315b5b2eb",9.917710196779964],[3633,"4cf0ddb1c81d272c85656c80e747f60e0b89f230a72f99afb1206fae634f09e8",9.917710196779964],[5826,"cbcf8dffe9fb13ff49e385546d1a06f24512505f63ad7b1801541c4ccb9f2fda",9.917710196779964],[19117,"0c182c4591fffae912f8c64cabdf93d260b23270cc226fb8e46b131f6471c41b",9.647446457990116],[18466,"d8cb0d59df889d14a9d482c51bbccd46519b945df256e7dcc5180940e40b4a32",15.91459074733096],[7529,"dbe266b53f2fbe9e16086f17b617ef3f0423333ad2ace360f2dd6a08488298ce",9.917710196779964],[17076,"fa2c7603af0a9b08322e88e9d1b142c81f274928f5ec274422b0b89f090f6250",10],[6956,"e0770c6c19843bb93e9b477fb10a292e06a336cd711dae15d02d0423780b3dd2",9.917710196779964],[8872,"d64773cc6d0abbaf6a0decdd2ec1419eb21a4517d610ce272322781c5f399ec5",9.317957166392093],[1677,"6e974dc4cf860db4e8f411bc1e8ec518174088e4f1cb436559aafa5a442d10f5",9.917710196779964],[11960,"3ef2ea60548b09d98be53da3a31d4b96a1599188e9d22efcff1e06f8f98398b1",9.317957166392093],[10833,"bad24e30d687705250dc1b35f64226fac6f9ec3d7a02d5dfab7e524dca561ab9",9.917710196779964],[11398,"209cd03660e01ecd038fdbcc2b30375d7034a37748b98060dc117ad7db715bb5",9.317957166392093],[7326,"928171a803b136a33437708f23d0d59b8e21f65c87379500f363b6922827e6cf",9.917710196779964],[15094,"92a75c449b5e0d3cb6a359ae23f02e284da4aaed35cc85040aedcc28e860cc7c",9.317957166392093],[7651,"d4894ced9aee700c42db393057ae9192107e2094d5d326d81b29a1b2e6d4e0cd",9.917710196779964],[13066,"c7c68b7177177e124d0f314340d302d4a471668056e49b564270f56e486433aa",9.917710196779964],[3994,"490ebd0e1a5a79ef04c20a336fad82a588ef85459e9d2d079b3179f85dd5c3e5",9.317957166392093],[12280,"c8f47fac435e7aabbf2a8f5767e0720704814938d9ec9e1280bef1961cd269af",9.917710196779964],[6589,"4ff3f32fbd8610ed9c9d9723c314cd43726efd5c25c46215f80891984a0ab9d4",9.917710196779964],[9859,"6e094af8676fe702c014a20bee29b73c207ff5e5b0eda49e95a18ab3a1d836bf",9.917710196779964],[12026,"18ceacb5c149db30e26c28532ac5beac9dd1618ad2195d98f2f49055169825b1",9.38219895287958],[10975,"3c95767a13e02d6d8e81bba6bb7432fd5e79deb9ace4bec13ea672c43cbd30b8",9.917710196779964],[30,"d4638f4e91d589c7c2c00bc274bba39198e57b0ea83e50b5556e773c3b7bddff",9.917710196779964],[10775,"fd390d37d8ed065960191a021087722bcae064a5ee58c30f1a62a97523b875b9",9.317957166392093],[10656,"62b426c27a1e46c905161c33d0860e13ba76c6a9f80f14e47bdb94b2cc7951ba",9.317957166392093],[16683,"33127bf8fe07ab95eb484b2911d726ea38a534b69e48ad15b10612096c34f258",9.317957166392093],[5116,"7254e4a20f748765d22e6f713143c59e3268517831165e28f277b0f9ea567ade",9.917710196779964],[8274,"75aa7060024ab0a995497cbc5652bfeb80f06559b7d9964a3efb180eab1681c9",9.917710196779964],[16458,"c995f588b2e6d572644d8d26a42509bf6d828b3431849a0543361ed01e93105e",9.317957166392093],[1250,"865b72d368c9eff0ccb5f73c202edbe9526cad18092f5cf50cf0bd7a1cc9b0f7",9.317957166392093],[3989,"8a567f6a0c329d0140d0f4384334a44ad46258fcb98cd9a3459e32bd9113c7e5",9.317957166392093],[12487,"95f52388a9788ee5fe631ef88853d9b5054f690fd587e681d1531df0b40306ae",9.917710196779964],[7192,"4a969af6c13e34b8391537c5aebccd2f04c76f9c270bdfd2b54d809ea930c2d0",9.917710196779964],[6519,"c26627c9aacfa5996a8e1c3edcddf42cbed48b4d4ee49e24bda969fb879947d5",9.317957166392093],[6734,"f1575a1a3272d413e31849b16deadf48163aa42bbbd72886337af550ac8db7d3",9.917710196779964],[11192,"96f7e8109314594135442a77c021bb3f53397c8a464899e267933126e794b7b6",9.917710196779964],[4590,"b08d9a58d7bcdff2ac34f7b809292eddc9c98121b0c52083400a25d9c503a8e1",9.917710196779964],[4751,"499b1d8729afe737f39d29ef36a4ca347315ada22eb90ebb4d7a49d02f80a3e0",9.917710196779964],[18695,"c86592890c3d4dcffd56146542b9923b935165a6212a518743669ad71ba2942a",9.317957166392093],[16890,"5974935e5b84360de5cfbb0a348379744cdccd71be0a40237b1408c7da0a7a54",9.317957166392093],[10240,"65f8da314d9e4cd0148c4ab9bd7dc9ffceed8d9548a2964e0311f31f0705c1bc",9.917710196779964],[18916,"9d5c22e178c49f3a1c0c0a3590f20554e4075be12a1269209d27ee605e7ae022",9.317957166392093],[13211,"bf7065d708f4ced48f1cf3e7146336591029a1427880e2664ec5d80bcc04b3a6",285.204991087344],[13445,"47e1ed885ab2d96f8f6d9656ff4b5049072b550d57c6e3817fe76717d00b20a1",9.317957166392093],[13088,"f49be480065e0b6de4f77da95cc10117e9e7feef1ce86bb5f3f8b9029a1dc1a9",9.317957166392093],[4214,"58c7b81bb2cb7d492087852be3f768a4f508ec416fd058437a373bc097dc5ae4",9.317957166392093],[8865,"d590a5389ac2995e23625448c04c6f20da915b01c48b5a7bc19ed12905aea6c5",9.917710196779964],[13906,"957940cacf72f81ef4a8d76c3bcf9940146d980a0ecee2845807d5012026e296",9.317957166392093],[3147,"f813b48ec93584102739605b94dfe6105e697a3d2d5114a66eca9deb7d375feb",9.917710196779964],[17360,"51c0abcea17310ce0ebcac07e11930593aa9e9450af66f4507a97218f189ac4a",9.317957166392093],[17523,"07f02ccaeb218e7bd3e3a0daf51d45024b7eb33ba41bbea8a785526d14ba1247",9.317957166392093],[10013,"dbad921aefd7f7a27986845dd8d83cc14440abbe0ec1aacb3a6dd0eba25c3fbe",9.917710196779964],[3260,"084940d0b88875a99720938d8b8fee2b2304599c513c95b075e179814c8c9cea",9.317957166392093],[17549,"d1ae4533bd7ae7c4151e08406e10a623b8a6f3c66df8fb67f8fadb650a967a46",9.317957166392093],[8953,"6fe6fb15d07b66f59e99079cd3425b8425b02b3c13102cac70e7deecea1b1bc5",9.917710196779964],[704,"682e17aa3446208897fcf358c2d4f83ed41ce57d24440fc6873960ca50d033fb",9.917710196779964],[9839,"1ba80cf2d29cb3aa69011472a44c700e3e8a83edae02cdc9bf9e3663236b5ebf",9.917710196779964],[1899,"b7536afbf61cb3b45d6612b4d83c105d67bb88f35c662e4cc34200222a6aa0f3",9.317957166392093],[13834,"0c8a51713df4d0705e5a91f3a45dc83f83bc0c1df0a18db60d7466218af19898",9.317957166392093],[14166,"ae22d6b1dd1f857167fae978caf945e18ce171f4f1978438cb87afdc5fc31b91",9.317957166392093],[15997,"54dc02aa0b2eb5ccc23043c97871704a79a7cb3c6ad39675a40406df93c39068",9.317957166392093],[6083,"3716eb9983eca80e7dc1b46342e88323d183428c4ef4c01030950070c5d67ed8",10.052724077328646],[11517,"81d405472389589c68ad386346accf0d7c20119f0c4b33fa061957153fe769b4",9.917710196779964],[590,"28ff7dbc39836c573dd944eebe667570f5017a3b7d6a68bba1492cc0fdc4f8fb",9.917710196779964],[6597,"008a60e0be567fcb924cbf404719101c364548932ad24ae700578260054cacd4",9.917710196779964],[5206,"e25f17a145c763793f2d04006c0105fc6d3ee6757eb509c9758fbe779143f5dd",9.917710196779964],[7504,"6d7501bb5521921ae84a4dbfa0505d871d57bbea47d9f10a860182efe808bbce",9.317957166392093],[18808,"9373c3c9c30a2d555a7f384a197d5845991fff82d8832f66906639db98cc6626",9.317957166392093],[1142,"333bd76bc6a9eddf39f0404a684910fb47d788942f2ae72d7e9465dcadc05af8",9.917710196779964],[14895,"6e6a10110138e946419556ac457f0d6c305b320fc92a7b393a4fb37f3fd9f080",9.317957166392093],[1094,"c86063e0469123991bab8bde21b93bff1f0075220ba8db98ad9e70b9068b99f8",9.317957166392093],[14914,"7754f6f6037fb3c104488fd8b01d6bdf0a4b48e5901df1df67185dc9c60aaa80",9.317957166392093],[478,"cc18a15b0f4c2a30858d83c2ec83444f97dfae5c801fa1371d6f815f8e1accfc",9.917710196779964],[883,"7db845b5ee4425567a9ad3c5ab1cd1f04c60025eb15d2333feeeb4894bab00fa",9.317957166392093],[4576,"c1581727839de6ed654ddc69005ac8163a624b7c5704e8fc2cd3df6e419cc4e1",9.317957166392093],[3063,"a16bec999adf92118061220f92a81995fd2a2115e91667359091a6319286e4eb",9.317957166392093],[4747,"52156ad02a98b4b8e5ac2da4876dbf65cca7a99149a18586d2b71641b869a9e0",9.917710196779964],[15686,"a393544818185b21a68e381fdf7cdd155d3dc87e092447ab70d29eb20e7bb56f",16.34954954954955],[771,"93dbfc340adaf8b443596c90a79d218273a8e1bf88347cebcf91f4a2a3d3bcfa",9.917710196779964],[17638,"40ad218a88a537342e6c701534c62b0ecc2fd4e2cf38d4fbb8733589f5756d44",9.317957166392093],[15542,"096bb7eff9cc1634383dc4e0449344b87795a831f0eb076ac204e13660812873",9.317957166392093],[1767,"5ce2a67f2b7a699967e45fb39be3a7873b6000124980c720a0bac7dd95797cf4",9.917710196779964],[17304,"44d8d49d8883bd322eb11b99be2b9229224f7c8e8e4969d9031d4cfb3a55e64b",25],[1954,"1a06b39a259782be11e7a6390d38b6b532f7db4f66a43d0f2f3da1379dbd54f3",9.917710196779964],[16551,"b0fa3afaff7c3771a00c70d5739a4509b8df51091e9baaa34ac1ddb1810bfc5b",9.317957166392093],[15365,"59aa67521888e47eb88ccd781334ad7016140e262295093e100ccc5047940577",10.052724077328646],[7835,"b394b038fd4feca6b28a551d07f5654c765d32f5fb61db68ea4955bb76d891cc",9.917710196779964],[2267,"3e80cb317effde62b5c542e1bfa79742369da259818819a82f971022f58b2af1",9.917710196779964],[2300,"3e870530d583c8e1934a0d78196abd4d15a272226d1cd623cb1e159482a803f1",9.917710196779964],[9540,"0a6c1748653967c183b01f8fc4627a6f9fc3aafd06bd54c81a9de0e8215c73c1",9.917710196779964],[1761,"ce76ba0e732ffe2d300370d6729ef3997bc8dc25b42d7867a68f14120a8989f4",9.317957166392093],[12595,"15827aba90ee189f7bac889061f4be3e4e2fa5d39bd908b48390ceb5301d4bad",9.917710196779964],[5573,"78aefe3c889e622c8dc4672d70c5bff2cb7df78d49cb4b2625fca8ec4fcac8db",9.917710196779964],[19688,"b3ed5295f718964a9addd97c5a235e08e4dd9fd0e6c1e21dc58068c0f93f2007",9.317957166392093],[2057,"1ef666560c2b78ce378f925609b69dc4839f73a347fa580e68b6450056fc8ef2",9.917710196779964],[14825,"9291ae4639d91d3784d96bf2c68ef72c3043691e53072925bcd728d6cb095582",9.647446457990116],[17488,"d3f88406a82377ce4bf232948e327098265f09c2f9585e833bc39c956d7ddf47",9.317957166392093],[1120,"9f977ac8ffed74144fc4627624a78059a95528a6367e9125b1015080f50579f8",9.917710196779964],[356,"5168ff84d1a76c29bd2c8696bfd25c41a984e5760c12b10c32935a938433b5fd",9.917710196779964],[9803,"c6fb2c319847a3990cfa939d564981bef458e220ded800d54d0847ccfb249dbf",9.917710196779964],[767,"e295f5675da699b37edb464f2e9c74bd643041e89a695f77bfe470ae75d9c0fa",9.917710196779964],[730,"dde5414b69bf7684adf44beac41cfdf7df917a9d24f8e56c6a7e498f0fea04fb",9.917710196779964],[19787,"eef7a9bfaeb42e3342c11c3589c84ab5b42aaa293656d112901f526defef1503",21.755752212389382],[17524,"91ac51ebf35180d88649d6ba7303c130d1e69484ea70b33c3b9ee9a21e520b47",10.052724077328646],[14973,"0ea5b9d88b3f5bb2cfa811742e67ce7c268af928c8da717270f402a959311f7f",9.317957166392093],[10735,"34db6260ec4872d67c2f3d4d8aad9f5d8c5fc6c0519a446705ba52524249c4b9",9.917710196779964],[10293,"bb5370bff3eb2e372fb65dfb355b972ba1f05d0d3136363bf98572827c6e69bc",9.317957166392093],[1729,"af9f1bfc4d2a9560271d5b1e29be733483b69937faf1bc4be7a4941703e1bbf4",10.052724077328646],[5511,"e6b002b09156814f3e0c74e89096d2cc550f5d280cf83a0f527926cb950528dc",9.917710196779964],[16858,"ac52468e78198c99f1e8fa5aad42e0fb5e8919332dcafb93d15a3dc414012655",9.317957166392093],[5446,"3d45e106ca1fb4f65b2fd059871f40a9ea22bb6aa4a5983e6112d869998180dc",9.917710196779964],[2672,"03900310c6eac854ba8f041984c892c6e0c247a767f35690a155d86406e8adee",9.317957166392093],[13520,"1c374846abf67c1bbd07db4dfa50e4e17a9f03323e3820960f3ac1a7d784629f",9.317957166392093],[18550,"862d4a643ad9522ccfdc659cb34ed8557daeefa3ceabe356bddc875214837330",9.317957166392093],[6747,"1a77a3699df72c486e306948c0a037c5fc2507cdc73bcc75eaa1ce8f034e98d3",9.317957166392093],[9126,"e852588d8497fe36976e712d8ca2adbb3b8be0109c89ce80053d1ee5ecdbfdc3",9.917710196779964],[17562,"3355f60f79989c5e109676687c26784b428a93e391975ea683e78fc47a605446",25.968141592920354],[6414,"a81ce99ca13fd91d06d4f8beccd62f748d9f35323241db6bc41530daad603dd6",9.917710196779964],[14705,"8176feefa38a1ead05ce556c19d67d62e4caa8dfc637c4b4d4ca74419307cb84",9.317957166392093],[9191,"fdcf65298546fb8366b28189ee9e511aa0c1e4fb7b87c80c0503e0ecfeb787c3",9.317957166392093],[3511,"69d8713a0cb56c90f550f1ffbc9da974c2def314b453a78adc94ab187e4feae8",9.317957166392093],[16439,"8c3b9564f3c73b100f6be8e1c7b5feeb3bd2e0e4889c82120381f6f9ac59605e",9.317957166392093],[10896,"ea82b8d219d8d4ff4570eff0b5b1771944fa05b48d325c5575afa6e3c662b1b8",9.917710196779964],[12424,"aae9de1f8c110853a055c220ad79b1c2503b111e62c3fb3158e864ee0cd969ae",9.917710196779964],[11100,"3a39dc951a996683ac7b1c5b832891972f99992f99e3ec9264e23023e3b33eb7",9.917710196779964],[12819,"b1cb042d9ba894d6ccb42c4dc2d28009763d62ebfbd746fc13ba2e5f6e96d5ab",9.917710196779964],[2121,"415e6fccb00463dd6f2feea77cb5006a38999fef26b173248e0180252e7f1cf2",9.317957166392093],[19573,"d53e9fcbb141f4043c557978407e381caddb23841898971d15f647ff356f7e0b",9.317957166392093],[4276,"337991551c1b07a885040c8909d411c4dfbd12034215a1fd5652360a5b98eae3",9.317957166392093],[6643,"b9e4dda4dcc7ce06189bbf9fc43d4415ba2b2bcda400108d3bbfdadb8c505ed4",9.317957166392093],[10967,"5b3dbacd802cc38b6f22cc5f9ec4a51683ee1a2d908940c92ad377ade00e3cb8",9.917710196779964],[7350,"f210198e06e77c5e96b35e1522a69222573a4c1bde2e76ddd552dfb80086b1cf",9.917710196779964],[11445,"b3e97e54b989cd3806893f042156e8f8620f0cd51a248d5671dd58163d02fbb4",9.917710196779964],[12591,"245aad3e9a15620fd4576fe777c2b843803214d5ed09674f60f472edcab94fad",9.917710196779964],[12813,"1fd85b739c308bf6b6567ce87b64838434b3ba1aef99d72075a791e0f30bddab",9.317957166392093],[5737,"0c15bf03a0b9cb99d722693f3153bb991aaa1fe2d0725824f2a32dfd7fa1d6da",9.917710196779964],[2175,"c809c60648a56ccdd74bbe3471a7c52df3c1c09f8e50a9cf0d070150ea2ec2f1",9.917710196779964],[12059,"26bc39c6dd54605f661c98418a236c7a06f2f3f87d5fb5d387f9ccb0a41cf0b0",9.917710196779964],[7819,"363c43ccb4b93ed60a2c400087847d674ce43954cc9d485b308c9b079b56a5cc",9.917710196779964],[11094,"f45150830af553bb4d5ec3820647582a02593eeb00ba48b30cf992c8e36d49b7",9.917710196779964],[6975,"c620a4aab8d6ffddec5ba117fa0eebfbdd928687a32cb2f5f5d74761d9ad21d2",9.917710196779964],[16846,"c7459fcd778cf1eeeeb7d875cee56b328f7938c17378bd806c55a0e54fea5555",37.05555555555556],[10302,"e20c3b54d59a94a3ebb8fa3dc07153a7916e66b85c91ee03ca469832e86f5ebc",9.917710196779964],[8249,"bc6c765d6f8e8f68961938d05eb8219322b49547336cef2fb328d09d0af1a7c9",9.317957166392093],[13309,"69deb11622500796204a2b69d1d5b9b5ddd8e6d750617c5e6473d3c07d4a70a4",202.50480769230768],[2014,"8050636f12c083d4a7ae3faa1c8bafc00fb5eecdc52799ec5ff77445c42beef2",9.651245551601424],[14213,"21110b58dfe9ad767d737f990cc484daf8beb5ed028cacd9032025c776efce8f",48.19223659889094],[7949,"f9e7967bb6f222deb6b38bb9f1904a01537f134cb49e5a6148fccc1d119edfcb",9.317957166392093],[10722,"15b549752316a92b816d324421b23a5d75ad068e2a4b8c3009e5c37ec7b4dcb9",9.917710196779964],[13279,"faa0aec5144cc1c85534894e7071db34da639f933c140ab253ea5f66217306a5",9.317957166392093],[18570,"7e1d3a7743835d5d463a8d3fa055b1dc10d3bff28869788b8876171612bbcd2f",15.073170731707316],[9166,"438c7c8d203bf5374c662b9fabee713bb669c05f343d114d7e072e744d56bac3",9.317957166392093],[10716,"abb9f2a65df0390cc1f69657e76f54b18b72927dfebf1a4bbd4bbf1bb59de8b9",9.917710196779964],[9108,"2ede2c365e697dbbabe738212edab7344b095fd0de3eb3049e563e41498b19c4",9.917710196779964],[10541,"4cc68b0feb511f973569fdb066f1a4b5e59dca01ff1b2723a06ff6f3ba2cf3ba",9.917710196779964],[10170,"ecddb2b7a0afabc57ce6987b4cf4437fa6eeff806e3fc4b21d9b07ffce694bbd",9.917710196779964],[4309,"1f2c0b0ff27a68f58d61882ddd0abd8e366f62357f9c6f7717da03b237a0b4e3",9.317957166392093],[5275,"3d3b5d4ee28e5c888a8082f4267cc50d1b3a7b9455c2ccea5d72cd7c55618bdd",10.028818443804035],[4841,"bf3415afdbfa966c90379930d19ca2476a7a92d3324912331bfae54922592ee0",9.917710196779964],[597,"251aa1170cba7a320d809a0698b1a936144f25c58950a12ee17d84b281dbeffb",9.917710196779964],[3111,"38fcf5948aeac0e9218d19af93235278dad9274103d0f788c6b9529c465698eb",9.917710196779964],[15891,"384f82e9589605b4fc894b7fee6bbea7da5f72ab1eef7df304d8626efadb336b",9.317957166392093],[12365,"401c930b6e8b8c120d99b5b086f0efbe241e047b6202c5aae9e11273f897d3ae",9.317957166392093],[10555,"4cb580c8e4294cedfb7a495570a32585d1d0db842043343fd674debe8b5ae7ba",9.917710196779964],[3169,"4fb321ade50e8a14b8d1c0d6f75fda5d9eb3bc4c7066b4ecacf5b51aa68d3ceb",9.917710196779964],[18937,"b08c86cca7fcba9b6ccbb5c6f437912cb6ae29c61f984d8238c7083eb5c17722",17.052325581395348],[19592,"bcf2ae0b354f3e246c14fbcd26ad5f0c90c72a133bed6368bd49a0a85804720a",9.317957166392093],[10584,"e9afc73b666fb60b96ef5319d075f6541983743983c40307e9d19a23b7e5b7ba",27.90088495575221],[13937,"455ada42621cbfdbe9e7c1e1481e7b40813c8f05866b11c9ac2057aee3d93996",9.317957166392093],[7537,"175e3a52625267420747ce0fefaf885bb7bf85f949fa6527cd4098ead1ca95ce",9.917710196779964],[6704,"dab614144a540fa9df6451defc4316aa6f9c24ec349ae22b1c138ba941f2f0d3",9.917710196779964],[18520,"3e70a67adf2f5e22513958d3cd1f8d3edb31d30cc6ff8965ba08e2e2c5be0731",9.647446457990116],[8141,"1e7f5d9f955d018a453ad145715ef5c254b0912613a9b96337b79a3ce42a6cca",9.917710196779964],[16636,"736618bf9b18b85f20ca281d01224a48323bef00bedab48d8d002f973d9f1b5a",9.317957166392093],[1577,"b1c8d454964d8c00c01c38181e4c2c8c59db843b7d8d79a8a31adefca982a9f5",9.917710196779964],[12126,"d1d54d594247f9097bac9a4fd5c8ab271df550c94d77893f8755845a9c9282b0",9.917710196779964],[18757,"4f8c9bd11be96a5f5f3a2af485d948bedf2524be68e519d805374b1c8a544a28",9.317957166392093],[8283,"bfc2f6b28a91f45c3354b9f4fd7ffd9c279749e49d4fcc15775e7b9e2a2e74c9",9.917710196779964],[4465,"e18d5416287b5621bf7b4d9dcd4e498523f1e47169fb62062c7ce9adb0dea3e2",9.917710196779964],[11373,"1646633dfd2ed1136dea85e73bac57aa8f0ba09b32efeaa040a3deb1930b90b5",9.917710196779964],[10085,"d7e24a4be39fb62afc829bb8c679872faf73287fdd7056941ca952800933cebd",9.917710196779964],[15775,"ec83f348e35d7779f7f3aef3259a3e521ffa838678b9ce75aee563be4f43d56d",9.317957166392093],[12061,"dcf4dfd7feb207a300abf10cdd68caf3b1186dbba19a6b98187158f42d57efb0",9.917710196779964],[14947,"80f2bd92bc6ebdcce3848e6a4d7e2f2f798f9502a0b1fd2532414aa438f0e47f",10.052724077328646],[18611,"bb6f7e9a4a7c52620a6c2d6948aa5acfa8bd12cbc4ab1f66e5019be3a9dd532e",9.317957166392093],[8414,"4b65a8ebd5793e36abc91e974c9f073f9474bcfa8a204f9dfefb8016a2f487c8",9.917710196779964],[14,"b0efdee4b619df38594c90d4a5859c371d8dec9bb935dab1051d8fe49565efff",9.917710196779964],[9225,"b362f732098c29ed9e6971e61300d9e6f02d60e30de3c93304067040462952c3",9.917710196779964],[3652,"feeda3df71143ffbaf004b0ddcfccd36bb1a1860a167ac51215ac0b5462deee7",9.917710196779964],[922,"a9dff7053b8174c69c56c531f67b866c9da5feebd009639987335c71f9b4acf9",9.317957166392093],[19850,"76ef0f3752353c97f50f93431ba4cbcd6d129164b3c21f7764b57e99f52bd300",9.317957166392093],[442,"c325403096eddd362da871f93fac827b15528e40d25edcd6fdef9e6715d819fd",9.647446457990116],[15378,"2a599552c1318f7c7f88f9d6506760f15c94ca51e9c678ae51dbf228316fd976",9.317957166392093],[18452,"d675147dc4eccbb8fc15dfd832c2830275be350cc413d7a4fb2bf03773cd8432",10.045662100456621],[8625,"a7a3e9758c82294a92368547320656cf6da79c5b764275975569c08e1d6d45c7",9.317957166392093],[8895,"5ae9db075b56a4bd21e4213fd745c3e5990fddff2ec5d11beea2281e93f175c5",9.917710196779964],[2749,"b7c40e8ae03a3ad3bc032415c3d53e5676f232b800f2387236251e42da861dee",9.317957166392093],[1713,"9a697a67b5de45562575e1b0314185dd0a87b6fdb927503cf572dc9c0310d6f4",9.917710196779964],[13583,"66e801a7afcf9c9730bad3d41ceaecc25c45a4d83b22966e1f0280c8b199d39d",14.188948306595366],[18411,"84f802b179c1bdb87bab74e92ff7126283c3d59fed3b9b5dd54c9f142cf43f33",9.317957166392093],[6289,"4d627db784c2f526d18dcd4a8d2610b26d244d888f3aa6e74ff253544c211ed7",9.917710196779964],[17659,"1d9baf97ce03412876e43f8179870ca9fc52637812e981228e45ffa4bc3cf643",22.68018018018018],[11669,"572577025588721bf0f659cfbf97a54e898f7cd4a6b7624c415d0f16b0d378b3",9.917710196779964],[11949,"49517bd50943b490d74ffe1ebe51a9f318911e8965c129a4947e059eb8d6a6b1",9.917710196779964],[17878,"55d410bd3c64a6448e63d7d5f334806cfcf3640e42de1b8cc7e0047ef199b33f",9.317957166392093],[15529,"f1c5b712e2965511761ffdcb3365f6dfcefca1b527c5c02d7e40732649ca5f73",27.151515151515152],[13053,"d9f699c05be07c3b29e80e2184bcec1bd6bd3aa3bcf8312e3339b7bed5d642aa",9.917710196779964],[17350,"e8f98e86fd4183c78ff32b17cc52408a258f0bfe547f5dfa16b1048c6cf6dc4a",10.052724077328646],[6872,"86d3902ca781fbfd91e7a3ee46651c54b654d1367ad18411697b88578a1eccd2",9.917710196779964],[12700,"7521b75af4f94a02ed76be2e86d0dbc16a18ba28f5d43d2bd04707c74bfb98ac",9.917710196779964],[6651,"e19ea4ce8f7d49c23b03cdb04a666ee8da43584a90852d9afb172de4c9864ed4",9.917710196779964],[3015,"ee1cd8123f3a5fffecf6571a6fd2ccae1a4165ad08bba2631d394b9106cf30ec",9.917710196779964],[16451,"af4bd5c5aca8c89786958cef3216d9b28f9f30af0bbb88962cd66172cc1c355e",9.317957166392093],[9818,"4d8c13592aa013bf09ed40646c407c2d42dcc941fbfdabc26125be7963d485bf",9.917710196779964],[3437,"29d3688e81e9e198f642e7ef399fd526716740e813894036ed389a5db3fa72e9",9.917710196779964],[2855,"e562872aa7c748aed6e1c5984cc0c7fa5c8ca2fd57dc97309c4daaa67d7c58ed",9.917710196779964],[11782,"e5ac028a15c191a91ea2274ff7bc673f0c911e7c21094b204cda209687e2d1b2",9.317957166392093],[7953,"6ef793485a579af07f3de01dccffc2970dc71c1663f49a57b9cf7003058cddcb",9.317957166392093],[12615,"ee487361840950b3b38827ce5085a9bfe98e98411bda3c36a3a21c50168026ad",9.317957166392093],[19232,"98072925340b43a126cd5afcbe676357e9b2528bf4f5cbce299821a012518a17",9.317957166392093],[14757,"6a34bf9ddd09e6bdac547e5016e4744e04689fc449a317d52b461e5699d2c683",9.317957166392093],[18449,"eebddb8ad9eefbc6fa33e1b548cbf540042f3196af600b47a219f8461f5ca832",22.49469964664311],[10466,"4ac612c36c9b370d9b3e97bbb0a93ac94174004bde0f8829295324b96a5154bb",9.317957166392093],[15476,"28a41bbfbc6bef8c74a2313852a75e845be395870192f86b3946edad46c08e74",31.05545617173524],[4628,"8af238eff237a513d868d033b6887b2c7d69a15bffc5f43dcdb75724b0d772e1",9.917710196779964],[708,"e0a2a93d2a637d66a4086a4cdd9c4230c1a62f9692c99a346c83f442a1452dfb",9.317957166392093],[1862,"7b95efce102eaab95fcd561a2418ddd6e36a1c3962c03ec033087d50223ad8f3",9.917710196779964],[15328,"788d7bd016833df03f7e50f2ac01d73c85088122bfe9c5fe24b148335515cd77",18.411953041622198],[13724,"f5d0033d77813ae228469430b1e32c51615670a3eb4d0e0d01155ee1e2fbe69a",9.497326203208557],[8236,"fbcc4689fa3a5f01d1c8f074e95b499699dd805037d9d5fe0fc728400e18bac9",9.317957166392093],[10260,"490d9e8ee6affb9a56047734a5731f4e7f64370f67f1cb4efa5b591e16dfa4bc",9.317957166392093],[11610,"600463d9cf2ab78c0b1a7eef60e76b02d358f60dd4e5d50d209eb1bb97c2d5b3",9.917710196779964],[8386,"424bfea7e8d0825362f8f5b04a093fb09057e28fce16a2d46fa60203e03db6c8",9.917710196779964],[5658,"feb55d47e41e422022125e8593800d3cfb27d0236ff743f9a36487ddae3846db",9.917710196779964],[8288,"62a26662c8ce16639b5bf913107697770afeb783d18f7447b6e106bd95ef65c9",9.917710196779964],[15338,"2cc94099c3354b229041c213bcc34a975f1656a741901d0bb55431531cac9e77",9.317957166392093],[12890,"cfa28fa99e983ef061fdcd03aaae913e66dab8bae25bf16b8a6a98d3e7c157ab",9.917710196779964],[8190,"6abc2312bc5d287a7779a53ef5786a7e66af6263f819ddfa1f1f85311f940eca",9.917710196779964],[19802,"ef64016127005700adcc793653d6bb002f15804675c73f03bd43e4e0288d6d02",9.317957166392093],[12907,"171dd6b460c96b0bef20a125d4c49451844248b89fc7d836575521431ec244ab",9.917710196779964],[3587,"81bc26ba6b82f9ec9c9728cba4316144ddebb30231d53f45214494952bc162e8",9.917710196779964],[8646,"5ba0591145897cf6a125af44d12bdee974d75ba3ed66832e40ef081223e313c7",9.917710196779964],[2394,"31f58510aef0f73ed26794a86851b48a49b6aa53d67ffaf7a1cee7cb2a9e83f0",9.317957166392093],[636,"089b2fb485d447d614d03a99c7e96702f785259636a5b37bf9ec765a8ec0aafb",9.917710196779964],[768,"0cd10ec18bffcf70693630f9e9924370057026838009ae921b159c3fa997c0fa",9.917710196779964],[16812,"0db20bbafb0d344e7464a2eaea8e96d4b8869b3e46f58360bc0a5d59b6890756",9.647446457990116],[17989,"6f361a8fbb03aa9c85e7193ef289e5bb08d93836fa26fee7170af88ab983653d",9.317957166392093],[6277,"3f0b579681caa43124de40c4ebf218cf9f11aae0ac2df908eff73f5545403cd7",9.917710196779964],[13521,"3cff03f8114c15838b4844dcaddc2eea476429e4f4542ff016957bd5a362629f",9.317957166392093],[4726,"83161eb94e18135d5a7f39c5c78cac269ebd125e3cf1aa8441847e64afaddce0",9.317957166392093],[19224,"cba59bdd2513de0cd9698cacbdb8477a9bfb32f5d0913bd6a19a160a883cd617",16.91103202846975],[4484,"e3ce0c62eb27fffad5ae9bb91638d669a1beaa8147b6b9a481c0452b9fee84e2",14],[4759,"ad622ebf7d56763eb29f2672cdc0a2daa2e963caf0420548905bc18f504d93e0",9.317957166392093],[11385,"5e86c763eb78d4af77939b3f247f6bfe0088f9323cf7af51a5d845a5bcea7bb5",9.317957166392093],[17466,"ad541adb84f08b10f9b98351ac5c7e38d10edd3e4d28aac82bbc94942b107548",9.317957166392093],[10989,"a17260a45e944d16150506c3e9536e4b4b6f769e165e427c095ff7fbeffd10b8",9.917710196779964],[7171,"18cc1c86352c0b4c6657fe6b6d73c823dcb6859e241eee40b130324c4df5e1d0",9.917710196779964],[6871,"d893a5d02169946d4e1a0d5198641ddadd0f8468bebe59b9ec0f55be5068ced2",9.317957166392093],[817,"0a0a8101123d97ba901e002494518e32b94261e485bef7f08d5963a58fda6efa",9.917710196779964],[12194,"3b9e37700be4354c469637b6ad3a9a4636e5c97271aeb0641f183b37b9ed16b0",9.917710196779964],[11232,"7626a5956931717cee57a25363f9fbbfcf941d472491f08a9b1364f5c04c79b6",9.917710196779964],[6090,"3252be214f85d27038ec219c3cb28c29a6362cbf1f642fc0c3bafe2378b571d8",9.917710196779964],[5639,"524b982db9f75c115d0cc40a37572b897f3f1fef0a198dc05ca4b3639dee65db",9.917710196779964],[7983,"c9f73771654bb6a249be8977aacbdb81d39190b721b48b6d965f8c125f66a1cb",9.917710196779964],[5795,"1c3acd35cac513bb65bf8ae5179378ca8edd655382a74c4f5cd38fb5275177da",9.917710196779964],[18495,"32c05862ad8b146a5f63898d985d834c9825248c2ee2dd78d40e5a62cdda8131",9.317957166392093],[1322,"ab2ce3313720126b4a5f7aae46e720561c2c8933be893b86bdc4e254132644f7",10.052724077328646],[19711,"5fa5347dda21ff955b4f15e6baa7a56b789f1fcc5c58244c7118f57132bb6706",9.997888067581837],[17137,"08dabf333cc2930c1fd66f6829d53862514c1b35a540a87f1a50f79a2b9d564f",9.317957166392093],[16005,"6c2157956ffa8fcf0a4e65e0d20e82194b1be8509ccea85fe544347f09435d68",9.317957166392093],[14637,"93b28de983c368f77b1c527e4e0912d7906987582c68e416a4aa3d2e2d003886",10.052724077328646],[564,"08795419a559298bdc9f11ef1b99fd3b87613012a06af6c181809205ff5a2ffc",9.917710196779964],[3021,"4914b8cde2a8f03eee27eed1d9ada7548266b4b9f483a08f870cb8fe0f7620ec",9.917710196779964],[15437,"de9bfd51e4c48f3ae199c994d91339b71c8ba5fc2963f4e1d3bacf8d932d6d75",9.317957166392093],[19337,"f81dfaeee671214b4f79e214e75c08c4ce76d1737bc6f43f034dd2fd4ae5f113",10.052724077328646],[8371,"6d4f2bb462613f17a831fbab28b71b156e8960410448c20f4feac5fae1ebcfc8",9.917710196779964],[12016,"0ea37fc9e31d8661bab4be8e6fbbdfcb63f558acac00f264d8e46e4d8b893ab1",9.917710196779964],[226,"0117c987dd35bf1e89b75d5de01ac0ff49eabc6597a94c41a8fca2897cd877fe",9.917710196779964],[4613,"f146a5b174c60bebe28125a960a80e7431a62fa4d2c0b9bba32ad4738b188ce1",9.917710196779964],[11528,"dcf5514ed61c3c00c167ad948eb65311bdfe62a9dade907bb69ae364ee7a5ab4",9.317957166392093],[14817,"adc5c4d2e1f39b1e90f7421b78bf7af4fe8b3a441633248c0658b77958fa7382",9.317957166392093],[14520,"b3dbe2fbb4e5cf17864a0e0e37076d6faef3e57ec946fd40248028178863c988",9.317957166392093],[16385,"101720280a77f79e6756cd95ccae774756e0c25351f4938dd8a6d0b79348695f",9.317957166392093],[19225,"d9ac8804909e3c141c31ed8a1bb2bb9de7090ff20e611849ad21d57c04fdd217",9.981900452488688],[3195,"86427a44fd7acc0e5ce6322176d08aa83d2f2c8d2f6b7a510034097c938714eb",9.917710196779964],[3892,"005ba369e19686db25720fa4ac635b75cfa15dcb24a458013b25d30c65e164e6",9.917710196779964],[11768,"ba62262dce09a4f573aa6dd9c525e48d80fe8e39a790c24dbe4a2a6219f1e5b2",9.917710196779964],[12181,"c117742ad06c956d478b7f36fdee79a87228fbd210183e7d880c4bee7d0b32b0",25.950738916256157],[881,"d2ca47e000594ceeed4e9eba4b1e4a5a39c2eef3d2e56bebf95baa53ecef04fa",9.917710196779964],[6225,"ce77ca6ef905fa94509227dc25d445067924321190cb51cfd7a0be98f76494d7",9.917710196779964],[8922,"d2c098bebf18436f56385136b48fed2586553e58e01a31e81ccb7ed9297859c5",9.317957166392093],[2764,"3b4f922845b1f25c3a586fe3523ccd4c832dd2a90d2e5a4bb1244dfe1e31ffed",9.917710196779964],[10978,"4efaa0d0b2b9739fb7249629e650478048620f6e03bdc3996b4e32ed42f52db8",9.917710196779964],[3650,"01f9e02f912577005d67a9cdbea8b867834c69746da71a8e204159bd64f5f5e7",9.917710196779964],[5998,"a9c9a0131f3486767882329f68646810dde7cda3c5fc12efedbe2b53145d14d9",15.971479500891265],[6286,"a018c735fd63dbd0baafdabede391aefe1c9fad6cc84f0a4baedc601e78129d7",9.317957166392093],[1308,"a4f71645af0e7378025fa0964cbeda666a5c6e475b65d740f087710fc91c57f7",9.917710196779964],[6692,"8301b52eb5c328d6bc35ca9139f0ed30354e0f979de999c02e64d47ef65802d4",9.917710196779964],[12248,"a1e8832b8cfe01e6502f7f735a8f2fc77536bd87e2d7f65ca6e0574cbdc7b4af",9.917710196779964],[7716,"57f1c9d768499aeb2af2a5be3d788b24dd78e2164c9d25785ac28504b5c46acd",9.917710196779964],[12915,"60779de361639dbb47efd66cf8d888ec15176bb5a891fe657c3e7bfaf2a838ab",9.647446457990116],[17099,"6ccf429d793e9a5c2beed6191a9b472ad6b557ab06cc26fe98c1db140c0f0150",9.317957166392093],[5139,"78c5b005479b10c03279234767a6d627c33aa2883a5397f681ab7e15f2f95cde",9.917710196779964],[10864,"670fc06276caf47c619006515db1a35c358e370eacd07b2f68181c349babdfb8",9.317957166392093],[12135,"722b6fd4fcaef0fd83a8135ddc6b51daa32e41b3ae04a4e2ed1bfe5a36ac72b0",9.917710196779964],[11854,"be4a8f1418b7634f9dd4aba771d3df24ef0838f24bc4e6a6616c49b8585c56b2",9.917710196779964],[5311,"fc7c2648f5d675b9972e1f4e855ff3afb02c71fd14c6535fa0157a30067051dd",9.917710196779964],[11110,"db5b238cddfd26dab6bb46c2e3f6c0d9b112a68437c57283934aae8af97f33b7",9.917710196779964],[12255,"6336470eb6057d513d7a694e6c22db503e47b09be8ae13ba4c30f70573b3a7af",9.917710196779964],[1155,"39079ba3cd8878a3ff6deb8b3bdd255183b6b05a4f1d559297f443cf939746f8",9.917710196779964],[19092,"851fb70e886902cbc6b0bfba44244f005a701910962ee048d5c60c632898ff1c",9.317957166392093],[3037,"65065e2ef49dacad16fd05896471765933a62840f97a9b560df3bb178cf410ec",9.917710196779964],[13168,"7cfd0b76e70d1efb54696df726d7766103ea7f923ab10c7cf98e3979d218a8a7",9.317957166392093],[9704,"e97573884b728f11730d67186b6267d2d50bdea2ce8bd81c317307a6c7c156c0",9.317957166392093],[10279,"b9c59c48635cf484bf929aa4e26dea1c605e5a6378bcaca84eca578940df86bc",9.917710196779964],[18571,"839d796b46e4b77466dab443650f17614c9a7790cf0d03b9b199132f1b88ca2f",9.317957166392093],[2679,"f29567d7570e619857754cc2dfec7b9468b4bff17e532c6d659f48cf7639a5ee",9.317957166392093],[6947,"2687d74fe165e78f44241fec8e14cf7129b32a96b6a1d0d8f7ff8289d5954bd2",9.917710196779964],[37,"f758fe956a0133f9a1afb801eea047331e9257593ae89868eb57e1554644c6ff",9.917710196779964],[1014,"3cbd979f8d3af57a44eab3d165bf58b85b71f2d0dea602923b26336793fc1ff9",9.917710196779964],[12116,"1437261ef2f2ef8dd6b3902d8c9a4a1673578f39b291035112525a8976d5a5b0",9.917710196779964],[2358,"267dc6ea759208e6c4c3f7f035af340b85b4ad949b4b0cddd4f8cfa023fdb3f0",9.917710196779964],[10138,"7e30a454d172b8a45b21173efd22f9882e3f7e98ed9beda10c1b74e21a3b73bd",9.917710196779964],[12404,"83e003685767c6694e3b42a0ada14dba01a1997a8f50fc3e2bc23f0fc95797ae",9.917710196779964],[17521,"fe8910d5277a26e229737012df51369171eab88b181463521e110303fd242647",28.09534619750284],[14003,"a9c4941f4682e13fed6fbc3185ac0a6c97e78e09499a9eb3679212d20f3cc094",9.317957166392093],[3710,"12024ac3cf0a5ac92fc10816e38a4b2b372b80b6732634f127a74c5c3ff286e7",9.917710196779964],[5567,"694e8a10ba52091e9777fd397ff91849eb0e78983c8470a2a5ff332ded10d2db",9.917710196779964],[19471,"7443de77676510969832dcdf113d8cf380cef0032212b8a8126dcc7d34b4620f",10.052724077328646],[18407,"0613a11c9be59a6cbad264a9387437518029517769d6ddf9fc9f6e47f26e4733",9.647446457990116],[8665,"88a3fb355f920194a0047c5bdc062b700d1a2409ba8079006606f83b6bc5eac6",9.317957166392093],[14568,"ccf9657fb87e020f3aaa0f17fc2e06e0d9036b995043ebc9614a09bfe868cc87",9.317957166392093],[18463,"b9256e5409395599320531ae2df75ce7ee65d935caa434624fd70b3bea505a32",9.317957166392093],[19364,"ba4f4d67f86ea10533d88b52b5565c8717217c702ca284beacad3aba313f4113",9.317957166392093],[14405,"e8d532a8d02ce470d1d7a1605d25cf95a9653cf6917a702ac2a241ea805d328b",10.052724077328646],[18437,"297c2d76f77f976b55202f2ebbefea494fb984379e0e713cd4726c3f724be232",9.317957166392093],[2118,"b6d3f40263c6794677261404d5ab3dda0dfbbf61c800cf96a6952c05b24d1ff2",9.917710196779964],[12178,"39f55b3435a43fbe1da3c9139407a097ff0fc9f64a1a730da3795554262e35b0",9.317957166392093],[3554,"8733c9c3d21e555051a14c39d9e71d3b2127e3b42f712554cfb8226998ff8fe8",9.917710196779964],[3358,"f563b75bb9dbf7d26fc394301115ae752f0a78ea15986449a44d45e1543bfbe9",9.917710196779964],[19542,"23ab96bdec579be9ed6588f3710d5b69c7df8d723facbe0d191f45f225a2fc0c",17.95964125560538],[18353,"99c289269aa277352abe4663dcfbd9a67d54a11037620a3a115e2ceaa8aeae34",9.317957166392093],[5645,"88baf0f146b4b5621575cafb0e897ddb06fc7be1d2ae12ea4b6f3bd2a9d15cdb",9.317957166392093],[16309,"edefe8bc1e521de7d420d5ce0a6ae846cbb1cee8cd76baad194c68188405d460",9.317957166392093],[11102,"efc387d174d15e3d60bbc1659a8f5d6f55b57d4b5d5081307d79713259113ab7",9.917710196779964],[14171,"49b557092006104d50f2559c2322d567ab19e223e74d3caf59d3157827300b91",9.317957166392093],[15787,"47f3825903a2fe33c8b865feebb57c63b7d39d3b8f20a3f2d230a4badad3956d",9.317957166392093],[13214,"74b01d1b78ee01d4cab487b2e8d694a9426125cfaaf850c572fbc318683e95a6",9.317957166392093],[11888,"67185af304972d416d16303e59992f570cd121f52cac9877ad9dffb5dbd116b2",9.917710196779964],[13281,"59fe1814620efec36db642d49b1745cfdafa4ba0209a8c7135394fcc3ef004a5",9.317957166392093],[11484,"99978a35ccb05cc0808a0afe3cded1df51c6ebaa1afcd613bd218e2662759db4",9.917710196779964],[11286,"a1ba50991b975d84dca8374f056e1296206674000f80b60f6eca7ece2c391fb6",9.917710196779964],[17876,"33bf61d9dbd737256d630972afecc51aa228befa8a9757a073962d67eaaab63f",9.317957166392093],[12857,"5b255c7a6b1ddeecd78b5244a538adabe16fd4dcef76794096d16d19ecdd86ab",9.917710196779964],[404,"4837266d31db719c150190f8db3bf9b70649304aca8bc817fb20ae244e7450fd",9.917710196779964],[10697,"720de9abf09003ece81cb2d5ac57ccb7be59b910cc4f6a929f6a49c1859206ba",9.317957166392093],[17157,"f8774c0c97f242d14c3b60afb5e23b109c5574779161a8744957b68cdaa4ea4e",9.317957166392093],[13526,"6e9ce609b9fa643649eb82f3b9f7186b75c183c74eb5b08ecbaa8d98a31d3b9f",9.317957166392093],[9146,"04acda8d288443501a84781d6cfd835c21c2a07b7a29665802709f970f6fd7c3",9.917710196779964],[10277,"309d3ac06b555208b9ecb6e1cb4fd54f923fee72d67b204ba1bc6bb7dd6c88bc",18],[9606,"a14f882ecf7c07811a4155c78043c7caf81d979c4f39083fe3092de66e7e02c1",9.647446457990116],[4029,"91c0c1aa35aa20bacc9359b263f842e3c6317014ac96fc8628cd0d5584de8ee5",9.917710196779964],[14978,"dfe7ddc967692905ad268773852e8e90e9338fdb8d6390d60c3837f2bdd6067f",9.411764705882353],[19352,"755267e6ebb32f47c1630d895bd3a6908d59f02017945a398acb2d833f508e13",9.317957166392093],[1186,"00fb18137aef4866e2d40a1828da515f65a9c135d654ab8fb0000571db1b1cf8",10.052724077328646],[19278,"3b63fc670cc7deff36af53ffe36cc1f0786b3e5d344f3abfe213f9884e6ea915",28.098939929328623],[18345,"2e3d56013896596103fb6c8407ed176d3eaa2a89caf05069085953411a45e834",33.523809523809526],[15523,"7c80a125e6b241314c24d50140fa5486b43223a7d0eac373a66b973862ee7c73",9.317957166392093],[10860,"a11f4d9dde2e7d2b88e9e8f7199bc82fd6e317a2af5bfeb1300d1006246ce3b8",9.917710196779964],[4220,"93cee4a330105de8262831bee64f6f38b4fbcad86747caadfb1750f26c7656e4",9.317957166392093],[8460,"2fa09ac5ab525aa8abb56edfd64d9125cfc480651228f7e1df4f24f43b5241c8",9.917710196779964],[3877,"e513f2515f7d104e5d7c6fc00a3e2e2d6344542759281f18b239593af53184e6",9.917710196779964],[290,"0badc7c9bc87c2146e66dd8ae6677d8d26595efa4d4a905bc5105f7bdd8703fe",9.917710196779964],[19318,"0c19c3fd48980f9fa0b36d0c5835e28bf51838ab08676eb3e2605ad249dd6114",9.317957166392093],[19254,"d362d52cf3b6e1148dec0aef949552574a263508b3c6ba27ac4704dbbedb6c16",9.317957166392093],[11235,"fc0638cd849c149628f5029b94b169638e175d385256aa8b8b331f30bbd673b6",9.917710196779964],[13711,"3644a2a8147da31a436bc9df8b395a08b3e7dda9fed21d5b077e34b95e7f289b",9.317957166392093],[1911,"6ed7773b1c069da0d43fdbd39a9988b97bb45722c134cf2209ac8b84a18393f3",10.052724077328646],[19220,"de867d99162cdf67fa478fbb77a1a8448dcff8c8fdabdef4f8c1a020c5290118",26.118721461187214],[1930,"ba5bd1848c3537f91e39d70b5c320c586053415d3c798c568b6b64d9a12f7bf3",9.317957166392093],[17945,"0dbdbcdaad41d5a143c99e784f8c712df235df14866b186161db65786952533e",9.317957166392093],[8356,"361ef2d5a91c0046e6e0f18492954a9d117b8fe223c437ecb51a8e9d4b86edc8",9.917710196779964],[19618,"62de2e6f9aed5df50ce420056bcfce19af9928003564b68b1624119032fd2209",9.317957166392093],[16209,"d9b3dd6beefb2f6e75433ca0df10a99d98b9567e3dfa9b1ea8a2986c6d7ea663",9.317957166392093],[11353,"a82d2e8771ff20fe24deb7a3c19937c7ae0198aebe88073f7849ee5967d0a3b5",9.917710196779964],[14080,"2f18e0a2fd60c5ace40d6940a26445c398307114d526da006fe1c83da92c0893",9.317957166392093],[18431,"f342fb0c8b9dc0b91fa35ecf8712b59c660b374d9649e87aa011fd3fea140633",23.00503524672709],[3041,"54c730b27ce3351d95411d44585ccb8546133c279848182b974b0bb4cf3f0dec",25],[14755,"508ae1640f1b7144ad189c9c781c4f5237ae6741191452576a31df1f307eca83",17.195402298850574],[16857,"dbd60c4d500fa366c435188167012421450c8636d0d1cef8255b743b91722655",9.317957166392093],[8805,"0ae70772763393f6e2db15804dbc289218062f6521ab18d38a499a7edd9d0dc6",9.917710196779964],[10389,"0d06b7618ea8067aafd225c918eded619bc878fe356c2fb8bdf57e69b3a5debb",9.917710196779964],[807,"6a02b24dae66465d3cc14b0bc2ffaad936e6b258b88a65fa7d870777d5b381fa",9.917710196779964],[17033,"1260a2372bb4532fbf2c76699d0c7633936b4c18ccd73283be7bade061c04e51",9.317957166392093],[1239,"c89b85c3f8fb3f6f6df5036fdd827ea8d8695ac837951e8283cc60b97be8c1f7",9.917710196779964],[11402,"4b4fbd3ad86e2408fc812f95c77d340d67662554813d4348d3da17bef5b953b5",9.917710196779964],[17141,"59bcaaf9587c00485190199382139d9c8ac370123445f9165ab9ab113549484f",9.317957166392093],[7972,"351b8655db1ff7bcae0615e69b17e89f56ff0ef1b6c170923b7743ed313fb8cb",9.917710196779964],[11050,"58f4315487f9158736f0279d00f42f0ed9ca06c59c01693b2333b89de416a9b7",25.114854517611025],[9041,"4da660df48f9aabcc4c24cab08834565c765b5d6d852dbd45fd5f344b55f82c4",9.917710196779964],[11775,"b7db231089f1d5a786e5ebde3d27c882a8c95d51337ac6e6c19157b00d66ddb2",9.917710196779964],[549,"e263142b4d5fba55d42ecc44f3c92786f4bac953f9e45fd27abf07077dec4bfc",9.917710196779964],[17594,"cbc448f2e20030e2b238b9648fd081a968032cc428ce6cf89d1aec882ee34a45",37.80782918149466],[792,"35991a45570903abba0dd71c16dcc9c1d0cf2f60e89a9abc581c8c5a9ab292fa",9.917710196779964],[6372,"08d119c4f2d8e81ab1b0402165de22a261c70263eeeabc6672c486e3294a82d6",9.317957166392093],[8146,"2e6db47c17cef4574a33fda4a7d8d825d4664a2cbaf389fbc4358ebb925667ca",9.917710196779964],[18613,"93cc63d1d6254b1b53ad6d0a923e24c9729302ea40855e568240bcf8b0f2502e",23.01298701298701],[17265,"633e2f07e17f6e6f0d4d0b73b5216a7188e461834837fb8b20b2cf848bddd74c",28.898446833930706],[19456,"7d9223ab967d0e11274c2fad4b562a4695686537d5056cc787060c990076b80f",9.317957166392093],[11244,"9dd4154156bb384eda373a82b5eee4c5f8433fd46f83d8785b0f6bfb590b65b6",10.052724077328646],[13735,"febb72b0e00f632df89425e4af198fc5f7e428a826c4ce597897d6439741ca9a",9.317957166392093],[15693,"176e7e7e3f0b72d804e80b7a8e9f4339da9477e593a0aabac32ef6316eeea26f",9.317957166392093],[17627,"320a37739553a797ff79bc61844682c36be438fd59bf4359edec85345db0a544",9.317957166392093],[4209,"4421487b7784898769da9b435d4a4d3d4668f5ec6674ec6a3c115679c4465ee4",9.917710196779964],[9502,"07b94ba4c0ee9d62ac0d8bbbac3fcd46e5ee4574b6f80344516d91bd9fa3aec1",9.317957166392093],[16913,"cbeadd7f1af035f75aeed68422962cc6c9ecf515599af5ef91fd24c11846d353",9.317957166392093],[18877,"06a34bb930923518b8168c2405571aefbba6355b17dca2daee649f7c2b4c2d24",9.317957166392093],[13259,"1a940b3ded7f4b623798cc54713a1bdb59e1ab5d185ef4508a5d18e5a3b57ba5",9.317957166392093],[18780,"078ef08f0b26fe31eaee0d5003b017965d1e1119537bd760db717732dc16cb27",9.647446457990116],[6599,"54cde98075e8b5071f478e443aa99afe710b7c893eec91ce6dd822760f4ca9d4",9.917710196779964],[6853,"ea25f1d42d99a9680d6f597d03fa5552061f8ec57aa833e269d250f15882f7d2",9.917710196779964],[17997,"9dce9e818a92d5ce4beca271c2a635c7b2a93a13a0850742d826bcc65fb04a3d",9.317957166392093],[14056,"9f7019b63015bdfe586449ae544924eb64e4b74d5931fe1fe1081487b01f8f93",9.317957166392093],[3556,"621b9d5399d6f5d97f5e83904528bd85a4515de7389030c625e4bb1cd2b98be8",9.917710196779964],[10539,"2ff917bffc30d2ed87a7a3493c939402cae435d561e08b16fa7e76c95c0ef5ba",9.317957166392093],[845,"aa9f7a9b8b0014966d019db1f7c7e73fd322842e834372d6f5f1d6e5197741fa",9.917710196779964],[14771,"3d69aef91c63c234b970b009192e9c6a3214919288777c3d36c858baf73a7683",9.317957166392093],[2307,"5e9dca19936765c449c39862b0fdd2dcd867267d9874c10bb9d3c5262af1fcf0",9.917710196779964],[6167,"8cbb2498ca785a04a1e317c4ecfbd0f89377731c96b74dc6850c0d919d6c0bd8",9.917710196779964],[5901,"9b9a7eb3d25873e13cb864a491934ed5f1c4c3d44961eff45fb82d46694bb0d9",9.917710196779964],[14148,"32f5eb15cad12af70aaae7dcc26f8ade6b4f140760e080b46d082bb0794c8a91",9.317957166392093],[3890,"8d668ec705cca8b58e84f449e0b50dd671f2455cf3751144457ab478c8d867e6",9.917710196779964],[4494,"91f785a64ed08503dee6c41f2237662c8d7c2666abae5ddf189cb9f81b2c73e2",9.317957166392093],[3598,"79c5c5cd8f71fd3fc24c9cafa5744adb0097388ed830848a30478de6f32339e8",9.917710196779964],[16075,"79f77a5e1948ca82d09f97776a2ea2ef740ac18e51ac1ddcb116028a3860ba66",9.317957166392093],[8494,"2ae5fa2eddb3043cbade63d1c9698fa047cf8e1fdbd6981dd9bfca5158670cc8",9.917710196779964],[7472,"0dba4e1bccfaa1c2cad5da21d03442e9bf20fcda7687814fae47dc50ad02e1ce",9.748672566371681],[19245,"e0d24720f5af64c37a16d4dc563b16640332496d47c87c49560680c926f61117",28.19047619047619],[14547,"73052d52b85f1a97fae284bc45a08916e6f97e26f8c3f9e4b2b08e09cb082c88",38.70022883295194],[8349,"e3f9786060ed355538cdc6eee1e2385a3a59dc0a247d17c4ba979d7b7b7e02c9",9.917710196779964],[3732,"63f11dabc1d8f897a72f4fd7922e893664bc3314be5dfaebd4a536de60d963e7",9.917710196779964],[14499,"be731bd38cf497b108b7c4875cc61c677d0c3abc4e24a92fd2da07ba059c4a89",9.317957166392093],[16020,"5ec49c6b0e74520de5ffd1f3b4cadfcbe7ab70aebf89b8a683cf81db4d5d0368",9.317957166392093],[15448,"fbdbc98451bd5f34cda9ab463825781d563f74f70ab5add954cf4aa7ea982875",9.317957166392093],[11290,"3c2bfe282619da3a75bd25d546b4c2550d889194bc3f8bcc45d2234fd33c1cb6",9.917710196779964],[13064,"c25cabffae0e392b6491296c19fc8d3fb848c924eb37b87d598ccac55aba33aa",9.917710196779964],[3893,"6783bf522ea0793158335826aeba1b1d6a373e6af56ec3b2ac2f54c15fc564e6",9.317957166392093],[1536,"8c65ca06efdfbbb1ff92b47ebec55fc3330b1261c9a4e450b5faae686be2e8f5",9.917710196779964],[5610,"a589c9a1946a563203f818cb6984a435f5afe2f45b1d124fe835808c5c289cdb",9.917710196779964],[14553,"6ab6af2381749af038b3426867724ca4c9e219270681e511044b039395d80288",9.317957166392093],[1643,"0449053b3105185e41907c78735b5e70cdb184a493c250ec7fffbaabb2d754f5",9.917710196779964],[18697,"68dd1572c1dd7d3539004bfd35e15a029a0d4c9729b9a1dc529aa5d6b2b1692a",22.52252252252252],[17546,"e94b53bab5d1fcc3fcd96becfbd434086f5463ebf410ade03280263f7ac29046",9.317957166392093],[18189,"9cd8e4f9cf5a7c622a48c72253e207d607ee5bed5b678b6a51c2486722aa7838",9.317957166392093],[17656,"bf893d3090fe3f9614e328264227327cf7ce016cd6f8f21e88f6c0bce6910a44",18.127659574468087],[18123,"ce5cba43608ca786f7d840b9d991ba5beaa4fa040a340c2e8d2bc95b8602683a",9.647446457990116],[4954,"4055bc81069e660aceea79dfad06ca961a06ed00c74783792d4e959b8e1786df",9.917710196779964],[9961,"0e38668db2551438e22ab02d05f7212730872a8391110017eef5a6f168b38abe",9.317957166392093],[15590,"31a81a162dc99f5b003dbe2d41ecfec98fe0ba7470508c94bd2e733c0eb18b71",9.317957166392093],[10681,"12bd1d058243e99a8db0aa323ae20ba4884824110e472404984ac35b3c932aba",9.317957166392093],[10060,"0c9aa4e4c8f3df189543388e3a00f0815d7edec8f56b09de882d0da93456fdbd",10.052724077328646],[5099,"e7c7eefc1ee38dcc78f6762650c593fc2bd1d6ab708ce6d8971c703de79595de",9.917710196779964],[17951,"67c032054eed2091d2190b8858fb953f930513fa2dd4ad018707a225b9d3353e",16.2152466367713],[1528,"10643d889ad989dadea83cdd9354a498a78875910a42f4f7850ebbb39967f1f5",9.917710196779964],[12087,"45494d614a4328f833c1f7290a43982b4e73a1cc0506a91378575f90e578cfb0",9.917710196779964],[19745,"4a80604a516a69bd0b863f136ea24fedaea6ceadffd1cb49460e3eb6d0c1fa04",9.317957166392093],[10749,"df72d6434c7d33401451c60e5719befb35facf5884e9d27e36b1f35ce5d8b1b9",9.917710196779964],[17080,"c7b99477b7a452de92d568521d83222a3442997f04de91f33acfc38f55524650",73.75743707093821],[7364,"a4d91d079db0199cb729293667c85119031d4ac387c8e81d2e6ca44839e8a1cf",9.317957166392093],[1416,"506b5ed80fd7d8743aa9da8ed3dfa0c3a5f746a2c5fb8a4d52b33276fec9b8f6",9.917710196779964],[2428,"50b2d9bf39692ac3b30cb09aec63a3b66f3d597c73fa2b5961dff7ca2a9245f0",39.20855614973262],[13912,"369682a469c989bf771e93d903e6d9929bb231bb8989df90e3e169538a1dcd96",9.317957166392093],[17763,"97ad1bbc2cee1588f50ef5ac8b64098f4edc5715f32ef504f80ce6682bf6f541",9.317957166392093],[13776,"f1e8566db483a4f57bf9a599d6349a3b6830e6f283c78774b5900a67d853df99",9.317957166392093],[10460,"45a985ca9204ac0f6fa5e655107ffba863a8e26e683338bb18211f57f5ad60bb",9.917710196779964],[1210,"5e6317a9d4284843af172cb9d45e15057ada70df99fc7cdf5f739f08bfc5f6f7",9.917710196779964],[4950,"fd8456671f0a6e3476a82966828cd5ea56989abd96e24f0af8ec194690c488df",9.917710196779964],[11444,"77e9bddfe56e0be17bc37087b027f5c271a7d05c7761868908bbb2ee47d3fcb4",9.917710196779964],[16361,"53d8bb2ea5093c2b8c6c1c2597386de7123a9f14288ebcba8456fd7a0197d25f",9.317957166392093],[13350,"dee8ac11ae7c19502a05e2051652d7a19e7d0f93a07406ba3a1e4b0165f27ca3",9.317957166392093],[11554,"7c4ef7bb9ebb2a230ac416d5b00fe70fc610c4f6aeca4cbc5b02aa94c38734b4",9.917710196779964],[4752,"a37c9a3bc7d3e73e68408e29d6bdcc4e105f00dfcb51401829f3c6015e8fa0e0",9.917710196779964],[9999,"826b97dccbfbf47df61a9844b567204a285296126767bf208caf5c4e816d59be",9.917710196779964],[9242,"25a60a731b6790a7b7946927bae1faa87990b15254f1c7f67e9c058de0e32bc3",9.917710196779964],[1690,"bc88aa724e66c201a1ea16a50b85053696b0f5a1c050feb170b4907b59f4fbf4",9.917710196779964],[11662,"383f9f0a9e014c2e65def22a6acf632e8572ab570d30a56a8cab1bc3bfdd7fb3",9.917710196779964],[8171,"c0bd0c075b85dceffc7488fb0824d2454d8bf237f38db4d4eedda94ff02e2dca",9.917710196779964],[8591,"82eaf7ec392d8c94582e591a42d6cb4e80c17a47a8ccb3218f560b2e36087dc7",9.917710196779964],[701,"2c9420c7dfa0091001d8d7ba6531f8ca7c8fe4075d4346a4be808bea9c253efb",9.917710196779964],[8394,"26eb1e1c7803c3abd1dfc46418d6eaa756e4de9d3a0d50b9faed1a998bfaa1c8",9.917710196779964],[9583,"ddea1f9c34d48e433851ff710eea6e20889149d5e39e087966e83cd2aad81cc1",9.917710196779964],[8734,"515dac7e2aa5069877db08dc65350de9e2e8e178c96a8e74694e87280d8e7fc6",9.917710196779964],[17784,"29a54dcf12ecde23ae115a49f8598a14a8e7dc9056b86d69e09acb39bd29a041",9.317957166392093],[17487,"73a96373111902b2b44ca6f1c8a561bc8761ac4f583d07a203e0e0acecc8e047",9.317957166392093],[9853,"9c9a313fa347b29a203388c2171e45faac65e9e264c7882de3f3f1aaefe747bf",9.917710196779964],[1607,"4d726f5857aa0490697df131027bed0908cb4c0ba8516c4e6fd1d1ab4c0287f5",9.317957166392093],[6550,"2b7b43c0ef947e6642ab29edad8e9c01f9efaa1819291877ff55754363c902d5",22.854014598540147],[11190,"febd3d877d5e4f6d6da920e795f3f7921bd8b0503d2d3a6b125269ac1d3abab6",9.917710196779964],[13578,"550be940ac0eea5b5b3ef2ebb1a8d4046e76ba4d1cef02db021ca72d05dcf59d",9.317957166392093],[11418,"d8c54144cf377a47dcfac7c31f94c95fa5e6c3710168fcec8f7fb2f7a5e93ab5",9.917710196779964],[16994,"56459a2d1ea58b166a74e3ad8b454b38ac48bd17be6979d627c59ddd66ac2d52",38.00353982300885],[877,"e23dcd929d6d7019c955adc4c57da9918ffde4fc1fc0e931d1fbf10f66b80cfa",28.09964412811388],[18127,"1de14ae0fb7ba55600d30b26b1a8fdd0d4b27519422af71aa1f2b433147f4d3a",9.317957166392093],[7567,"3838ddd7e7b55423b79aa6db93a52a4c0000b3901058a66b7ebb15f0959063ce",9.917710196779964],[13042,"c211495c96891b781fab2d2ad0a945906bae224986453236ba361d6ba9b24caa",9.917710196779964],[1018,"6bad75600a171666ce5fad9ca8809c7beffdb3ee1c1755a98c585e7f6aea1ef9",9.917710196779964],[18289,"4d07c3acc11464329b8bdd716971aadff7ccf78a927213d9b92ffad67d180436",9.317957166392093],[12391,"70dec721edc7fe1a51a1054e766d67bdcb054ecad872f3fb47174e2f3eaaacae",9.917710196779964],[19059,"dcf8985ec18b7fecf43815964e2ee7a41a4f1605a45e328333f5036fe995741e",9.317957166392093],[640,"f5422e1ff5ebbe65df51e8eda8244044cd7e04f84e62be24382905f302b6a0fb",9.917710196779964],[7278,"1f486f0437446c4ced3dc1d1c28e48508344c536f7edeff3e20fe4caabde2bd0",9.917710196779964],[14065,"fb406c5c4e6d5df07c761dd28f500fda30521deeb7346cb96713a63bb07c5193",9.317957166392093],[15953,"6805002e3fb4880f7bc52dde4a9d61ccbc2bb1bbea3ea7d5d760bacfe5ace569",9.317957166392093],[14710,"e3febd56eb0d25b5877799427ad1c8b0ae3e30f77a14fc4cd4bd3a33af5fb784",9.317957166392093],[16993,"41066dd2311419052562f3e472df1faf75b5dff7e63307295ea35fda15213952",9.317957166392093],[2396,"45960b211ec05fa223f5db18ac9e798e49704ac6f5f711b783399304f9ce82f0",9.917710196779964],[17386,"680799b1b1c19318d1e468db4968327ee01330d2e243d80d7fb4f7bd136b064a",10],[13546,"d3e71819ac7a5fbca5e334f3cacf5d7e8bbe5de5b8182a4474cc81a2aec8d39e",9.317957166392093],[16358,"a19f5d655f6a85a86aa7f1ed85d7fb1856a3fc756fa5ccc1b3415c13b9a9ee5f",9.317957166392093],[18989,"01df1ca9b65c96499331f6dfaa2d88468e3f1f1e27cbb1ed3558594cb05af820",9.472566371681417],[7030,"5f8ec5eeb5fa6989b728b703395ca4b56621a9c4626d419ca2e61abcb5acd3d1",9.917710196779964],[18322,"7b5934190543b43dfea668c87abbec0c928764eefa5c81254aca7ab68aad7235",34.77580071174377],[8095,"e9c4ba08803be0410793cdf2535bbbf1533d6dee42b016e2695d9e0b06fed0ca",9.917710196779964],[10566,"045dc4be59d0148605e7c77811cb7e0a998b4773524dcc6aff81d40eb68dcaba",9.917710196779964],[14161,"820a256e655f71c9b0295e823e5fa43d95ca0367e0bc61538ee03eac96443491",9.317957166392093],[13650,"2e9cf1db4c66813f765872146485a3a442fefb513a908916e70e306a84f53b9c",9.317957166392093],[10804,"88b5d544dbbd578ec9285c0f9845e69d78bcda786593cfb98f510204fa1445b9",9.917710196779964],[19103,"ab79954f804cea67fcfef3a3ee6f0c27f5b640f19789878fdcc71b65bbf0a61c",9.317957166392093],[5740,"a5aed0b890d61f34c7ff931dd7c05ddefa9675e760f2fdab767a3f7f0ef5d2da",9.917710196779964],[8128,"74055df153e129879c672f046dc7b6bc5a20a00e0a416b2bf1f6fd2968f292ca",22.265486725663717],[1269,"ffa7182be23ad5189bd96c713243e8bc708efcdbeff66eede00461f9ebb88df7",9.917710196779964],[727,"f40ff594be584f27b5de5e12c3f592512db862606052afc52b7641be6e9f06fb",9.317957166392093],[12492,"c7580d1d5773b167436470df4215ebb9d7f2eb2784de9d330168318fe4d301ae",9.917710196779964],[15489,"2f51f485eeffd91e84c88d55d4572a6344e16ff022964f7749e8188620234c74",9.317957166392093],[7325,"3e0f54ce527463f52925997f57627e8972e40642ecea8b6636a2b0de09dce7cf",9.917710196779964],[1905,"7a99ff1c825b5f2a031842060cc7fca85bd6cc29fc055a7c94c2282b6f2999f3",9.917710196779964],[17646,"7fb55379335c3ef5899030b38d322d17d28933710f67f1455131bc30007b4e44",9.317957166392093],[3794,"828446f376409958b3b4f235553d0bd397f4649ee6bd8245fb29e5331197fee6",9.917710196779964],[3084,"5c1e2b3d7e774925c3e06529f9421133b332cdc7a373384f42533f83225ac1eb",9.317957166392093],[1263,"73c5f447e23200b6e4c811211b0822bfeaf930ff2bf7cb929e62124189ac93f7",9.317957166392093],[19504,"0c43b64e91b32214f4d18b293aaa1236bd516b1ae97e5c309140dda227e22b0e",9.424083769633508],[5119,"8d47af4fdbc2f7794b2fe243db3c3246fe8808285dbaf9255d964d654ad479de",9.317957166392093],[13327,"b99b4e154742cdc8649b86887513fa01cd27a58a5abf251c21eba54dcc1e20a4",25],[9404,"8cdb425a55107824035e84f510722e3bdea2d63a1b990412aedf5121c49841c2",9.917710196779964],[6755,"55d6f1b9cf3ea423faf322e76a9743f2687b7e5b20653b06ac606b75185b90d3",9.917710196779964],[11072,"224ca481e8cff054efdfc8ffa098edb801146175bc72e631ff256e1391ad86b7",9.917710196779964],[13666,"f72913f9fbee8af15ab57c92ebea5f0e3a09a2651c8dd0bb6d121fa6650df39b",9.317957166392093],[18292,"953560e7dc1e63958dbb360806e6ddefadd130e06fc490a552ac427ef4b5f735",9.317957166392093],[12726,"71ff9463261521a4125e2cf76c942cedb501e8e8ee0c0dc083d1af2386d96aac",9.917710196779964],[5759,"a4177599db86e99223562531094e3503bc10fa28c9c2a3c675feaf55ba64b7da",9.917710196779964],[14260,"09e0682a6b7b9ce619cbdfbd2b7acffdc0eb1ef959472f3552f75897611fae8e",9.665924276169266],[5635,"5f671ec2bf183710c3e24d18802412d8d83a6275657555713feffd86e3f36fdb",9.917710196779964],[14370,"a8102e0b97148a4075c04fff028e3c419c5b30719bfb296a323d2b3d189ff78b",9.647446457990116],[6637,"6ec07bab41c78d101dde3a2abdab9b9a0cdfc2bafa02bc2ed6e4089dc17d6ed4",22.869409660107333],[12431,"227377d9c5a95e408df8cd016e7f9f3e3ceec07274e43a2ee9359b8f42705fae",9.917710196779964],[15213,"5bb496e0e4c358fbb470d92c83ce7e3121f02de1f98c5681f413f6965e463e7a",9.317957166392093],[5952,"aa2baa588913efa12f80e7b62c2ae35243ecc93a4900e053c5b00936948768d9",9.917710196779964],[14356,"036ca35afe50aa4bf4a793439151b1e09548f17cdd71ae934fccd061fc7d448c",14.352402745995423],[17909,"3629f85f371c9d131ea8a61af3bfecc53027343c0260b70a95b93f59a283153f",9.317957166392093],[4302,"52c0a41351f78611654f9065cca022a312aaa8953f59b48b306bc19680e0b9e3",9.917710196779964],[8482,"a58ca206e23bdf8e5c850bdc9d641098ae6304bde7949e69952e912bf29f1fc8",9.917710196779964],[13101,"53c236c3bb5760e93ba5ffe3de8749829f87f8fb94f0dc1e9482c64a2c293fa9",9.317957166392093],[11164,"853c67e156eb5a94562574eb7d3c7f210eefbe2c7e7f5926d2b234ef651ce7b6",9.917710196779964],[5027,"f214c06278de1e7f08a462f8bdf1d37d72768a06f59de0be8550de39ae5203df",9.917710196779964],[10658,"4f68757496d053f1a91c6808eef713fb9e582d12a34c31677997b9cd47494fba",9.917710196779964],[12691,"ad9d93091ac21e18638e328ff01e513dfee0980b158489466deeed94cb85a4ac",9.647446457990116],[3503,"2742151663e0810ffd622729b276b879a075d6bd5b22d7314537c9ecdb4af7e8",9.917710196779964],[19085,"653e3152900fe0579d5e1edf30f29ccad8da37b69284856c62a7c067cf13651d",9.317957166392093],[12065,"db445ec5367f31dfa54544508144d271bd60087f785fde4683a049dd117be5b0",9.317957166392093],[3896,"d0f71e6d7c258c236a9b1e168c38ac913e8d69cfea803e1e25cd6f87625d63e6",9.917710196779964],[11157,"49f81d272b70ff04896b31b80903943c8fd800f1a559f5c0a1c613e978eaedb6",9.917710196779964],[1208,"feb9f8893fbb4ead39ef12bb7620ca6942a2926c1ceb349f92e6c5f48bf4f7f7",9.917710196779964],[1074,"c330a1a2ac3374b4d71f0607d872f6553d7bc0e35ea24c8395dc50992327c1f8",9.917710196779964],[15987,"300f834394feae0a92452dd0f0dcf770a685ac03ea44af0711a1f8668ca4b068",9.317957166392093],[2159,"2e1cebd10b85ac231f6a0e9d9961555034908f14c5d049e751a8721ca6c8d9f1",9.917710196779964],[5673,"440e81fde5150e7cd7739f204e38d34e5360d64b9b778e1811afe66428242edb",9.917710196779964],[711,"1453d92a0d2bd7c6110d61bc239d833b0c1ead18bcbf33f863865b8be78327fb",9.317957166392093],[11815,"5d9a86244d8ad118d37aee3a9c7b292d0ff573253506f369239357a497d49bb2",38],[18576,"9b9fc05ff27387b646e25d97719f94182fd51de5143d4f62971e020e8223892f",9.317957166392093],[8770,"f047eb55daf624dc0a091f0ea690ee7961838b2d8eb2b1c34a67f1d7a2473dc6",9.917710196779964],[12725,"d1b390a57f9ef0f6b9f735e33f46e82d64d44efb738220c0321b8c14756b6cac",9.917710196779964],[2257,"287d6c9f9c9f0a7ca50bbd7017c4187c3d7760c883cc54dc2099f4b28fe937f1",9.917710196779964],[3497,"12c3200bfe271ea4bf774a4bff299e4a675e9741263ee77ca9bccb47b61602e9",9.917710196779964],[15239,"63787509de27fd1f948703e54532d91afcf437281558d505ae9cc695cf5ea979",9.317957166392093],[3823,"ee9a1a3a6ff23e9c33199edab7cf7bd11a5698e4524c38c8e309a6553ab7dae6",9.317957166392093],[13625,"65147ece860d5b9b8031d20d0f8bbf445769e4519fcee2adff802c59d7a6d59c",9.317957166392093],[5149,"706707c91322b4d6743dd16f7120bc2144d20808813fd3cd5bb4fda49da54ade",9.317957166392093],[849,"e722b0af07c8e82fbcf8089667e492e5719e7af73e6a0167f716f467b9e93cfa",9.647446457990116],[7310,"a029b69df8e0c96dac6060f69ab76b0dc3ac504adfcee86ae91816fa07cefecf",9.917710196779964],[13050,"d4af217fcb9aaac8558b7ec04378ad4b87e921c1bebdcef3b1ba035a0f0b45aa",9.917710196779964],[5870,"d2483b34e651bc8abff928711250d07635044ab33f5437f8244ca8a56111dcd9",9.917710196779964],[16585,"c4d12332cba4f1f71d9f7e2da2c4b1af3dfd294a34ddbfcb0c89ff7f0b2e575b",9.317957166392093],[10680,"611fb33b849db84d618c3cb7fd2e35085bad2d66925e58ecf5c625d6e9fc2aba",9.917710196779964],[6437,"f38d876f068e054e47f07ee1054bc5f544dcce32f2bb30491189b5313f1a00d6",9.917710196779964],[18464,"c52a2489609838694b262b3cb07e4f10d8525a835bd9b74eac268a5697805432",9.317957166392093],[7501,"f2c151f02869e42f56d785bc1b7c08107f8b916f1013a455a215d0999918bdce",9.917710196779964],[17596,"12941f40f46884d834fad40729c472cb56d250dbac63740837e9a7ca86733d45",9.317957166392093],[15006,"242bab51f78473b5928d765ced924e8326c0d829a3176f1da1ebcd179e1f327e",25.839930404523706],[1314,"92ba4bba985d78dac784101d7fb39706b5e760744fee07a986044c5c727653f7",15.915194346289752],[14488,"11d9642cb69fc0644fad53f45e2290d00fcaf3d2ba6e926270b7addafe9b7089",9.317957166392093],[19248,"bea4393661abb0188842c3998ade7f45f1f270fa02e4a4bcf997e1b09715ed16",9.317957166392093],[9513,"5818cbd935edd73565b13ed0026cf6cdf1ec8d646658b5c73d623b92b16f9cc1",9.917710196779964],[4491,"f961491b9d16fdfdd261d8f29b412425992cf6054925f3433a35384cea8978e2",9.917710196779964],[15614,"f78f66c5120aba76005914751cfb9076145a886fdf3ac26ab1a078c387ba1771",9.317957166392093],[7073,"d8a78f553c332b286d67c8ef88379a2ea68b6ba5f6c02574c365fd62ddf37ed1",9.917710196779964],[15836,"4eed7e681c4fcd715749a7e40371d05bbe8cf16ad57181f760df1e68d34d956c",9.317957166392093],[9554,"0a4fb9081769a64259ec8c69c8ab7ecf658177f29bbbbe94ec65eb2de60f50c1",9.917710196779964],[11382,"378c2cb2b50b31e91f5e6a23c3ffad291b3f5163cc05bf6206e80b407ce381b5",9.917710196779964],[15807,"485a6cbafae1156f337c0f49675fde6f2238441dda01a49045add0c1d4253a6d",9.317957166392093],[4777,"12e838ad8a2906ca531fa88a00be22915d78304ac051676511d53bcf493887e0",9.917710196779964],[16473,"5e29536a7df2e072aea4909d5e9600c3724eeb6cfbd00c15a8fecb80294dd75d",9.317957166392093],[11179,"e7ccfb97f5897564c903d4acb0ceb7f822d07f82a381421d171c1a7b675ed2b6",9.917710196779964],[2494,"01bcbb86b9cc566aa09d626aa1885270f6264da290892599ed2de8a34048e3ef",9.317957166392093],[11751,"c759b867f31c586a3160f17b73804417db18e7c8921434b5ba21def21060fdb2",9.317957166392093],[15321,"dfa65a4d451d813835fcbf9099d552c2e704315d0ad1763c67b8c5e643afea77",9.317957166392093],[3200,"e00e1129ccda932d674c32e5a79094a9b4d99c3cd3668613a9aeb0a36f070feb",9.917710196779964],[7353,"972b949173baf604dc8143868a8fee41d59f42d558784f5cc4bbcb93eef2aecf",9.917710196779964],[18887,"7a349ad9ecc3ce2156a07f34d395dad976fb849cfaf963dcfca359a087cdd323",9.317957166392093],[1736,"3c55327acf0fbe7c8a2bbb6e43483e082dfb52acc509a927fdb2d6a6a416b0f4",9.917710196779964],[2995,"38623c7cf2766c725b648b80c8e0174122f8252f2b2d6f466c8e907d549353ec",9.917710196779964],[13289,"77eefe67ca21c6596c76738123f9fd22f1d084be1385a87a7c5d405ae5edcca4",9.647446457990116],[5695,"f76cdd827874dd1682e5c81e14d7c05ad5c350ce3c1c19a0eb1a6fe336d415db",9.917710196779964],[17317,"0ba7dcf0851a4a0f3ae9b0fb239b63c4315fdf568b28bffb85d314db6390974b",9.317957166392093],[1305,"8f9c3d5bdb2d495c7c72707c9eb178ff432fb364155dcdf788a6a219162d59f7",9.917710196779964],[810,"1f0ce254871a8d0ff072eccd25cd712f1321fdb1a4047c9ef92e849925be76fa",9.917710196779964],[832,"1fb85119e6a164ace5b3378954a7513282a912d9214660b57b04105b882c55fa",9.917710196779964],[14796,"b48e29683cca483862465121f4423b893f2546fee3479a145d5a0c5f061e0883",9.317957166392093],[16911,"251d0ed0e252158e312966180efe2be8b8c6d846a713fb8252210b8cfda9da53",9.647446457990116],[3324,"07b6a766e5a81cd735adbc492862c662c4bba4638f7876c17798879051e637ea",9.917710196779964],[7711,"896c4890ebcd373e69d9fc5571f9b25c874f0591b52996cd948473526e6478cd",9.917710196779964],[13808,"f464ac171ededf8a61f6f52e0f9d66c52ca233dbd3bb28724dbdb4bddcbb3599",12.053811659192824],[4925,"a13d9e22861b2aac8965ae2d5a0a205287bfcdf83249cfb3cbfe3ab29611b4df",9.917710196779964],[2928,"2cf018c1c563bd9380ae4a27b1863d212d603e43ba9c818b448af87bb732ddec",9.917710196779964],[5355,"ef2acb44829411c67ae4c7c1c618951a362cbc89175b8cb39047de6f2f651edd",9.917710196779964],[16709,"52610dba2969247fb35124f355ee69d1b8440f7ff99d8623096ed115184c6058",9.317957166392093],[3529,"28de70a059faa154e6ff40b6be611cbaba307da902738c1957d3b42fc262c4e8",9.317957166392093],[15124,"467e1c5523ee2feb2a344e2a65c0cb392a12b57026d6af1ba413ef666951327c",9.317957166392093],[10918,"0b12070de9a963a7058dfb924562a905a2d2fc429a4c5cc82b740d3ab06a92b8",9.917710196779964],[9742,"c279d0d2c5a23c591ee83bbe0a18c7c6b0b17be6e14f22c101d7e197cfa209c0",9.917710196779964],[2096,"3ce7d2f0a3627a4d520e3b1d20f5edaa3ea4dbc292af23e2d888f526a30a46f2",9.317957166392093],[1500,"1f662bb1ec846dfb130a51c3eab436851a665ea81cd97a403c0549d4496021f6",9.917710196779964],[12478,"5e4ccad233e6e21c7a9fe44b93474346d09d76481ef81dd9b7bd11fa587f12ae",9.917710196779964],[13129,"9a4874155231c293d972fbf8366c185100795547568ac3f8b6b374d0fa656aa8",9.647446457990116],[1658,"501726f54c51e96f2a6171e9e42352d1e1b856f8d3596be0253cab12a93137f5",9.917710196779964],[14396,"6d8f91a9b2f1685ee696d83cb61547441c55005eb2f8aefcc9242f5666b74e8b",9.317957166392093],[5427,"596669c78ae443290e3a85f660f08c5d31c1b448e35f991b5898e880a6a59edc",9.917710196779964],[596,"f5e55815c4585cd07b7b890c5c60ed7c45e3470067a43a69b8a5bfebdaf7f0fb",9.317957166392093],[8791,"830a47f62a2eca2c93058e24d2af6764b6d8fd9b16e341f78b4ac108127d1cc6",9.917710196779964],[586,"91e2bebbdb4f2e4834173721828303ed7b514e84551dc6dfdb7e5b32a44904fc",9.917710196779964],[1496,"c3fadfaf931ae22d9782c3f6319c32ec40a4d693f3b4642b86a60e0a581624f6",9.647446457990116],[2703,"0b4f2392f9c97ecbb0cc1e33b4099d4c3ea78d578ca8314a2b259b6a888d73ee",23.945812807881772],[3449,"b2af143132f3510ac256fb36388fd38af3a2e47108e49b88d9db3d2772cb5fe9",9.917710196779964],[8984,"b5bc0b5bec4fe71a1e807bdbd7698f82776e04f097f40acab05b22b87a3ae6c4",9.317957166392093],[6347,"a74a3b38a2aa12a1247ac9e94113058d409ce220216f76f1bc2a2bb48295afd6",10.033508207818581],[18701,"5649a840fca690a3c0b4c74329fbd8b996f5ff629d3dc742abec2f04cbed4b2a",9.38219895287958],[18231,"bae7b95f2983b55e41f22e47b6efad174248a34234c77b83baf5fde991165237",9.317957166392093],[14704,"d92b1bcbceab3a8ba017e7493fa5f6a2a023c1e53d2a82bfac185de5d9f5ce84",9.317957166392093],[17983,"68ad8a25d6a5e1a75e3eb79f4405e065304d675a6965b0a145a1559ea8537d3d",28.099408284023667],[7422,"4f25e6610abd391fef7707ff353d645e79d25c1d769b13ed8a1f40d9331b3ccf",9.917710196779964],[3481,"de4ed27a5eb1f5693c79e3dc1ae439203f7acbb326da261e416111e5b47327e9",9.917710196779964],[4657,"207dfe35e28f486371503e2e5622268c1fc4dce51d19230968dedb9afe7a42e1",9.917710196779964],[8631,"08b4d87a417ecd552e677c9d919196675de330dbbcf2f28eeed7e43461173cc7",9.917710196779964],[4324,"baf29c47dba7c46cb564b4a4b538cb3d592b69005322d80d28ecc05817509de3",9.917710196779964],[19570,"df138bbe511689ac11fcd64cb95978296d02ebe1ad5213fdd7ae665d82d6d80b",15.942959001782532],[18413,"85a43d1237b05c4fd5b8408dd6588852ab66891ed5abc7f74a8f10fcfffe3533",9.858793324775354],[10004,"d4c11d0e67e37fba5da7b7bd6aa3dc1d468430f4a104e4653af2a783fdd74ebe",9.317957166392093],[4148,"c99d71af2d50bb2bdabb9bebfe81c3b85edc43d6b0e365bf4df454feedc9bfe4",9.917710196779964],[18883,"e55a8ed6ada40c35c4e4c5251fb2d73b3c160b32dd0ea342e6d788f63368e323",9.775743707093822],[11800,"25ce1bde310403f28cb79d0bb1135513abe7a12c9fb69c302ac17e930ae8b4b2",9.917710196779964],[3120,"489886d4e5f30153983ef6cbc6b118b1c789c21732572a2bc82a62221c8c89eb",9.647446457990116],[8341,"5d2d683716ecf5c9c4605e0ca92ab34fb69a9a84602d3fe50937ca58f15f11c9",9.917710196779964],[5178,"33c83b5429401ad2ce88c4ab43c1d0089c786a4fada763bb264c37b228ed1bde",9.317957166392093],[8529,"6c93fe4621ed0566910748c361273dbee764c7231c1eb8164d9ca17decfed3c7",9.917710196779964],[2598,"8104104834fb674cff20f42c88725488b1b7af3a91597386629f64a0dcce29ef",9.917710196779964],[18325,"b13374de9c373782a07b3447dc069749190cf479fe139b7dd095ff5146a45d35",28.187082405345212],[6219,"cccac245816076999c66106f87641c50367f7f7258f206b67cc10c3773e29bd7",9.917710196779964],[11352,"f9a738856ec2d603d9c9a1be46e968ea0daa619f0c0643190a0e6914eec4a4b5",9.917710196779964],[11486,"c5a3c170238ed850d1b9eeb9f231bdf2efcd6bf3dc6e8fc09f4eb7c181039ab4",9.317957166392093],[627,"e7c9472da9ca0ba4a65d44eb8761f6e5aa6dfc9f00ba5a19200fc4aef09abdfb",9.317957166392093],[19750,"ab37fba008777e25dadc6128c7210f8439b93b4b937afb42128f086c9992c604",9.317957166392093],[3952,"b88e71f64aff25bd6e75b6fb0850b8849ebb6d8dc1279f6379b626a1b60800e6",9.917710196779964],[17436,"28563bf68936d3a5f74ca7d215739be729514abd893198c32129e3634f1beb48",9.317957166392093],[7220,"f71142df524401ae67dd14efb515abfa0750d54c806d9aea9312c3733ce68cd0",9.917710196779964],[13592,"ee0b5b5bc8eaccfd0bc4613f1b251a732fd22e11d7eb8aa10a5d668bfe1ba69d",9.317957166392093],[12129,"6f3e7909e833b9062fd7b48ced9f4a122008a92caac5f206d61deb4519447eb0",9.917710196779964],[15490,"1b0932562e6f5d673f7a2351ed279d7fcc21ecc52e51945de7b57a45bece4974",9.317957166392093],[12123,"086e496a200ac000a95dc1459f47c4b5971d7de1b3686b579b8107aebfc491b0",9.917710196779964],[2670,"580b2cb63cc6abc8b65ba7279ea51145b121c68eb93f34d8ef6c795b7286b0ee",9.917710196779964],[12860,"198a4674b2583b8769161e14992b8a3567033bd2e9955e7dc3728f82eb2584ab",9.317957166392093],[9700,"11923d32e15cfea02ad2ceab1d8bc6cb426ebe4f3c1ff796d84f5075e5dd60c0",9.917710196779964],[2114,"e8aeef484516d8ece3be5ee666cd0e3967b7ef1a421b305e32682575495323f2",9.917710196779964],[9219,"86cd5ba23a4890d9592606951c1e2cd6b95d33d30e8d58695b84b184182059c3",9.917710196779964],[3054,"6a9e9242b27bf9d3935d96c6c00142105e0fe99e77fa7a6f7fe7b57c64fbf3eb",9.917710196779964],[13274,"1c1a38c2d5c2979ba8ab63221676fcd15ba54f15b69b9bf7ad9b6d8250ec29a5",9.317957166392093],[8158,"eb2bbcbde5ab188fcccca169c2d5d9dca4530a21c71cca9b63ce7c1578b54eca",9.917710196779964],[11057,"978a926d5c4cd3cd2413c0afadad51edc0b8d64eba7e1f31bb0f667261729db7",9.917710196779964],[15409,"6aa00cd91d0ea8fa3cc553ac46baa125101ede2198d24b8a6557cb31924b0d76",9.317957166392093],[4955,"dd915aa5ff628958327c91349a8de16e4e557f35fabbfd1c843cf57fa3b785df",9.317957166392093],[5068,"81631df3a3d5fbfcf443214795d06264b7213ae5920e04ee993b2dce23c2b8de",9.917710196779964],[14975,"dfb1c3e81029a19610e7589f35e470a322546f5a7006301a12454b51b0b71a7f",9.317957166392093],[15776,"4e697261d8252c995ee79ef1258e568da3439254aab7917e95d49449746ec96d",9.317957166392093],[10332,"a2849f77722916b82e479e9b5deb31afef9fe52ce839b5c73f2a3808bee61fbc",9.917710196779964],[8310,"10c58055de162a9483d491d07992473687fea24518a5e2d83aee4c5cf0f241c9",9.317957166392093],[12887,"538433044785341e6c40a5343bba71a12d2097e9485e70fda96a221a20725cab",9.917710196779964],[8188,"0d150174b5a7579f2e11c7e4dddd21083515f1e65f27887586d2c2f1bf1912ca",9.917710196779964],[7728,"4227cfe682e9684c86b4b24df9daa9327fb1bc9e8413ebce49ccda710dc64fcd",9.317957166392093],[12036,"5b4b450d7160d1b7f874cdd48e2e990536c8f82b186d31b51a5f1b6c1da40eb1",9.917710196779964],[18447,"984c5b4ec8ff6bfc355442caae70ca38380f5554b3b7e0fa293ec0157adeb332",9.317957166392093],[785,"58a0dd48914161b6665a8408548e63d0444a2f30ba8efac8a86cbb887c759dfa",9.317957166392093],[13037,"8555d1382667fd4f13d85881473be1e68743743b7679650f08f056607c505caa",9.647446457990116],[17311,"b55e936225c2e631c3177c4d264bf2c361ea7e78d6ef8b6437c845842899b14b",9.317957166392093],[11145,"5c6662cd6e60b370a68df961e2f5bcef712885beedf8201f6920961af28ffeb6",9.917710196779964],[19087,"e43fb3154989b13b252aca33f621d052b699e12bee335c87e59866b534b5551d",10.052724077328646],[9325,"5035a68f69210bd97bb002a077de727321b7edf0304e824616690ef77715bdc2",9.917710196779964],[18857,"2ed4766563f709dd8690de317e38a06c537fc87c318f34659a6cb2d710fdcd24",9.647446457990116],[1198,"0d6a3397e3aa58b36cb80fef19e987454db0d58229bf463abc14fc81092b06f8",9.917710196779964],[15932,"93f182c357f528d378dbf378de2fd6b0bdad141f47cd23bfbd7aeb6a57687a6a",9.317957166392093],[18093,"edd3e204ce3d83d7c1f88ccac49a7ea5d6afac39570f706226c39dc8dd54123b",9.317957166392093],[17855,"e70db2ef98a4eb7cd5403725e645d32b9cf4cdc8a1643c6d83dd2cc254f42340",9.317957166392093],[13387,"f5fe7e5b7d35814329e3840e349cb17cd638ba28d0caff42c7f65e4602f1a6a2",25],[1545,"c23a817bb362aa4deaa1dfbf6c0bafd26e2920f940ac61ef0d64bd689f7adbf5",9.317957166392093],[5544,"f8c2d010f25d4dc1197256e0fdaf4705dac1b50fd6043fdd4e18ecb5f963f7db",9.917710196779964],[5006,"b9dea40538ccded81d683209cbfba7c0e8c72dafe68b25c52ad9c78843a720df",9.917710196779964],[10618,"a0431d2bb4a887ed69ed443733942619568f6af5cb7aa061538414e3593a92ba",9.917710196779964],[5145,"e08a762a2ddc86f8bd56ed0e6bd6caf1490d3d74b9ae5326e2271846780553de",9.917710196779964],[5295,"206be725ccf1915ca5b59ca54d120bb111abfc825bc9738bb9b4a69ccc5771dd",9.317957166392093],[10055,"c990be5780996c17e1d7ed07fc1022abff34a8b4e5e2b138456ad876e3e504be",9.917710196779964],[12938,"72ae5a1b0a3cdb6702562f76d8544179ee9982af214bbad517442c7585a400ab",9.917710196779964],[8592,"435f2effb93e3d358a7a771f1315e30e6ad49dd026f2d586b291ea828dcb7cc7",9.317957166392093],[3999,"c978c1cb4a5b8738cfd97700df0b3cae176293af70341a8f4c9af5559c57bbe5",9.917710196779964],[8780,"45415cba293ae6cb2a48918ba31fe7bdfe5bdebe8f547d51c0b754858e4330c6",9.917710196779964],[13362,"613a19dd679b53adcc4ebb64fccdb5560d65815bd18cfdaf762d22ffd71342a3",9.317957166392093],[51,"2cfac5a17f943e1059e1360520fd670181d9fe91fc72c76a95ec252c0d0fa4ff",9.917710196779964],[2699,"33d6641488d73901d3471479bd6291ce0a151fb5aefdb68406dd2a7f27b67aee",9.917710196779964],[17799,"e37f635a242867127d35b5ae708a5e88a87e89c2031c3cd4bb6964793a265141",9.317957166392093],[3519,"e05085022625fd920e313349fb41b66f29a9360f111a93ff744ff9b3a933dee8",9.917710196779964],[1865,"603ea1f74c9ad20d1a6133bff263c46d9fd958645665b787e9093a0ecbc7d5f3",9.917710196779964],[14063,"7e85f143bbdf286dae7940f37299bdc27196d324f9dbadb58ac1765f25ae5893",9.317957166392093],[880,"88eb68b6015e49b06806e0977f310266080e451a6a1bed0e9fedd1f3692006fa",9.317957166392093],[19425,"0cdb321cc38a41e5deeb5747d3261a651b4c866482b8c697fc86c63ac2209f10",19.066666666666666],[18575,"ef661fee49182fcff52300ee4cae6d68ab2b6a5a352ce572681bb0317c67892f",9.317957166392093],[1765,"f5dcf704bb08d49d364c80137b4b057cf1ca4b80a0f569360c135606763e81f4",9.917710196779964],[6407,"04fefe8f9f31321c923c19fc2688207d1d1fca8c5ae985a3e50de050ed1449d6",9.917710196779964],[5755,"663ccd6de07c4a91736839a572a66ced7de161198e92ad74191b589474e5c0da",9.917710196779964],[4699,"b3da8d8fbf11e485854b0db6b4cb02bd9b0dc1479784c521c1fe893a225301e1",9.917710196779964],[3537,"e8976f6885eef04bb589a67fcf17de7d340ed7623c6cdb5eee2e212da5eeb9e8",9.317957166392093],[15498,"431a71c940091153d30d1fdf59c09bf3e8fccbf9cab51f486a150a87cb822074",9.647446457990116],[18706,"aac7f97d4eba3f084170e85fcde9d4e8183d6a898019869c02f17df98e06142a",25.60096153846154],[15717,"c96e8b67c778c615884a7c62158ff0110993ff45698bb87cf5b611d573e0216f",9.317957166392093],[5381,"777d1bb602f05476cb8b32d3423749e715cac3bee314cec3a4cda8b06139f3dc",9.917710196779964],[8029,"5f7fd4d52c77ef0391350ec72dc07206a215bd6532797e11ede0e25d65ab5ecb",9.917710196779964],[19805,"0dff3b7b7a3c5389773bb28dae456f7e6438338d51579851b45023994ded5502",9.317957166392093],[45,"8f558083d449b785531ae8de314f070a2cf00546e7153577a55d278f2bf6b9ff",9.917710196779964],[529,"690d59710f706cad8de651c8360bbfbb5d55695e1c17c0535705132a1f367cfc",9.917710196779964],[541,"05b643369ffea0a65bdf34af0684a3dfd345d56fc5046b1131089297e55758fc",9.917710196779964],[17622,"e372a2af4e0d52a0f1b2fc6da3575df2fd342e36f374e6050b9205564964d444",19.073643410852714],[2830,"b9dfe83d8c232d8dcda5a7223cc2fbdaec6ebc83ccd4fd574faba871918d7eed",9.917710196779964],[14640,"935ddf288d72a2f2064444f6bee05760d468c82b3fb2993a3b54a4f831652b86",9.317957166392093],[4609,"11f01be66a9142e8f67486489f6a694b63227fcb8186c2fb45d38cb6453e91e1",9.917710196779964],[15255,"2109af3f7e221674940a76a5527d294b6da245792629c4739160492c5a865779",9.317957166392093],[9941,"46d5bcbda70b66032648e5c78b7b02e1894209b1a355453c171b15e2447eb1be",9.917710196779964],[19489,"a7ab0eb96b336cbb844f7015b41a040a8a3f65bdeb9d77ff94ecdf3d9745c90e",9.317957166392093],[3526,"e816a464a39d8c1dfa59b5a2282fb39bfa79e4fedd70e402d92a3a3d9c1cc7e8",9.917710196779964],[9728,"8c0b5c5e4430a63060ee83b3f8545387fd856fe11baa9a666d6864a3586420c0",9.917710196779964],[3781,"ae61ac2d3615ca0ceeeb88469691afcfc3f42cd19e4937d121f5f795454b12e7",9.317957166392093],[15343,"9e0423ee73d1d7b1c1aa0d78bf3954679381abb0bdbded2dc9683aa477ef8077",9.647446457990116],[9874,"29c4572c11a5ff6d3c24f87c9ad69ce1e4b75ac44a5cb851f9342016ae9518bf",9.917710196779964],[4269,"d7d5381c6a6fc94f21457e905a6c5f0b076df767b247481d004241337e32f7e3",9.917710196779964],[422,"dcc61d066b828074190ceea6c1de007a684367938d4d17ae371d5a99dcb93cfd",14],[19078,"c07349d268c05188134e35a4812988593f58dfdce5ef2f04fc406ebadd3fb41d",9.317957166392093],[11309,"7e8101b17b1b39393e86698af14eedeffa3b96e87992ae7f345eb6451e96f1b5",11.165035877364645],[7614,"26974da62d0408b8d5abbe3f17c6a1c95ef504ce86b4c73ea6497257f9ab1dce",9.917710196779964],[12092,"844ab5bd163dc472ceb0966fd5a171c849de63bf9bc93ccae293b66586c5beb0",9.917710196779964],[6010,"7b64d27b72f19240cf360aac6171b0f19120eac06578a9da019862197d0703d9",9.917710196779964],[1951,"8ea8e9d89010f23d9d855e68b1725de773a8008d7f7423cbdf724fdc063c56f3",9.917710196779964],[18394,"0458655c5b911fe3abd858bafd1a61db905a55cef6f577a50033e4a4ff239433",10.052724077328646],[5753,"b27df0e791631b02795e390700e00754f5e93bba6561edab9ef53c7eb702c2da",9.917710196779964],[12625,"b94eb53b179f02615eb988fd6171c38077bda8dbadeabf0f6fd59a6bcdc31dad",9.917710196779964],[17168,"80d5374c01a3841d3829f9144b6e1766b928499af3cfa07cffc31d1f4d3c8b4e",9.317957166392093],[19179,"e58aba956e0bb2ae10ea79ab4a761f4260a46d981f751a82973507a56a7f4819",9.317957166392093],[19151,"483e5ff49e736b23f748acc6176a91759be1fcf1b6d401ea634869e1c3e36f1a",9.317957166392093],[3368,"0698cc503b5eb5182bbb25a209ee39125e3f6c752c4c16a5d0c260ff7c7df2e9",9.317957166392093],[12659,"d87f475f5b67503d5a439c23103612dac6d81cf9fb6ec659238309f38d3ce4ac",9.917710196779964],[12555,"6972c5f78b2582ab91ac08c22faf8f79c3756391a02230336da35d229d6399ad",9.917710196779964],[8086,"baeb9a1d0005edce046d9be100598776a98a5bcc244191ce7d1cf2ee9b6de2ca",9.317957166392093],[7959,"919d8eb94164d3ceb630658e20e0e200250aa1c57e2081be8a6c4eb41b9ed9cb",9.917710196779964],[6351,"3d234826c05bdca11aa478c14606300206b107350a52fbe5f3d2e0078591aad6",9.317957166392093],[1408,"a57417ff890ae3a443f7a0d8a9c86a5ee4226ec26271b8dbf0a72f3be5fec7f6",9.917710196779964],[6933,"e89e4c67a8361f26b9bebe262fde8fb909e3ee744f2257a3b255d91bba276bd2",9.543147208121827],[2600,"9b63c808cfe2b569f1fb4be40b372b959adb829c7d36c61e98aeab2ec02b24ef",9.317957166392093],[10261,"d830679dd16d18481a867ba7d202889a86c026693924e15ba9ed659dbdc1a3bc",9.317957166392093],[4487,"76a24773186df6df76c58dc488b92f0d894aef0fb833c91d5bc0cf4ba02781e2",9.917710196779964],[10258,"e430937144d494535ac63e9ab6f0f5df2ae5fbeb00c5a62dbaecf9a3cc56a6bc",9.647446457990116],[11029,"d7dbc05cc8c8ea2f0e60c2404403022d1a8d321b15e74ddddd545695ef9fd8b7",9.647446457990116],[7419,"18efbab4cfeabac572ed781b6c05ce642dd6f80b5bf558a3fc77cc442b2045cf",9.917710196779964],[19062,"6d29b78126c9c5201e42bc068d4802d1c44fab919507a2f1a413b535e6183c1e",9.317957166392093],[13831,"f4fcec01e587a539e55b05a8decb258c0c574d27e46738ab9c8cc0c1b5b1a698",31.753424657534246],[3220,"592f6502ad3daf9ce5b069e09ea44a4be791dd67fbf3c076b062f3c8cc42f0ea",9.917710196779964],[10639,"eda34fc2048a2e83fedd2308a39d7e2cc60e609fa40d7e3ded83f1271eac6cba",9.647446457990116],[2883,"3f1596bc17a0e81b430f5504f924f6962cb9986d548709164f11e6f264fd39ed",9.917710196779964],[5686,"74a090fe034c65697532f27f5417779749dd87e59e9c1b13323239b348b422db",9.917710196779964],[4636,"b5ae2edcab137918136c60a5fd0cca2aefcfb2a8989c0831d3427e0bbcfb66e1",9.917710196779964],[13974,"0f985cfc4cffc8ce80482d4d91d855e15ac80ed5e1c3d96ca9d3088c91798b95",9.317957166392093],[7126,"6b3110b03bba64827b390194fabcc87453364bcc547f562b0f7b7609396124d1",9.917710196779964],[1565,"969f8e72bbfc6e98e4437f8a86f31c77e1aa198aaf6b4f3c02d041d7e96db9f5",9.917710196779964],[11074,"b4c0ca5ca9b50d6c10ef5fc52a045f050088ad7ef60c9822c9f4bc22a0a27eb7",9.917710196779964],[9930,"0fb29b6629938fcc3d60c763de8909824418b4d5bb30583f86af414ff928c4be",9.917710196779964],[6455,"4115851afec6ea7e8b5c992ddd4dfdd3f62d767fe29ca41fcd31b8962222ded5",9.917710196779964],[3181,"a6ccdf5dc133699898b4d3be7b48a0d85ad9c7eaca5674e1794186942e0025eb",9.917710196779964],[3378,"1a96f3515009b53e0b588fe69a89318835f37c243b36c337426728448b26dae9",9.917710196779964],[17298,"794014a1837edb19d4c357e7f9bda0a4e227c203426ed71c29e56529db940c4c",9.317957166392093],[17477,"3b4bf7472abbf74666ddac151872325c7f7bc4c4254c5116ab1d1881b1ef2448",16.132544378698224],[2550,"9d85cda6f75c7360b38d2d584b7f4c5d651d98c2962bb1f278cb503997ec88ef",9.317957166392093],[10579,"cda9e2c26443d7c17288bc3cbc4842094061ef550c332193394f10f6437bbeba",9.917710196779964],[2133,"4756faa213bdb5cfa2cec18328c3d20b2eb927a4c7f5567db94fb98ae51108f2",9.917710196779964],[2352,"6ad88c8595d01196f52a3d51d972040c6b0fad98aa66ac30ac45f40b158cb9f0",9.317957166392093],[1188,"d4d38551cdbdff8bd8c281fff9551e108dea69134273360f0d648bc38f0117f8",9.917710196779964],[12437,"aa2f7cdeba2de32ab85866195660ae875719b708d0e48d34d550a306be165bae",9.917710196779964],[9947,"1b71872efb6b4e5eaa88460780e951f7bed950d693a53eab654e4af2f6c3a4be",9.917710196779964],[19756,"ec17647f1e83587a2acaeda1b428f89fd84930953f5080db755cb4736b265604",14.188034188034187],[19396,"e9e3ae1ddeb42ef9e3884a70ea4d5871defe25906ea3aa9a5f5b9368ad2ae311",9.647446457990116],[15058,"35f2640a37f72fe002398ecaa49325a367746103d8479947ab6cc75c562b667d",9.317957166392093],[1563,"b08f755407a84500e41d1fcdebe34186f587a9750642a44ef366fe8e0cbfbbf5",9.917710196779964],[5987,"ab3ff4b1d7fe4254f9f51213c38645b93d9c602f5dd7c3220b526978b16a29d9",9.917710196779964],[4253,"fd51a7dd345d3012d30366b9db3bdd5dd0d1a7bbe613ab887c7c7284982a1be4",9.917710196779964],[1293,"f4bae84e4b9fa20069e606fdc2751d70f86497eeb60bcabb03a674e8f67d6bf7",9.917710196779964],[458,"ea22d9ae96328c4072d9c6221deda5fa52de4e2c4d4412235fb213764a57fbfc",9.917710196779964],[5532,"23eea9a3fa5353bddfb7e12f885f0d7f84670340de47aa98f7706d65f3fe05dc",9.317957166392093],[7752,"86f4c7aa8f13a7dd344331879bf22a0a17324f86f9fb14163aa783d5e53821cd",9.317957166392093],[7355,"b69ab10b1533333c99afc4aa6945b1952ee3a515a47324405f6343b6266fabcf",10.052724077328646],[4800,"b3c44913ac3635488c500c014171cf05f73bb558d5187b0815b0f08f7cb660e0",9.317957166392093],[18301,"c734b682dcfd25a969f8ee6172aeeefb7ed2b1c4e4506f3959c97f4b7d15c835",9.647446457990116],[7062,"a60da4508405b24c7cdbe4156d5c3c7cf60a9e269d7f71608a4264c2392097d1",9.917710196779964],[8260,"455c22801eb831fc24fd325132ac8f21f2c02e3504016f94f383b9a97c309ac9",9.917710196779964],[10334,"5a0ae0b502942123f13fca48ec48ee1b07199bc81f39d1659f8774044ac61dbc",9.917710196779964],[10414,"971b3779135a45ddd1a9d33cdb9f0bbb47178c9d562236d5fff2e876adcfb4bb",9.917710196779964],[2176,"991fec8ddadea828d9a529711e7cd94f649b0bd889121e9e4a5c590c4444c0f1",9.917710196779964],[19666,"0749eb69ea3cd645e5cc7e390e2594d2826bba30cc9f5cf894ef482cb6129707",9.317957166392093],[9355,"4dce193fcfac061e2b7bb1172f5f9ae3a10a9ac009bc0bd3cd5947cafd9d91c2",9.917710196779964],[9990,"fa7aef229401a637bfbae755f20714772b0b39e673a6d2844cabdbf8ed2c62be",9.917710196779964],[991,"4f3aa682db9e881f972192f60562d313c96bac535ad9bdea37d95996a82145f9",9.917710196779964],[16753,"000c108f1b7753fa29a8cc44920ab7e92f7bcee7c92fe498f096414518ed6157",9.317957166392093],[17831,"2b084544dae210ed4996ae8970e70bf365901f6cbd769a34b42f0d883d8b9d40",9.647446457990116],[17527,"85ba748215e25361b396433438406afaad270af92ca7526eeebaa6c3ad56f546",9.317957166392093],[12882,"261d39f37b4d00ee50c6174dde6fbf7e61e98dbb502bbbdbca17703d780f63ab",9.917710196779964],[7869,"162585939a2672ca60ece5bddddc64bbfd9cc5cf423b87fadbe810984a2171cc",9.917710196779964],[13288,"7bd1c3d089edc05a972278978a54aa8288846671fd3c74da2dc68b527b21cda4",36.83769633507853],[9692,"b35dabba8bbe0c0bb484daf6dd85864168497e2bb56a7821236ce1ec354975c0",55.245535714285715],[12550,"dfc12e36c8b9157269eeda2d7e8d46793844180477b22fb97c6f22e10057a2ad",9.917710196779964],[15881,"b3be049c67b04618bd4dd13cc1d74c4955aa5f09f5afae4a593c4ace959a586b",9.317957166392093],[5058,"64ef94eeda4e3f28ff961e07cdb37a7d5700a5ed59640ae7e58bca03bf57cade",9.917710196779964],[18878,"b10cfbe1c2e89e4234cc3ccb8e8a5c3f7d0cbaf0d7e27dcfa4eaab46bda12b24",10.031471016209265],[4788,"176595a2df533df69a296b41670833864fd370e02531c7a1cee31c346aa17ae0",9.917710196779964],[2251,"77a3a3d98c6496499574557e009c57258db5b467dfc527d44e875cbe933e3bf1",9.917710196779964],[9488,"cabc4770575f7553a3fcf3eeb5cd849d371d3cd6a11a6d293feef4961686c0c1",9.647446457990116],[2019,"de55bee401b739c882fac17f9284599be6e73013c5857bdbe6cacbdad78fd6f2",9.917710196779964],[2288,"046c8a6bd67a7bf584eeafd0366d79a2752e71d06d3097c1f0ee574757270ff1",9.917710196779964],[16868,"b81c2e5aebb3729b80c1ca072184fb6796156c9b95f2461d9da498b35885d254",9.317957166392093],[3233,"4e188ee87e498123fbd7a3c44fa038dd86b35f2b9f10114fc0c5c8833a79cfea",9.917710196779964],[17891,"00d20d1a524a9d35d4618f8dbcd9d5cf3cf67a04caff6d9d33e380e3b56a723f",9.317957166392093],[4993,"0486de3ec3d30e5e73fa1deb553752ce88184576d13603e931a5a87469343cdf",9.917710196779964],[19730,"74bab55304ab09c0e44edef7d10a32e7ecfb56f92bb2b564bfebc0c7bddfc305",26.09252669039146],[506,"e98e1173f45f2c590853f15f1beadf37c601d2b02d829d93a34d5b1e7f11a2fc",9.917710196779964],[14246,"10901f1ca3b04e251682caa4f663136af698d4010fe94ce826fb9f8a2884038f",9.317957166392093],[11223,"7ca3ebbd7d3375c9deb3a3c75e59b4682ef2ff1a21e588e14296db3df50791b6",9.317957166392093],[13718,"d800bbd2264177ca0627f0a4c1d517922c3c0e361b21c5e9bf19295f7357fd9a",9.317957166392093],[15113,"ac81f9da8a96637e4f543e9c7da7e583f9d30415ac320ed60b1864d2d70e5b7c",9.317957166392093],[3122,"3abb751f9148f9bee80e95817f9c7b4941ccfd44a525863943d214eac79e86eb",9.317957166392093],[12009,"377b4888d4cd0c7da0d6405193b14f7fb6c72ebff44db0e6f736ed7938c242b1",9.917710196779964],[18976,"90f875cea430c23e15cff201f40c0dc34b23085b19c4d13e50d798b65d805521",9.317957166392093],[10081,"0837aab4d2c13ce1a1559deb274f40a8ae79498788e03c1d619b37d1bf8ad0bd",9.647446457990116],[15467,"0717b956de3b9505621e3e0505b6a2e9e442522a3673e99823117a42241ed774",9.317957166392093],[1271,"7018f528e32de4025905a868d7581e9ee0c0490178a8ac8356de99f257208bf7",9.917710196779964],[9518,"3c6baec64278219113a07154fefc49803c265bacc39681b662560a5d3b4195c1",9.317957166392093],[5097,"284176832193d10a56929e46d979862affd9a6226ec3f81cea7bc6674fea9ade",9.317957166392093],[957,"7f08f3fd1745cfe71132f1b9405b36d374bf94c4c5a26defee23690bb82375f9",9.917710196779964],[15521,"469b3b9fa7390911d3dcbe9d5a2d75fb0245f3b8dd344ffb06fe561eba199273",9.317957166392093],[11410,"a9cc81ab71e28544f40d8f1c81e7426438929fcf0c2c1023d7ab943e4be04db5",9.917710196779964],[8690,"3b450e47a6f4395bc668544bf735019155b471ab4ff1574547bd81191cb0bcc6",9.317957166392093],[13406,"9b3d2daceb370fa00813a2fafdf8479182363d957013555de2fa4db7de8e2ca2",9.317957166392093],[5930,"bf6c2ebaa8755a9944542ecc9a24ae7d72de6d93c9d679a047c9b3f8f5967fd9",9.917710196779964],[16389,"a1b802c94973a016a8b8d044fc216c1663b7996b4a11237a4969bdc95e35475f",9.317957166392093],[13907,"7f13f9778d9aa6ffa702c22fde49c9345a1b3f4dfc7b43fddc88a426e8c3e096",9.317957166392093],[1366,"459593b780dc06ab5d120d0042ce726350cc83aca4a0ef0753572c116742f8f6",16.03628117913832],[9106,"58a3385c3a8b117af5fe24ff25ea9336331eb60ae39fe7742255f717d2a11bc4",9.917710196779964],[11131,"5344ca6056e140d188797b0dc6fd4c2fea6d9b9bcd6aba37c2e2ee4d5c011ab7",9.317957166392093],[18214,"52b9771ef82b842296af19376f3d230859bcd7e7f8d604804e7b0b9027c5c037",9.317957166392093],[17008,"29509fb028d5a95fd2d240ee272489edb51cddbb1a99c51dcfb5f47f220ce451",9.317957166392093],[13339,"87873060989a8b2c62fbc069618e3d6099f5924359d020117952bb284cfbd6a3",9.317957166392093],[13721,"c2df1b984caf174fdb6fc010d068914ad6dc5976c64403520e6b3a3dc718f49a",9.317957166392093],[15077,"85b9317e6b0832ea6c6f8be2fef3b9df4992b562f054285d5e7cb4bed1111e7d",10.052724077328646],[1481,"73dfba03a594714b366933bc3dea0e48b195d0b1989b58a962d8453c186e43f6",9.317957166392093],[3430,"5d9746f7ca4a5fcaa6ecdbc5e304c333c07f6e0a9601ad332716abbaf9c17ae9",12.064171122994653],[187,"37c01b94907d5598ec7f6b6b59c89d816c82170794566a87c70eb826e357c4fe",9.917710196779964],[16498,"8a78bf031fb9df4bf2e5405566b3aebd9772d9bda7eb9e690b63cc0c87b04a5d",9.997888067581837],[8166,"d590f8d46be39b2fdd56258e4e94ba36194e9305a390242cc90bc6dad5d133ca",9.917710196779964],[3331,"0e2c2979132fb353c463bd2e93f1b39173edb1c793fd3a62c02c7d1d236729ea",9.317957166392093],[17810,"66445c7f15bfc79b2a2c78da2666421b816769356dc7bb91990f662936a30c41",9.317957166392093],[139,"dab6497860a733d738d8609922ac520b81739c4779ebc1381ddd7049705313ff",9.917710196779964],[13411,"30d19e5ab1d0788f3a595a2eea76b9638bd4c97153c63f41d2ace8fe6aeb17a2",9.317957166392093],[13779,"08bc5df547405011c902f5c3b6c19eb83c56773da5164c1b4702801a52f2c099",9.647446457990116],[11506,"4853f7496ebc899cbbde1c21eb5ce3fc8944392ef12edcd81c04716aba8579b4",9.917710196779964],[16828,"87f3bcaf53918dfce1d9b3bbfcf3955e383e4f72eee824f591478856511dbb55",9.317957166392093],[12704,"f8a55198b3051425ada69b64dfbe347e0e5d14572b47a940402be4b6ce4594ac",9.917710196779964],[18038,"80c7feb3ee7b85675e5aad706947c8220f6dfaab630771fa260b3a9e942d933c",9.411764705882353],[18051,"8c795ffed3e69052d0774eb37a54e035781238b7de12fd5d12b1f8c195b3273c",9.317957166392093],[11976,"adb3846cd536504e48c5ec340675b216e1e1433fa77de3925e924c18992076b1",9.917710196779964],[17682,"46f21518095306d55eef753331784f5ebb4812d03ca178a6cb578862f6dd7d43",9.317957166392093],[10395,"5b9762edf4f5a4326a74fb7b30cd7c041608291bb9c25dd461fb6c05470ed3bb",9.917710196779964],[18335,"3d24fbf299c5a258c2c606014b6d27e8e947e58b23809ebf8c6a0df7ce6f2835",10.052724077328646],[6665,"5f2c71ce603497cc4eaa23400d0efde5809d4eb0eaf99aa9b54d79530d9932d4",9.917710196779964],[5651,"293fb3828490c8df1967a2b816890527598d11d02830467dcd9227a8d68e53db",9.917710196779964],[7,"47002b51da3f2ea398ee61cba1409c5ec76e2d0e6208c49a0bc41e3de9bef8ff",9.317957166392093],[13505,"6322aace99ce0e0b7e4420d83e2635c3eda24fd90f5368ad4c13bdd245c5ae9f",9.472566371681417],[8819,"7c9117ec36d14c68981d714c12d3639518ea96c2d74824cd6366aebbb753fac5",9.917710196779964],[9783,"a51e8f858b3af446341248471d7f8f84d1e7503d3cea3d8a119e676dfa7eccbf",9.917710196779964],[18368,"7cc0bff1338116f0c51c48017c3ac7e42dd431c6587c030766c18941af4d4e34",25.294077370763436],[6471,"2a0d8a0b42b0f228939c33f8a148bc182553763119a03cf7b245e3b9aa12aad5",9.917710196779964],[17248,"47766b1b2e55cfb75268ea418b035fb71ae07064e5c906c769fce8efa86c054d",9.317957166392093],[9965,"cdc1da91ef1ca02129f5b5f2198a1d27f5b625f21c8eeba9c7cd86ba487086be",9.917710196779964],[5678,"fb8754cef8f6d4811eddba8dc99e65a1e9cb11b8451cd6551a931c6c67c92adb",9.917710196779964],[7516,"56fb83c517f9218855e50e1e13c30026139c522dc3a67df02e7053c83446abce",9.917710196779964],[2072,"495b837f17456434bf1ed4031db82e769820f3b8d31695035f8d3cdb659970f2",9.917710196779964],[14904,"f27e9693a0d44852e34fc596b219238ceca40a64ac261bf92a429d6e625fd280",9.317957166392093],[9258,"a8bfa8f889fe6c6d73100922f8007cf354087a79e876aec29f83d03efe9d17c3",9.317957166392093],[13902,"c960f91e8ce412483ef6d61eae3ecc8669709348640a378ee5161a344ba20597",9.317957166392093],[18024,"6fe4282254baebceb7ef9cfa953af8b198e60de24d15cf34d259fa8d63a4d23c",9.317957166392093],[10109,"c3e74285164f70b246b3dc26e621ee7156a762958959361510fb744e5606a2bd",9.317957166392093],[10282,"2270a08dc672e0a4974486ef1451c2c9070d027e1f93e12e93611f4e351e85bc",9.917710196779964],[1162,"bd8fa52281c11c2edb09101bcc6f5fbc94f6596ea627cfa6409fcd54b34e31f8",9.917710196779964],[15701,"b7c9d2b9f334a057311fac024194af14118da01470c32e9aa73fa43b3005776f",9.317957166392093],[19374,"9ebc48c8752c7d747f2582a97ab9a216be0bee7998cd311fd37528868334df12",26.173719376391983],[18729,"553b72e565af698f76ba3b9ff317c5bf4a812baead674c2929b15b10f09a6129",9.317957166392093],[8363,"612fb8b5ac9ae50e583d8ed87874ec8ffae77bc82d1588e6054484d841d5e0c8",9.917710196779964],[16791,"bcff74ae312297646436101a925ae0f28f1cd69e7eb47bdcc1e12091e1468956",9.317957166392093],[19696,"e032cbf753d001a417a2c9f00cd552a209b67410984ced02f3b405f98f09f206",9.317957166392093],[14218,"7d4fc95a9bdb7ef729b4b0030ff2cadf46296f72d9a4c586abdd718d24d6b38f",9.317957166392093],[2630,"39627ed5af860b056ca09904fb99b61977f948f9a97abaab327a7d0665ceffee",9.917710196779964],[12922,"06e33fb12204ee12ed269e5a885e9f54e9613e0acef467f69fc801ebe81929ab",9.917710196779964],[7748,"455030f3f14c59e8a5db3e016af9af72dea1ac22cb2fffe489c69dd8f48126cd",9.317957166392093],[17703,"94f989c14fc12e66b39ed1602bcd5d33340c18e9081faccd1d4752d626752243",9.317957166392093],[1745,"55440a36630e82e7a088c9612dd490d781236d2ab08a0754fd93de9d0dd3a3f4",9.917710196779964],[6555,"b979f0b202de5d12e10e7d1bc2b352214379f5bb94ae2b1cb5357a9628d4fbd4",9.917710196779964],[3705,"6f64024e5f2f8f37f9a094ea8104e8f8453da6404870eae0d1dd22e3da9390e7",9.917710196779964],[8360,"d33f99e72bfcac1169b835a904a73e9940c1475d1bb68841c870e287efdbe4c8",9.317957166392093],[16057,"1035545e44793aa6366fe6671b6449a428dc618ced0f7241623d5dc1d4134067",26.117860380779693],[7153,"03ab17a664fc4586aea87d6b4b1871a8f48e7b323f4fd1a7c9a38602e2baffd0",9.647446457990116],[17927,"1c1a89a684af567618f7c9cd6f6cfa453790d1552ad89251b95f0fe164b3bb3e",9.647446457990116],[10710,"9eaa4e7cc37ba06e938e09fba6532308c168b3487fccfa138aa078b48815f7b9",9.917710196779964],[9352,"f35177e96fbd9ce663eaf48a21570287a1d11297785888efaef705b4052a92c2",9.917710196779964],[17648,"28a987e4ca42149b68430b26c6556ed28e30543b4225daa9a5978b0b6c1b4844",9.317957166392093],[15045,"a7e5138e3c7975cd2c4410905f91c355cd17476205ce8414e9574b0bb75ea97d",9.317957166392093],[15677,"590306b2766cfee28ed39ad9109e52b817e6185bc27a6858b0d200c09d03e96f",9.317957166392093],[4318,"0788299607c1494fbbc7a4b5a522c25ae8863304458ed645fa9cf349f4b2a0e3",10.052724077328646],[3350,"bdd7523cc478fbde5c8df7d9cad52e79fed404326271fe27e8db754577d002ea",9.317957166392093],[4754,"46bf6c3db0cc4dcf515576849133c2a6d230aac5bb5e1700a4594fbe4f839ce0",9.917710196779964],[11241,"1944f68b2f350f088204f1ab1af8bc2d2521b6394ad242563442cb5babca6ab6",9.917710196779964],[1082,"c0809f15776197e07dcb7433f6dca5e22a5e557e0265d85e1dea29659c9db0f8",9.917710196779964],[6343,"d701cfbd73f80945365e2cf169fd88d511cc76e9cf157b5e071dc3ad5995b6d6",9.917710196779964],[18434,"6b0953b39a13cbedc69c73e61595b697df9ec11edeae09c8d613fd53e511f332",9.317957166392093],[6685,"0359d24c8961834ee7b817763f8a5b1809eaa8a68804b94345a7112f986014d4",9.917710196779964],[12507,"278d5cce1b528dac565d41bc0937bd51be4203f568927d6b426d5d564203ecad",9.317957166392093],[18945,"b9d9f768a6394c8ed9849d1cfa284279777f39d94d10e932acf62ef330344d22",9.317957166392093],[19729,"24c164e342c256805ae6e3aa1ce352ef513ed134e4cc5f077baec227cb59c705",9.317957166392093],[17550,"ac41a605bfd0cbbe37803aac6a5fc25159fc74554ed17a9f02fe46b21db87246",9.317957166392093],[13180,"7765928ff39af42cc88fd3013f9eaf809a3f181f74d989778fea068b02bb64a7",9.317957166392093],[9596,"3e0a3065a47760802ca8a7e28bbeb99950aa9a7ab489e2b2367fae6ab11b09c1",10.052724077328646],[18090,"3d247480aa7fd50bcfd74f301f682e6f4d40d5ca92c8758505571558c65e443b",9.317957166392093],[4912,"bb7a52accc0c15af834834e87a802af2ce334c003532521ef58f10b94fb2cadf",9.317957166392093],[5594,"50fb6e45270ed775569dcef07ac4959be560d3be992010898d7cf6e62e07abdb",9.917710196779964],[8776,"6dc12beda42e7a5cf5e052e474a6d436cd5442ceb7d104f223f0801e60ad35c6",9.917710196779964],[13118,"eb3eb2d3f2aa55ab58c698fc949711e769c9b4cace2040065e2887850af49fa8",9.317957166392093],[3832,"df686f2c3523059d37570157afc9cf787b64dbbb90876caaf97ba44cc430d0e6",9.317957166392093],[16176,"4c362bb85acaf9495b0cd98722084097a988c0b11691b3c72ab3e71217f47a64",9.317957166392093],[19211,"a6b55e5581889950c1262046b0fd407b2175ec8734bf38f791bc3905e6506618",10.052724077328646],[4007,"0fc2752967a06a353d29570984f4f49621b9fdaf2ed421a8a786aaf35f2cb0e5",9.917710196779964],[12856,"f8925e7984c6f7346811e773d555650054b1111eccab99b96192c9e38e3c87ab",9.917710196779964],[13580,"27ce98bba1bb41ed7852907f40a3d805bc5ab2e5dc5bcac0101db06f3390e09d",9.317957166392093],[4731,"34cab9c685737ddbd81335ffa2edfa3e255454d7ed44913fc52255ee12ded0e0",9.917710196779964],[3332,"9667fa1e32cb9a277cecd2aea018bcc4215601fa907841081b7b1236f05f24ea",27.094076655052266],[16503,"0bb87f9ff69395702577d3b7cb02e5cce5997c0ab3cf3d60c5da6f9fec2a2b5d",9.317957166392093],[9527,"bc9cf24d0fcaa5781bdd432b9804190a2a51840396efe2f4befbe44f2d1283c1",9.917710196779964],[7439,"1382b807faec8372a3d78a0af87d2f641110d48b1eac569b4fcde3be39f624cf",9.917710196779964],[8433,"91e544bdf5aed53453fb020fdbdacd17c78d55349578d027a388c98a2eea70c8",9.917710196779964],[2221,"858387e9a7c62ff269a99e5fef2eb3efd892d1c5374fdb7c25b357e17d9460f1",9.317957166392093],[13977,"1585aff326816ef219031a69bfc1843d08ba6c42bfca48e23bd74211d3608495",9.317957166392093],[7197,"6bfa1bfb4482f451302cfb35490c843ca2db9425eea73c52ff84b79bc7d5bbd0",9.317957166392093],[5204,"a342ee2542db6b1eaee72859082ac618348fa7438d5c8c8a8131e372e625f6dd",9.917710196779964],[1920,"42422a3a53e3af9064c490ea5123dfc9e0818c458f685429590760a1638289f3",9.917710196779964],[10391,"d9d95eccbbd959d69419232e94c80da1e606bec30fd8854c2f3078f4d30edebb",9.917710196779964],[8992,"dabbcf9bd1839e7f4ed7bf01952105a8d9a698d7286d168a3d3b29b688b4d1c4",9.917710196779964],[12204,"524de4c8ae0c3a7439f763a009dd0123d92db1554cb02db567bec5b926a00bb0",9.917710196779964],[11762,"e2f7fa08c20b4df9f8f9fa2d12af621df7267cf831d7d0f70db06c3eb768eab2",9.317957166392093],[495,"37424e134d7477ff91dc9140abcd48c388ec644150ad3e188b5ea390bfc5b4fc",9.917710196779964],[17254,"ccbf4fb760fdd6af21c9f72c0117fe1af1242a676a5dd69b6fdbe2779271f84c",9.317957166392093],[4965,"d7794bd2aa103efcf76a901aac75d6b03f1ce24279d05ebfce6edc3558c66edf",9.917710196779964],[3756,"b265b72ab475f36125d85908b6d66c19373a9efeb78a9f04c8f1814b892c39e7",9.917710196779964],[9340,"102262cfa0352c835d0fb0767c5b05f9c6d1d1b96fe7370bbf30136d09f7a3c2",9.917710196779964],[15155,"53b6a3e2ba2ae9bd894c0798bd3f6331bd11a9834121e421b25331c46bfa677b",10.052724077328646],[16653,"8955275de9af8f7bcde4b9683eafb99038d4740b4117c9c61d31b5f0d84eb859",9.317957166392093],[7210,"f71b3a69798e3c68e47edec23b86e85c026c24b377b2029b512290c6e5d6a3d0",23.15541601255887],[13910,"33767963a5a5fdfec3cd6445d3dccbc2809852f715dfbcf0a94b06f375dcd296",9.317957166392093],[16383,"00b41af1b74e54cd93097070faf8d213387be60ed415ede16e2b1de9db5b6b5f",30.94168201350522],[9852,"c5c935b05f36210e6ad5d8bbbcdc87c944203785710b940dd82e5f81899d4abf",9.317957166392093],[15923,"5a20bb048ecf9284f15e96c8e0f9e68556650c90f98ef881b55657ebb034a36a",9.317957166392093],[8725,"b856f6b5a8e8842973fe84cfb6ad4436cbbf083cf012d16e95c7b032ba5e88c6",9.317957166392093],[3743,"39c9a4cc18b190d6ed81d6f3a9d31af0ad823e310e20f57160a88d6b527549e7",9.917710196779964],[18392,"eb82235e3054c619d44e32a3746a716bf17fa430ac6bbd6d2b21c41c32339a33",9.317957166392093],[19588,"e9ef494e4b78fd1cc2bc43f2a081bc3517343d1c9fda103357b13b8ec0149f0a",10.052724077328646],[12101,"fcdbb66ba24856613ddf3a24ad69c2d6c7922643380a7bc0da1e8d74e04ab1b0",9.317957166392093],[12476,"e0d5e127b98c60e16c250ebccf22037f743cb455b652bdc5318b331f1e551cae",9.917710196779964],[18663,"14109cc7467278cb2afd996e88c920a94e3b107dae9cfcb76edeadad8a24282c",9.317957166392093],[11546,"2b0d2bb3805f44e7606df27f0a928d7748588303763a361dcd42f08c5c8c42b4",9.917710196779964],[6152,"0ce655f6daa45268ce1811093aaac6c19884b7ed335465279560a3c9f93823d8",9.917710196779964],[11919,"454bec99360864b66a234724bf8a90790ae39326bec8a031394184fce93ce5b1",9.917710196779964],[16326,"8178f5b7d4ef483c866efdf5959bee3313b0789f442022a70a1a375e6ffb7c60",11.894551845342706],[2462,"289fa753bbf45086c7c055c967e231db21828061c1453f4c8f3372268c571cf0",9.917710196779964],[6517,"c4e561b7c59f82cc684cf90c7aee6ab13d5c541b9d8a4e4fa8df615ff94549d5",9.917710196779964],[6593,"9d224e44c077bb7cb5815609309069da5b429c638d8531e868315434ea39b3d4",9.317957166392093],[8563,"b45894d6906ccf09de19ed33ab4b5ea5ac56e2076d98592ffecf3292685fa4c7",9.917710196779964],[14980,"bbca0718f739eb9f103a28ed1f3b5928d93bc29e38bffbb944cd0709fc0deb7e",9.397642257991386],[3812,"d713ae15b879833ca68da27770c3f9c774921e6b432baecac203c4a0e961e6e6",9.917710196779964],[2958,"b6fd629b632412d9cf83df4b4e220220ed39ad9d14413c62d0e55cc1c62499ec",9.917710196779964],[5623,"dc8919636e1f35eceea0fa65f6de6aaa5ade94920d4abfe952387eec09c786db",9.917710196779964],[14958,"d0ee0c51beed7313c54795bcb59de90699958e129b8b25308ba6e3d702c1857f",9.317957166392093],[5332,"cdb4eac7e10dcc50d22d92bccc766c511541e89bac5f31078800195c36383cdd",9.317957166392093],[9434,"7789dc97a90e7ca792a1310e2adad76e8e283b596b4326eac9d01631995120c2",9.917710196779964],[1456,"d9b0603e8cd376e3f98970b12e44f0917717e4ef378ea7a8c5ccb30f2ac977f6",9.917710196779964],[9751,"a33fb01bbef409a107e8dc0f638d7043c662d29da95b3efb0c913b09015b02c0",9.917710196779964],[6042,"2b06ff9365a7ddb81e558ea0af14fc955e67f902fbdd84b8828d580f207bced8",9.917710196779964],[2107,"d466f290f169d53b9b917a3960b95689e098d286097ce8010b9c3b6ef47231f2",9.917710196779964],[8752,"aa47d7c8a290f9d37175a95d492d33ffba682576e0385e3b3805293426125ac6",9.317957166392093],[12979,"93e3a5074b9295cbc230ffa34beeb35851fc5da1c5ec0831aec3ed9a31a1bbaa",9.917710196779964],[12666,"b37c8a1edf984bb32a0eefd2985db7506a806e58fb1baadcaffdf4e09cd5d2ac",74.81518987341772],[13550,"395ff31a81f87fea75a62211f7fbe7eea3fe3e037cbe21e504959a20beeeba9e",9.317957166392093],[5374,"1fd3b779ae51e95e86ac3d3f8ccb7c0ef01c9f683467bce3dc931255ea94fedc",9.317957166392093],[2761,"e7895e068daa5861b1ba4042fac50fe5b23e937f311cb0c884d386f30cce08ee",9.317957166392093],[7954,"dee413167fed8e7b6a93a2e77aee1de73d08c99f5f0a15a06cb1bf7dbcd8dccb",9.317957166392093],[1505,"6d73e1bb4651703046e72a514a73d0a663b3b6fdad97ec91f2d0566e96af13f6",9.917710196779964],[377,"307cd6e82a61070121d58ab576d1bb58aa2aa8b0adc27fed77b058cfd7e081fd",9.317957166392093],[15392,"08210b2f954b0696a100ea0bcc5092db3e921a58e4e3e4c02190f064088c7076",9.317957166392093],[868,"711946b542c5744c55b8c51471f8f59ccc8993d4f371e69c3d3b74bd88491dfa",9.917710196779964],[11827,"c4387654703553e81d0572387aeb03c6ea127c7cab0387efe8beb6099de189b2",9.917710196779964],[3617,"4bdfb8ad89bf724c8fb0b2a8ed44a6dc79490681f1e96ed6f43d62d4781a20e8",9.917710196779964],[17403,"5cc5f97939e2a8632430ad862d554149687626cb5ca577ab5f67adf5256eb749",9.317957166392093],[19834,"7d63ea62153d89b3277af5a38ad89e6345aabecf85e8b1ecfc78cb43f6086b01",9.317957166392093],[18321,"1c7792fc93cbb79552f2edf1d5df024b16ac7ee0eff3e1812a7e431c4cd07535",9.317957166392093],[4290,"95ab73036cfddb2a0cc9212699f2a0449f37180e3474c602f8cab70b57e9d4e3",9.917710196779964],[13192,"1d132ef3845146495923f11321cf522bef805a2f84a9323f57d2f1cb728d02a7",9.317957166392093],[8852,"94ce29ce22303e073e88bb645948d58a904ad4d0121521cec259cf4a1dbfc3c5",9.917710196779964],[17532,"cb36dae4e3c9e409c48ecbcce9bffd1de7d5322a8b47aa389cc36afc1bbae446",9.317957166392093],[15093,"dcea497f7b7a263ad45652e3d1e1ff139a91336cb0d4f6dff6983da71606da7c",9.317957166392093],[9377,"3ff0d2cd95f5a440ebaf6c05c56a69511aee8facd84da7ada600e9a3adfc63c2",9.317957166392093],[8931,"9a3d8959814134189eaba131deebdebd245b99952b7e999091890c571c8e4dc5",9.647446457990116],[7820,"db7ed9cf6a157a949460f29588d940564819da00a35cf14871c126da1537a4cc",9.317957166392093],[2954,"42eef5f6c80ff6f139016f2718b00775dda965143606c8ad16460fab0f929cec",9.317957166392093],[18236,"8b62c562e53218e5f0af3eb740e71decd7c39271868639a38285f049bd054337",9.317957166392093],[10608,"42f5f8f70434d6e203bb4a9220c37f0f2b826349f6d4b31bfe6d21e5eb0e9cba",9.917710196779964],[964,"c9847291459d92da2440f21e96dfce5b29f2d0154f8bb05320479c40d0da67f9",9.917710196779964],[4509,"cdb6777db09004cc5f363a4e1951347d4bc7118b1386daeecfcbae33e51c4ae2",9.917710196779964],[10875,"9481adf4195db2e4a9e49df2439bb9e1161d1983a286b1956b8ab9e6d9e6cab8",9.917710196779964],[13957,"6397a19876ffb204ca5ed9932c238f95dd0acfe50b3a76216d0e26470958d895",9.317957166392093],[18795,"9c1b9e4830decd6f67a83a70d543fa627812b7a5bf1ff0743cb5f36bf6de2327",33.171110718700334],[11689,"a8297cb4883232326f752319f0c16198a9c328fc9cc3949cf5948267108e5eb3",9.317957166392093],[16597,"e46317819243905f6f2b2e810cab19c43e6c0664bb4258eded6bfe0518a1f55a",9.647446457990116],[7625,"7db2c041493bdb63ffc093a25388b8edb5a9984f5e468ad361433e1cb5b70fce",9.917710196779964],[10341,"7c8cf38f2087f982bca14e96f587653120bdc52db5a129f7e7605f2cf8d114bc",9.917710196779964],[3234,"ec95e337f61df6c11103f0a90c0adc1b98c04caaec859a11a56317fabfa5ceea",9.917710196779964],[8565,"0188618f428c35bc68d4edb56992e0219ad3560ee347a07e003fadd0c857a2c7",9.917710196779964],[2153,"612c18bcc7fa31d99bdd725285a698a4ddbc4336b36d9a910fda762c7e73e3f1",9.317957166392093],[17263,"3a5048e04af1e64dbb7f02a3bd9533ab26fa951aa221c71061beeb096143e14c",9.407572383073497],[630,"4345a2b78b4f4181cdeed3c202f053215ec435a979478f2b92f450c26963b6fb",9.917710196779964],[14772,"761783194ea1977bebbdda21f5c85b980840c717246199968c47c70f43fa7283",9.317957166392093],[4475,"6227003bd0cdfabb33f5f2a2e5a2ebf49ca39d973296a7d8b12365397f3390e2",9.317957166392093],[359,"f247847a8a6826866e92b36f02270aa3c255c17c181a545f3b0c109b2bd8affd",9.917710196779964],[15310,"5d0b04a7d48b7a8eda45651d1c5b9e06e59a80f7574a523837cd0134c3ff2c78",9.317957166392093],[4702,"ba67c44c77654d49839c8d26a98535ef50733af5756a8f7e52b67c6d78d9fce0",9.917710196779964],[1135,"692d313a7446164dd986428e9e3c6ea45b6d88a12bdd58e0ff141c755aa762f8",9.917710196779964],[17478,"538fa899af62af2dd41cf514e68e875e06b593588f821b4d139485300cdb2148",9.317957166392093],[15525,"865d6eff4de23bc36ad9a0fad09245f641275b95f9fdc843e6c6d9a7f7da7573",9.317957166392093],[5185,"d6617a7dfbffb1f90abb4af6ae8e843126baaa684c0a04a568606fa3c95811de",9.917710196779964],[8963,"f35e6bbfc1ff3f4eb4b9fb4ea608cc6ed96beebbb53d861e5df01b96b0ad0dc5",9.917710196779964],[3916,"646838237df607e8de3aa1b435d65febfcb3004d518c4b7a5f6208102cf03ee6",9.917710196779964],[13270,"6a0f10fa7868fd21dcd54bf7f74c4aaa5e3d786eb1d7a665726d8a9f3bef4ca5",9.317957166392093],[18230,"4a45832fb73a016ca8b61efd999bf0b540d3eecb26a63a9ba274082123515537",9.317957166392093],[8830,"2addd32d7c03e6a03b72f05bde69d78eb2cfb784d7a511b4ef26a3ff2901ebc5",9.917710196779964],[3119,"7c1a8e1f05e2e83e04de6676a1f39fd061be807645cb7e8059f843ee06508aeb",9.917710196779964],[17450,"cf6b7a7657588f06921d6e0745e07f5437932f00aac8ab8a396b16f467e8ac48",9.317957166392093],[1987,"998ad5aa35a85e081ebd62222d9ed01b5717cdaa53b2e64eccb4a3b0a54e12f3",41.35472370766488],[10854,"f0493d8d7fa523d952082a42c09494251ba6f6d72b69d914736fc35fe77ffbb8",25.912263210368895],[13090,"24268dddc7925c193b4c9efe6668e64403e1f79e243606d7f29b4bdb3de1bca9",9.317957166392093],[9114,"0294eda34cdb73c88ca916195931af0ed81e009f35c64e5be7bf0c27f3370dc4",9.917710196779964],[18391,"ead012e807120d61ea3b61adf94253a5c2b737e2afe5060dd3ead0f199599a33",9.647446457990116],[18870,"1bd1981b14c1764c34e907210d59eb9dcee3d8f88bb86de33840eccfe3125624",9.317957166392093],[10721,"fef48a91a32ca255bf25c695c824f13414b2ef16281bb743157a148d023addb9",9.917710196779964],[15951,"d4155c0916e2a8f23bdd170dc02c392786dec17ddbca81840f891a2664a3ec69",42.26310160427808],[15017,"f1f2f0f846ff9d25fbcc7c61e18bf7e0399497347b8832946b14453f744b077e",9.317957166392093],[4741,"e372f597bc3f732a9b6b351cf3c12334868d5f1e15f680e6b9bd3c9612d3b2e0",25.426621160409557],[3696,"5a2a70ebd54893d9c606d0fd642e2ce5c3c4cef19e79bd31517400f283609be7",9.917710196779964],[6604,"3236c09713981680b48f7b4754e676fecbfc9d2f610ae5cde3bec361e1309fd4",9.917710196779964],[7785,"a88ecfcabe797f14063238cf0d2df86aa71573f4aa181a4d6b184b830933e8cc",17.97173144876325],[4376,"6df0292204ddbf0c014a7f5d7a7b8d128926d2ba7f730a3df7c977dc46473ae3",9.917710196779964],[14237,"c58cf5c13122f79d5c42ae9fa6b91d9286de802398a35e02ef6ff2be49324d8f",9.317957166392093],[7769,"b7b3eac8817d2ff771e2da91db6feaae1f31ff6913e1bc297c5b66c35bad03cd",9.917710196779964],[6970,"40af274d03d8370fe6a6510b5df4dae0920d3b7fcfb6851438e9af924b3129d2",9.917710196779964],[17096,"6a6daf63c4105d4373cd4c5b232ef501d34b17362160cd6123e9002e43290750",9.317957166392093],[11523,"8cdec609689dc4a42cfa90d1bb2db12529248246a622a9112e7fcb11ab8561b4",9.917710196779964],[18125,"ee3ed7396d9f6219b2f853f178315d2ee9e95b4e50292edd24bc61c6cc67553a",28.899115044247786],[6839,"c0531d615b2d7d71fcb6f373ecd69a3c02d203e6d5c0dba0e18abb98aa0503d3",9.917710196779964],[18777,"522f9413fcfb213f561ab3dce14c6c11db54d694ab0aee4e5fee10bd3d44d827",9.317957166392093],[6065,"00839954bc75d44e0fa786bb91a04d3a98a0d819fb853c555ef5d7b82467a8d8",9.917710196779964],[17504,"a416b608f5da19e36988a5f83e32f71ef4074d5571dc2a23227ad4a5f94c6047",9.317957166392093],[3757,"0708520c72435b8928cf63d6e1edaa8d827e4d3ad48b18572a4873982ea734e7",9.917710196779964],[13993,"cf076f9d4c656f4893e54cf1a2e1e1e77358f1a0f641c9a4ec4d974a17fb1c95",9.317957166392093],[5101,"03def356f984cfc4db33544b2816523fc030ce30543ea811661d8bd7587792de",9.917710196779964],[5603,"eb5f0efa168a1011e72cd38d6ee453966329691943b41db8ef4ec1f43eca9edb",9.917710196779964],[16515,"873d2bb8c0a7044d4025f6090cdaf2b1dc00711c883c6a517e6e2e6ff4dce85c",9.317957166392093],[10493,"813221063b3c6dd76ffc657b38a92b80d74721ee2504ffd860a16e96cb8d34bb",9.917710196779964],[12385,"a2d703a77e1a3a7a41321408cfe1f927a90dcd5b7c7ddafa813d42237c02bcae",33.724381625441694],[14902,"1cf51207133e2b553e92505c2dc090449e31d4cef338b96eefbc1e21f848d680",10.052724077328646],[2331,"26fd6ba71be91e7ba132fbcfcb0b6b9636124879e739f28b388b8df00975d9f0",30.128205128205128],[9077,"bbd815ba340bfed99e6603e7563dca8ac6852a0e0b5ba56d994f1a064ab549c4",9.917710196779964],[6888,"13c2787dd35a7646034bb683d1aa1bb4efcadbdba33e06e00f83b611cf8db2d2",9.317957166392093],[10010,"b84cc409cf6386201ee675449edf141b26ea1850d92e9e69ec3f7f20704043be",9.317957166392093],[10732,"fd612c12572c6273aba60df368feb4e1b245641d6986cff1a661df2b6ef0c7b9",9.917710196779964],[12295,"8aa3b382472b2b2296b0253f01ac9c020a92e0519b0a271826dd22f4544644af",9.917710196779964],[13576,"66f2882e1600763a11ad0c3f009e70b26b178c3512693ae54d254335f5cbfa9d",10.052724077328646],[18704,"9f47dd87e387469bf40faacec1d4e42e76e7adde4ac662e48529b19258f52f2a",9.75609756097561],[11197,"c1ecc8e5840e989ecf275ca0cd690e506e9ab3ac1ca9c30170dad318b6fcb0b6",9.917710196779964],[16059,"e6080e9ffe44bde84620a40c1fca1e6418960b52977feafe2062c060e2783567",9.317957166392093],[16378,"af9110f856e7318dedc32ae9afa28200c32c31552f1c89932cedf53b80aa845f",9.317957166392093],[2050,"bce36f4361964ad8f7887aaadd6b7d13a00423a42d2367cb135a30d9b955a0f2",9.317957166392093],[3571,"82b64ce5ed63a379bf59e36af439de9dff7152ef8de65528e18aacd3eb5579e8",9.917710196779964],[10403,"5c088150478e7e5b8afb62f59b5db2989454114f840d3b2a8155246bfa6bc6bb",9.917710196779964],[19861,"cd9a5aa3ba78ab5c499989b6d9d33ea90db3cbd58749c976fc25462719cd8500",9.317957166392093],[18416,"eeaa1179dc35ecc6059d310194b65a651cbe8c200bb2ca8ba55a5e6332513333",9.317957166392093],[5351,"7114de7cfd7ff78eef7cfcbb8bc170fc62909b3c9797b5215ee4917af78624dd",9.917710196779964],[7762,"9614d7e8198528b759d72d24c11b5ca925e5dd0af21f48264b3d9f2a619c0ecd",9.917710196779964],[13756,"3ec7471e0a1a4d714b4f514394d8c488c0621ce3d74c453fb7609d300476439a",9.317957166392093],[254,"7fa9ed29f78e3469265637b6d86c3939e5ed2f2400a4ab8b7e6e51e3915f48fe",9.917710196779964],[17007,"1159b5ecd700ea8cc7f71b032222f9934ee3f57df610545301a49183d700e551",9.73393665158371],[18625,"6de3574b573097cf758c7438e6039f4ac67b1b1ac8c0e7ba103118259e15042e",9.647446457990116],[14964,"8811a1c8e93408542646d92a621d463bf3b34b21918a7cf14de310e8fd6f4d7f",28],[10319,"c27cbc73a75cc4fd91feddee17ed2125f7deb168547c337f3284b447b7ba37bc",9.917710196779964],[1927,"b9d2fd3f006e15477f926dc90427a3f595d59de68e1405f3b40784eb831082f3",9.917710196779964],[8275,"30a4424b771242f04ceba731b0f6b483987921f41c82ffdaa31e655f7bc87fc9",9.317957166392093],[14126,"0b2e5385fc3bc57e0a4f6d9b724a1f882139e799fb1f2a242c2ea5ab5651f891",9.317957166392093],[12439,"26c85232073b0d3f0db5dd0b36c85b2d16b4997fe8effc9c52deb38b985d54ae",9.917710196779964],[12504,"2c01a4f11a1561ba9d94f4a7954a0634870bd1a74ffc4cc59609f286c295edad",9.917710196779964],[14419,"7f7462302a9ff98559e464d6fda158a8656e8607e74ebbcd03150597ca8bf08a",9.317957166392093],[5891,"528b8636f81f842f00e85423ec10c4fb88c3c0ff21f60fb5795fd8758fbabed9",9.317957166392093],[10954,"d2acc04cf0f8de0996e5f98ff70b4e01a87b81c945ef2796c1d697bde91b50b8",9.694581280788178],[7161,"e65bc73b7e1f5f6bb104279686f2e1fa2955879140d86fa4c3b66c819105f3d0",9.917710196779964],[13242,"5921cf7055a3d951d1414795577b0bfefc80205ad485a2735db9cf20dc2812a6",9.317957166392093],[8189,"fb2d43d75a59aaefed1acd761b68c9f4ad832766ddaf2f6873c767d5986f10ca",9.917710196779964],[1977,"81731eb23ea7b351bb65a24d57b36e82cefb1992129f58b05f373e2d38f024f3",9.917710196779964],[18164,"6c9330e484d84e63b241c12ef41b754ac3316340384f355563e0008024a50f39",10.052724077328646],[15010,"74a99fa50eaec10d824712151e1b0f165bc39f300dcf272908bf43d0a7ac207e",9.317957166392093],[10234,"2d7c6239e1205823a5b73efe6b5608a53869b8ab105ff3d60a25b0340d27c6bc",9.917710196779964],[7285,"567123744e766f90dcad5fb02caf8e60a2fcf637f436b3a98f2eb4399e6428d0",9.317957166392093],[17837,"26905759103269f0e27939fae11ffac2a462d6a1b9ccec5531b203e35bd48540",9.317957166392093],[5768,"9688200b6a049ba308f94727672d4c65eed8a8bd507b470d9ed55db28ff8a9da",9.917710196779964],[8449,"80738202c97a0a09d14240149b9d961c430852639859f68ea5e297f7f5a354c8",9.917710196779964],[11692,"31246bacae326e56cc647ffe68dec96bf79c045316cf64ac0eeaf86c7f8354b3",9.317957166392093],[3541,"9a2548bfb859a6af05be59f1d74ea34e832d1f9bd965e9bbf379c1498f30ace8",9.917710196779964],[3210,"759dfdb38cf303fce0344253c1e02831d51826872435770cdacfede13565f9ea",9.917710196779964],[9541,"2fa4b171a1192f66b4f703ed664742101867205ee174da895da8f1337ac071c1",9.917710196779964],[18761,"bd9815c93d1321871a72c8a18b107c98448a7caf1daecedfc9dce77424643728",9.317957166392093],[2726,"0e4e712f074907f206ad51a298b165fb8d79e4d13f7cd8811714ccd99aee3eee",9.317957166392093],[8322,"06a64bd70447b87abf4adb74deb075df48c70ed9b522784a438f003905e030c9",9.917710196779964],[13092,"a25c63afc58b9789c7fc41efe3fdb3b36dcf7873acbfcb5aaef13c63d478aba9",16.196209587513934],[9000,"fa0d18ae93191ad0a11eea57ebd985c5f122a49c772007b713f08f0211adc7c4",9.317957166392093],[17741,"5603b3ffded51774e34ba6e082d395f1c60f81e9d4ea149e0ca498d180526542",9.317957166392093],[8521,"4e9236de0eb243be394b781871c8faf7e5a887adcc990d446f68576e331ae7c7",9.917710196779964],[4528,"1c824806681c59bc25e58bf6d4faed3c429d21660a0a6d423c5129b81a2d2ee2",9.917710196779964],[12000,"847a46594a1f20f08b36516de06d257e6704f5496d537cb0776f3ef461f950b1",9.317957166392093],[6084,"a9a45125f67739149b5da011a1652697804facc17b5181de1241ee7877dd7bd8",9.917710196779964],[5017,"858ef3fa42c60480b36ab52d01c07e1a48f2b50677c80f40e1172cebc9a00edf",9.917710196779964],[2872,"9bf4108dc52d438a0d6939bd3db2041d3a8f9f6b4481decc248970f54ed049ed",9.917710196779964],[13796,"4c06d0cfe8c068002dc39cda0a64a79909b491ddc7105cd60403eec3122d7f99",22.88256227758007],[17642,"7e7d85cc08eafa926ee04e607c1bc1201efad71808cd0e2f81a21bef1ced5644",26.138297872340427],[10156,"18ce969251ad4b59d0fed12fc9c195c2d35173cfdeb8faf8a6e847d769345dbd",16.142857142857142],[10273,"4d43aeb9a6a5511e02adec2a64bedf21e4434fc8259afc9776b17d84481b92bc",9.317957166392093],[16254,"026c62865f4e62bc67efd3b9f929a943f505ff469f7a9fa6e4dc214902ba3b62",9.317957166392093],[362,"1b3a84fe3430b8654e2295faa7f471d7cd33e32a05065bd9906467795352aafd",9.317957166392093],[8572,"3ad3c739e733f202287afa7be276a986590f18f6813d61bfa75ee230867f9bc7",9.917710196779964],[9391,"5e99e93adcf38f54e0b3b5f25f7d2ca1674876bbf1baacc0cb693874731c52c2",9.917710196779964],[9938,"f8d0b6f2437afff5f6e961f400b1fcf8acc08e79ae3184598b59e20780cbb9be",9.917710196779964],[14851,"d12dbd513d385b19143e409692922e09ed08315a5c2e191e04890d136716e781",9.317957166392093],[15263,"4ff4690c996f8608a93eac1ef622b5247d6ab2c6a2cb147157b61f59cf5c3579",9.317957166392093],[5453,"c8f9b17182a288f354b30dbc2e5ad961aade270a4fa244703bcb62fde9f476dc",9.917710196779964],[13384,"4c435a7facf08afb89e33102737cc9a27b34812ae8220207c57c22ef653fbea2",9.317957166392093],[14332,"90d882e35600bd3d3af9b88e372444139094171da8632f4b2553d0951862a88c",9.317957166392093],[16168,"05d4eac52e7aaab53c16957155f5e1d191df4a9e364bb76955897d563aae9c64",9.317957166392093],[18219,"b297b973313bb8d05b3562b05edad79cbe94f8e7ba2476ba3ceca0bbc857a837",26.109396914446002],[19157,"837e647da64d9c6831b9450f84cb148f68741f9036218a2b2aa21f0ac45f541a",9.317957166392093],[19820,"505a663d8424a8b5784f09191cd4e86e69eefd8dfcf0512898af8e82eb68d301",10],[1376,"e25d84adcdee44462499990b506a7c1cd52d9c0502316a55d049d44d8622e6f6",10.052724077328646],[15943,"522de228f89e2f9487a5f40425b3742bde91beff0702a448abbe5bcaa9f9166a",15],[2228,"f9421b485119d3f3a3010e0a41822ff306d5f39f2caa8c4f53078e2ea7d159f1",9.917710196779964],[1316,"0f9916e9e93544a7fb0b51dfdcea67918e3b1260b78739dc001b21565b9351f7",41.04347826086956],[12760,"79989c33f3edb0688a00e9a32cea95472b8c6c4073b2ec353d4d66d6fe472aac",9.917710196779964],[16271,"3a220bab72f20144bbb20aaa002f563d1fdc1c07db3506a061fb5a5e0031bd61",10.052724077328646],[18439,"5c9e2f1d4ad4fa92c302c75ce32f92a84b5169ba58af2d67d6e1ba4dff01da32",9.317957166392093],[11439,"43b1eb361bc48bb6bfb4af5ba7c6baac62cc101f85a55b985b8745006dfe03b5",9.317957166392093],[9099,"d7bc898e8efcfafa0820836478cd44f04d8f48eaf89be229584d57a33f182bc4",9.917710196779964],[6504,"ce7b588b4aecc90b7309977ea77c91889804635a128c171c9ca4f7aeb6bf6bd5",9.917710196779964],[18873,"0792a137e534a1078df7eea49116700c7653a18035d2ae961fba7c859a9d4f24",9.317957166392093],[3875,"ea9328c4174330dd18c315ca54c35a61cef6804a598f21834d583317767f89e6",9.317957166392093],[12386,"5f1d3156b5d50ef16683a98de8a5821e4873b66baa0e62c3582cb0c44136baae",9.317957166392093],[13427,"a0465da78e4a74233821154ad7688de58e59f83f9a54f85ef511cfd26f24e2a1",9.317957166392093],[17132,"a039e25e0da3575887c430b6aa66cca13058422062130052493e18ba916a5f4f",9.317957166392093],[823,"82b8f49104b22b3247bc4e090accd8ae75875f9d955acd933a603da8591d5ffa",9.917710196779964],[11195,"7fb4a88d03bc1013e90ef6f74a3525bb7ea510a637bfca6fbe6e41592009b4b6",9.917710196779964],[186,"7aaf47a48e86e1745a53700b5ba3a11a8155ce5c965957dadfeed23b22ccc4fe",9.917710196779964],[10742,"2bcb67aec58772811537e8221446b4fbff5f36ff7f4e44453b239e0f2c5fbbb9",9.917710196779964],[17649,"d517a5cdcdceaa16072e7cdf7c456032aef1a1d9e60111c379452187bca04044",9.317957166392093],[17908,"2d2bfdadb538e3f1b3af984d5d9171e647c73d0309a95b68b52b4095b3a1193f",9.317957166392093],[7956,"7cc9eb4e37e72fbae9139098cfac472c7e792cc7a1c523ec01676c0039c7dbcb",9.917710196779964],[15220,"329441e37a74ded42a11c6d83608d2daa393117b50523e49aa019447c0af0f7a",9.317957166392093],[19478,"93d0769d40aad822044c01ad9032c8220c1183b6656623546f74e9c5c7023b0f",9.647446457990116],[2545,"c45a3a9769825e627b70f2827aacfe1549267f40912802821b51a76d75e48eef",9.317957166392093],[6051,"4e081e83f2c3d668b9e74dff89930f43e8d08792f7d64f45c9789545e6b4bfd8",9.317957166392093],[351,"168dd6785e2b6e56c81acd5d168dd4104c5cecf36a1eb533099bed52f805b7fd",9.917710196779964],[19208,"7323a76b0d5835b3592e40e5a2c54f84159f69fc6ed34eadbc28172210a37818",9.317957166392093],[12678,"12ed0d846dda2d9c94025d91c384bcbef78adcf3a0dfa10998430947fc42bdac",9.917710196779964],[1112,"af99156baa4a419c92ef666ecc856c7cdfba8604d73acb1f1fb06e98c9a181f8",9.917710196779964],[13356,"8d025721273a4f1d89b7f4b22abab4bfe5ea9cd6e4f8a57e584cd8e84cd859a3",9.317957166392093],[19359,"96aa7753ade8a985cff321b1e42d6ec58faf2b32d7197ae8c7e1a7b7a6245b13",28.09964412811388],[12309,"2f13ac6eef15a5e1d209af6d6809cb1975d54fad1bd919732435bc6e654c2eaf",28.054919908466818],[13436,"332317fdaed7b837c8a063f90de86a6ca0b5e8cc5acf88579a7c8fce465da7a1",229.2876712328767],[19669,"c52841bef11f96fc7294112e72c1bb15c451425f9956a1e22a92104a572b8f07",9.317957166392093],[9826,"d008e06f4f5edcd2fc85fa1e94c07806176849ddb60b2ef1222af55b72fe77bf",9.917710196779964],[10590,"ee9ff4adb615a53d7b2743997e6c43d02d33869077cd222197214e68eb08b1ba",9.917710196779964],[17000,"340a7ed86dda2d7498a04d9115cf2e5ff3f032860f9ad9252dd369c0d935ff51",9.647446457990116],[12626,"7b0f6c7a374f34a7387fdc81dee672c6944ccc6e2496e2dfb01d0978fcd31bad",9.917710196779964],[5443,"0495086e6a127c7a9099161ef8bb67a8ba9b3b37c35e9af3605b2bd65a1285dc",9.917710196779964],[811,"4b553080b69f2bfccdfac4d9cddfd23dc46486d869cc2746f6828a28e7bb76fa",9.917710196779964],[14747,"92a7b6cf2bf2e0a9c2bb0e5064dbfe19da8a60eda6be88d3ca77265b9009f283",9.317957166392093],[3980,"2c6eaacc1f19b4ffb0ea41e6309a5e16601d5bccbfbb6cfeae80eccb82a9dde5",9.917710196779964],[594,"ca92a077973504ab1c37b41a8907865d75d2c827f607541870bb6489b3b9f4fb",9.917710196779964],[15884,"4a157a2991a8ec478148312cd3c66be5d785390527c7c2fea28cd3d51bde4d6b",19.2],[15854,"68fda30d9acb105dcfe00c12082bce3bb93f0bb937cc7e02804cb4f742b30c6c",25.83111111111111],[11182,"7b69cb08a933df61edf7a7111a9069e9983efecf0b3762898e285df811f3ceb6",9.917710196779964],[5000,"a8b5df26171086353061dc9b836731351eb3596afee168a087fa474eb32f2fdf",9.917710196779964],[13677,"9a09fa81f71f13cea38f3377b3a82a824e3222b484e4d5ca492a21e179ffb99b",10.040705563093622],[13182,"b5af91cdc2a0851f6a25bc9df54e68ee4a1ca071909235e5692ccc3e2ace5fa7",28.146596858638745],[2241,"1d4af4d7ec3b1a9a435aa395a68571fbb767af845a3afb7b5ddf6a7111444cf1",9.917710196779964],[6465,"2e4406c2f461c4bfd8f75011bd09a88ab054642f1db65c18c05a40386e30b5d5",9.917710196779964],[16844,"8b77904c648b7a05bb8cef81032c49813c59cd92ecc478795e5749145e3f6255",9.317957166392093],[11752,"1991b97451bc9dac6255935e7f80b8ea5fe04dfd1fc7e7dbaeca198981adfab2",9.317957166392093],[19395,"b9e7ad026bf8c01ceaa3fa35c86b0330cb5058381c9203fbb078f79d866ff511",28.098939929328623],[3355,"4c7ab7c301e03028e99d81ae420d97a9ece5f46a12f5bc457ae166b58d1600ea",9.317957166392093],[1842,"fb2f7d6e4405d4864e4bc286a03d4c044c2992f8ce64e4b3435c5a7c43d2f3f3",9.917710196779964],[15858,"5db3d2dc914d6c37ced3523662fbc9aba4269d539e9d8179e1be10a0002cfd6b",9.317957166392093],[9072,"8ce0a087c82b26990c38f1d2a5841a09adf05b9d4e475ed1c09eeb79822a50c4",9.317957166392093],[16197,"4b3d90331b1a4cf0cdadcac9f37b08ad2f8a56cadc4dbd09c1b389d848500964",9.317957166392093],[7090,"4a6b4bff51d8d1e658e1549cb347a7d747c1623f168e799cebc2df95878d6ad1",9.917710196779964],[16853,"41ab1d55ca86eaba058c896d952bbddc62aae5611bb7132ef0a3884887063955",17.056105610561055],[14780,"ff83221a0417432ae99dfcd4787d3775fde864af0b6b1675e830a872425f5783",35.825783972125436],[11073,"bceca5560a4e3153874bb76dd6d7006797e76e60c3dd283b628ca036b9bb81b7",9.917710196779964],[2666,"c769d4a711a4a6c2665c2e5959f37993113684ba489ef38ad98833420584b9ee",9.317957166392093],[4680,"b8f56fde391cd7aebf6a555472e3142c268e0c1493880e7046eb871db1d41ce1",9.317957166392093],[14087,"2f90b1849ab7f9bab65533e3bfd316589f436b66efce4f779c7c99a85b25e492",9.647446457990116],[2838,"b729226455f0e59b0292f4c9eb2340e61e54244dd9abac7d7540fde3bffb6bed",9.317957166392093],[10005,"fd6b4b6787ce4ad9e7740c38d24c9d77068b41f238ebd6c04d2908f2fe2b4ebe",9.917710196779964],[6920,"4bc800af603c7a533d99ac39431ebc12361423611a982b2999751802133079d2",9.317957166392093],[18966,"749e825c5e320bf9e9ba85451b2c0c5e7f867dfd386666ba64a478d422b49f21",19.170909090909092],[15969,"1a531d9cf5b31914d1b44c6066f53cff7ef0f9da4d620b42b2ff09cf1afa6669",9.317957166392093],[6570,"d94b68bca20d526f034c9eaaf88f2f70a989970a2d2184ff40c9ec8846ece6d4",9.317957166392093],[10642,"c2aaccb130f110519447b1138d44620d0f80c4cbe125114e9cb1b66d0a7f68ba",9.917710196779964],[5336,"3073adf9c5f6f653708ad8fc8e23856298cc5cc3d0dcebc7e60a7eedc6c533dd",9.917710196779964],[15744,"67b3f01511f5bc087f3a3fada9c2fbef52160d5f0a6930addbbd09afe367806e",26.03693931398417],[1145,"7e2bf2ed4eaefae335a05407242c0f7f50065ede8044f5e8e91978ac842c55f8",9.917710196779964],[56,"94c9f5aa44502f568bacb6237ca0ae845607d7768357de2e53609d4840fa97ff",9.317957166392093],[1274,"472fc37d7baf00daf266ea3d67ca0af258d32d9f0a8ea4d60220aead896c86f7",9.917710196779964],[8499,"512bf7b1018cd76b567b544605ffadc3d83846626f2aff9934a78d10f7d206c8",9.917710196779964],[7967,"6e8882fd2443eb9449aed634970f7f602ddf352a4139cfdecf1e960ebaedc6cb",9.917710196779964],[1310,"0874929e0fe11b8b747a754cbae00f8f70434d642700d3ccd8abcf8629c754f7",9.917710196779964],[8654,"eedd92368902cc72b2d57fb3834210ce3329503136bc1bbcf2769df0153601c7",9.917710196779964],[14605,"bfd876b0b4ad0e66c1a2dc6adf36573335f382ac0c880c789007c353a08afe86",38.00356506238859],[6903,"af63e4e7d5d8466251c9157ecb4b888a5e1941cf2a72186fb59c2e0e70179ad2",9.317957166392093],[12346,"1180ef8f04ffcaf5d527aba52e00d7b4e904b4071a8ac7894e17ea4bbd8febae",9.917710196779964],[2936,"d90abfaa921dded6748eeb3acd05751810a41181ba326957ca40c2272c23ccec",9.917710196779964],[15296,"1b209a78cc02168b6259c11ae997729f67d23ce50e1440d609a85b12713f9578",9.317957166392093],[8936,"de6a920ce814dcafe3c4dc53ec8aea62213c4c6a9456641671783e05a34b47c5",9.917710196779964],[14905,"a20af25538129e1d74afa341ee8786e1a724b05fd1d9f36b5da41b8aaba7d080",9.647446457990116],[17262,"99587e40dd9ebe7bce959a5a8f83325072a78562a131962aef153480b97fe34c",9.317957166392093],[8299,"59d0eca565939b9e766d52b4083aafc0333ce7df10f5bddb84734c03c27356c9",9.917710196779964],[3795,"15d0956dcf0134b53abae6edec50b84188307215c8fce4bd82a476fb4c82fee6",9.317957166392093],[15814,"69556c1e950fd65fbbe77b7f2816e728757737f380a8c6d49dc7170f0257246d",10.052724077328646],[249,"3306ee4f478865ee47d79fdf5f937e61080483ac327fc0e29506c1ae10ee4dfe",9.917710196779964],[13383,"56b8837bc98d54212f7ed94cad00514b633e9fea0d9d5a6cc46e726bdd1dbfa2",9.317957166392093],[16143,"f6a3caee0ea1b216353583d267fc8f001c05cf4f2679803fb2cc703230c02565",9.317957166392093],[13130,"1863d06623919580e57997d6cf96c94bf6e8afaa9eba556d201afa8a7b275da8",12.24070796460177],[598,"82eec47d09a70116c304bdd9c56251a4c99396a621da9f6ed5e987230c68eefb",9.917710196779964],[18546,"3290e4a3dc6f8a1c2ec963aea82add696d899835fdf30850a72c66fc9b418a30",9.317957166392093],[6526,"8b63e06c8f21f29feef7b2b5a28247937b1097591d52bef7646ba9a09a0a40d5",9.317957166392093],[2009,"0db4146f26b26ec3d18fb7bf5d31947ea9bce8c1c72672d2ec8a99dd67abf6f2",9.917710196779964],[2080,"9c52c417c9a1ed6e9afe556ab2f493860f00aa408f04c3590dc6d6fc248e5cf2",9.917710196779964],[2180,"1530a4825f65db3cbe2091d6af8f24f9971be8e1c67be2e85a3711c0aa07aef1",9.917710196779964],[13581,"b96e06fda49f206d690d0c9acf379fe5caa340aba57d5e63f61e71da7798dd9d",9.317957166392093],[588,"24f4ba4dbe6b0cad0e9b3d43d5634a5fdc904ac17de5d824baecd98dbe05fffb",9.917710196779964],[18376,"cf525ec2da4070950c547a25240f6a78069831b837834354a2d89803f4523134",9.317957166392093],[5039,"10863e94492fb1013bc7a200f172ddae12665e8b12db0dae2a794dd18c73f2de",9.917710196779964],[11015,"7e179d4300035f87b87bfee606b8ec88dc6a9017b78e48f836639f5dd788e7b7",9.917710196779964],[7426,"fdeb89cd42d62a1112f942f2d36d6241f10cd29b344253c7a0478fde903e37cf",9.917710196779964],[8014,"722a6fde498677721a5f82af7e058e0a6d5d8484e41cd86c487bf60ccd4174cb",9.647446457990116],[7623,"0700289bdec1fd0c9d9bfd64923d03f6b61ff3c7b92e7310bbad03e92f1113ce",9.317957166392093],[18930,"06df0d3530cf88769d3c6634b828bb9940b6cfab49cd08891049d81982298c22",15.003322259136212],[15332,"718e8707bb3ffebe5728a6563763f0a3170b8adb3089e0de05bc3865f9dbb677",9.723356009070296],[15766,"ce96b97574d022d7f64692a7c7393f32ef991bf17a9908d905caf165d12e0b6e",9.317957166392093],[2282,"8dbb12296540aaaf810e550de78f0820f2bc82c4bd1a21c26388348cf1b11af1",9.317957166392093],[13422,"53227dbbfb0d40a31fa269917f3b2a6f7c990190022fe9f51e2bded184abf0a1",9.317957166392093],[19424,"1d216d01c9051e29b2095e60a5361e10e9376576a8a423d3e392fb1badcfba10",19.23112128146453],[17287,"684b2fde14a9bd5487796c3cfab0ead68859bed87b5768620beaac0c5c526b4c",31.022727272727273],[626,"8898230c5a94f6c5378d0f36300c727f37da0114e67404b75fb14f44ed5bc0fb",9.917710196779964],[1715,"d7e5818982858b78aa7855d23783ae42fe0d40b1a89aa86b7e3a8d1964c7d4f4",9.917710196779964],[146,"ba4f4e7f8b5756a23c6a3e6bbef37468351cc7a564497abffe093a07309600ff",9.917710196779964],[3913,"ec83ec0a24f4d4909d6f31b085c08cea599c8c655ff1750198892ca4aae842e6",9.917710196779964],[2393,"39faefef8c729d474f724fb985cce3618ceb0b28086adcb6de8113a01fc384f0",9.917710196779964],[17992,"2934f99778fcf1fe6edca35e8b58e83e672a70e6aa87c493c76f04d68989633d",9.317957166392093],[4035,"d634c334984e814a36178c3b3e5f1b78e7308382f41a81ca752b86d7ce8289e5",9.917710196779964],[17377,"3618d931f22a891f722613f02c36dd6b4564bd33dfba6d8e026ff2e35d013e4a",9.317957166392093],[13872,"b635eeba0fd0f504db54ebd393e41c248bb094081b9f1545f62031b4ed26d597",9.317957166392093],[9507,"9e586eccc1e0dff84677da8fec8222426a60b61e99cf0ba6e34a5bc8eaffa6c1",9.317957166392093],[6247,"c8f5b323a44fec008ee653d9ef7b7e65a253aaa840910d64f47e8036b99c69d7",9.917710196779964],[15853,"04035859f7823067f7dfad02b5ca9f361ce22e1d64cc19b486fab8f2acf1196c",9.317957166392093],[4503,"1d4471b91a0103b7c796a8827117a58d96cfe3e919ec16b2077d4d41857f58e2",9.317957166392093],[912,"2131a69ee04e848763d382847e63a1f6bb63d75286dda2e268bdee1815d0bcf9",9.917710196779964],[16071,"d4d9546ed43831d08e970387c09e46fe4158ec0a3e2a56fd538d91ccf8aac966",9.317957166392093],[14437,"5e73ffa74e66aba57b3b5a401fe6e235ccb777e8c5e806ecc22649cb0f4f8d8a",9.317957166392093],[2967,"e2761bf237245a7dfad107e27d7dfff335b1962e7dfca4497b07653270f385ec",9.917710196779964],[11218,"3560d352c7b18811a598258f3d04ecd8875dbc6541630e130eef2e29af8f96b6",9.917710196779964],[16475,"9b5847632ee85e8eec477cb7cb8001b04ab86fbabeb39a283f6bbab6a1face5d",9.317957166392093],[13336,"7da0ac0e3f34cd857629def0281d1bf22dc9de1e4f8eb21456cef35e9e61f3a3",9.317957166392093],[7227,"98ea850911f9c4b9759d01af69787f0cbe1e268455d72e7aac78d2b5737f7fd0",9.917710196779964],[369,"c611f3e7852efabf8a8e47449743dc8ed3fcbc591332649451554866bb04a0fd",9.317957166392093],[4983,"96f2271b7571fea3dbda7ac28b549816bdd8c7021445277a9571a5ffd3f24adf",9.317957166392093],[18561,"c4bde48c4a66ddc807629523c864ba9c509fdae773a79ca864c7be7f63df2f30",9.317957166392093],[5389,"add7a5644a886342d69a58478e0ed517c79e829df6bde42d9f869d172bc7e3dc",9.917710196779964],[14552,"093fdcdb11c41795c9fa49b8d6b2bbb7ea407c0d425c81484e24348d1bdc1d88",10],[6046,"cc9216dc8178ed2be8f4809e253110cdf4b74f7a69e18da5a1b9beb7b61ecad8",9.917710196779964],[3452,"b84ee87fae3c4244adb3132d4cdde4277126371ad3ba39d3bf93354f671859e9",9.917710196779964],[8254,"c7b1f19a4873195d7a7420f503702f50c8ca70ddc389d824eff66ecfc47aa4c9",9.917710196779964],[5698,"3885894888ea74afc5544d52a9ba7cf6552c065ffefcfe0837b8d3f98d090ddb",9.917710196779964],[4183,"2c4c92b58ba3b71c61493ce16fd4469cb7ee648bcacdc6a72f6663eefa4586e4",9.917710196779964],[19180,"177c862c8f28a9e29ba0b44238c65a82d29333afd2cebef9386dd7a7cf994119",9.317957166392093],[1095,"c124510130b6ad770f5448504d37e976eb5b8b8f6d37c07e6444d1e1426696f8",9.917710196779964],[8441,"5b5c6120f6fe3cc3e1fe12df38370917bf150a186e42e996ba912949268960c8",9.917710196779964],[3815,"4f0ca9c4f6861e4006fccf1aa5cb851624c6cefb3f93bc012a47a3ce19d8dee6",9.317957166392093],[13971,"161dbc05a462875316ccef4009bd767c03d0441e8338a0312b7a1822e778a095",9.317957166392093],[15903,"55c3c4907c9bc0e70c812a84006586a4f605e1dff27ba29b3baaf72fc2d2f96a",9.317957166392093],[5811,"d25cc1ef82458f0f931c638991c8667839e6ad650a565af10b3b7c3c6d4d52da",9.917710196779964],[8771,"5482d622e21cf7ad05958608f51475aea037af97fa3521db44af03949cc53bc6",9.317957166392093],[6306,"bed3a1a4f82503c40d9c28fba503e4d9ffd5e089be00375c99dc131b8595fbd6",9.317957166392093],[392,"2072bc1e4fc578f1e9cc9cd5df43f0ee37b8eee9cc747a33a3955055b7ab67fd",10.052724077328646],[7664,"445ca8fbf47a98f733b6e60a7b55f87ca1585c4682ee329acf4c3ab556a3d3cd",9.917710196779964],[11553,"3c06c783b3a6de972a5594ceeef5f6647ff3a941b5a703559b421840c8ea34b4",9.917710196779964],[3284,"f4e47c341e85dccbf86e3a45ef35d04f6972aa178c77c2f4abcd2f0d69d280ea",9.53899480069324],[7305,"b015f32268386e8104bb3e05e0a08e7d211b09765a955e273e2f30e112b909d0",9.917710196779964],[9413,"119e144dc4539837cf7eb57f4a48044b63ac2e532b41181b278d185108a334c2",9.917710196779964],[18656,"076c9833ac503b1d3cb07202156bbd8935382458eb0c95130940aa2ed9d2692c",18.19178082191781],[7137,"bcd2d397c0588326d7dc7307e1a69bf88e36537fd1d2ec1cb9dc5c22ffb41ad1",9.917710196779964],[2155,"8482a9e1a25fa4a3dea79dcf078b00672bc26428d0b153f681bd4b777e08ddf1",9.917710196779964],[5676,"958d4695d6b71d0fb1ed17fedb67adea8b291c93837086eca965311056142cdb",9.917710196779964],[2663,"61881bab5550e7f198b863c166455fcfa2748e6db540c627e0c498d1d572c8ee",9.317957166392093],[12443,"49af1f6434cf8351d20eadc52ff5255abbd9bb26c098fce52fe31d67a33450ae",9.317957166392093],[5004,"35101ba6c7949ad3ca78ee8657c33f744ca7ce1ccef2413d051e887ebd5026df",9.917710196779964],[13589,"535c27761d559c032074d14d74d82694577929c9a047a1cc058ebf7cec9db69d",9.317957166392093],[2046,"a2065f9cc59a89dfc2e457e5dd3a8a4b805206d54f31c41bcf6b3a336d77a9f2",9.917710196779964],[7876,"d7669febff2723ac9198d14ce803e19c0af80b2f916277265bf0818af97c6bcc",9.917710196779964],[5345,"854cb6c21c797cf61c67b7a8bd71f6eb18ed84a49f13379b9c3f7362fbb82add",9.917710196779964],[5515,"52242e82aec78d91c962579f6c5f140839c850caed5b5a22548ddb16b00c26dc",26.647686832740213],[14344,"2d0da34ac3af5f8427ec26e32153e9a3d490157b80ada15000cf56cb49ca7a8c",10.052724077328646],[12163,"73efafe2f9d6fe764be91d5916ff4ff5697362e9c2071a512684fbcf432648b0",9.917710196779964],[2398,"ac9b09dfd6478fb75963f2ad3d20fe76e3dcbfc2f861a99ae9cfe0cb652781f0",9.917710196779964],[5172,"666cf912d227ea7fc67059f5d119ca90aa3d383c6ec6a934f25be0914c3d25de",9.917710196779964],[17056,"f593bfe5ba9760f3c5eb2d5f551249d630dfddae4fd16f7058d6f2176bb1f250",9.317957166392093],[9339,"c6f858158e3fd82ad20c45eaa865946012dcff5a042e67bfe98fe18c7ddba5c2",9.917710196779964],[11343,"4134e4f538ab63157620857181a3d07722c53aa43427939e2108131b9643b3b5",9.317957166392093],[5729,"c998af57849ac5ec9df0777de29ce938f7869a65cf24e5386ddafdeb49c7e3da",10.052724077328646],[4399,"bdead448f371e3b2ab012a2645fdb22c3fc655bcd8e6d12dc1b0adbed5d417e3",9.317957166392093],[8619,"3ab910e0f34eda536872cc001d64e047bbf391bb7313a080d46e628cd6584cc7",9.917710196779964],[19765,"94943deb95f68b4f155486ee2098f86321272fa9afc6c7b4630739325065e903",9.317957166392093],[8285,"9b9f2249701c46fa59d6a580c66d38b3383d35197cc3a65b1db64e0910ab67c9",9.317957166392093],[8762,"e16c526308acd1c8d77a8ca74d79a0da74f1ba985e614a5fa4835729680945c6",9.917710196779964],[12070,"dec5777f177c47cd8b316a762d718780f72b36fbb69c46766eba1e5937f1e1b0",9.917710196779964],[12722,"35760df8c1173a7ca4fcb3d2377ebde02a2e863cbcaaf429f182650f6eeb6fac",9.917710196779964],[9057,"ef0983ac007bc2264c30805eb78712c7254231e7edb6792bf85a1fbfeba26ac4",9.917710196779964],[17288,"99047c0dba2a3bad807266e5401f59f387bf11d416615836f2daf10037f86a4c",9.317957166392093],[12514,"d3a29819846acadc81a93628fe990cce62887633b9f7d7d84763ff4cb996dcad",9.917710196779964],[12782,"526087ec690331bc65cb9fd12bb409de37fe4acc03c5d2abd45a46047d0106ac",19.228318584070795],[12146,"ae19200d41733a50c65e50f9762b6b70a1563fc4baddd46cb665599080b95fb0",9.917710196779964],[17223,"3bd747a1b5f55c4dc76ef79b07a49955ee84cb6dc330cb7c94a4711693917e4d",9.647446457990116],[11301,"7073bc0a115877440e1118424bdc17b9d57f6bdb4b3761783384bf6779b703b6",9.917710196779964],[4695,"73505e13a1483228ccf72fc9449deaec034dd34bd94ca440a95bddf57f7b06e1",9.917710196779964],[11494,"051598d5911c7a732b541efe75a94b3263375604894e82d078bbbd9552928db4",49.88864142538976],[2745,"643897388a75fdc542186e4227f4de2b38ffea09d037ad2e500573e7b0ae25ee",9.917710196779964],[5316,"e50c1aba93c612600c9dc07a922c7dc5d032f3c892c3ebabd40f8c6d68424edd",9.317957166392093],[7003,"d759b1ddb25c51b0f6b61885e7311f34121df69dfd415097d0cbb39651b4f8d1",9.917710196779964],[3590,"bfa97e17fb7291abdb34e7a18e234d844dd4f23a1a158792a2314820fc955de8",9.917710196779964],[16437,"506ae52671ab3cbb2bc70a058df54ce4c1c8dc4122c764b8cac0655e33036a5e",9.317957166392093],[16837,"7d3d7d47c000fcc635124819bd90ade9abe93e2706d39504360e36e5fc2f8f55",9.317957166392093],[16455,"3bf8d92dfb6d0b6fd99c84fe93e8066bfbad8fbc080159b4bfc0ff4b718b1e5e",9.317957166392093],[17848,"c32c6fb35840b5939b1220047b937ffedbe3c06b77577d400f9bea23dbfc3d40",9.317957166392093],[18793,"2409ec1a873292cb50f96804a4680af5d55f6fc61214c1740bec422c2f5d2927",9.317957166392093],[19302,"a0b727f250f1cc73e6319addc75453d308a837f6eacd2b0175e1dbd6f7b5ee14",27.853658536585368],[1999,"d50218f374e45bde66afc3444fbf4703d2e97f0248b0732eca128d957aa007f3",9.917710196779964],[3263,"93651c0936e99a2ecd98dacc5685d321d21cd27bf900856eb64508667ef299ea",9.917710196779964],[14130,"1c8c10b876667f6ddbda1ec854863d737c52b21031eba9dd942c52db5d62e691",9.511228533685602],[15501,"fccd07b55b030faaeef6302732bfb6689bf9c2bae1d03927351fba59cb1f1c74",9.317957166392093],[3500,"7908593d04e329bcc53a06540cbac01cf9b69863d4287390911217a46a43fde8",9.317957166392093],[4135,"bca106250d26056a8e9a9e0f7f2dcb8fc458a9dabc1010593a4ffd5497bdd2e4",9.917710196779964],[15955,"52bd5990e3a153a88f420b8afa954ae13f5ff8a836bee493f022d6fb18cfd669",51.11175616835994],[16335,"920d95529cc414786f812681d9addabd1ffeaa1afac14e5387efcfaba0b95960",26.972340425531915],[2863,"166b67b43ab58200c4dd0933e942eefa4b0e038cf50fcfd096f48ee1e97454ed",9.317957166392093],[1568,"784e90e1a81f220b3db0dc47e17567d5c93e5ea1a2b3e2ebd9b1921c19cdb7f5",9.917710196779964],[15650,"90d494595438b608a10046c9aa77ee8371c268ac3385b3e274aca9effc634e70",9.647446457990116],[14724,"85fb5a836d6042a52ee8291780b50855dc342c1e86b518cd808d897ec7657284",9.317957166392093],[8788,"9af5886c208ca9d3371471c845752ce2e7c4121bd3a1ca4e2b6717721e2a25c6",9.317957166392093],[12423,"9f0918ce18cc8b2ae8999e8c1d203196aa9a40028cc30e330a39dac8313c6dae",9.917710196779964],[8639,"c06a9fa698b345521d618afa8dc9f16b6fc8a16879bd5e275a2756af2ecf2bc7",9.917710196779964],[2594,"6c87f703d27c93987245cf417fb9ba6bb87e49cf100f182f0100c0837a7f30ef",9.917710196779964],[16527,"a53b6da1ac576847a3d12e555c7d6135bf9c1357259b1db5db548c715b408b5c",9.317957166392093],[1462,"592eb542a48066a1f6dbc51231db18a6d7c3f87d92d002daaa7dd61e54696df6",9.917710196779964],[12336,"3e034f698008c29ea6a63acc6443dce2bf1524a814fe2311ae37cba6cbacfbae",9.917710196779964],[2357,"a00a69979eb6f901e69a4c0750637f5f0221fcb4e64a36abd6dbd03f74fab4f0",9.917710196779964],[13373,"b7c26e398fdcd443d0ac3f1b07f5c8b5153dcb9adee407328e92f66b642cfba2",9.317957166392093],[19429,"fecb71a585d2eaa96d5d6098f757182c26ff506861edc759d71b42ec67578d10",9.317957166392093],[7615,"5226e4d3cd1d2f425a49a4938e83d476bdcbd908d13178e6f77d4cf861111dce",9.917710196779964],[1744,"1a819c6af462b448072e104357b398c9b3b74ed04c68c83a43ccae0f2581a6f4",9.317957166392093],[16187,"ee21dfba86633f85f856ec2cc7367c188869f198642418559af06ec02f073364",9.317957166392093],[9196,"ab93f2c3b28c979fd6730eef8ccaa783a5eed3e9aeadc562643953a28c4a75c3",9.317957166392093],[6922,"28c60dcef4f0ef6ac799b795235a6d8cde4832187048ee63513cf9493fc876d2",9.317957166392093],[8906,"67a591d432ce03cef1bfb2cbd2407b582a9bf1adeca7bd2aa22636aa08ea6ac5",9.917710196779964],[7513,"92288fb249ea77adfc559629addf5520f56831773c6030d12910aaa5a261aece",9.917710196779964],[5387,"9df5b396bf83d54db9853eab3f2261e692eeaf3b339d129329e8cf2be22ae5dc",9.317957166392093],[11719,"eb3ddaa68fa598d44c0c2a694eb2542e212671d8647059417d9d92aa30b92fb3",12.063716814159292],[16955,"ed8398817f73506ffeef2d8e468f44b8cedf5a12d645dc86b0bf42df389b0e53",9.317957166392093],[6758,"c9433f7b7114b704a29c71b8d315b7548e5b39a9f4c33fcdec3cb3b91b5a87d3",9.917710196779964],[9019,"a6067a6d89e4ad974c15eb273407c9f1606652f4585e95683b0b57709d8ca5c4",9.917710196779964],[16751,"00a74b627af1c2b1cfcbf0abaae594e0ce86a88f0179d9f68d70284e7f386c57",9.317957166392093],[8585,"6a6e7da8328d683f07d204c5b5a02bcc14a064042dc350ef4e6de834995285c7",9.317957166392093],[16356,"5207c70fbd85a97718788de3a138f857b32c572babf54fcea4ece436c926f85f",10.016260162601625],[3953,"3b5fd18eaadb75b438608e7e84040c6baf7ce1f9b3140a5d658ac3cc813ffce5",9.917710196779964],[4793,"4ed4bc09a64c68901a10ebae98eb4182531a0c1bad9b08815d1dc75064f56de0",9.917710196779964],[15754,"e64beaa3448ca654028b7e3ff3523227d4d74209229c2c5e4410dfe71009476e",9.317957166392093],[2902,"c19a300ccb124d7834309bc933be3bbfc0e9246ed4dd93270e71a87a42521ded",9.917710196779964],[4207,"7adda028d697866682479ba7e50263906ae508d7b45f0bbaf79650b420fd5fe4",9.317957166392093],[3276,"eaf2fda05797d109c341e7b2da17e0d8fdb58be0315a37fbc677647885f88bea",9.917710196779964],[3232,"69732b68d06391bf6ae6b001adcfc7f74deb018485d9fc6650d9b7548ccad1ea",9.317957166392093],[6451,"fdb1f4b4b94a6f0997fd720aee6266aed318cc122960e380ed0d1144cba8e3d5",9.917710196779964],[19657,"0dcfe3d929df57d64b26bd732dbf77de55cc46ca25e1bdbf265e3176949cdc07",9.317957166392093],[19045,"17fdc0b94b97aa91e04b11bc289c71dac2ebb1ff4e0b6234ffc816c92254081f",25.401769911504424],[11154,"c207de3661f2dcd92310c17035bc8772afd1723def8e7979d8cbc33d5f6bf0b6",9.917710196779964],[9597,"b168a8869fac2e9b89ff42498e2449383c53f0a76c81434231a455792db808c1",9.917710196779964],[15898,"b85b418e917c7775e20091567d64a695beb049626ab2ec9aae47dc7b3ad6106b",9.946524064171124],[4438,"2b864c22d4a2238a107b90986cb00040dee7a951793752ac5e2f33f3c799d6e2",9.917710196779964],[10985,"7e61ded3d30723cbe0c77846fb7af12a9376d1d2833c27d17e949b5d430e16b8",9.917710196779964],[19446,"f25479816e702da9bb6a4e14bb1a38aa58487cd7d85989b6c5e1e93ec3b0f20f",22.279646017699115],[18530,"3b8d7293c8bba586fde191dcd8de78afde9a021a6a9aa2e69ea2e08d0c9dde30",33.40961098398169],[18247,"b8166708c89edc876bcc6368790cd24008d4c8486515bf46436b1644cf280937",9.317957166392093],[7889,"fecb6760fd85bcf112933f36b02ad4977a4450dd84e663e03236b97589c753cc",9.917710196779964],[7836,"ebea2fa67a0634af1694a884895ce393290bfe9c771e3503799facd8f06e90cc",9.917710196779964],[7157,"3602d42a5ccbb58f40b844c1fd6e7e70d58b90e19333afecc328ce752ee9f6d0",40.11899313501144],[7284,"bf4144d51d30ec1cca7757d71e81e5dd4e2098a5d4aecbf12cee6b7871b628d0",9.317957166392093],[4420,"3ac0d7ef09b5b6e087c8b58d44addebc19a2d8c4acbd55ffa545a06b14aff3e2",9.917710196779964],[9183,"80065606ce138e8c3ffde80926b249f2a238de0eacbcfaf878203b01053599c3",9.917710196779964],[812,"bb92961e695368ce4ccf60b8b835fa2b538f1d6cfbdd871362b2bac5f93c76fa",9.917710196779964],[6642,"e9df54a89919e30d88aa64d0d01963313fab1b0d0384e6aa2efcb1c63b4161d4",9.317957166392093],[11339,"e9e66695ee02f0147d42b182bcfa07daa5476cad1caf18c7061c1bda20b8b4b5",9.917710196779964],[10321,"ab3213ea12c96b396a75ac6afc6dd5ed1caa345c8e34f5c000a8ad5cadf335bc",9.917710196779964],[6370,"d09e2bde8cd6bb5c971f1c4b21524b516fe338e92cb1ce9e2e33454390628ad6",9.917710196779964],[14664,"485576e067cf4c734b5dc3ec08ef7b169da13459e8b7ebf958b1b6822138a285",18.130434782608695],[12649,"aa33d6e5976c96409d813813f489146f4b30d77a3b00490eaa6a89fad40eefac",9.917710196779964],[16066,"38679435c9bd40b2c9dbb7294de8283610dd3d81a844cd7d9b2324691f590067",9.317957166392093],[2741,"9764b58979c1633a7521671e18cc4b99219fcf6bdbd2be81077429417f612aee",9.917710196779964],[15988,"ce53d156d04db06dcde47119617cd5ba3f844bac0464f6d2267462e59c67af68",9.317957166392093],[600,"235813e9f621ef0896d859b91a4f95122be199c3153cc70f999d7d1a8590ebfb",9.917710196779964],[14872,"0ccabaa2405ca6d736e3e3e80a1073f0b5f926d38be450169e6ea69b0bee5c81",9.317957166392093],[8515,"126027c63bd6a934ad00f7131202eb9c24e284b727e68ce1c40db6cbf797f6c7",9.917710196779964],[3388,"694f7bb0f1b4e4143afdadcc1adf3645e923ea05cb2715782fe31c9c6e3fc6e9",9.917710196779964],[19687,"ba28adc8144ec42c5e10edc28228180452aae237798bc1bc91358f5e92ec2107",9.317957166392093],[14189,"fd8220b275b94a98c2eedcaa48da026b683af17f3f9ad8d943a1ef8ed69fa490",9.317957166392093],[15286,"04bed3397b883c4cef0f83d64ae780f5704b0f30baf050bdc415c25d7453a678",19],[1157,"95cd80ef2edb184458c95f476482943f80dee3b235344ba5eea53ce276ea43f8",9.917710196779964],[19150,"b4abba8fa51bb864e846361365388e2328d766ae6f0116da8e9ccaba5448841a",10.052724077328646],[3363,"cb4653d28ca356f955d68902832a6f07cdc780c0f0e498bc5960069b757af4e9",9.917710196779964],[1258,"247d27664ff3b4206e30c1a8e567c0c43ec4df48234aa3f18b32240af9939bf7",9.917710196779964],[10684,"e7c180550a56e36492d6f55b40450f70c942d2a32e34387bd2576b103a5926ba",9.917710196779964],[7160,"db7b2a512c566a9883c3df0a42d944239cb10727c0c70dcd1c5a77c54870f5d0",9.917710196779964],[6111,"955f17e028f4e3039af2635b81bc596ead7dd08edfa5adb0060a5b293c4c5cd8",9.917710196779964],[19351,"37d54b29ef21d0ca99b77ce9fb75c098731a088c9ef462df343aa7e3c8289413",9.317957166392093],[19241,"5b0f4088b0427137e32e2e7f98cf8e02d3d8424d53765c6aaf190a73f5732d17",9.317957166392093],[17315,"42c66faedd4c2e60f2c5c120ca348f66c45d8bc6f5c30ba200d0c2bab681a34b",18],[14365,"16edb2473937ebb3803f9f1a99c3baa917378891bb424dd30090d27f59f6258c",37.03429101019462],[6255,"73dd90ddb0f3b526515cf20eb06ba7ff9c56497b8a12b3651770d857abd15fd7",9.917710196779964],[14528,"6068600f041e36f298f3b57fee92126fa90ae8f98eb85dae85ec3ed53978a388",9.317957166392093],[3822,"f9a48e5ec7eac0dcbcb17d90a1ea61821e4f9d1d28beda67c8f21662802adbe6",9.917710196779964],[15283,"2176a50c9d9f720a0133c04f71beaff4f591362bdfa2731ccc899f05e9bfb478",9.317957166392093],[6584,"3879d036a4f7522e440d01a8ea53eb918d26b439fa9e2fe12c61592e4070c4d4",9.917710196779964],[15995,"3f18f3815b9693c13ed36ee34f96fe4e07b4e7cc4b2ad298272c98e0aaff9668",9.317957166392093],[2753,"fdb667ebd404f7110fbbce0cac0053f64eec5235c66307dcb2aac214ff8f15ee",30.14218009478673],[8959,"26aed3de4c5c8808c1c31a246751d49a22db71322ff7aff312029c7e642f10c5",9.917710196779964],[17906,"1164cd1d09331adb8566740273a0f409b2837f7a3ca8d3a242e2c1f6e5b21e3f",19.079056865464633],[5819,"f3b0ba73b4887ec5a97782d6a16ef7182dc377cc4aba3977705a8ae4d03844da",9.917710196779964],[12147,"4069035e1c16b492b3262a0aad2f094e5fa3cf4e06351aae4c5de5908a465fb0",52.72745391131041],[15063,"821211e773346edf2aeb98dd410574a45c33a0b2f2eb896a760f3ed1cb1e547d",9.317957166392093],[428,"159327566ed800af15717e32aa06f934656b5169e73079da0f7c504c5f6b2afd",9.917710196779964],[4994,"68bfe66b1ffa750a2df4c4e8b4434eaa5aea0a37da312a2a505e6841edc639df",9.917710196779964],[4945,"4d30630d2936e51edd181c7fa744bb3938c2c4d1912b3390f5d9dd0c72958edf",9.917710196779964],[1051,"4effc3b1d102612c30ea5a99cd16602726f8bc2f0f52984c6495a0ae2642eef8",9.917710196779964],[11972,"b95ac989d7656e7dfe9146d2f7468c2006651776563c10241ce9e47d393880b1",9.317957166392093],[7281,"1abea982ab7f57399e28d44596da1d6a1035fff41d9e3157640bece9ff3c2ad0",9.317957166392093],[1450,"feb65f369a1c168c395d7d2f9f78b0a16637700fa16913c0fa6456d3ed0a7ff6",9.917710196779964],[19325,"e9c992dae523786c6f82fee60c9e56a3315d7b94f23f7bf50fa1bd8cb5cd4414",9.317957166392093],[5739,"7ca90eaeaea32e376d96c3620151100c1036177c5c86ed992782a4ad1ac5d4da",9.917710196779964],[10418,"cb7174a415e22799e2a7bd4987048d5a3a98574ffa7faa66c9271791cbe0b0bb",9.917710196779964],[15061,"2ede579ebefc28fe14a7d5678777201940af7998ce1e28219051fd7a60985b7d",9.317957166392093],[9983,"e08b86509fa9af3a737043b3d17d1a53ae9c760a134f3b8d9f12addd50456ebe",9.917710196779964],[19445,"1c562d27ecf24c68c7524185341f85fdb6633ad35f8c3f56c728cf527542f90f",9.647446457990116],[9703,"eae1a6e15598b9ea9fd4bb100a60919850e6dd36182b8133b8073c1a9e1857c0",40.15586945932781],[16556,"66f8238d3173ba3b6a2383245dfbf6905ea710568e8ce1c6590623830b02f35b",9.317957166392093],[9761,"918de0812ba0de3c15edea48ffc435d09f2a78e01460f37a5b76866946c3f2bf",9.917710196779964],[3240,"80b9171495cc6ab158e8a63573008ec44e62b61291470ce3420b1274c82cbeea",9.917710196779964],[7572,"518c8d1a92168acb6007e0a85eace51a3cd8896da95e772c760ed57a05685ace",9.917710196779964],[17888,"73085fe928fae02ac011f15723cd0ef5167e70f15c54def5015d47c736777f3f",19.215686274509803],[11680,"9f1bcb4a9ad045b143f0bf2412bb7dfa260a7e8c60ecfaedf7e2d176afcb70b3",9.317957166392093],[10914,"da72efc34cdb98542e33afe82f874453bb6161151afc0273921fa7bc18f897b8",9.317957166392093],[8605,"db6ae729b545b0264fe2691ebdb3ea43f7e2c5574505bb8722103239733167c7",9.917710196779964],[6885,"ef623e0de8e8de454db45d54a53dc0a3c2948fc6b8307c19b49604a35a2fb5d2",9.917710196779964],[8470,"bee9f0353550ea8630c4918e1841e10590eb48589743c7b422ee91e0287233c8",9.917710196779964],[18067,"510ff7abd8a8f4bfcbc949b42f45116a32d25d417f404dc1315ac93cd013ce3b",9.317957166392093],[8847,"4bb8b357f796f92e3f56c48e2592a4b87e22d336cca3d7cb4875ae986259cfc5",9.317957166392093],[4749,"c5b0a303596fbde8654062e3878b8926f3c809c3919d26afc9a62f5497a8a5e0",9.317957166392093],[8859,"ebc257af5d39e7733da2b8c315a7659a27989d4e8ebb70edf48b7d766163bac5",9.317957166392093],[3289,"78a529b676c2a7e6de58e9cb13a52b539207705138ba756c83cf8558cc1a7bea",9.317957166392093],[6808,"d4b6829b1ffa9265bda2b82487fc12ca473ead41a24fe104c37d9219ce1838d3",9.917710196779964],[4009,"e8d90b981c251544ca2888b7d4cf65ec398e9a1c272f3cb10691f1a96a47ade5",9.917710196779964],[4920,"3415d72adf016c30e2614c0343b1d4bb1b1d469e88436f7fee0ddb3e4d03bcdf",9.317957166392093],[15130,"03f24b91945558bafacca53e375ed02d5e19208b56908ff245bac329a50e207c",40.362537764350456],[5350,"9ae7f20ef042a4a678717c901e40d75f3aa8be9e47f46e0885038527481126dd",9.917710196779964],[15274,"3ee75cc642b3384c01f3b5c8ea2954dec066eb0fd167c4d0a2f8663aec37f078",16.071748878923767],[15897,"79ac658939bf1ef38ef8ce2df7b4a8115721713c534b199d52bcc746b1c5156b",12.007504690431519],[14966,"76bd105e38fa6354b58f0e2c33f01a1b27466fb10622e2d9d4d81abb401d3e7f",9.647446457990116],[16514,"d95e910a68927b9d4babe6d215db28e2dc99cfb45e8b581fe6fa0eade76aee5c",9.317957166392093],[5114,"11e4eaf6dbaad8027fac916f50cec224c59343e7fde31d835d37ed6fcdcb7dde",9.917710196779964],[5407,"570da72610d48fa07bd89ffbb9eb9b575904ba2b8f9cd54a9cc505618958c2dc",9.917710196779964],[13763,"2c8cc972ae67f9812785e00c94d7706e1ab90963855aadd8d208f6cc79bb129a",9.317957166392093],[11699,"9e544c850c00e82e57f07ea1c4a1ae1a6891acd02d23cd6de51855bd14bc50b3",9.317957166392093],[15875,"7afa5384b42d6eb96b1e16dd6b6915601166ec0c0ac5cb8708cd1d5d67bf7c6b",9.538108590364518],[6884,"41a7f6da9ee5d63f499979624b74659d87ffcd024bc1ca953983395e4f6bb5d2",9.317957166392093],[5240,"25c572e15b088365a9ca97aa4e266296892621bcf69b5706eb87b28a4fbbbcdd",9.917710196779964],[13633,"a5410b464ac9e49e9acb1ba279ce9d31b133ed94e4a00d6d676105d51fbaa29c",30.164383561643834],[1705,"3ac4f8378e9a8308ba08dfe05cad16bae273083605e4e05c41301a0b1209e9f4",9.917710196779964],[1046,"e004466cd7e9c2dbf147f93d62f7c1af1769f4b5fc91106ee97725ffc25400f9",9.917710196779964],[6623,"98e533fa4278fd9c9c0579e4fd2faa99a080d31e2e49f167022c1823d8d67fd4",9.917710196779964],[15838,"49d186c9b30024fe145cff0d0adbde2772fb7edcf892b493f46b75a08148916c",9.317957166392093],[12733,"7055b135a95d62bd3849d3e606da31c1afdb178dbd09b2bb05bd81abb19861ac",9.917710196779964],[14841,"6ae4686b136779df7bfcbd2e44e07790be10672821ff71efea52c07ef1b61882",9.317957166392093],[12932,"a47c2318b30a008d8a1805dd58394b806c3d463fe55bce2d32ea285f1fa505ab",9.317957166392093],[12198,"c95f6376a325ef875bc6e6fea5a732097e5bf944b830326fe9fec6eaf65412b0",9.317957166392093],[15784,"deddd76aaa80a39f784d46420d51ea5ecde2b8d2a0f8b5e90f429ec408a09b6d",9.317957166392093],[10317,"81c802be30fcce9fa3944ada49b27cfecfaa1a0c685df9cc39155b6ecbe53bbc",9.317957166392093],[6409,"687e88ffc6f320ef9239e210a896d9384e0124fdf38796c20e8d170bfa1548d6",9.917710196779964],[16127,"d7133f14a2323af0d7b6dc7d4817d56b6da884814c5fad436fd7062c1f806e65",9.317957166392093],[14201,"19461e85bd61f903a6bfa1d1f5be418dee7f1c230b4dddabead5474ce5e92990",10.052724077328646],[9863,"946cbe6a42abadc9787232b9d05fb4f282cd0b267d6a8705e6801a29e48528bf",9.917710196779964],[11690,"a8a5013cb88ffc3e2d9eb3583a636883390014d597934881912a1142868258b3",9.917710196779964],[19758,"95d5dd75ccd57b94eb3f811eeabe9e915b9a26ab9ae106a3d1173c62a7b94604",9.317957166392093],[4931,"1574510dc5f9f06a2ff2c1accd371f5dd014ce59a829fb30672a198359bea3df",9.917710196779964],[1890,"472cb458065824ade5a72e5075b340aae0c3c512a0567714a541ce6cdeeba8f3",9.917710196779964],[134,"5e6a53b1edd597e3d831fc1d755e3ee44fbbcfed888bfe45e67f6ad74cfd18ff",9.917710196779964],[1768,"1412ee8a1f66a927ff96b179abedbeb135e060f5fdcc79426c171fad5a877af4",9.317957166392093],[17786,"496b4782a21b6f4b0b85358aa3013782943961eaafe02c2eff67c4ff68d59541",9.317957166392093],[3384,"b41eb76ab460ba9799aaeef44f5a36e2fa0d856ff05cfef1f973b27472d8cfe9",37.981042654028435],[14477,"a6bff832dd6f295c93e09d787fe1e00b973b22d4a04878d49d12e19a39f6b389",9.317957166392093],[8670,"f49a019dca15844002fd82b3769516d6fdd7959a46c37bdb8a538d37686cdbc6",9.317957166392093],[12381,"6cbdce03e2f6493247f5f78ff5c2948ecde929df48b318a6f381dd6794e9c2ae",9.917710196779964],[2899,"c77fc8254957c51585d310d2d5df745b75c3dceac47f89f6dbde76a20ffc22ed",9.317957166392093],[461,"fd57cb6057611aeb1ce10c38a1f69105837161c68720f3bc4d814a4fd722e7fc",9.317957166392093],[7221,"2171639be455abcf75e1b353fcf3370ba324b70edeb2a3d04c450fe2f9648bd0",9.317957166392093],[11955,"3d37d99b53332c623fd4a78622be47b8df9f05200c75f619a9564765a835a2b1",9.917710196779964],[1595,"7b34aa12e0f5a9724bec5a8d4d59536f28dcaaf4623bd5a91ecf5afb8cad93f5",9.917710196779964],[17783,"e5ebb2309d4fd3dbfdf09bf18d25dac5897d5f12bbc453f225f8556218d8a141",9.317957166392093],[19667,"a4853baedf979f52173ddc2c117ae6a403ae7873a57955281e59f21244439007",9.317957166392093],[15496,"fa00bfb06a59419eab611eeee41e78882e942eb10475bd9b7d7f1de6ded42774",9.317957166392093],[11442,"353093856d61e0cdbb793d34c73dd8d92bd184dfdbee11db9fe597529db1feb4",9.917710196779964],[1050,"a90cc40d9a8fa0c95ea155861cbe74af189c4f1c8b410f3c4c3e4e24c18df4f8",9.917710196779964],[17201,"726e3fe96a900a729890d2803734993c5aef8986cebe059074dd7eb24db2be4d",9.647446457990116],[13674,"00840d33e6661041cbba3958b3be64c51f1b05d9095cee710e96dc7cdc4bcb9b",9.317957166392093],[9487,"79e7aa318830da7b9a6526a90cc57dcddfcee9f6aaeb04856b8cb94e1815c6c1",9.317957166392093],[13105,"4837d551dfb8f4c9261c41e6b157d776e19e85f4735c32e13b4799785355f8a8",9.317957166392093],[17161,"a96583985fbcfe94a37fecfb16dec563178db8fc266b160cc41ffe843771d14e",9.317957166392093],[9922,"8c8f7bbfdba614bd39479c98faceadf69e86931990214fc37886c49e0ac2d2be",9.917710196779964],[5301,"d288d5a491685d1351ef252e0aba98d6c023611b9b971074e7510f09538763dd",9.917710196779964],[13730,"329f4c11470123a8043de9319e67301858767aa96b64073134d0f6397b85d59a",9.317957166392093],[4110,"61fe575f4458421f212eb4155a94b497c443e6ac35960cc6aa715626dacbf7e4",9.917710196779964],[17955,"88da53f18212bae58675326bc959773a0bff4825d45fd2ab56f22fc2dcc0223e",9.317957166392093],[7327,"78b6a4ce6e40e4300098b5ae8c8617a528dd33096fcced4996d05098957ce3cf",9.917710196779964],[18089,"48037653423c6baf4f9e78b1033fd606a453bef825128f9290cd964c781d4d3b",31.611834319526626],[9155,"8e8748da8d761987a754b983e87a468c4876e0ee396a8b70b52213363f42c9c3",9.317957166392093],[13034,"85df1e880949f6a412d65003ae4eaead235bc7b69b817ef156a7d47d222c63aa",9.917710196779964],[1785,"93ae59a9b3769c3d88b2e9c065e6f2178242a16cc2774886101c7dca532056f4",9.647446457990116],[3317,"ddc55da8fcbfa2fc763378024ba9da635002e57b77d85399be9bbf6395953eea",9.917710196779964],[654,"1c897f8d7ad982ff80a7de5c58471f57e67347dbcd5b14363fdd0e2f9eb48cfb",9.917710196779964],[10380,"6ac22d69f4402a8b0390a9c5aba7b3628ccd9b2f452f1fadc784d014f96aebbb",9.917710196779964],[13113,"73b800376a89eb39a869dbcbe3a656f0007411f46f8646081f39d21eff97c3a8",29.33653846153846],[7379,"70f8d8a0f9e96a9ed7b048c107079bfd9d97d56f758f50a33555bc40338d8ecf",9.917710196779964],[94,"6510e6637f208dcdb70a0c6b7f01999b96e8b2e5daa0a9ed01e0f809477e69ff",9.317957166392093],[11673,"f5c287cac08c342040fbe05558e2f95e3ee2ed26a90dc4af8ff9e897d7d273b3",9.917710196779964],[11242,"8a1f430aeb5c6f360271f63fafa57f335d61d9eb06009ef5cdba05bc2bff65b6",9.917710196779964],[6964,"19d6dc86d71a82a7f6126da746b126b2c5e028e5586619db43c82efafe0c30d2",9.917710196779964],[8845,"d3c589c74c16bc475c706b7e62a94439776a898264dd7cd8a5bb36349473d0c5",9.917710196779964],[11791,"9cb5371ce09b75a16016b680a54a2e06ba98863b5efab3716b7bddaf33b8c6b2",9.917710196779964],[11251,"19c2b01896a6eab78f2f3363f7ba727fbf0ed345ad39f4a63c75683c32cc57b6",9.917710196779964],[11,"5e1944e9cda15dd300c2448f2411c328dde52aac0c902c4dafa550918317f1ff",9.917710196779964],[288,"5d46eb2ffc73dfe95254b95d586cd2091b0083180eb327995ca5d7b021c103fe",9.428571428571429],[2485,"bbb45c52642d7c8236a9ca277a537122df2ca8dd11bba89f90d12d52e381f2ef",9.917710196779964],[11531,"2028f676f65a5587a8df4a616e0a7a12720d4e867a6ab1d3322b708b480c57b4",9.917710196779964],[11601,"ff2d85387bb7d1ea3cbc0f169e704b5b8cac2095f18e0a695a6069b7909ae5b3",9.647446457990116],[11006,"b695c5dcc99849aeb44da871e096c7829be25b1095e028c23e179bf42b3ff3b7",9.917710196779964],[1963,"271f970e0d9cf07cd8b17efba551a7ae9e3bda0513858a1c284f2e03d4d745f3",9.917710196779964],[2099,"0d69a8bddefdd1b805a51ea5c2caac946c1f4e80bc13f10b5b92bb49a90c44f2",9.917710196779964],[6786,"4288dcdf6776eeb6aec655170026d8acfd38f5a3f3899aabd2705f86325962d3",9.917710196779964],[10461,"5d91114e285fd38b8da81660652caef5d475b361dc61bb89994b2d33991b5fbb",9.917710196779964],[5248,"9cd40c62d21ea0521a85bd1ee79d29eea27604727157e3b67cd236daedf0b4dd",9.317957166392093],[5500,"ec3132c33d6f65eebf1cbee024aed333183d8b1834c8bd1c748c8f1731db39dc",9.917710196779964],[9638,"2384dab09ef47828d01bf1731e338925c9a9f8a986f6f09e6516f2198b4dcac0",9.917710196779964],[4053,"e612add0ab7e6c6850bde9b5dba823dcd21a7090cdd873f302cc56b5ee6c68e5",9.917710196779964],[8442,"680a2f4fd9759f53627125dd2f92e18c1a24d236031d5c4504054a6adfb05dc8",9.317957166392093],[15522,"cdff49b8bd21182e3b8d134600a3de19a9f6907f123ca1bffc8e6e7b007b8d73",17.089005235602095],[16772,"92af532ba7db25c35eb2a27056027440a0d384e41c91cbc3df4f28a1519afc56",10.032829052018817],[5174,"e5f44b8b6d35da1271fa4a3ef8d306d37637f9d64f993e81cc7bb3a68f1b21de",9.317957166392093],[12366,"f75215dcfb7e208c7637751aca2715a86aaab3f52b676717ba8e62f99f21d1ae",9.424083769633508],[17404,"56aeae789ac89036fcb8f796ea01fcea7a65f3d92d058c4567f9d9a974b5b649",9.317957166392093],[3357,"b3588e9e76338257bc83404bf7db6a3c165818ac3884e6c5b002fe0c3795fce9",9.917710196779964],[6322,"04ef99fdebeb0f9829a3cea3fed957a6c890d8a5203b1a505a3b4062b9a7d6d6",9.917710196779964],[16819,"b8f905e1e696e88d5d9313f9ce89f3262885585239673a15fd0df0d6753cdc55",9.317957166392093],[6669,"aa930a4f90ba9e59b4578a989a0c7f06663e63566ad1b7c9c29875ab40bf2cd4",9.917710196779964],[5625,"e8426dac84a7b86e2bffc54e80a329062d5a3b98ded5aca83a2a4889589585db",9.917710196779964],[6919,"7c195020cbefc1ea6a3637844428d0bf6466b4209a5c5236d1f95cd16cf979d2",9.317957166392093],[15671,"ac677c05162b9f7bfed50f0f926fcf363ad832ae380f0df31812d223c4f4f86f",9.317957166392093],[5830,"d5be2c56d672a82d5058a7217e051f177ec4a9099979814a987109c63de928da",9.917710196779964],[3118,"f074696ab83d634b2dc0d0e8769a2099d1e6445f6498bf5954950b313e4e8beb",9.917710196779964],[13139,"b08f8f9afc0159c43c5801f90623d08cbd79b723a79ff46fd97c7c39275b30a8",9.317957166392093],[19021,"1aad5e93d19d650402656b0be07b74d302f6547dafd4bbfcfe9424c6207cd61f",10.02710027100271],[16530,"a606f5161a1ebaa838cec0fb981b0c9fb402dc97fba79a0a08f2f61c841e835c",9.317957166392093],[16485,"cf314ef08ec36fe8c8f46eec136b581f66a79be8e8918b8d67932d6c44cb855d",9.317957166392093],[7067,"fd9315c1c3079cbaf4aa0754c06ce656dc10f942a3567a5247276b9154758ad1",9.917710196779964],[15558,"97cb31ea818ecd09ba09b8541a3e3f09e84e0e920492da63294969d3aa599c72",17.23658051689861],[5748,"4a8898880b92e6fc4c32e510dd78c519d70e9fc25fc10c5107bd8c1381c2c9da",9.917710196779964],[6818,"e133335b075c4fe81a4e2e3361d36a2c27adffdca6b0077e759ea20289512cd3",25.358885017421603],[16880,"cc5e3f383c2822ac5f1bd755e5753e90c6b2c4dc05a0da5b58df8fa7602a9a54",18.09625668449198],[16359,"82d49164d7c37763d3a271f8189a483bc154c7247bfbed2b0892edb0696ee45f",19.25179856115108],[9849,"1e6f6de39db1ba5a3e2424a284376358c8932895514fabb7c9d34f0855764ebf",9.317957166392093],[4627,"3c8965e409eb4d457cf4560167bbf25ee27a93e550b825a4959a23daf91e74e1",9.917710196779964],[15405,"806477c80841e37c43cd85528f9c8d1e5957e6bf7e8c4ab5b1d7439e81143476",9.317957166392093],[1318,"a6ca8ad013ddfe39ed808d7a595982906c85de87d448bb65c7b7251966ea4cf7",9.917710196779964],[7001,"165e5141fc72dc8b99d7f67798b38fb35e1886313087f2dd9c2e0533b0cefad1",9.917710196779964],[7990,"6b5b58448435a31f7037f2f203246f3c251ec0d309de63d76d21eb26630797cb",10.052724077328646],[425,"f2110fa2ce680662e85966a119594a6932f4b1609965cfad100bde6baa3534fd",9.917710196779964],[4169,"e5c4d9f29da4dcb01e95a06aa0ecac84e31d0ef8e3712c68287711144c89a4e4",9.917710196779964],[8943,"8eb00a17df1d253a45620586eb88afcfcd47a159b5e37e4c5337c740392f2ac5",9.917710196779964],[4301,"9ccfd11d18bb5da9fe2cc2625c75520f026169654ffbabb0328f1f5cc627bae3",9.917710196779964],[9959,"c8b629ed168d41ab24d8f683d40f11e0f991389721a4d50b47574cf0020293be",9.917710196779964],[9659,"4c081558edd6c0e8261a661aa372ece9350a8918cd78b4b9fe87d9fb3485a5c0",9.317957166392093],[1550,"ebc87829bf7f60e044a2a2fe24526c5c57e0b0f6d84051a77f450d285c8ed3f5",9.317957166392093],[4080,"8c51efaf85eb91e0ba5e5a95025968e64adab199f6a1ccf4987366d00c3b34e5",9.917710196779964],[17792,"18765325a64da180e70ee5a08c8c8758bb12d43de8fcb6d0e3799bf9be1b8441",9.317957166392093],[12361,"8d45229751a2e1f523cc6d463d90842750fb775f6b7b40d075f71749abf3d8ae",9.917710196779964],[8614,"bc7b15c24b9c8ee29d615148fa27a1dc0e8619c92d408ff5cf8fda5bd8ff54c7",9.647446457990116],[3407,"3358970593286a2717e34e3ba4c32cfafadefd5933ec07f872314fd13543a3e9",9.317957166392093],[3922,"f2c050df25e6c718aedcff5f8b47704fac1dd49f83c99ac22004fce1da6032e6",9.917710196779964],[2605,"7aff98567f58c31a0506fd55bf1341c7555719332a6df0fddee5f69fd6dc1fef",9.917710196779964],[19242,"4a257f26ed4a34f449da6a263c5962d86dc4d540debc7774de6bd482fcfb1e17",73.19778188539742],[1783,"75f9170483b93a98ff0dfc85417ac040f2643e49467212844d1b2d383e0f58f4",9.917710196779964],[754,"56fe97ef267656a4c6eadf95ceabb4453b04b08b78fd343b76278a50950bd6fa",9.917710196779964],[3048,"b5b7720e0e21513c4a79fecf1dd7a00b542a5268d8e071bbdbf3ba94b3e0fceb",9.317957166392093],[18659,"a4b3620c6faa90a22719849160f13ec54930bd0182134ca82264348bade2512c",18.109734513274336],[545,"c46b2be3ada56b16d0a950883c87daf8fa4c70e1d96c9ea8289e9aa39a6852fc",9.917710196779964],[18259,"91b56768909388d17c11578723af047ab5a3ec54462c43621fd40fdbf7d7cd36",9.317957166392093],[9265,"c5035b49f68a8f5f1c7cbcb1067c72f1d3f74d7ee8cde8acef924c2b64340ec3",9.317957166392093],[5150,"202ba9ba18dfaa7fbca0fef71dc84d179f4f8f8ab1eeacb022daea14765049de",9.917710196779964],[8978,"0cabe8522563c6c78343773a5bda8667e67a03cee08efc222220c6111bd7f4c4",9.917710196779964],[255,"d0bebbe7efe471fcd21b0837bba2341c6416043f7158b087c6a299cb8c6a44fe",9.917710196779964],[11023,"5d99e864683bd43dd2842f9dd0ab600bdc323bb4ef3df5ac53811c6c2c43ddb7",9.917710196779964],[18159,"407dfb0e2be4ede150007565e06713fa9afd4cd891e9996698b42ece0c3b2539",9.317957166392093],[1935,"bcb74b3eede24f57d3951f1c4f1d1b2a15af84b4364fa4e46d1bf34c6a0273f3",9.917710196779964],[5512,"1c027d94ea7a8b8c137676d463537a7e6b2ce3b0d96d9861dbf83229435f27dc",9.917710196779964],[15695,"07462547fec223d05e31d644ce7468c5055d6f2cdffbc960dd7bdeb961b89b6f",9.317957166392093],[3379,"f29e23a87944cbd495b580559309800086bcc54f12a803ed49ede4c2ba2dd6e9",9.917710196779964],[14820,"905a91cc4af19f4232fc218a612a913a3e91a79df9d2ef317e4af523e43c6582",9.416370106761565],[4281,"b84a3d5c10812d9aec826150c0953cb0d128f2c076e150f73ff281f4213ee6e3",9.317957166392093],[1405,"783c4b970b9ba8fea7311364d1ed182a80576f4cab4757fdbe928cb5accdc9f6",9.317957166392093],[9799,"23c0bcbd0bc6ab4a901b077cbdc9da601add2216835faf35969c1ead1d1ea5bf",9.917710196779964],[16990,"365fe4f6af070f50a4530863b82adb453c5a8422a995d2e65631bd181a914852",9.317957166392093],[5762,"008ac6d9715ffacad61266b59ac4ad3587b816f961a0a3894107e87bd869b3da",9.917710196779964],[2224,"f158e17a0e987d0bee5752c6d0a14293d0eb22fcc36dd6a12a064c507c935ef1",9.917710196779964],[8759,"8e4733ab660132f62811da52b74b8581d2a4e1896da8662c405fcbb3d1b446c6",9.917710196779964],[1561,"73139aa85b647078af0e54df619c34df9dac397efb8e6501242f245681f2c0f5",9.917710196779964],[13185,"9e087b2a1a46669a6768810ee950eda9e18a0fa33ad85f46b6299e8b107c4aa7",9.317957166392093],[12383,"c6496ef32548d15fd967e0bc5267ebf7fa37b8ae03225a387338b01be683beae",9.917710196779964],[10796,"d7b5f1aeaf232e840808b8aafddd78adc3cdb8e0127aedb55c1d067677cb51b9",9.917710196779964],[19491,"89efa0fd31f4b006f8a38a27cd6fc89283aaf4557324936d7da3b2786925b00e",9.317957166392093],[7810,"9764db4fde32123bfd6785209a5ef7549a057c14134c1733bd991da878adb5cc",9.917710196779964],[10803,"aad88ddaac8a598d42f976044336e9e2ea11e61e8cc2635f77a829acd97945b9",9.317957166392093],[2071,"a67f7fc7e3893a418cacef08f7e3463a1550b7167ecf5bdf518a8d6dc5f970f2",9.317957166392093],[382,"591428f336bdf6bdfd99d35bef648cdc89c83cc1350c104fced71410b5e07afd",9.917710196779964],[2715,"dea24f721eb8af15e1c728f7c501af92df955dd9e653afb2205f13f0069e55ee",9.917710196779964],[18944,"f0a78f39fadf31289d6e83a16565a60d7c0760c17ea9e1afc4abe11ccdef4d22",9.317957166392093],[1098,"fbefb737f063eea56491072dee88862cd70525725ab59878e49c1a4443d594f8",9.917710196779964],[12191,"96904820fe42df3f2d50b11979fa5a57227a67bdb49c3525f39c163fa47c1fb0",9.917710196779964],[12950,"a8604d0a37ed12d552133a5e05237d9566cc2986628a9bf9cd1363bd0777e8aa",9.917710196779964],[10598,"d6348097195be6c1006f860ff374fe24da1596fd1de653c4602e4bcca535a7ba",9.917710196779964],[7634,"edb43ae05828408b76d0103c346bf8335c894f1330270a10f1648132f0cdfccd",12.525612472160356],[16104,"b3665903305a5a0890b19f11243bfafb48c920f49c956f735dc63e6f48520666",35.831932773109244],[10851,"2721f13572e6b5dc1dc75d1fb01516610b6191fb42aacc5b4d039c9907cdffb8",9.317957166392093],[781,"50edc3d0c3c2d852e2d299297a2fa8757e4150679af37ed4f9b7b4006a7ea4fa",9.317957166392093],[14160,"a85bfa82c799ffc92bb4b9ce2bb3ef9e7eef9a241eda3b77e2db65719cb13691",9.317957166392093],[14768,"27ccff31e39268831b0ca5392c1273aed22c06a95c0cd878b1605fbaf74f9283",9.317957166392093],[17372,"6df164e24cc4f8563d7300f60389b13397c58de6d15f1f4cc68413cf604b6c4a",25],[11400,"0779a3ef1c232952106570eaa076da5a08823469afd9bf1d79e05020785c56b5",9.917710196779964],[3142,"fc86dedf79727dd847774060732b12c41fb5c57a5f3b86fdf8246f129cfc6ceb",9.917710196779964],[12195,"9e55961e060ce1dbf330240523f70e4496b0ab3a07c4338207a9c458b21016b0",9.917710196779964],[11267,"161956096751137ef8b2692219e0cdaf71d199bfd2145aa3bb5d53e0094c3db6",37.935483870967744],[13903,"29dc5cba39bd99f22eaa0e58389546079e05042984348e0b5e3d9a468862fa96",9.317957166392093],[17279,"7253bae0d43a2cdd9190a5fd6dac3e53607214ffb42d56dc8229dcba17809f4c",9.317957166392093],[11569,"f6556a1ed83913540bd3aeb240349366edb43db21ccd01565a6a2198c87f21b4",9.917710196779964],[7493,"15f578ae7686c831fd69cbea56b202b71c56b9e7b12edb027ba26a18f297c7ce",9.917710196779964],[1190,"020fecffae979f1909a586d9aecff10698ee7e6be5029d35b92eb58e1b1514f8",9.917710196779964],[11300,"65a1a5c4a5ce4a526c9786915bd3f38647384482075d95ce093e29989f8a0ab6",9.317957166392093],[4259,"dcbd957c34d008cb92e937742c3401dce73dddc408a0b52e8cbe64e4a54e08e4",9.917710196779964],[6118,"da98702ad8d2896c7d6ea26cfa2c0e2c799e91ffa836fd03bb166e2b9dba52d8",9.917710196779964],[17860,"bde9ed7571b04654e6695afa91ed091174b0c0f0e6168b0898db8a4a68b0f73f",9.317957166392093],[7298,"ca723252c7ff0ffdf43da402a4f45cc1eb4551c0d203ffa26db06da158c516d0",9.917710196779964],[6204,"6adbfb02a513d373209ce3e14a23341413984e285fe813a89a2363ca8d0cb9d7",9.917710196779964],[7012,"7830e604ed11171565d3f2f0f3c92b4b1c0503f8e2e9bb990a4864358b26ecd1",9.917710196779964],[5637,"4972943331bc9cfdfb52514e5df7b96d3bb6a02c2cb538c1d26c7773a4636cdb",9.917710196779964],[3475,"17f25277a142dddd9a5ab50c4ff41812e07897ba2e59dc4a35e0afee630633e9",10.052724077328646],[16802,"aa54b7c1a37fcefc79ef67e6b80d47b0decc847aba50eb2167e1108a485d3d56",9.317957166392093],[11509,"c439550d71255ba74f41a0782994b3c54f36b250633266880c4eca80c12076b4",9.917710196779964],[3491,"a9e02a743dca8bba1d881f8d0cc9f745a6532b8727e26c420e7d9ea9dd2615e9",9.917710196779964],[2262,"930f74d3168b9be0bbdf5e290988c3af22d67ff656be16358a978a4c4ba730f1",9.917710196779964],[3279,"4a170565a62fe3c1b03a0c0dfe2cc08098e7ac52da654f7d61032cf316918aea",9.917710196779964],[19748,"a4fdb8f8f36e34ad14989fd13caae0176a9aaf779404229d164970bd8f24e804",37.936395759717314],[16507,"b34b196acbdf7c1e1ae59b0fabab70602e68c1bc1aaac0f5a9bd140a9e791b5d",9.317957166392093],[11401,"9514fda4d638ee0534f9881a93ee7725fd560b7636839baab9d14a55173955b5",9.917710196779964],[4499,"fc17d24e7d2fb9e977f9285ca3abcc5f576d03e109ff2a2ca1414914db1168e2",9.917710196779964],[18187,"d40924d1c93b74e0ec4c89f034f9ba9b0167c77f0cd65a18be2ec0e9b07d8538",9.317957166392093],[1620,"836f2a39307e1582f90d280734b28633fc32f667ae3c6219ad7affaf373573f5",9.317957166392093],[7740,"1f3d19aedbee4dddf4019f9e2e8db393f77ea2d74285529dc2e8e5a5a3a23bcd",9.317957166392093],[8035,"d3e89ec1c2e16747f3b1e481d69b866e6c46a644479a43c6948f72e326ca56cb",9.917710196779964],[17743,"9d3bfebef98e1d934e4328504be0af873ed0915be6cd4576775ed0e6c7085242",31.05169340463458],[10330,"885a89fc660e59fc78c24b28db75ca570ee76d32269a8962baee67a93b4f23bc",9.317957166392093],[2418,"42c4c266a3c8cd9706beef7e22e5c689cc0ce72a2f2fcc137f397a6e44e257f0",9.317957166392093],[13133,"9ae3b902b478a0879d9a2b472fe53bbf7a68fc4bbaf48f3bb0ff593b73664ba8",9.317957166392093],[3241,"5d9688a161f435ffeec1add9b8729ee1f2fdd71cd6810f24fd25b360dd3bbaea",9.917710196779964],[10462,"b87754395f5298dbf2c07f83d231700e8a75379c8ae86365358d3845d5135abb",9.917710196779964],[7606,"9e92e3ea9e1f0458c46bb0cdaa7176662050a2d1c4cbd1b32e2350221eec2ace",9.917710196779964],[14742,"72ac9366ef0a18f9cdfe6e9d281a33c93e67de8e12eae2e1b0d1bfff03150284",9.317957166392093],[19376,"205bcb452aa05af518852a38451d790bd192409223cce347b5df6abc87babc12",9.317957166392093],[10845,"20d3cf76ce041cb8b39622849ccf4423f71fc91aecf50e3e2f9c71c4adbb06b9",9.917710196779964],[753,"2e42094dc65d097d033926d3699d0ac400df8fef4ccebb793bee9502f9b6d8fa",9.917710196779964],[360,"806f4d3902713bc1f541c75d5064e48f0da344da453554a412d0aa5fefc5acfd",9.917710196779964],[2566,"695cade054107867f6fff60f2a49965f6cb60f34df9658034b25312d261d79ef",9.917710196779964],[13222,"3a1618de711bdfb49d57fc2ab6213cc24b216ec21be4496c726f2171c0b877a6",9.317957166392093],[3342,"f55f0a44025b6bd5ee2389697bfea3bcd6f976adf21888b7be56b803506d0cea",9.917710196779964],[19071,"9a3e10064208f0f0442877fa8de1dc0f968681d630e6e7018b7a387a2cb6d91d",9.424083769633508],[11252,"0c692e9381d53a8c7b93bab308fffb66f906e34cd21e7811c37121f80e4c57b6",9.917710196779964],[17714,"64553d08f3aa0b54a76353bc5837f591bff08632b66e335cab9cb23af3c6f042",9.317957166392093],[18720,"40169b18558f2b514df070829ed93dd05a05d0ecc145e5fe009f5d300d65ad29",25],[10184,"4aa927d2558ef996981c1ad530012748780c64d15e4ac99d47065f11e74b21bd",9.917710196779964],[106,"21855b3fe16e0f556faea4713d80c1b8df01ddb9dff9fc04a9bcf697c39856ff",9.917710196779964],[14326,"14502f6a1b03bd995f6853c042f055ab62c7ab1c6ce53079985eae66f63ce98c",9.317957166392093],[18031,"d75365db995c4bc072f644fbff4dc1cc28d927277141ea76f12e1211af4ab83c",9.317957166392093],[15497,"a0c7b43d22dcd34f442aed72d10cb015a164c5965bd0064df127953f48ca2174",9.317957166392093],[9285,"c8f6c41a240d2d97bf45f6bff08de5bf93a59859d35d29014630bec5ebf5e9c2",9.317957166392093],[17020,"1b16954c0a70efa61d754b3b808b6e09166602a7245471f327198f9c1ab38d51",9.9869192561356],[5679,"c17bf9013f3a2caa4803468184cd02d8e5680dfa04964cd6c1942a4ea04e2adb",9.917710196779964],[18204,"591416d6573deffd4cbaacdebed9e55ad6c563ad37345c5f924908b823791038",19],[11311,"8790c404af657847bb3644660bffb7ec4f147a307631787297f435010f05ecb5",9.917710196779964],[393,"d690d630aff1bb0439a49721377b32cdf0af14b2e2e91a634ff38c2adff864fd",9.917710196779964],[9026,"b3e5b794dc6b84dbf8548138006bf6eb414c9dd38b6587dafc90a2bc78e69ec4",9.917710196779964],[9649,"11a1e2343c095f7c0460c45e40342fff775ac83b7281b61417787bf88c07b6c0",9.917710196779964],[9378,"166e4c5a756a3aefd399084240ca36f6319f1f738d53544936f3c84b9a8a62c2",9.917710196779964],[16698,"4c383470f34e6d5fe6fdbe922aaeb6d7c3990cbbf61e48ec4c50d7b811a58658",9.317957166392093],[15949,"53d2031f19f419e8049ca9821759d160c354f5b30d39e437ec7ac3984924f569",9.317957166392093],[4163,"1b71d53bc5daf46d126540b0daa3cc7c7d8bcac55c384ac6c52e9719690ea8e4",9.917710196779964],[7433,"76719bd9a29b2ef6bfcfd50fc1331dc61856e39b239f65e039ff69f6bfb62acf",9.917710196779964],[1639,"23cce3663be140efe0021c6d1ad8053722c70439728814cebf541113a7f65cf5",9.917710196779964],[1671,"e2a92d1bbdf51c51627e43061156dc01f45c3febeb22e92953eeea2aa0ef1ff5",9.317957166392093],[8951,"f619bc18c6906e18e503e2ac354aa1d0b175d90b94a0ccb32a0df7e5e8a21dc5",9.317957166392093],[9681,"56006b5f76535fafca97bfce49fa2485b0328614c92a469fdf965128f4c084c0",10],[18598,"8925c23bb3bc692bb2432adf1cd873d0eb8d1d19235cfd378b3c98d92513c82e",9.317957166392093],[9568,"2e83962f9c1cc53dfdc3b5096272ab281117213a7935e37771cce08e220f31c1",9.647446457990116],[11395,"856e978203ca52a626b7b00dbbc3128a30104767e24216876d70daef4d9a63b5",19],[5632,"79978d907ee9a104393b571ada76bf77fe7c6b3bf23183ef00cecd39a8c370db",9.317957166392093],[19537,"48d2c9017753ec8b03af555d594f12f02ba1cad15a09246383012e32c6e03a0d",26.17687074829932],[9795,"9d20b9ee92dcda0d6d49c47ee53def83531e6819f98de91b858de66a0f80aebf",16.07111111111111],[14009,"f62818f66abf34cc7786362fd6264fa58f32dbda1e7db868691286c1e5e79494",10.052724077328646],[1539,"460bb253dd8b36b0c987e08f7342c9c4fc97f872cadd2db2bcbcdbf92ae1e5f5",9.917710196779964],[2720,"19de5d628a86854388a5947f1323bd66673328b1b6ebf077fb79130dc32e49ee",9.317957166392093],[16891,"4a7888428d58bf451dcb37fc5eaad80086adf150a4599ff73b2ba3c3cdf77854",9.317957166392093],[13424,"0299a03272075e30fb1ba1cecc4c64b4a7a17162d28357cddbae6ac44e9eeea1",23.88170055452865],[9330,"062f0efaf838b64dedcf0ccc0fa347b86800e533d260c6a44f49f8945198b5c2",9.917710196779964],[16060,"7ea456808d2a889e9cfa144aaf2c8f89da3af36927c2beb3bb4b438e6b5f3067",28.126696832579185],[5209,"e488d1e34e78987dcd44d299951797ec4da7bacee5b9d58ff5e33193c9c4efdd",9.917710196779964],[16430,"8640ffd45e609307fc607b3a95bfd69e4945d6ea7350d4c51cb86ac4b788805e",9.317957166392093],[11130,"fb74ebbe1cb464d6962b3adab1203235b41b12fd4955073e3c6863a0367f1ab7",9.917710196779964],[10115,"031159ad364384bd26c82b30b99e4aab0faedf8b97fbc4f324f292f493879abd",9.917710196779964],[17696,"57268ce6a92cc20561dd32fd07d18a1ffe266c314ae57068588b984ccff24843",9.317957166392093],[17283,"0e64e297a6c8a451a7e2b5ca01aee5259222de14fb73534b3cedbcd6ab49884c",9.317957166392093],[2752,"17c9deb92f09441c75631363c6cad91e130c14199601d98220d65db5f83c17ee",9.917710196779964],[5352,"71d07deebc994d426db8df8b12111a1b57a83c79baa3aa10879c15ded7e623dd",9.917710196779964],[11895,"1997d88f286e99fe8bbabe0985d04cc5185c0297961543109562bc6c890010b2",9.446224256292906],[19684,"ef67de6ceec01aba54357020dc942154ccf03ee1d751d6373c870fb22a573f07",9.317957166392093],[433,"6d13e5dc9ca74a8fcdd62b0c642be9c28d4765efdd9ebf9d985cacc44b9d23fd",9.917710196779964],[18707,"98e5b067d9bdadab71af3e1ef9d811a0c64e32079ba07ba0551583cc0729062a",9.317957166392093],[16866,"d42ebeacef10182cb7bc6bb47d0a767211acdbf2e4fbcb471b7badc64384db54",9.317957166392093],[11287,"09fd149dcb14c902e3a6b8704a4a15d8c60597fcbd3d7343b9c20d82b5f51eb6",9.917710196779964],[1295,"c16d8f34fb50428980d0f3e77c2979d754e68209d60c7041193391d3fa6667f7",10],[16631,"41b03a6b02c6f8cb58f2ae18d30435521b5398efcc551e4f068ee8b73f0c295a",9.317957166392093],[314,"458fbe51ab3bb44a0ed852d16db12a7412e60d18a328e0bbb5a10d4f7424e9fd",9.917710196779964],[2004,"adb05174d926526a569289c122bcc48337ba13f88d3a52861ec3306240e400f3",9.917710196779964],[6999,"88f029f7536e77290a280f55eb5a5259a6a8fe13728b9f237ea65800a383fed1",9.917710196779964],[5764,"e9e7e2467d433bff441114d0ea6683d87c70f6c7b46ff4faf59564fa809eafda",9.317957166392093],[5559,"09395ef299c11e7d0a65428f02388d84c9d7c439db8f36bb16c4a81de841dcdb",9.317957166392093],[12543,"966660bfac91541ccf50b89382c5ece2902cf365a8ed0ca31c60511dcecaa9ad",9.917710196779964],[8214,"4876d373552f793693f69d0cee58cd162a3ab873c9072f7f747ad2b77a6ce0c9",9.917710196779964],[2194,"fbf87676aa6a49f368d59fed52cf4da1f73db1e9990a7c0472b227806cf296f1",9.917710196779964],[5128,"f6b1ce4702bcd8657681334d991e740ab6066abcf2f17c91e77d049a83536ede",9.917710196779964],[19212,"a08699aa548517d768fab713053937863312c9ac7349c270b40a02d2938a6218",9.317957166392093],[11158,"06f587a36c148ec13426f4c5f2c07ed8b2629d20b5508fe542d7414178f5ecb6",9.917710196779964],[16450,"6ae99268c5ebc41d3b14c200428e83ec2d27dc27f42225fee4483a91b298355e",9.317957166392093],[18472,"5eb62434da869e5e660a673b775c0c0d9cb1f24bd51d5f382f1163c5277a3432",9.349282296650717],[18423,"5e37eece4dbf85e86d51a656e9def6393c093d558082363289427cc0489c2233",9.317957166392093],[16472,"9614e6b7c2ca21006f1ba6d07f1d1443abbca79f32d77d3f6186cef3f511e05d",9.317957166392093],[3252,"3b352c5210a7a53124abf5d9794a73f8f6199371f5c8794c654e7f16ab92a6ea",9.317957166392093],[6016,"c2c52482a0421830b93800aebfaf33473dae259677bcf2b2a724dac3866cf6d8",9.651245551601424],[3266,"6a54384d0ae9a33f8f1e20eaafb620a7e4d878fcfa3cff1e3dd45cf5cc1b95ea",9.917710196779964],[5052,"99a6f0c82cc66660f9ad6b9cf0303cddae2256ac507bc302abd89beba512dbde",9.917710196779964],[1522,"90816cfe36511d79784534853e6e34e547375228a68d62b11e449b88d6c9f7f5",9.917710196779964],[3799,"91855a14d72cc918c25fe6256f14a7926ae3c7a73c2b18b5ad5eb8d3572af8e6",9.317957166392093],[14041,"9439c5c35c21fa7e21607f6a99c406b60c5f9fd599015e7267a2aad2a912d693",9.317957166392093],[1339,"b3a377ba87c7671eef14039076cb8740716835afab58462fc850b3d18cac26f7",9.917710196779964],[17928,"d10ce7b5f96ff5f9c3e621a98a81fc10402b5850a66bc529ee31c0a7d938b83e",9.317957166392093],[7195,"0ba6e060c7494beb00196eb1c1d12c29a7858ff5bc7e8b612a2cf8574253bcd0",9.317957166392093],[2662,"b52c6d5e65381fe40b36121f39084dee210e6252f14a636b63a2b92ca7a9c8ee",9.917710196779964],[17566,"1c40eb15306df65c5d9406b05717fd260ddacd64f0090c709daf2e82e0c10046",9.317957166392093],[16090,"c144cd4509b73f67564ff354eb35f167563de643f52d60ad57ecbdfbe8347566",9.317957166392093],[3341,"acf0cfc9ca6e75ef0cdf5aedb22f9c1213be061ed099eacb6f0bc7a9b05f0dea",9.917710196779964],[15455,"f79c9ef45748379a950207fe6ff9a1cdda8674f284ae21818bba1073f12c0e75",9.317957166392093],[1527,"62ac73f54f804cb5809ed89f11f4f30a29c61f6b6ae7aae114075142befbf1f5",9.917710196779964],[901,"9e93ff2c4a96f1fc90f1ece452d50a8a9bb4426e1d778aa68ef23d52d97bd3f9",9.317957166392093],[19231,"ae798ff9d58821d5da41436b5b203280f43e1ecd4e5f67406964b5588cfda517",9.317957166392093],[1076,"1aed5659389f98cf59dc9506946f064d03202f253b728824cb1ed9235080bff8",9.317957166392093],[13544,"a790365dd55f1f6a5eb89a54bbcf74c72c042dff8fe4954e4523c864e936de9e",9.317957166392093],[12913,"eba37d5a955afc80b75804bed967009c780b07c8d0f8567a5f9c9979355d3aab",9.917710196779964],[1834,"d8191eef2ac97c8cbea4d326d99708f9a91ce2282385f59fbea3fede960509f4",9.917710196779964],[4580,"b3f43c5ff1480484c0c42a52dc6ac77a3082b34e9f496a584a592c29b024bfe1",9.317957166392093],[3752,"a641fb481ec8c73a54239fc282817f04b64341eac0fe4faf607bb43a5b5d3ee7",9.917710196779964],[10651,"81596b0f253f9ddfb701b4a7f4a8512647d5a78a9b4d5e29fdfe3f650c835fba",9.317957166392093],[4998,"fb254bc1625bbd1b033aea6e54c9d1a27c45db1256eb33b9396385e6f44032df",9.917710196779964],[18536,"36c2f9ebff9037d018353bb11940d97e0120e8419696c09a2ddfb498ee5cc430",9.361256544502618],[12965,"f2c77119da18d03a7a65071387e14888648233297a1b4c577f5feb715551c9aa",9.917710196779964],[14182,"4d5422a4b65c67a8ab13e72e14adcc0965fab383f21931a1d848e7ca7d43d090",9.317957166392093],[13292,"59ce1783adff236fbbad9359f1195247c0eb88c73582904f4026e81858eac2a4",9.317957166392093],[4308,"e9f2efac85f260d5f64db4eb7258a26c8d950b15eba8dafdfb806a025bddb4e3",9.917710196779964],[2795,"297d5b63b7643692dd875d12ec52f8b9a0df89169b54e2732ae2f835c789bfed",9.917710196779964],[12024,"a22e77dc75302ee41c33f011ce6c0d50ef93542d5a6b37db983c3f4faea729b1",9.917710196779964],[18915,"1e59b0efcb30c1cca8196af782edab8e29c4eae09baf66085e7288aa269ff022",9.317957166392093],[15989,"680558a94772622d2f6a8624e06cdbabac2f204014f7cb7385967d5f57bdae68",9.317957166392093],[1573,"46f1387ac4dd66a252992a32458110e36e51545af5890dffb911ae1a4642aef5",9.917710196779964],[13382,"c664a1ddbd41407ea0c8d1433939ad23d389febd0e78cc690cda7867694abfa2",10.029095337979566],[3080,"0a4803e3d1d2081c8783df169d2e27a7b1a75c6d246422647be1b533dab3c4eb",18],[19423,"906035732215839c415b9c128f783930edac5221a03c5d2df182e9c94f51bc10",9.317957166392093],[6717,"894a6fdf65330cb64495ee3b18c4e4dd751b1ced7c5e0ccdff29d86ee34dd4d3",9.917710196779964],[13107,"b03adaad1885ee44af049a5c110bc583e8e924ad94ef069ca3740f73bfeceea8",9.317957166392093],[6514,"bbe0e1b9a6a569cb41dcb6dd5bd50df6ade90ab4a464a3a88a9a54efc49a50d5",9.917710196779964],[12692,"a8e1d933e3efb24bf39ffaf0d4924a40641ec8e7f4e6fade18e3d3fd1072a2ac",9.917710196779964],[6730,"16b2a8a2a51c30f09f6372ce2be69728f81c3fac0434c99a3a73ab35766dbdd3",9.917710196779964],[18064,"764ba9398b82b63f1786670542b65c4e16efb3c551cf89e89bfed2d0404bf13b",9.317957166392093],[4501,"e395b2d007561a9851332794a22ff153e15fea0e527580473f6d54af0bae59e2",9.317957166392093],[18516,"71023eb510ae13f41e0eab3f4dac8c25cbb8921942dd64bc5264827d48311931",9.317957166392093],[6201,"9497782cc532a2a0274f8d16a4c38d14684bf328164a3493b5c9b2182793bdd7",9.917710196779964],[7254,"f1f7f781207b1445f5b8a3e3f8aae14eb695745c04bd12432bf7651011b658d0",9.917710196779964],[1952,"5839c441e3fd87dd9b0a0fb5f61c5aa422e4ca233cd56496b295d6fc4f2056f3",9.917710196779964],[8082,"5f2796b1f2c76efc175a0e41586d0b518db5b67a73900101bf444238de89e5ca",9.917710196779964],[5368,"6b73a55b21811c2d4d403796c951a5670810c2e9e2cbcd01ed8c822cf84e0bdd",9.317957166392093],[1092,"5409a556c2cab11acc49e8ffc82a9ff3b1884bb127bb8c644ecfe844e1f39af8",9.917710196779964],[6563,"2542390f6f86a4d149de1dd61491b28283aded9d4f633193a1b9a32229adeed4",9.917710196779964],[1966,"fe178239e2360edadf56d6a4dbf28d4f4bea39dad5f06182191020cbbafe40f3",9.317957166392093],[1392,"a2d9ac7073a7d65a3f5baf92a0cea752c993d3d7c680c0c1b15ccb5c91b7d4f6",9.317957166392093],[9100,"66614cf993ff15d745fdc6667e40c81ba848a03d00ccf25412509e28afca2ac4",9.917710196779964],[5032,"9a5721cab0348febf724807ae582de8de1cea99154fc564388ff8855c5bafade",9.917710196779964],[9130,"ef7b172b85b84547ac017c096c4a146cde11fb99525719a1f675433eb2b0efc3",9.317957166392093],[4635,"4d8f167c903cd46e68ca15658ce70f7325f72fed6ebd144995fdf61bb53667e1",9.917710196779964],[17863,"51c56b8b695d94adf3d902e238b6057cb408a79f83bc45de3e0483eab262ec3f",9.317957166392093],[250,"e93f8a101ac701752bc62af6e3119c030f5226f5ab8862659e7156a209424dfe",9.917710196779964],[4645,"335d73071a89ae277bfbd13cbdeef5a83c9e7b04557f1ba7cdca2824fd8e58e1",9.917710196779964],[8766,"1080fd9ef2628e81c9b3805029e6be7307a7421c6a32c862d44c59cd01fb40c6",9.917710196779964],[2240,"ba0a1de9825a862eb956833809c27c89368c7eb3e8d16f7480fbd6bd941b4ef1",9.647446457990116],[9186,"5f56f6a139e3962f3c61b77e1dec75674b14073a70343819b5467f5a215495c3",9.917710196779964],[9332,"d3fe86a4031a8dbadf279368bf14a72c531b9fbcc82c7b62d39ef6388154b4c2",9.917710196779964],[11507,"0b2cfa2e29d310d9faf241e2ec91967a000cdb2209adb5ecd227077ccc6e79b4",9.997888067581837],[3593,"43154106c0dda1ea69b39b9e647a4501a6516f35a5b4e9a72b715e6cc2775be8",9.917710196779964],[11355,"b2de86a5fc836398aa8c90395ba8bca6e17f06a4fc56044e3344eab85e49a1b5",9.647446457990116],[16032,"88ccb9b01478a67219aca744ac009af1b686fef12a4ac067718de78efb93d667",9.317957166392093],[16440,"799b47d1c593f370d1c76974615a1a955031d2398d5c7f5ecfad2402fab1565e",36.807291666666664],[8707,"1c2ad6cbd709ed20babbc320d0c516067c9f706cf77894caaa6c3b0b435da8c6",9.917710196779964],[4079,"4f57c50ca2b214a5877d7ac6a84d2cc1d2db4dcb6ef7de7f60eb3e88797234e5",9.317957166392093],[10810,"4e40e3f2fa7524038917b2162743366a222227c89e2347d2b6d7f1e3486638b9",9.917710196779964],[15675,"791a9ed29c60d9c805d67e21e6c6dcef84fd2b85637d7645ed749ce177bcee6f",9.317957166392093],[462,"146cb9001577ecac7b1243ca622d9227ff016e167af886ba993602297107e7fc",9.917710196779964],[9036,"1e30043c91e60f08e576feead89a158e7ee9b65b44a396e5c47a6adfd3bb8dc4",9.917710196779964],[4448,"d4ce2d4100d5017b7d1487506173109e821e51a96b95ddf782c213dd0a88c3e2",9.917710196779964],[19476,"5268db7e59880e3bf4f76cb20d173d94ab45a9029154ed83fc4969fa607e3e0f",9.317957166392093],[1924,"5fc6b83acb3d536f22fdd33a50ca3881d3327d27f7a3a7f380773ed3ff9585f3",9.917710196779964],[432,"81db7c7e557d8ada2d601bf8c4139c6e6afbb2d14ff6804cf13bf366d30a24fd",9.317957166392093],[1583,"117462d707da5a2a816f95c916fdfea621c52f535bf085fdadfabaf443e5a2f5",9.917710196779964],[19079,"4647e9049873eb4eea92d3d29473edb6f0845b8c0a453400da64603a9b7e911d",10.052724077328646],[17843,"c037dffd5827f2e2f36b5bbb0a3836516022a70db8cfdb1cf8d2d263d2286340",9.317957166392093],[12427,"78bc0ab2ea83386642a5bed7e026db6994c69f6cdff61e843affb6350b7468ae",9.917710196779964],[4108,"d5fe939a2c2d899520099f416e226e12a055b3dda9be44e6d919d24742b400e5",9.917710196779964],[17684,"449b7c8f9dde5dcf8e3f12e1ed76da8694ceb6d4728dea54db7b211f995e7d43",9.317957166392093],[7834,"b50d16b377c44710762fe7de51a986bd775f82b9390fb861eef06530212b92cc",9.917710196779964],[19105,"ebb767f9cba08279edea73ab2b03c2e9b847fd3342255ecd6d3f6dc64dc98a1c",9.647446457990116],[2583,"23a49074a2b50b6a25975e0158f258cc9d8bccbb64304a5f380184a82c7944ef",9.917710196779964],[19358,"1d9cd1f4b995abf3f0c68cc60a5f683c0fdb46583648803c981db5ca3d366313",9.317957166392093],[17589,"a7b6579d7425678ed1f70ae5175a2f86ac423366286354ec206991c1bbfb7145",9.317957166392093],[5580,"068dc102f180a98940653e16e84a1d500910f014f9ed3531c14e91f18ec8b9db",9.917710196779964],[18097,"d50faea049745971ec1bed0e54b4093d840427907e68e002557502da2748063b",9.317957166392093],[12981,"08d324bf3d64a14d2c17624dfd9cde9ffd5d229f2be1295d25e8b2de4c09b8aa",9.917710196779964],[13491,"8ffb1953e4564a291a00f7cae48b0eb032229fb8f8ba9a03d23aa51350a50aa0",9.317957166392093],[2565,"f563b53b2ba52f1e3e6c633f5371af8b9742e67b2e0de5f9427778c5ff327cef",9.917710196779964],[14306,"1e8eac58487c0ae8be40e57e79cc1af3de7e28b426d4eb028d458969a5e5718d",9.317957166392093],[6013,"0396fa9f529f017769c5dac12ff40de8ca6b5c369ba110f710f95ac5d4c3fcd8",9.917710196779964],[9384,"39de2f6ba9cb991cb9a62a5d55e395b4897d483982096356a5558bb424f15bc2",28.149732620320854],[19719,"065b781c1c487604ab8e2051d7bbf7465edc8bf9994b7892482910006a721006",10.052724077328646],[8009,"f26635eb18bd737f805c23bdefd72affe107a319434f560914c301fd455c79cb",9.917710196779964],[3034,"1070255bec636ff108121743751bf62596c0943378d73e0edae196e4416d14ec",9.317957166392093],[13396,"b008bb73fbf31b1586a03aa6381022cd013d5b1ebe2480760e39646713eb5fa2",9.317957166392093],[9345,"ceb962bdea1fd6ea977ee8f0d2f38374247d42868b4699a4d849764113619bc2",9.317957166392093],[4549,"cc83e3ceb3ae4d29e39602cd3453f4f2cd32e535a6bce68b5e35ceee62b502e2",9.647446457990116],[8206,"da04f9e84fcd60fe2caaeca25bb1024c6f8a9e650223933aa3a124668cffedc9",9.917710196779964],[7613,"1f4825e900aefc06f16bacb8da179dc215fad95f7d7b6527a9341684af1b1ece",9.917710196779964],[12929,"3e1d3e91de42bb1b38bfc4f160ea4125ae2b26be04cc8b600782644160cd0aab",9.917710196779964],[19770,"334fb58ab965d1a11beb7816fa7fbdc4d773a388adc59329f9638a997993b203",9.317957166392093],[10917,"b9f3fb3d144464e320b33655390b5013fe4f9b89954ee5830b9849f3d2cf92b8",9.917710196779964],[6043,"4ebe999f1f9b293c87b9c2891adc2df36a419b182dddd466b6170e3cd648cdd8",9.317957166392093],[9117,"3046ff14a68fd0c0119de6e4c10fc0f63091ce7be03f28c404866bd9e47b09c4",9.917710196779964],[12249,"11d0aefe8ccfc59d7eea0ccb0f1048acf66438cc780a233f3b43a98e7357b1af",9.917710196779964],[4224,"fa8c2fa2f87c4a2071753a2dd2e777a97ebb5e9d212eba97dead325727fa43e4",9.917710196779964],[10183,"94afb0e84fe34d0e820456487c75d1ac146dc63f789cb06aa3e5c32f306d21bd",9.917710196779964],[11326,"f2d6c5e17d4b04b4b842d82ca511d525ae7b7d837639d365efce75d5f822d5b5",9.917710196779964],[16686,"19e1a65b61c6b7e27880ecdc103a824529a306b103eb126d57cc6a955024e758",9.317957166392093],[19321,"c35e6840461809a6e3007620410e542aef80c19aed91b22f5380679b86235114",9.317957166392093],[17587,"1749f1ef77bbf7097f3a54cd98b0c26d4756a5e71187eb972b4f7c6dbb377a45",10.052724077328646],[11482,"654ae5d1e7118da1f8a16ea81a2ebc34b6eaa009235b9be8f8a1a5e52424a3b4",9.917710196779964],[14701,"11b5600c364ca2eac1984e0ed533414785826c01f5e21b1029da7b5b23bbd484",9.317957166392093],[444,"314b40aafffa6eeb726ce2a8c77d33d90717941b9884af01f0377d92c3a917fd",9.917710196779964],[12836,"86b9af653c21dbc4534f68627f3596e850f2297675ec21c959d59bfdbbf0b5ab",9.317957166392093],[6739,"248d587247ff67392509f913946bcafeaba88d1640f8b273cc5195c89408aad3",9.917710196779964],[2918,"1c5fef26c64c0659f4191ba795c12aeaa239b0bf13e9274e8d0568c327b8f4ec",9.917710196779964],[4583,"f0f62b5d6bfb94a2c9e490b054c6a6df7e9baa41e6173f99f1e56fcec276b7e1",9.917710196779964],[7008,"d0cc92d8052b2bffacb47cc334dd31e4680ab6078c93c28eee2c89d88a8cf3d1",9.917710196779964],[4140,"3f22db51fd4dbac066faf969f850132929653b7436e51b82c84651dfbac5cae4",9.917710196779964],[12169,"6bebe8dfb3e92e22ec2f1a621defc702333a5b97688395b7c309d905105d3fb0",9.317957166392093],[1036,"e668d71b01e1165001a6365ac037a334b05a874be459007d4940f89165680df9",9.917710196779964],[5996,"64d8b9979d4794dd8a47f571422a0e337a83f73553a79e0b908f0d70291018d9",9.917710196779964],[8811,"1be5ac0569a97eadb48df286b7de0ad267e2ea1bf1c2236e1614f7675acb05c6",9.917710196779964],[2092,"6b06397f01a07deb73a66909e3502a54459d1d793bd878f6f5ca7ffad0884af2",12.082379862700229],[11720,"0998b0e34c1e00d0deef16bf5b296ddebbc2d849438d30f80ec956643ca42db3",9.917710196779964],[4780,"111d51f6d0096878cba32d14f7b74d67b56158d1f3c1724d75051a01603c85e0",9.917710196779964],[18026,"c32efa1ef1c3189f921800399fc1bba07d654b9c9cc3450b7d38bc9c9e3ac33c",9.317957166392093],[13566,"d9d192da0150bd93d20140019bdd349f29dd38eb7d8e08cff321a7a7b5b6619e",9.317957166392093],[14811,"ee42a3cd01b33ed4f87df3ae67d98286bb16fb5401d7563feedfea2486839182",9.317957166392093],[4663,"37bfc8db2d43e791a7803b1fccf577132a85a4b1061f64f5ec8b3274c9b437e1",9.317957166392093],[12375,"d7942758a1e441e64d3a163dfd1fb6e3d664f7b53830ed8854b5e2d78e97cdae",9.917710196779964],[19817,"6e15f052acf8ca73e4a7a1723360296b6f9eba67167d7048dc04027052ef1302",23.003021148036254],[7101,"9ad79ffee5a939c0e95159b7b770ef03565d5e810a7e05337bd1ea6c1f9355d1",9.317957166392093],[15047,"f1a028be93e45ec40d85c841e90b56524cc34f6f12cd56f4eb0e72d406029e7d",9.317957166392093],[17916,"21413e1e08eff6ed54a8cc74054d9cfe588bf4a8fb959ec9dca126d6038ffd3e",9.317957166392093],[10699,"862fe56ace331946e1550a2833644f42118cd06848502d8c8e0a92aae27401ba",9.917710196779964],[16400,"a3db6d228e0447905875b80910298831a18bfd38214134b4de5e623a4c11225f",27.080357142857142],[6668,"4e98ba57b338abced504a6f66713210cad63c2fb49ea6fee20f3679cfa0c2dd4",9.917710196779964],[8224,"482a3f540d89aea3c7db4a3712aa137cdf02042ae98d04aa9dd4c0c491cec5c9",9.917710196779964],[4279,"00835796979ebbfec988ccf1d0c96ee534d3c241d58ccc8713b2e584b3a7e9e3",9.917710196779964],[9412,"a7232a9c7a996ae8650908450592c033e8e3439dac2fc948dc1ba7e5aa6e37c2",9.917710196779964],[19578,"2b6531fe8f4009a2b236d1e37f542380cfe165499eb472bbb56f241ae687410b",9.50445632798574],[18861,"f958d8890cf536972de8d915c03f685926cbb6b4263260fc9ade6a952815ae24",14.953846153846154],[15009,"91ed35abd14c7f0b8c09c5d57945fcac2bc59c70f09aa159646c95fad846217e",9.317957166392093],[19541,"1fcac5ee6f35077422a6fa2f1aa881e8444eb6b046afadbddf4ad3fdf0970a0d",9.74610244988864],[7531,"f89dc0ba08f6df871a3f75ed04b3e011f1d26a8ba9439189dec317cfa9ce97ce",9.917710196779964],[19223,"947131ba9b504bb911476e17c838d399f9ae5e1a40505f394456f405ac70da17",22.5],[8497,"ab42f69395b2a61f58b6cc281c8445ad29a8af7cc9fc40a76f92ea3afcb508c8",9.917710196779964],[13846,"4cba110944c544cf50751f0b30cb5d2b772f59a8ae0048693d997e5441e27198",9.317957166392093],[11744,"caa32b8ea304bf3983129eca227b7565c38768544129c4e19ea4e60c62a00ab3",9.317957166392093],[621,"f7cde3ba01582ee1725e1986f46295491093ce900ac61b83e5ff20d24833c8fb",15.91459074733096],[765,"55c3b9a9f10206b2597a01389a1bc85287ccfa988132199748af0c9ef98ec7fa",9.917710196779964],[2876,"26c4fac3dcf5838ab6cc0e81a459ee8bdaa524b7e7aab452167fbf35088042ed",9.917710196779964],[2139,"8a74a9ae4ac0d4adb306062c83107f0e38387d73d5e49b376ae1f14ae44900f2",9.424083769633508],[17182,"f03216d3e30ca191e7c1fb46414767768e172f377df79c7c37bef53463292f4e",9.317957166392093],[9213,"bf9f3920244afc9910ecb9cfd4ab7ebaf350cc7294314c1b56a5235ee8da61c3",10.052724077328646],[14886,"708bf6364dcb696abdc871055d4bbd234d54af07e93362283b3728a61bbe0681",9.647446457990116],[9310,"bb055dc8908c7b403879e43c7f3064e84d0ba9972e3afa676f4b1f6a9559ccc2",9.917710196779964],[3065,"318bbacac39311691cb7162cdadb143fa483489826efdb1280ffed73c582e2eb",9.317957166392093],[19042,"1d9fb6df11ea353193fadfd7483ed54293c70f231be4e1cd320d43cec3df281f",17.16883116883117],[6757,"289b4a67bd3ac6e6474924bd348e2e33994ce4ed7ecc638fc9312bbde84d89d3",9.317957166392093],[10768,"ba400c4b3c0d065e5bcc45096a2039cbe9be224861724de4ace19b6667cc8ab9",9.317957166392093],[16708,"5250f61bd8cbc0a60488d51b2384c6846637d11c39971ae44bf1414664756458",10],[5852,"944fa1f929304b9664dfa78846ecbdb2715a69ce6a568273badbf6171dbbf9d9",9.917710196779964],[6552,"4c3f1fca945812f310d07dd4e4c42a760d51cf6d9680a3ff46f006ce659501d5",9.317957166392093],[8925,"df04679b523a04cb8f6de1f947b2a720edb9807fbd3e54f9d0f335678a6f55c5",9.917710196779964],[10225,"b0cef8836b63c369d3b6b42bdac6fbd459c6eaafea3b3debf140dd50b214d0bc",9.917710196779964],[2326,"49c0488c098005387f42bd2eb045d7d9a8ed33ed12a8a37d4f3550cc8f21e2f0",9.917710196779964],[11159,"b322442739e123732d934aef67a202ebd5126e87c6a9e1a5383eb51c02fcebb6",9.917710196779964],[3941,"c912b739f76c976f45ef57d265709b453170a30e038153817636f941364c0be6",9.317957166392093],[773,"22ee70ffaf70a43e45ed7f7b7aa1488116d285f990561cdf662b918195fdb7fa",32.91139240506329],[2849,"fcdc39ee4efba0f669fac6aacbbda4b756e2e578b0c4f4cc8e608eebd6645eed",9.317957166392093],[10661,"45a5c795f9fe466fe3bb04f7d1e5e14c3992cfd7aa9c5bc13f11ba13422448ba",9.917710196779964],[10625,"6079ebda9ed76fa6f98448fce7ea8f7559d6f697f749c9a3972cf7c8563187ba",9.917710196779964],[19767,"44d868e5af51c0151eb234e289e3632aaa448f5cd30381eb2b1313f67dbbdc03",9.317957166392093],[12139,"482ff9ee3745c1694c89813594411ebe8319ca6be2e1c0811ff4cd064fdf68b0",9.917710196779964],[14263,"eb6b45a1abcb61d7aa53418edf38b29daa4243c6cdb817d2f2e86fee3258a58e",9.317957166392093],[10243,"5cea83273b6857614a9f054bd3507ef08e4399db10c66b61a8c93e026487bdbc",9.917710196779964],[16436,"9a25d25fc31b1383dc4f4f86ab8f3c4032b6979bbe4985460d9b6b1b0ad06a5e",26.090592334494772],[14358,"583249061ea0ebeaa21fe7bce60a297b8b870c0d59d5a3312fb14743a26d3e8c",9.317957166392093],[1613,"d553abb6c3f2cd86029a33953dba63935f4d71b3603bd86ac93a0ccb38e77ef5",9.917710196779964],[6899,"9c82dbb028043e8cb97a5c707b826c9f03cea520d869a7f58c03f5b5ae3f9fd2",9.917710196779964],[9579,"90d195cfb55efc254cbe4bce502a432bde263c505785b321613262a8523621c1",9.317957166392093],[7937,"a14864886ba93212ef48f47c1be37f4664d939ce11842cd93bd651acc5e8f3cb",9.317957166392093],[5900,"fa60290c91f890068fdc1444e88c864a9f15c6389e7dd42fc1777e67f439b2d9",9.917710196779964],[8273,"7f75033b4d9df4a745c0d70b43b06064d832f4a12e826aecd8d2e28c688d82c9",9.317957166392093],[3484,"87d7eb3685c4b62bb7170a8ba8726da4f9510de64e6501cc9fa7b1720f5e26e9",9.917710196779964],[16804,"498797f876cf8b1a4e9237cd61a0a2935651be5898514c01267524b4699e2a56",10.052724077328646],[15089,"942536a0272f3b53ad66e4402ebf7042eee923f8718b9c864de930775662e57c",9.317957166392093],[5042,"58884a4f6e8784da67d3c095a1422611bdc088d1ed360a9998ff555a9e95efde",9.917710196779964],[6487,"86f43779c270c457a3a0f165e699e02a862f0a9fc1743db8868bb649934492d5",9.917710196779964],[12577,"09b5dccadd7a66fa396ace35745fc33438f2e813b15ac57d04b7c9f1c0c969ad",9.317957166392093],[358,"25a3f4b78fa7623e9f3023f66d1ed9dc169bcd90b5cce98cf87b4bad8340b0fd",9.917710196779964],[3930,"70a7462ad174f49abdd5481385abb05f72bf1f93359ea95f9c278d09c7e928e6",9.917710196779964],[13980,"6f4d9c48af33e0b2cf7d98589a18ea5a23ad8c40b97305fd4bf23fe7d7ff6995",9.317957166392093],[14376,"d5277c37c25d53ec480a1e0dee5af13dfa5d8a04174f7859afd7a0fae843d58b",9.317957166392093],[10787,"391f974152fc23406ac2f74909d878dca5aad0a19d41d311c934a83c631761b9",9.917710196779964],[13432,"96b5f492137e5f0aa4eb18e6ee62165541b1c1515dfd49d1a84ec37bbf83c5a1",9.317957166392093],[6989,"f237eb32ec28294a7f34dfcf6c2a63cb628f789b93d7289dbffd8b46e98c0fd2",9.917710196779964],[3548,"9de9b9178481cd689f6a0b5ca0b57842bcbe91896d5a5e3b6243d92a4ce29fe8",26.00263504611331],[8231,"3da48ea3fbd4e575f371dd194b2d541102c88ce139cc1ef16a83cbf7ac9ebcc9",9.917710196779964],[9483,"baaeadffe28cc32ca045a068c51d76676f4d3605f1e3a95c118f3433ccf4cac1",9.317957166392093],[11231,"fb1d8facbc4024065ff5b9bcf00af3661c90a86ee0f90dea0fe10f605cb479b6",9.917710196779964],[16010,"03f03ed42f1105be68af51ca56b45c1f3617da8d8acb131d47f7c048ec483568",28.126696832579185],[16479,"48997d84c72e863b16e983b9c40af0312123de5696493b72dc36304ba748b15d",14],[8773,"f375013450202149f83224a858789f30779e28e7ab5cf3a1c0dd5f7829343ac6",9.917710196779964],[18334,"d5f89af43683d179df160592094bdf53db62067974da50277a6a9c07dd7b3135",9.317957166392093],[12643,"d000811f8b15197bb140c850e92c0790bfe9fa136c73b4548db270a540f8fcac",9.917710196779964],[8096,"43a6af4a185cf09ef7f01fb469225628ed05e1a4ed61db7a5de7af7ab4d1caca",9.917710196779964],[18993,"edf812d782c024bc4ff0382ae5c8a884f316ced2f589689c67f2eb8523f4e520",9.317957166392093],[5752,"697a01523db4a8eecee66856149a85d18a6f3a7777723e53ef758dc5e479c5da",9.317957166392093],[18009,"9cfc68c8a627037c480d4e0478868b0fb9a81b05e404ecbc7131bbcc1b18063d",9.317957166392093],[18157,"c35fe572710660d6a9311637df450a3817c54d83ed6db821d9fd3301211d2e39",9.317957166392093],[17032,"1b1164f54db38341fa390accfcc5306932e4ddd0fed63dcb4414245586315551",9.647446457990116],[8869,"b0731b5289c9e3a9435dff15ee4b1614f91737cc6632d9c25edd36e367d8a0c5",9.917710196779964],[16889,"91675d8a9bc767c29a9f45491c715ee13b803cda9190aaa240ff61f00f397c54",9.317957166392093],[551,"bcb803d03f82e8b02d7425b9ce8c1f4ae1851fe1a9e3f186fce885f6a63547fc",9.317957166392093],[966,"225db25bb3c2db9919801c01de604b4bb7697292b796029ba1062d13c50367f9",9.917710196779964],[2658,"819a8109b9806b2550f5786f99957cd953976541d136fb78722a43127665cfee",9.317957166392093],[11185,"ac71842217b2ef9fd46994c61139bf25faf356c6557b1484637871196d42cdb6",9.917710196779964],[7038,"5ebfcb5732c7f8c4c02632a0a3d84be5389fd75ec38e28bceed2f71c6da2c0d1",9.917710196779964],[5395,"2ffd204f3df63cb87061af076b23980186ca2829222182232078b78ae709dbdc",28.035],[2701,"668477cab20fc168bafa5525d1c13e1ce41eda003f07df316feb0d706e6f74ee",9.917710196779964],[8020,"1b80746e957c917e8c0e96d6bbb6e165a07e84665f21cf675fa616625a056dcb",9.317957166392093],[17215,"e9b0a5214d47a5a222307ca5c99ba5a45ee6905b70cce90f97c5368d129b904d",9.317957166392093],[18508,"e8875bfc4c8733eaadde1a1536f4746a6ea49cf88dc15d6bc78f604e48824831",9.647446457990116],[14678,"0dc9da47659da178375fe365d155aecd04ed4da5999b489ce3d2164e3e534d85",9.317957166392093],[11320,"81c1231bd881ba3ecf8e097745a2e12c0757a5a829893b96c55577afc9addcb5",9.917710196779964],[19737,"8d277eb0f2d90f010814f9cf0dcbfd7dec884ead5797848445f17d28e8f38105",9.317957166392093],[7882,"37c769763d85b6fae04e279bf386e664bc51a87370013017d20ee015251d64cc",9.917710196779964],[1703,"1033c32680e744d945a42225ae1549ba4082f7dd59eeb366a39602766aa2eaf4",9.917710196779964],[13866,"536a2909167d3e14df0db31366a779f74137934c2b1cffeea445a9a7f06ffd97",9.317957166392093],[755,"b6454eb7d8b8f8e875a8ca1ad90423a8187648ba9f14f6e9c9bce5e21fa9d4fa",9.917710196779964],[14100,"9fde7c8ae55a7f5466f95b69f009b82f2d126b123995bf6d6772a4f5894b9292",9.317957166392093],[17672,"7507d90dd7c2b0b98d7d085a929e159bba2f54397480f821848d50a748ecb343",25.40463458110517],[13837,"2cf4a6d282b5cb0ba962c27c9937f279c9ad96abe06cdc69bf21610e4cff8c98",10.052724077328646],[11790,"831c861728a49a2d4ee640ce6591cc3df195ab83b40be4025ef13cd770d0c9b2",9.917710196779964],[19430,"4ac2b4014e74235598980a62bdba00029e966dfd1a1daa3275941b70e31e8910",9.647446457990116],[14622,"a7297824349ee53fb6ab35bcad86bbfc5477f7a4ba346616fa983eeb73728086",9.317957166392093],[934,"d64b00dd9e81f25aec9ad2192c364aa44bdf2a7a778ee28dde9650ae9b8f9cf9",9.917710196779964],[14011,"1d2d78a5206941ee470038536af37b27814d82980817b9943220ed60ad0f9294",73.19778188539742],[14184,"bbddc3a39ac8e77f50750e1eb858b05d59282fe8c784516e0c0e105f791bc590",9.317957166392093],[12318,"9e589ffa720f0a4a6a8376f1582346d72d082903b962784dafdc885b67b516af",9.917710196779964],[4734,"80487bc506cb626f33059ede2c5ea46bd921af9ad8d4a1a8747371a62cdac7e0",9.917710196779964],[9960,"c8b3724c85500498c57ee81f17d49773defada5189e49d659834676c90b691be",9.917710196779964],[16045,"09e448a2f7158f4e488f11ccf5f3308c976e53ed71e72a56495d9862d2248167",9.317957166392093],[8672,"0da81b242aee1bff628873aeb748bed94d0a08aa0765200f41e7dd2b5064dac6",9.317957166392093],[2991,"b3fd075269bad072b6cf96d77f13c90c7542ae717fb0212db677ea9ef48158ec",9.917710196779964],[8920,"993919adaf16d40c9d1818e348c4fdc1ac00aeec2fb435d37c3ac962ada359c5",9.917710196779964],[6427,"05abfdd6b0013a38704586a1f459c4904964b30cb307f04a6c0c0f1cffd415d6",9.317957166392093],[19236,"c34e41e2f5cf76a7eedd41a9fa5b0e7691d4f6b6462753fd60b7ac2d84256317",9.424083769633508],[6965,"03de5a80aafa67a0813eefc4737ed46396c2364476027200cf9bcc11a3d52fd2",9.917710196779964],[17796,"87d5e428c591c248b9dfda8a0b4a8eb467982e79827de833de900e7f81df5f41",9.317957166392093],[6798,"fd3ff3b05169ec286eea76f84cd73172788acace9aa221827af797938ca649d3",9.917710196779964],[1222,"e7b138ee5074d759a4312f50803fcfd77be8f3118093f3a2b72b2914044ddbf7",9.317957166392093],[1675,"0a60a2fa82265658ce028c9a096d1739f896f5d61d2d04bfd1b1a7c8293d15f5",9.917710196779964],[9902,"ba49983b483f0f963d6752586d4c6ac2b0285951f00e337837aa94a819c4ecbe",9.317957166392093],[18864,"b2f045da699900482141f06b12f19d4359764ec9473b23ccc0a10d948ea99224",16.169611307420496],[14473,"542e8ca5f26b91811d96e767f1e62823fbcde02989418464e83e7f36636fc689",9.317957166392093],[3261,"4ace04997a60db7e6efaa8a2175da77b76ba21158acbdfe4e1cca3a453e79bea",9.317957166392093],[10795,"1b255d7e1f41bf28d3e90fda315fe8053f51212b58982f22227eb14d69ad53b9",9.917710196779964],[6374,"b5a2fc98e76340b9a7674a528450588485582e2e30fa089f242c98b808e577d6",9.917710196779964],[5553,"75fcce05732c9dfcbcb935c0ad17915b4f269b45a92e760a2c935503c618eddb",9.317957166392093],[2773,"1c1f14c19938851fdb38dfbb66924221d63a0004e1e9d57b7e42637c9f4ef4ed",9.917710196779964],[10394,"d14b7481d753f098f54f884bd321a02da872f28ce2b27b464acb01a30ab7d3bb",9.647446457990116],[6851,"2b4f35d2bb10c2904754c0ea3ebf585ba9654f2eba4197aef24800901e11f9d2",9.917710196779964],[18306,"62d9ead67e4461d30385927b8ea0c234317bac209c9a2300c953d2df0ff9c035",9.317957166392093],[17537,"3e1ebb47d80de697bc0a3e869824e5f7c80e1908569cc35527a39e9f6419ca46",9.317957166392093],[3492,"2007ca9a4fb68bf9984e3968acdcbecb217beaf193ec1a55d09e1ef18aa80fe9",9.917710196779964],[745,"52f280b5a600e685e8cd97e127a888732a06f2322e9950981badb4a62a88f0fa",9.917710196779964],[18903,"49648d7b5ef638e9e8dc9d7ee7a2388b2296251e23730e0015ad73127f587023",9.317957166392093],[3392,"74713b30a542ba1fb7f65ad4c90963deff997d27fe15ccc29e3c35720f4ebfe9",9.917710196779964],[15794,"e4bc5c4985aa150c9c689977ad502003de59947bc530bb67824235c6ed257a6d",9.317957166392093],[5886,"911de092d09f5d90a798e227cb74f1cefc445be0409692e1eded08582336c2d9",9.917710196779964],[17538,"dee0c830c28c5f2e88b8f1837b5ab74163fa1f352b007e72e71ef89847c8c246",9.317957166392093],[4061,"72a724f8c91a81f03715ae7beb1d62652cf0aceb419e8f71950465a42c9458e5",9.917710196779964],[13170,"e689948120053edfe896df2fd8d3691f9c35cebc0f83fbfc24e99df869a596a7",9.711670480549198],[3619,"d0bded898d80611da94314c2eada734b386e7ccd17701e60fd9b0552e1701ce8",9.917710196779964],[17093,"68d0ede6e7eada17d5e6817d1855dccabb034fa920a47e695368ab139b7c0a50",10.052724077328646],[5677,"d5ccff17770a28a0516f86ea190ca4e280c8b1f6f69be13c12f55eeb34e92adb",9.647446457990116],[7225,"73e6905fa633cb067081056b36a6d9c1fd42c28fb779ff4d2f707001d60c80d0",9.917710196779964],[10648,"72345f3db1e33a933cc942eb60c0e11a5abda328c3ae49354078ec4e436664ba",9.917710196779964],[15471,"e485de7bcc7f1a33ffa87bffc70ddb6dcda05902c32cb31137d1ab5daa85b374",9.317957166392093],[19196,"4bcb8b6f76677676f2e33a1b488b684a2fe02e78dfa6db9c9159d0070bc4c318",9.497326203208557],[19524,"6ca3a330d72a6309d93df2c44c6337a1117376de35eaa78308af888dcbe7a90d",28.14867256637168],[2385,"462b6f0fb18308e5b4b1ae0ac187f821693b3844a97b91cb59942a5e82548df0",9.317957166392093],[12843,"8545264fbacca041b1ee2ddb653a321a6e38909d1b2377258090217d324da3ab",9.917710196779964],[4121,"7ebdb481a583ee67e047163f20d4fbdf5b3ec02eba8b1d7cd7b33634c25aebe4",9.917710196779964],[13554,"243f23acde78a0d16640f4c30568ff3facd5ad79f1ac08ed15748e4f3d12af9e",9.317957166392093],[14636,"5a99b2a84c6f56f2af555f3dd1360777d63369cfbd715ff6d93e113604524486",10.052724077328646],[4968,"d50cd034600f58aaf2eab60cfa9c4389ed124181c58f01c6bef2cde446bf67df",9.317957166392093],[6686,"3c157253357946d1df85bcadaa7de566d174018313f43aaf7d601f0719dc10d4",9.917710196779964],[11440,"6bd9829e259053acf5eb21c9724fffe7d579679b844093e0c939844b7f0f02b5",9.317957166392093],[12038,"4fa97e88eb3ee5799521771b7fd83472e8aff0d9d1125499bee69b8362990db1",9.917710196779964],[11608,"2102115c24a46c6f2ff607db32abf955f2b07feacc811865df27b8f3e877deb3",9.317957166392093],[5106,"883e75f02e54c51bfbb1e2036c7010b4a5d199058216566de03ae0b4cca388de",9.917710196779964],[13390,"157eddda7effe7abd92b1ec729136b9ec2fef7eb18fe49b1e0380024812f8ba2",9.317957166392093],[18943,"09c0207da2fe2a4eb7912d98983a7873dec9f7ff04467e85ff6d7d0eb0225322",9.317957166392093],[11346,"3eebb62239f33c94deeec54d99736e8f6bef610ad771a24f0e12809f36c5b0b5",9.917710196779964],[5218,"e5cd75093ccd3d73dd748cca70bb9ba2aad2fe02c1105352dd2898fdcb71dcdd",9.647446457990116],[15465,"efe55c769a3900679c9c83adcbb58e1e6c9232d0b8c3c6006e38364d7998de74",9.317957166392093],[501,"8ecdb753020bbccda427c327c4fb7ab10d44aa55bd84ded0f33870bf1a8faafc",9.917710196779964],[821,"511a38115b5f545096b7c0ef53265101fe79cd3441ac06b71a46d5574dc062fa",9.917710196779964],[9880,"6c5ee17e4d954d080b3bf8b1d9f231ca7e16f7ccbc28d5899a0fed917e0014bf",9.917710196779964],[6684,"b9281f678bad8eb206c037d67961f52cb9d1c142b6ee8aaddc414299f56f14d4",9.917710196779964],[12578,"e7bb0fdc9daeca5dc58eaa635fd727cccf10bc043581bdf2f5e146f8db2267ad",9.317957166392093],[6532,"2590c78104c1f530d960b5c08d7be00906e405c18da53aadda339f46290e2ed5",9.917710196779964],[118,"8ba31a0956a957dbe541f8ba484e52989aa207520e73141239f0e2c3933e47ff",9.917710196779964],[16549,"3dc6b6c3c8520074f70e05f35d8491b4236381f24d8a23d82dac00e0e49c085c",14.188034188034187],[5430,"1f202610726e961249e0f4e540f6d7e79de6487544d2f2cff7cf241251d299dc",9.917710196779964],[8328,"fb4e3032e8e3ecefe10ec396cffb02493505c2805c544d3e02db8f49e9f021c9",9.917710196779964],[2712,"c5e3e58c519918729ea379aa07b5fabbc88b4876d1aec8a90b862579107962ee",9.917710196779964],[3171,"ac4ccb9c6bbc364cc1e36a0a536fd59c13fac5f17eb3621c97871df9f3c334eb",9.647446457990116],[18524,"b46ef55131713dfaf35faa6cad2efdd177bd10a97807a2689f4e1d3295e0fc30",9.317957166392093],[16762,"8bd2727f19d7f03d8c875148863d5c7f55d29ccb6733814fed743adafb9d2257",9.317957166392093],[14458,"03d9a648114e50715a580438e2461a626dfda710657bafb431ca51c2707f188a",9.317957166392093],[9061,"de988106f9e1af8c51b24467da19764e50115064f0815fd209055e7ea4c367c4",9.917710196779964],[12527,"379e72c3aca7d3db1ec6454d1d8772c522b2bd53df579760d112092e1241bfad",9.917710196779964],[2038,"e162e678f110be169d47c1de0c3f7b7fd0164c0500db399b5d56d94df11abbf2",9.317957166392093],[3749,"56df983aa2fbd515957f911570105fbdb146c99a3d8d34a6759d942ef20441e7",9.917710196779964],[4621,"da67626ef9aa5e15549f2cbd03709f5a526100eadae80cc2aaadba40baed7ae1",9.917710196779964],[1974,"ba04017802628bbb27ce8b2eb145f4691b8f281252c3a0ee2e4ec098063b2df3",9.917710196779964],[11009,"d9090eb74e8212167e939c1f170dfce92d21eb4e815c30e30d8ae0f1618eeeb7",9.917710196779964],[1351,"4f7d4dc4ef837476cdc18a3347c26344f0c86368f8b99cc4d7aa122e7b5411f7",9.917710196779964],[6721,"360883d596f0339124f31c24a3af5993a4a100ea1948189dcdad108e2bf0ced3",9.317957166392093],[4713,"9638639fb2f1b097746782d040de1d0380f9535ccc261aea10ef95d580b6f2e0",9.317957166392093],[3779,"2d22168659d64e77bc02dab225fc95665f406678e0d8d105e0291b61f36e17e7",9.917710196779964],[14794,"4b3da0fa526326a788a569c62dfd3e5dfe03653d30fdc4a195747516ebde1083",9.317957166392093],[168,"f0c1604e54766da06a3e939f250fc49953a2047e7df373bda9e54fa629badafe",9.317957166392093],[4975,"a1bdec2d27b1677e9819686ee82dad8eae4baf20b9205a34af567de38c6b57df",9.317957166392093],[4960,"9ffb8b96f999b809ec0bd678438d5771f20f21f827c10480f1f34fc462967cdf",9.917710196779964],[1386,"92af38e562fc7ea7ff6dd4c4275f6b6d2014b25373948b28358509e4465ed9f6",9.917710196779964],[2854,"b8dae176fb239a8f55c4dbf4b1f75030328870e94a52f954124626d78bb158ed",28.09964412811388],[267,"60f98e74904dd588f9206d52ff6ada802e44f8fc1a1f851889e579cdfc3226fe",9.341346153846153],[1816,"745cfe575329c0bdc29dbd2d02434b7597b2fd766c00685c29059652092323f4",9.917710196779964],[16332,"e4f1cd1f95356480062718f70ef0a6f9b2235da08bc6f5129615997b18ad6360",9.317957166392093],[5963,"3820437332b66db7f8aa13580b3290f132a566db778386f08907cc08341655d9",35.88830715532286],[14498,"15b0ec678aeea63ad5f14eae46daa95306a2594d7016983f3fac4b592f504d89",9.317957166392093],[9431,"00f6da9f2e965376bc610f67aa6004d681b16d20398cdac1c61390f4fdc826c2",9.917710196779964],[3465,"2dbe4ff4763d05516208aef4241649d495ab7dd287608f787da9408d3ee946e9",25.837817355058736],[2337,"113ad49f334b1636d9d85d75a9073edef9eae5be3154b1b6d9e798fc62ceccf0",9.317957166392093],[7187,"84abcc2351c3bd1ecd55c08fc3d6256071365ad84ff936c15dc5d39b8435c9d0",9.317957166392093],[3346,"ce2616041b573cfaac22de6c475d445432a35092a7b161774f803afd654e07ea",9.647446457990116],[2508,"3a449e981ff6ee80fd7f9884e4aac3678bc3ce7a3688ed52fab71c7f5ba7c8ef",17.072553608703902],[8300,"b876aa5362172d5fa038fb4a245ee7c88d5d631bee236e067ab9433e44b055c9",9.917710196779964],[9842,"6a56aa5c341f7e9e33afe971a7eff24a0ff50453a254815280e0e6223a7159bf",9.917710196779964],[15320,"3a74c4447854eb575a3244f3b151af8ea1042f880c8bd0f14010282f427cef77",9.424083769633508],[13676,"d635bc14cec0508b118f4996791db45297e191a44fc0186232e457d0c7a3bf9b",9.317957166392093],[10247,"8959aa532970abefd612f18b56aed3a5c3f22ae28e9f772779c5a7ee052db8bc",9.917710196779964],[12535,"89918a55a9e267d32fad6f1aff2d6777938a3541d2f2bfb59fbe6c4106fcb1ad",9.917710196779964],[13892,"a0207eda6a31ba18ce52830db589fdcef8e13b76c72011dcdf113c3d878d3797",37.52860411899314],[5140,"fe6d1c548058faacd23d9210847b697537007ef0835aeafd309a96d1158f59de",9.917710196779964],[5131,"adb9f2e58121f3f219775591cd763202b5de81db0a77bf2f60553360e0266ade",9.917710196779964],[16641,"176bb4f97b3b12930c98a8b43b40d561bab17dcb619b0b9f62a740f1e6c7fb59",9.317957166392093],[6240,"4facc3e47257eb7843fe3f55412f5087064e363847ffd3e3a56a846c9f667ad7",9.647446457990116],[919,"b3f58c39d88a0ad9d181aed1ede25d7eb036c0f80e6f64ab9ee991cbe7edb0f9",10.052724077328646],[18773,"f28b42da07f793c3e5e25f6933edb2862a841172562b7a2b6cd7014e520bf927",9.317957166392093],[16967,"c49ed5e9845c15930ca6262f0df80f43f177895ae8ae1c959d466c02cc3bbb52",9.317957166392093],[6847,"35ddde34d4fc1e9c6c9a51310554b309063268143b6d7be6e87ca6b949d0fdd2",9.917710196779964],[9611,"3e7125939c0774d4121abe9de8961d25cc633b0703003de05644c14b1176fac0",9.917710196779964],[8923,"75105647180ef252267338e85ea7a0fce578cdc4de65338dcb48a731195e56c5",9.917710196779964],[17671,"86ee3d2a4ecea3f72c2a5aa0052044f71bc25bfcd9f2e73334a4157e2f71b443",9.317957166392093],[1113,"43887979e0f76ee280d9aa742fffd4cc1bbf17567eba086593836d7c8eab7df8",9.317957166392093],[7509,"7424768e5c05f08d9d4fddfd95c595846c7dd10ce823666716e2e1a8c1aeb2ce",9.917710196779964],[11305,"e246f3d11b37f3f6a7076b28dfe2cc49fdbd6e890eee1579eadf0f0db22ffcb5",9.917710196779964],[11425,"6db1bd4a7bd511bbc929b7b222b404b6ada5dabd51fb4a425427aa6b4b6c27b5",9.917710196779964],[3791,"54072de723a91b4f2985392fd7f7a9676b31297036e9fc457cfb646ec3e302e7",9.917710196779964],[4019,"f8d698edc2981490cd9bf9a459adc396aebc3c5f68d2ce7011566f654a12a2e5",9.917710196779964],[3403,"f409cc85db5de87f2ba264247e0e57a5670b6d7e3007231c1b5a3a7a715dace9",9.917710196779964],[2209,"60a5a46c78cbfec03ca2f4f878f0b1e033c915f477f6a3fd4be9b948ae2978f1",9.917710196779964],[4134,"84b317a98a92e4865aa7bcd3424a35a28db7343d040810d9e5e62806eb2fd5e4",9.317957166392093],[6928,"58fd8cf69b2df5f8fe37653633b374c117799672fb9b2d55864be0981d6f73d2",9.917710196779964],[7693,"3e514fb5af358db5635f256b8a1f9b753d0510d267fb853ba22372c44a5097cd",9.917710196779964],[13782,"2c810084f031baee1eec16407251848c1a4e67d820632047803b0687aad0b599",9.317957166392093],[15311,"ca530729d9ebd306e94f22f19b21afe724ae34440a1aa8cb43553ff991ee1978",9.317957166392093],[3486,"bb9f4ab04f67fea70f43d87ff50af525e7b34f95d094a64e06928e47de131be9",9.917710196779964],[19846,"360c75e4a4a051253bd547840b76e7038c5172940e9133b58d159d7c20e3f300",9.317957166392093],[5391,"909baa6e59069b09cd8d34e27b8f2980805c1043c1cbc67a2491e469e0d5e1dc",9.917710196779964],[13746,"0e2fa617350cf9145bcf4b21661095cd28c1d6c756f0cb3173ffe9b620f6869a",9.317957166392093],[10824,"2206dcd33e56bf0b9bc74897857e34f3d8927ac519e7b09c20a1669bbaf825b9",9.647446457990116],[18425,"93897cf1043448efa9a3f9e11aa996f9d2981b9c45389a5dc97f7b12b2561533",10.052724077328646],[3998,"73a21967a641f8e99cee36d97c33725562d9b926b97162a93c598482ffaebde5",10.052724077328646],[15931,"e82e6c04fc30de35d1ad7e4f4e3c82523dc32a2bf94ef333c6a9be3aad2f806a",9.647446457990116],[13429,"234a17830903ac05c33916895b4e3a905dbac3860896c19d0ffeab94adeed7a1",9.317957166392093],[3367,"a94b414e8666f30aaf2cf721214bf6c079d49906b8a39c39291987cc9ee0f2e9",9.917710196779964],[7916,"a73cad0cf0fd363df64514add4c9e665821168ca499fea13d34db29f8d101ecc",9.917710196779964],[16039,"d023f1d139e86f6fd2c190e1ed41a83970af25a7017d6dc75d595cbc69c49f67",9.317957166392093],[18453,"5965b002a40894ea9d4a453b3913309f8eb0e0439071a685205aecf9c1d38232",9.317957166392093],[15024,"c4975459e5efaab792a7b04966b5105c9a4f0c9e0c0ec5eaadc5ab2a711def7d",15.956521739130435],[19555,"b9caed8993dd170f4b597fd88422901d4a9213e13f458d8ec25606288fdf6e0c",9.317957166392093],[3911,"f355429ff818aeb880a55984593d13019f3de63f419d45c71ea73b26c93248e6",9.917710196779964],[16269,"ad5479e8d70fd65fbcaccbe7368772e2fc5e002901a9ab48577c63e6caddcf61",9.317957166392093],[5050,"d1a2005962eda4309bf7113dddc78379a9ce7aae21d150adec6788a1d5d3ddde",9.917710196779964],[14668,"91921b137f74f3633d0d6fd8b5302fa74cde50072d5b9556d1a42b0b897e8585",9.317957166392093],[15380,"f7b24ebf5efc1b033d490d1b62a3fbf95ae446ee092164388edfc2438de4c876",9.317957166392093],[13302,"59f63661d4354790adbad8385e637daa61e6df7d1a64301c3aefa205282384a4",9.317957166392093],[8167,"ca684e7d9a9ecfc6c892d21a1324e54693f8d610f3b0020f9180991db5962fca",9.917710196779964],[11186,"0c80bece611fe7152b8029544e69b82b2d53058e2acdb6bb419dc93c52e8cab6",9.917710196779964],[6907,"ca06756f1371a2dd59ecee25ebdcd8ca186c41cb0e4379dd97cbf3506fb28dd2",9.917710196779964],[13972,"ebf6b6d4d6bebddc55e0f21a72c4114fb7d4d600eb4932f2fe850bf828e09f95",71.65836298932385],[9584,"db5278d2a5bf092b28a79b442ad6706e859e1a88414e3c2856e3dc43ab0d18c1",9.917710196779964],[7756,"a3e954855dce9d9197440a0380f5440122dbf269963a5143b9b2207d77df18cd",9.917710196779964],[10723,"85feaa51d7dfeaf471e9e419515316b1b0eb1cef0a173d08be0b7d61b0ccd6b9",9.917710196779964],[986,"70df3f5a49ceb5386bd119bf31d1fadd6694c992697419bb03c7723bfbe34cf9",9.917710196779964],[19347,"f559f7ba23fb3b965a806543b575ccb043417737e3a7aecd3066efeb7b599d13",9.317957166392093],[9002,"a570c39286ac8986bf07bbc6d7d367e29641dd7b3399ec0efc7993dab6e7c6c4",9.917710196779964],[8318,"85e58540c5f56d3f3221794b50aaa023b83f8be1e235e4d4601599a4d9c937c9",9.317957166392093],[19630,"24a46888e37a24c2159b3d21fdaef9524386d6e4172ef009af45bbc9b33e7808",9.317957166392093],[64,"65ed5b76a5e971e2a841ca0ca8c6113c2ba0ff501ee8ae6279c51c1a81918fff",9.917710196779964],[17915,"2bd1a3fc5bd860b9a29367e57d667de89c4b9efbc3d9c6d064397fa63c5c013f",9.317957166392093],[9802,"3c334741cd306373d5bd32ba8474658847127766c7c04429feecaf5c17ac9dbf",9.917710196779964],[3859,"a8ad52c3900acad4e55e27b1eb6a0c0dba56eb5ff6d4a9e248629385cf889de6",9.647446457990116],[7144,"ebd602b04354522723178f094640863b1b069f281494f92a16e4b02d67720dd1",9.317957166392093],[19677,"4b226242d99de02116b670e1a79080a4ca629da50d3ad86c3ca03a806e3f6707",9.317957166392093],[648,"fdc886883bf6a3b0d2570700e1b96cf913d60243caf58d037f933969f0de9afb",9.497326203208557],[8312,"20ddb4b94cfc0001cbf5539ede386aa245c02edf753462987eddd14736fb40c9",9.917710196779964],[4796,"69e80e4b353062f1e0c17a72ef41479376d87cffd01ad0df70b4bb99887f67e0",9.917710196779964],[6886,"2b34a7903e87f4a0e6b8e5e2ede0be5e19b5710d4219152588d221371f8bb4d2",9.317957166392093],[13514,"5fbec240e9d02a0bdf9d0768b6bc8a9f203c7b22d78cf06699734714efbb7c9f",9.317957166392093],[14585,"ef9cf892f7c0c9ce3ecf9635e01529d40bf003a5edf4c8ba73803b488f8c6e87",26.118721461187214],[11337,"6b487b069b5d2d55586168569422ba0b1cffc8641a40ee0d01920a56dbcdb7b5",9.917710196779964],[5371,"0bcc31f1964ca7e8c97ce4fe74f61f5567fe4c861863fdf0cf974663f8ca08dd",9.317957166392093],[11656,"a8cbc9c92f497a17caa2efb16f821a1bd6d87715bd5023e16725d430e30890b3",9.917710196779964],[16939,"0c3f771e15166dc8e4829bab02c2f99e0cac8df35b6ada32ab13861101465153",9.317957166392093],[3158,"608657e11047fffec67bdcb12eff6459eb723e7e1906fb899bb8873a672351eb",9.317957166392093],[18356,"a3c4fec925c54f8442eed2ee5abec3ec362cb805ff75a140e4c134cdc7a8a234",9.317957166392093],[4162,"69d318fac8ac7c19fa77983011adb8d246d554f03df8690b976696fa2719aae4",9.917710196779964],[4238,"d97c945bbcf9edb8bac38e6b8010bc7b3e27f6361cc7e98a69360e0552e92fe4",9.917710196779964],[11674,"21f17010354feb87880cf9ebbd4994cc6ba3c0afee11faed387190bee79773b3",9.917710196779964],[10381,"07f1b399949d56408aa2dcc2e935fa045e12e44ce73c83704d103338b230ebbb",9.917710196779964],[13191,"a0bb61b7eead76823b3fd2f1e9cd7b912f5e7eb81d07a95433207176e9d806a7",9.317957166392093],[19354,"bcbcc937f9f532e8fa989c789719c03098993269104232adacfccd60e98b7513",10.052724077328646],[5860,"aa3133b5e51fc15c2db0a3544879ad79615b367a6daf71fd3079753b3c56e6d9",9.917710196779964],[12158,"3d88dac75e07a77749e79eb9829f0bb725d2b4c82f68ef32af83b53c547c4bb0",9.917710196779964],[263,"0deb8080a45041e68e5f68aeaaca483de3bf734336338d3ef81b0581aa1f30fe",9.917710196779964],[16151,"1aefd8336198c42a03a74dfd582767cf130e788f8f8cd9657f102acc688c0665",9.317957166392093],[642,"6be7fce766d1ef379c49426efe7d4bf86711a7664b43605d19322be2a02b9ffb",9.317957166392093],[9785,"fdc9c8752e9a83a410ac06579a768beeba6b34edc6712a8025064e989be6c7bf",9.917710196779964],[10915,"dadf8ead2b8126f0f93b3fac6820b7c4558dd9f6e00bcacd6c4b6c2ca8ab96b8",9.917710196779964],[18953,"b5d5bb6220c40d1098aca7d34f1c171b9ccde6b2d92c40a1636e0487d4c00022",9.317957166392093],[9528,"a8391490faba4696776a547d2fc780d3487dd4978921e1d8ec2c8d5d968881c1",9.917710196779964],[4571,"b43064ad0abc15c77cf3fb6d5dde356f0d2ba5fcca8e83fed6730f2462d2d5e1",9.317957166392093],[16438,"70960d811b9ce69a43de8678044d1995df9ca6d98e5c6f95f8efc5451d2a635e",15.003322259136212],[4417,"1a860c31ae3ecd97f557a216dcdc538c30ad8c9afc7b336100c1271982a8f7e2",9.917710196779964],[14595,"fa51ee12f3d0171504266da2dbeddf80eddc10cbc6b868e691910398294e3287",9.317957166392093],[11090,"c803b4b35e800eaae39bc606b85dfffa8746dea458d9663ce8c08db0d3df4eb7",9.917710196779964],[8661,"38acb450b7e2b7376c3a9dffb1e1e1cce9e223bd4be40043b58737983a58f1c6",9.917710196779964],[19561,"7a01c2818d8783f61b527a3c7d08b3a44bed9656f9c78f7074cd8d0070a2420c",9.317957166392093],[19505,"ed7e3a48c322d8bced0af147a9da8d31e1b2c8eaea4ec1e800c45494890e140e",9.647446457990116],[4184,"61573bfffe22919f54a64e9b0cd743215211c8f6d3cd271c40e5837d8c8b85e4",9.317957166392093],[12804,"173e064933825921df43d6559441bd92c554de6c8898f289bc3642fc8c2be7ab",9.917710196779964],[18442,"39d3feb54aba2e86f64867ce4164e4a68a2c50fd24e35a5524bbb0f29740d432",9.317957166392093],[2147,"99c2fed3d6ac2fa88865a71f80c34fee536128618353cd8d337866e0b56debf1",212.64988558352402],[16663,"6e4b17adfeeb727c33dbf6784c23a1259cf189242f25d9562cda3c3032997459",9.317957166392093],[3833,"9bc5564ab720eca2763f1298fe4bffb384c4ac4772a806076bd12b3814fecfe6",9.917710196779964],[9357,"4119887772a80926783e872609b122b0476aec16bc732d2955c0e8b616758fc2",9.917710196779964],[8012,"47847ca6bb38a9b5d93e8c944c64f7cc1ecac974765efc789e348060cce876cb",9.917710196779964],[9793,"79ca571a0787f7baa0eb532165fc3272b307c09bce734f00bdabe9e71e8bb6bf",9.917710196779964],[744,"443ab06003a1145e3067edf678c99b7f37fe580a831d3a6baba055c8464ef1fa",9.917710196779964],[6802,"23c3a209c714a32a79759d6a58bac1dadf721c029b6a280f2dd8e812cad942d3",9.917710196779964],[11257,"872eb3f454a7e0fafd9c74b300118d92e120779cc8c83d00fb0b9a2062154eb6",9.917710196779964],[19788,"8efcf2e0659d70549ae07f0cc4fef7debdf80c6278429c18c243cf969be50803",9.317957166392093],[14759,"398a03fb19692eff4d4ce09590108f766ba0c5dad19cdff685a89887b10ebf83",9.317957166392093],[12974,"1b99a549c44ab504f69f52d3e3c929618b59107cfe9b08c13d87cd9f0678beaa",9.917710196779964],[6126,"3d7844878db04fb111836d44b6bcb425f03210a97a895395743071b86fe248d8",9.917710196779964],[31,"e0d0909489ee379593b57b9c0e4632479479d0a529cb10363fb7a6aaddfadaff",9.917710196779964],[13334,"cfcbc3df0624e04245d4affa4dcf4b65c01578e6aab03f1032763959acb5faa3",9.317957166392093],[8431,"34babed9f2ad7b28ae56de2a25b4f02e831463f239967b3256ad37d72e6571c8",10.052724077328646],[6,"875cdb434119b35ce34de44796fe457e4d246efbaafa089ac652f0073f71faff",9.917710196779964],[6157,"7247609051169d7832a634d38d08a9d9c360d2ce3eb736c923c58232fc6c19d8",9.917710196779964],[7707,"ac0600f844a231f699666347c4d316cebb61eeb4dafa5676e0243a23aebe7ecd",9.917710196779964],[9777,"addc0272192dcdc046311c45e4f9a15bce72a039444377a2f9309abc5dc8d1bf",9.917710196779964],[2044,"75742d1fb4f4c414a8aa1b37ddec72d4095c09f11dd4318018774a2290efa9f2",9.317957166392093],[3079,"374bde93369571c93eab316fd4e2aa9dc188e191532be2a1b2910b0a79c4c4eb",9.917710196779964],[8511,"4f65f4202d97a8c7f4d0ca38afb1446efbf06b4f6e78bd5b53f3a036aa74fbc7",9.917710196779964],[14778,"70f1bc10cfbb0240d8f76961cfbe6f894986cfaad13dafe775b94a8662565f83",9.317957166392093],[6700,"7c21656491634c587d3c2eb2970e90f909f60eabb222caab19368071285df9d3",9.917710196779964],[2172,"5eb3d61817e0330fd71d4c06155f1f34b586452692f0ebd2d7d7c28f6fe3c7f1",9.317957166392093],[14764,"3a71233e48218ce379e321d41636e3136477edd47e46a88787de3f66927da683",9.317957166392093],[619,"e2f4d2401a695aadccaeb1059175a9e75737ff2175af314a288a1323db84ccfb",9.317957166392093],[10266,"ba68bf02fa70ea346b5ae8242a5c00c531cb3b57bb25624e0547971974379dbc",9.917710196779964],[11613,"1f432ad9a34a4baee23d4b6152e75801a3190d1a9a5daa2809301c1c440cd1b3",9.917710196779964],[15864,"ebc15df39bdb19e31d0430c0db6326f914d0b65fdcb7c585c51ad0723cd2ca6b",9.317957166392093],[6479,"75198c171798c9e563b141a3dc1affbae4e2bebff9fcc2f91d4d5e18ef529bd5",9.917710196779964],[3128,"5b4d935c76c5c49decd46b5f988613b9e745208dcfc9614307e581410b257ceb",9.917710196779964],[5075,"b89bde6a150faf2cb6b196c51ce5cac1a1b4a52af5cd7874a1b05a3b11d8b4de",9.917710196779964],[17143,"1ddd14b3a9efc5c52517013a4d309387e9041b3c1bb26182dc3381c6beea394f",9.317957166392093],[16696,"e32089029235458f179b987672cda7230ee422ec5655ac54e15b61c1846b9258",9.317957166392093],[17979,"f6a5561320a9b57b68defbd99c0ec0e1832be0f855d8dc71608d34641de38b3d",9.317957166392093],[11175,"94b6501d7ac9c144dff20a70965573bdecef2c8ebd1f67fe8ab59d21d615d8b6",9.917710196779964],[18829,"df92d06ddb59de86fa5b2fe4ecee9abba924e052796dcceee39cf35f47dcb525",9.317957166392093],[6569,"31feb8d882c93484b18d4daf891849dc301cda662b24b915b0ed3623c3ede6d4",9.917710196779964],[14039,"5212ca6234a3f460cedcfe72b1dbaffeeec9c47b258dbdc0a6941edf619fd893",9.317957166392093],[9820,"1f5cf2d8b1e231f13e014f8867ab94edaf3781e76f799ba8db8cd48a7fbe7fbf",9.917710196779964],[5073,"1964a58bcff930b40c6cb1f009b3cd90298de2c5418a1f0d0ba9a771f7c4b6de",9.317957166392093],[16903,"b08b9cdc315e0f125f8a146ee6373ff7b19bbfb2bee82f23b0cf0aed1aa51354",9.317957166392093],[18208,"d0dc2a5fd0db7e568a4dba2d8e3511392219c2b01b7eeffa92afa5d7fa7ce037",9.317957166392093],[4798,"34db01cc1508e0eb56906c67f781f8c9b326d13f93fd1b2f6d9b77b0314c62e0",9.647446457990116],[5911,"cd7ae2d54d2460921755a52dffbe712565740af0205583aea7d1a3453b2f9ad9",9.917710196779964],[13830,"53655c011ebe7dc5bbe0bdd429f441692c9c042c1342714c6682a26b9486aa98",9.317957166392093],[17249,"c5dd8345d16eaeb4cb5a67c5af0134e150893b188abb9c54191a71156dfa004d",9.317957166392093],[100,"8253cd00ff2ecf741c55bc9ab590309d4e6c7a67755b0b0bd9699e0875d660ff",9.917710196779964],[18902,"fefea460ac02eabfde9369083b7598a6ec41de8e6c48af343e91618524f37523",10.046511627906977],[7609,"c4c6cdec74671eb1a7671355d8e82c0a244c38991bedc8fa736b592d4dc628ce",9.917710196779964],[15189,"1cd610beebe3c752f6a350c31792f072994e71fdb963332fa5e8dd750ae9b87a",9.317957166392093],[6577,"4111d6c24ac43f18e9be9d49d1fa014b638e9d4d2ea6b116ee01bbbb2ebccfd4",9.917710196779964],[8127,"bf117de6b0b0f4cbbc43b6a6b53f94289215a223ad9f79be12c4c67ff10493ca",9.317957166392093],[9732,"76aa9c1e8efe0abe76409fd40406ed5eae533276d0b9d422d9340d50b9cd16c0",9.317957166392093],[13084,"eb34386807af74fc8f504c3a5ab70e8e64e834de51ce4713a842b43a95cad1a9",102.70022883295195],[7962,"c43f428584932390c565d9eb219fd64cef7c7109939a8f452a8c0d0e9c5dd3cb",9.917710196779964],[7569,"de8c6a723518c74d983fb062c1070d7a440e889a05d4f4a152f67225098b60ce",9.917710196779964],[5636,"f4f53a82ea600345514fc8306d04a6a54d96379f089a0313e0e7c07915826cdb",9.317957166392093],[1255,"dcd44df196e1d6ca1b888e002e1b9583778b1583bdbe3bcf38d14bccf1289ef7",9.917710196779964],[14415,"4a6778661c03df2bdb699a4b8fdc43f638ec416ab051cc96513600e42f62208b",28.041828503137136],[9380,"f59de0b21531de903d52679ca981d51440d480682753633a197452a0359f60c2",9.317957166392093],[12091,"bcfe7e5ed61b8c7e20fdfc8f2d02a98c1438761a61f027083fa0b3fe11d2c2b0",9.317957166392093],[9095,"8a9a5e955625fbc3a045a04d54aaa5234efc1604e30a431b74d4cb2f1fb72fc4",9.917710196779964],[12315,"cce2f4f79e106ba92a1ea3e460a91b2037883c3a3db46aaa2af7fd28887b1baf",9.917710196779964],[16756,"1555d4cbbe03259c4595cef9970a8bf04f2950f0372d40b96e6275872b335757",9.424083769633508],[2243,"3ccbfb5c518d668aae233742667a3c9fccffaf03211b15c1230774cf20cc47f1",9.917710196779964],[10759,"265407c55fa955a8005c0092f9896eeb5ddc9cdb32b064bbd1a7df9dfcc19db9",9.317957166392093],[1848,"8be2b71814b8695e8795cd5a6e70cd69dc23d2f20c688dc0c937c1493befeff3",9.317957166392093],[14214,"d41007388997307834bb8c779ef6e969556fe707bee3d0552d38e28a017ecd8f",9.317957166392093],[16540,"6ce0f4f38ec93aec6418e043663211bf7fa0df7c7d010016d50b4afa85b2545c",9.317957166392093],[1928,"e1772b043168c4a940f0d490cdf2421b312a1696461d8f900045b7bfc8bc81f3",10.052724077328646],[9871,"e6298aa37560e25707d8183787fdb9579e5b1759c2b96bb09e368eb9205d1cbf",9.917710196779964],[9177,"771663e6ab63afeba50a0bbb884845f363e0d01c535704205cdae4705207a4c3",9.917710196779964],[5539,"b20ba9cbe7030c10b805f5ed43889ea11324a0fed6e2abfe7856535fcd43fbdb",9.917710196779964],[4117,"bfc9a9ec8c23980cc45bd7434309fb12106c309405018396f3e52d361828f1e4",9.917710196779964],[6144,"7f9f8f53b484f484b74d712f20eb075df36de9c8a7c0731b4381dc4aa7012dd8",9.917710196779964],[4043,"ae49cf52eed8f78c10583abd217b737ca538ac4f6753b54489103d9d12df7be5",9.917710196779964],[15119,"93954df9a8f831f6c176c085f43a56dbf8b8de8bd8c2cf602af2b3906c65507c",9.317957166392093],[878,"a9f2d705b5f4ec7a8e3c9d48f04f8fb15d100e0cb888de5b910fa5a48d600afa",9.917710196779964],[11465,"adc5b44be1a6ee93c4a81f4210d6f19250be7fc7502e441a3967a1de8a5ec8b4",9.647446457990116],[829,"7b94903333e9134f1e131dd31b1e96071ea21126d5a41afb00f49527fe5159fa",9.917710196779964],[16125,"2672997e87115f637aa2da68a92b19d00c654cf841e7d2b300dd278e7c697165",9.317957166392093],[13252,"d2a20e1474bfd99285dd439754512d7b023f795e111de17fb662de79e429bca5",9.317957166392093],[4115,"c7cc1c49a1c28b0efa4646f4d59fb35da64a6bdac181e59085c8cd54f721f4e4",9.317957166392093],[10809,"42ff0f32bbaca5488fef9e81fc1fbf5b6bb15d939d4643a14ac28676e04f42b9",9.917710196779964],[18751,"84a23aa4fad40b12c42c01c66c1b692028c483d7099c5dfd05b32cd4bfae7e28",50.03700962250185],[2149,"8671d78cd08096cd9253a5348da3f9edde39e0daa8141dbd8b84cd810800ebf1",9.317957166392093],[14004,"4692f4b6055ff2cdd5f9dee717aaeea859784815a62d191b67877a27a28ab794",9.317957166392093],[4858,"7b8758d41966517082109c8cd0812eac9863c26ac51f7ba01fd2817df3e915e0",9.917710196779964],[797,"5bcadb49b2a039a26e69b446f40866cc114718f731c364db169e71f9db8f8cfa",9.917710196779964],[1101,"0c071e7597be96a38b511d96502fd3494850d7226c093ab4b2d42b1d21b892f8",9.917710196779964],[12829,"6f2950a6258281b6cffd084d12b2a5e51d5c7d9caebe0c0edc131de98b24c2ab",9.917710196779964],[4034,"f93022621c2293cd2cdb866cda57a5835c6b170d8324ed1e6120fd6c40b08ce5",9.917710196779964],[11464,"ef63bedda5630253250add6d99cd4263759f551d5843282a1f5be8f7f934cfb4",50.02901915264074],[11829,"2e937e3f3c5f2955af3502f03d1bf876fd879b245f2459cedbeeb240934487b2",9.917710196779964],[19739,"67381f0fb2cc42e084684959549605e47e7b93d71549d8e6ab65a00b59856d05",10.052724077328646],[9672,"87f095487b00704112fdf95709eb1082a4c65e612603f1e2d5be82e9b53792c0",9.317957166392093],[18155,"c5d828ab05a381ff122786a0210b49038b93e2ed50fe50bc7b503dde4bf83c39",9.317957166392093],[14802,"59308987da7f27a11fafc73700a21b223b736912344e24aa450a54e3cedfd382",9.317957166392093],[10682,"7eac8acb7484b6064a55bf7e135ff1788165331577f752857b4431defbf626ba",9.917710196779964],[15226,"0817568c325fbb81884bae89c323cbba2d7cff63eda6aad5dfb6ce2f8f92f679",9.317957166392093],[10799,"35146dce2dd0094d490be6472e2a059b4dcfeacdb8f583ae6a71cc7fab594cb9",9.917710196779964],[17619,"457195a3b36d5c5df559516046798b87df4c7d33db88c3c79f796b458a89da44",9.317957166392093],[19591,"1fe7206fb26789f2e6496347063862a5a365561f07cfa4af7ff38d1eaff1910a",9.317957166392093],[8160,"6222f8e6b81a1ea7eff830f4174c4420e031d73542ea3ddd9e15c88bf89947ca",9.917710196779964],[12130,"bcfc9872b3f4b23660e2a97d74424149b05e42356e3fe7e7e1dd2cc420657db0",9.317957166392093],[14343,"3882667701553eba26307b9911601f55412a52a80d92b7d30093f690cec77c8c",9.317957166392093],[12277,"29443a1a4b4e1f07975d51bdb1dbebbac1b2bab63693dca49dd7e9846eb76eaf",9.917710196779964],[13131,"c278a369ffa9aa466e026e019c42144445f24f8487b4abb264b62dd7003e5aa8",32.066528066528065],[5979,"169e8de1d0048ab719cbe2e14486bd2d821a749660c23de5e7f32f847e2038d9",9.917710196779964],[12145,"f552767165c353d9f444000cd55a94028314f04d0a94456a6f14832c0ea162b0",9.917710196779964],[2847,"60b0f0ff794431ce600949195efe3ab2315046c612f69f44164118ea7ce360ed",9.917710196779964],[12650,"908b6584968a80d07af8853e78db5b34fcf7fd74f6b4896c991cb18be8aaedac",28.098939929328623],[1650,"b263b82fa935181df55f35d5b5903135790d728f69a349140f2bb98f10ba45f5",9.917710196779964],[8519,"9fe937f86ba431d6d2e7c1b3e8134170e274e500d8d6d7d3657e4a7a141deac7",9.917710196779964],[11152,"897d13b02ef141790fbdf19328084a5efceb0a1c0e615f7e0eaa8e8cfebaf2b6",9.917710196779964],[8621,"035c72585e1ce2e2489f9ffdad217549e7f21b81ce41778cfe08ccfad4a04ac7",9.917710196779964],[9547,"9f181e0b64721e984238994f301a5ce2290802e4e1a6b59d32e8108ca09267c1",9.917710196779964],[683,"638e8ab9afb8b5a85d24c2699bc3e935a031c2e28306111511fdbc3b8fa85cfb",9.917710196779964],[16384,"13c6da775102f1eee8685c6d41b5016b2129909a1d3ffb8ec1ac609ffaa6695f",9.317957166392093],[15387,"2dc85de8741197f42a8a1cbdd1c3bc2c4f25310de5e26515c3ee754ca18b8b76",9.317957166392093],[9629,"dd240c18c32100392acbe537e8d00bd2d179cf8b4d31548101ffb14749d1d9c0",9.917710196779964],[4689,"7cfb4b034e4e0b1eab7453e327a67342792809b72653757d364ac0bb125210e1",9.917710196779964],[8675,"45b2f7f5d7328dd7bbeef590635996f9e35d577dd7dfd9743f0027490964d8c6",9.917710196779964],[11920,"a201cc4245133ca599d8939270f32aadd5d4fb10449afb3e9c4660af565ee0b1",9.917710196779964],[6790,"6997986d2b5707fbac87f144c761fde4257b5a3ce406ba255b969a483b7d5dd3",9.917710196779964],[15269,"53de0e959517f85da1da2a73e907be7b9f58b0b2c9ea7e58d0763fd40169ff78",9.317957166392093],[7713,"0e9025bf77b9b9fdd17e5af5519ef3bdc18ad842c86111f6b4c4fc44321673cd",9.917710196779964],[2529,"05ecf371dac5f1293f93e789fc244e75bff94a4485fa9d87dc1f927f3bfd9eef",9.917710196779964],[12588,"229693d425bf9a3483949b33d4c56f1e40f981e4167aa8159176adad023c56ad",9.317957166392093],[9711,"6ba4e828bb3a1b503759a56947dbfba8b641ead40be730146286d1a1d9074ac0",9.917710196779964],[14855,"9db47c0bdfd9951e93fe3e1630c9852c06c95547e1fb463d03a91554d369aa81",9.317957166392093],[14805,"a2d5f41bba28c4f845851fae4332ef729da88a48ee96d7af43a702c7a31fbb82",9.761819269898265],[242,"378c455597ea10343830b18be17261321503cea97bfd33cc9249a446ebf35bfe",9.317957166392093],[10297,"30ec6b165a87ef843ace1654bda6eaf43c18930946b01de6c58a4a61c22d65bc",9.917710196779964],[7437,"8d7917672ff8f36e1f6c973ad1c556db11785e0cf27ba5bd4bc5929f734f27cf",9.917710196779964],[13165,"8e85c308dbee48e32919c3828dc5c559ac9f31140307085afc680a3ae5a1b5a7",9.317957166392093],[15576,"5cf4a4521fe26ba7dbf28b434d7960a36ab4a7c628a673dde245753cfedc1172",9.317957166392093],[920,"dffc3b6f6babe23a4e645ff390efe21dd8859721dbc6952a24a6f27a264cb0f9",9.917710196779964],[11725,"ba06a3ccde51f856ed20e7eb47c592e5f23449f8354a916ad26dfac85d3e1fb3",9.917710196779964],[7248,"a76772081d7bc1b83f9ff707f574096caded4af22020e71b7802ecd8538962d0",9.317957166392093],[426,"a8c0047f8a31aa42ddc488e54d086554ebeae85419ce7ee34c1e9f1102e433fd",9.317957166392093],[7500,"0c3f006dfbb5d58cd4902fd86973f40b5c612a9596f99c084123fc2aa61ac0ce",9.317957166392093],[11675,"18689de62f9461add41678170ae31e5c47de88bb69b38cf573206a0c0b9273b3",9.917710196779964],[15524,"c1db3926934ffcd8588529a1ee83a2b6220f6bf23b2baf25a2c2101778e27b73",9.317957166392093],[11421,"f5675082b6d41d0b5db50a9f95d3017a84a5d1ae547eb68d5cf95ad25b8432b5",9.917710196779964],[17788,"e9429a934f0a2cd7c739f7d44a551673a1278a3b44d3f3a2e1fc2ce13ee59241",9.317957166392093],[15398,"9df4f3c3f333fd4aeabc0583c99349c339da8039375ce3a9b748104ae5146076",9.317957166392093],[1997,"92569768c326b107679698b25cf2b255ea7de0997f33a8aac6bfe401feb90bf3",9.917710196779964],[4979,"fcefb01d55535d03bf52f508f7eeb6f1b6ca8c2952320b5c0708b62746ec51df",9.917710196779964],[9489,"3f3cac267fc5da88e79172eb35f5b0b8531b5c6331d8d1d973271fd71846bdc1",9.317957166392093],[4914,"3ff48dfe6126eea2e785ea61cccd269c31f27ef463749a620656e3dc829dc8df",9.917710196779964],[13740,"836a1d558d91fffbcdbe6e995c7bb4c051982468ec9665c7b0b18119be05a09a",9.476682093271627],[2492,"eccfb14d3785014a4df23a4676d9ecab0d2f28cfd673c9c96e0a39e00091e4ef",9.917710196779964],[13045,"eb060f8f7bc2b290884a4476c278b79bc9b7efbea91546f5b3b1894928514baa",9.917710196779964],[11679,"2300d7c82d9d586f896ca1a574be89cc2bd6e6c03e0022478cbce18f1c9e71b3",9.917710196779964],[15705,"032391e961593e320f8e04be7bbea5dd880eca4f9448e0de739f6015bc90666f",9.317957166392093],[6242,"04c596e440d8962d0af522ff386948a46d7db0db1d78fdd58c750967751b78d7",9.917710196779964],[2839,"cd47ebf9d2eac4980984285f5300550c981edb962a8ef15db47fdebacfe069ed",9.917710196779964],[19413,"5e68ffbce815810f532e763ddc5b6e4fdf0bbfaba6c7df7216dae24354660711",10.052724077328646],[301,"0e89885bd6e8dce8917d93a15256ac360640fd98667925e7c5bfa1b69e29f2fd",9.317957166392093],[3937,"2c4d5124c84d5d3b1be224e49501d820922713df2e8dc11816edd953228917e6",9.647446457990116],[14632,"82a25fafa713cf2acd0d5f04d880e3a6db5cc7225d4de5c2e36d9dbf17a65a86",9.863013698630137],[12229,"1035c3e8059e810cbd365b07f35553db33c4ebbd2c705103ae4ca14536d6dcaf",37.58222222222222],[4226,"0475f0acb540ea096c23f012c35662d3fd5ce74e36df40e60c1a0429b59340e4",9.917710196779964],[18217,"65c30c0609a7939202cd4f2ed19ebfe29fe5910ebee6c7b617303d17da2bb837",41.69230769230769],[7037,"a27cfc3a7e652fb80cfaa3348732f4b217b2b65f5a41da7ebcfa7d4b2c34c2d1",9.317957166392093],[7896,"9ad9871aa66b920c48fb2ca8ef9aad021804b9e2d5bddc0206283c8f50b844cc",9.317957166392093],[2956,"cdc40ab2c4c464d36b8e1a5686741b3df14573983785462e17611cf2e14999ec",9.917710196779964],[11647,"7936927d1e7ae9dd8a54cf9a513821fb3b22dbde0b2648844a29ddb8ce77a1b3",9.917710196779964],[1804,"1adc30808505bff81d5687ac679ab3e5de4f0c944283ec13642f45fab58335f4",9.917710196779964],[12325,"c2b5ca142a2506c2b2ccbe8c0dfc33fec29304eac2bc2da4b81fa3282dae0eaf",9.917710196779964],[16982,"233207b5c038b9b8554c2c93f91e6f81afc13b92a692449eafd5656852e57752",9.317957166392093],[15244,"47a978b7b067166b9f9c0e0247ee6e78833337bf0bf8ae7f23b5aa2062dd8d79",9.317957166392093],[9160,"ef91009ee95ef901e7b2116c26354d4c9d10bee3f9d75eb9fc28b7504107c5c3",9.917710196779964],[7081,"8d81bb5468de781dc85c97af20f4b2fc16edcfd5cd0eb495929e5ff112da72d1",9.917710196779964],[10794,"e80f2dcfbc12de8276305cd8541ca4053a06768f67d2f3c0705eeb65ce8a54b9",9.917710196779964],[1427,"9a929c8b3272e78ed167490072b987da15c0062f17804a2d3d0d8bd51b75a8f6",9.917710196779964],[5832,"ccfaac2198d8efd6273d09ad0968e7ec49a7c18e5744defb1bea67a62d0d27da",9.317957166392093],[15745,"3d583e2218085fd9636936b96e2d9d03ac9758b2490bdcea68c09994fb277b6e",9.317957166392093],[16619,"42cf6fa163569e015c9cc299d2e88269978626ee900693deb39aee2d6386745a",9.317957166392093],[17422,"9e4f042e19a6a0eadc266ee93c6d26ee4967152c759d721b73bf2b67ceff5849",9.317957166392093],[19583,"7995534d0c07840f87a6704c4ec632b6421020fe4a09705d3f1ca4424fb9e10a",17.09090909090909],[10767,"6e6031c28c24a5c51ae7385f41fa922ff1c6860d20ecec91b82cc31d1d218bb9",31.06376811594203],[18581,"1f381b5b6bef099194aacf7725ff44dc54bd1969d7d01bc167413129e8f95d2f",19],[2777,"4deeb575b36472920f38806fd18fdc3f5078c58cc6dbed657edd96e76877f1ed",9.917710196779964],[5293,"bd9489b08ec354013efbefbd401120d7bc95eff0c68209feb543567fba7772dd",9.917710196779964],[8623,"cf53d32cf869aae3eee378858241bccff6458d59f38fd72cbcabdd0765e647c7",9.917710196779964],[7488,"171227893e22de42caee6be2a13919fefad0454c9f22df1edb942d09e424ccce",9.917710196779964],[6945,"b61cdbbdb8348c7220cae1bd65fe93b06cc64318903468f7bce4b183c3164cd2",9.917710196779964],[16765,"8caafc0e5d054c74243abe5ebefcf7bb42df0b11249ae28e993d212541d81d57",9.317957166392093],[12428,"92031109bcf184139ad13c73f7b5510eabb90c7dea57a414fa5b8e9a376068ae",9.317957166392093],[9964,"176c79b73b94885b8874550218041d15b4bf0e5a2e9864553f2e975de60f87be",9.917710196779964],[16614,"d20d89cbc44dd4f8f85144b768d4abd1b1363c7ad35efaee1da77dde4a2c8f5a",19.2],[14720,"6735bfc69c1924456f3baed81fb481bef49867e20cfe7046d80c78de357b8484",9.317957166392093],[13023,"0a45eac2d42bce404149a5f59bbf5149d29e5ceeea1331b34a89b9b4bbb86eaa",9.917710196779964],[593,"0a96255839542ed605a2a997cb31cadcf0e4eb9324e144d3fafab9adcbc7f4fb",9.317957166392093],[7534,"4e1c7225916238c160294613eed3f5f52d064ca114fcd2396f67fcc11d4696ce",9.917710196779964],[6699,"3114566d300f9803f93e34f80f8f409b4596d1fc436580d18d842aa14464fad3",9.917710196779964],[10416,"e2c65c99256ab7119945967f8f796982cf15d0b1fc3242d16459067d9736b3bb",9.917710196779964],[15019,"4cc5f2f35c81cd38654aff2abc972c5257c5bd389a3d67f788132c358d3bf87d",48.07692307692308],[8955,"da08dd7d46d20db1c351262790e4fc584de06a93225b039526359ab24c8415c5",9.917710196779964],[1749,"1b8b9f9c6ee5ae043ce32c558efd40d28687bd50ceda8d4eacb7485de0119ef4",9.917710196779964],[4871,"1caa50c95ba5e32553070cc0bf1149d7f08bed0e4b6bef9aaf25a3f648df03e0",9.917710196779964],[13494,"d1c436875be4b1d3e91aaadaac61058dc1605ce39e4c6ef7005b319bd665f19f",9.317957166392093],[4350,"38a64bfd19b5487f9503cdb37d817fde1591df298aac69b9cab8f525d5726ae3",9.317957166392093],[12196,"fb827cdffd95e68b71ff23bdc5aef5fb6106421bb07b19626939779e541b14b0",9.917710196779964],[14074,"21f02c8a422699c60c0344a9644d0912694f3897045030c5195b650307c21f93",9.317957166392093],[7336,"7b74a688a30e0e3ad088a25477010d70b77a1629681843c5a1f838e2b37cd3cf",9.917710196779964],[12564,"3fab7359fe10ba9d47a808a26975f238baf866c22b76b58db44123fb4aed88ad",9.317957166392093],[19474,"821c92de04e05ecf50ef493de9eae0fad83a4267bcb2c117a02f606335414b0f",15.942376950780313],[15802,"2f8ab90eaaa271c8d8381eb07882e4a94e013a23c116cf50a0dcdbffdb2c4d6d",9.317957166392093],[12452,"ef484f58fd5ee397e7a4b04a9462aa941e1c7bdc3d62af2901da0bfb213545ae",9.917710196779964],[11648,"6e979dc5289b16a1126828a9e3555fb98435b577ea6fe6261ccb20aa3be29fb3",9.917710196779964],[13367,"ae5895f3ce112064dce59788163d02fca3b57502edbf54a54c23dc5f2d8b21a3",9.647446457990116],[9602,"0b474a7578e54c312849ae65cd96b9d080a5a176413a404eef16c43666c304c1",9.917710196779964],[612,"5e2a42629934bc3a05cf6699a9bc3bd09346f1a8b7ca29c6222c29cf6c97d6fb",9.917710196779964],[15037,"6e7121ec686c48feab143b667aa75e29dc9e4d8d1f6883819c279e828122bc7d",19.014694508894046],[5104,"059dbe053c657c3164197bee4e3908038565b5c127685116d8c043a6d5018ede",9.917710196779964],[12541,"4880e4c1fe4897b30ce0335de863684efcab0ac1d7b26aa56c3871d7aaefacad",9.917710196779964],[17990,"ef9052e302ad51adfcc57d225ed9bf921688f8e6391b3dfaefa6e9c2545f653d",9.317957166392093],[17647,"a7980069f0fef64b5aced4c536f5d382e8ea695f71e3d9ad8157e239e8394d44",9.647446457990116],[2454,"a140909822a033d9b33791b81757780520f7d5cb83061decdeab3199ded72bf0",9.317957166392093],[8982,"7ff0279501dc1c0fe630cd0afb98d94d0f5392ae089d1ccaf3df7479f9bfeac4",9.917710196779964],[15526,"9244acb67b3b7007ff456ba99f6aa4a2e1e9eeccddbd2066a179ff48ab146873",9.317957166392093],[18725,"49f0061cb116a42515063c197a25a117c86f6f8613b9986e2f01bd035a1a7029",18.030981067125644],[1150,"579a02a7798c91937de2a8b3de55c59ec8b93cd5fae46879ecd8fd05cfc350f8",9.317957166392093],[1107,"821b08444d0369c14ab25a2fd29d628bd23c71a44849cb9cdaa944e8ea5985f8",9.917710196779964],[15922,"63bb24bd3f5e637a53cf94e4335c8800c104e48485c3fb95d50c6266f957a96a",9.317957166392093],[7662,"c25a84afadd451e0d7bc3bccf28a73541f568a6cf07d95323050b1c288e5d4cd",9.917710196779964],[1742,"dfa8480aed5dfddde5230549c75b9c46cb0a511cd8bb6aba1062ed626b02a7f4",26.173719376391983],[15166,"2d8160b7e83ce3d8e1451a4f5b1ab35a8c0bc3fe4c564145062c6a9da083247b",17.09090909090909],[19034,"106cc7c455ce3fd19670f435af8e26749a4c7b7c9bb9334816bb6813cbd9721f",9.317957166392093],[18232,"67c927bf121dcc3527eaa7318ac686ebd692318efc784845a75a88f637265137",9.317957166392093],[5801,"b0886e0a5f7de4dddcbe32796cb446c9decf62ae1744f5d618bd39dfe9d46eda",9.317957166392093],[12874,"8aae806e9cd4a12f58627d99429a512796c9b1080eb71db634296a8717ad6dab",9.917710196779964],[10949,"68383a3f2cac91369fc627df91e8dedb22fe9293e21e2388e116e1c468495bb8",9.917710196779964],[1404,"bbc1a69a4477f4d1722a02f7f68719dda9f6bb2b09bb9c3a27816218ff31cbf6",9.317957166392093],[13833,"14c515d2140722a55779ee24ce8f35a29afc95ef6b126c7056626dd15c69a398",10.052724077328646],[16568,"9c0088d2d98e83db2d4d7f0b0fcc5f0b1a8d7d3a608ea7c2520a09c6fdbbc45b",18.059405940594058],[4060,"c65717b3f5f18d33dd08f81f6e7b73bb73e1207c44dfce57d55125451ba05ee5",9.917710196779964],[16336,"792f1e85b337e145bc0e990afd596c6b816029f9a52f33152a7f18deffd95860",9.317957166392093],[216,"22e3e70c728be468fe53000593909b4acc7f32e08b5c02ee7ad68b2f0d3885fe",10.045662100456621],[4295,"7e8d999899de22a74197e9fd5fafbda0185525bc0a15c0b5244bbeaebd54cee3",9.917710196779964],[8000,"b6022c78b7efaf87bb17d4a2b3e16f3fdef3cacf734846ecaa6bcac443ff85cb",9.917710196779964],[7951,"205869f1ea39ded3c9a70a89969a69085d36c282068dc3fb21cd268b5c56dfcb",9.647446457990116],[8879,"0c8f35b116e20c00110c6d6ed64cef1c36e5c0ceaba2bb128ab2d893162e92c5",9.917710196779964],[1368,"731241ad580f85aa0eb42fc7ba04aa0de1d7436fc07c195da618ea50dbe7eef6",9.917710196779964],[3428,"e5c58d86b55e7e4bf2d340c6eb4a0241f6ba2a62c20af2ef1b2dcc6bf0467ee9",9.917710196779964],[16593,"462649df0478970643ca9a229463d01984a5e0ebe0675feca0e6e498a8de0d5b",9.317957166392093],[17780,"098aae8b6508718b5687d33ab1c9b1da415c15f80d18ab5591d34a98368fb841",9.317957166392093],[10652,"8a35b3cd52d6c3102d582e39ad9dec9961cf3ea5d6b6c38ada0ecdb277b85bba",9.917710196779964],[7619,"c39c93a674966aa3b075f0f928856e8db5cdb6804d39c9bd50bddeba265d1bce",9.317957166392093],[4248,"224a8ef3a7237fbe21c3b0b9f17912dd18e74c9c0edc2c51fce32942c70323e4",9.647446457990116],[14336,"18b33e216fdf1d38417c6bd96bafc69cae78c81184c026941f0f1d754556928c",9.317957166392093],[10463,"50c867a0b71938bf38e976134e666a60a47de97ec7df9cc2a13c2ba4b8ef58bb",9.917710196779964],[1214,"3f2849fae44121bfdf78b42562680140586ae4c114b34dd49b455dcfee13ebf7",9.917710196779964],[568,"9433a6d4c1f29ba81a53a6914f6f54f3e1a77362f836ae9f88737708e1ff23fc",9.917710196779964],[16998,"7504c7486f96a1228065679a87bb2ca601a997e89317ff81208799dd94520852",9.317957166392093],[18794,"036637fca0ed297172f42ce8965a1821ba4d8f80d1f3ecd1bb0a5bda021d2827",19.06290672451193],[890,"9372d7cf434e13aea8cfd195b0cb4f767dcd389f1d7bf47e27619c2cd3d2fbf9",9.917710196779964],[13047,"ad87a76170574cc02bbd1394cfb7b22810f9ccc942146b5bd15050eba3ae48aa",9.917710196779964],[5210,"c71041afa43a0e1aeaaf9d1b54997a66947072d8de460df55e4c157848f3eddd",9.317957166392093],[17314,"8a449ee2daeba25dc49be1f33db0078adb01ec023170c29f64c1f33a950ca54b",9.317957166392093],[8700,"0fe87235e8710210522ed461281bfade0383295ae927220727612b01bcfbb2c6",9.317957166392093],[4485,"45b30a22b97ba8b9cabeec1e283dd1ba76223d1235b13600c8df7524378a82e2",9.917710196779964],[8296,"d05b7378c082625cf8ec1165763abe768ca2d5595a4a020de60e6e543f895ac9",9.317957166392093],[10071,"f7a8080d2444a1fd0110aa505900da16cddd95b64e50fcffafe9e8519adceebd",9.917710196779964],[12663,"665fb56161f61e37e6b734d9fea9dddccac4d7e767f4abe64e8dcb5b6586d7ac",9.917710196779964],[14868,"77e897086837af486b9f6bf71f8b24852a2081a8452e4a2accbdd66ac8606f81",9.317957166392093],[5080,"48be42f0953d3555cfc3121f0b38b85bed4927b3488714dfb5ffe1691ee2adde",9.917710196779964],[15581,"e96b4c6061945921e9c0c892b8659d157c44681c37122a53333a256469e4db71",9.317957166392093],[5272,"46610ceb829c590ea1ce98832363b1966d529ae41fa40c4895cbe1456a4791dd",9.917710196779964],[16996,"fc136939cd3b297488d6595cddfbb170b378011922c7126c6fcb917a46061852",9.317957166392093],[7464,"eb9038c79a28887985bf527858c141d37d85b396f7bcff6417cd5c930b57fdce",9.317957166392093],[6028,"f777fc9527493f6e6ba108071274f345586314d8a28487f19ff87ece8890dfd8",9.917710196779964],[6791,"2317728542ae8e100abae04703055b3ee450f85175ef9d32c36562ad17f558d3",9.647446457990116],[8123,"16d898fccbc63204d973840c9ec179bc91ca564898242f168eb1c7e8816d9aca",9.917710196779964],[6002,"8a21f24c7387060c702e49f1170eeb039ba7bdb10ea379a093463b2136aa0fd9",9.917710196779964],[5076,"a4c19acb399aed2cf9a81cfc001e0e3c863f0222e715f4dbb70cc39ba629b4de",9.917710196779964],[15685,"d770fb91ddfb566e7a8723959b4e822dade99399c154a9f3db33db3f5a26b66f",9.317957166392093],[17853,"6edd4c9d7aa07125b40a710e4b020e5e976df62e38df514613434dbec7842d40",9.317957166392093],[5650,"087341e7495450820bd20560babed63556dd587dfe06b8e0dc529c28be3554db",9.917710196779964],[8404,"91ee24739ebcf2a8294d47c1b5020d7abd3cd17249d329a4d40ddaf04fdd95c8",9.917710196779964],[13453,"8becbdb52114b78a4fb41046516075c59ae1a9809c52be406e2062afbf7000a1",9.317957166392093],[3370,"23db1dff8ce51fca10a8aa4e80b6946c26971d912490c05a35292792f3abe8e9",9.917710196779964],[8816,"ec8afd59b7f812f81e508e3a4cde3372ee2592a5fe415dd21156382e92b802c6",9.917710196779964],[19736,"745052e5f889ac4a18710f6026b94b083fd9b652a5bb0dc611242f35274d8505",9.317957166392093],[8105,"9f32966c32f7b14d578e712babfde95a37e8d046a57d92e46dce185b5cc7b9ca",9.917710196779964],[8077,"4bba035491655df8164f373da8f53dff2749477d47f7542de9bc1fd64afee7ca",9.317957166392093],[7287,"c7fbd556968547b89a91de20fd30e4c28cea17109b0ddbf5427b7ad7edbd26d0",9.917710196779964],[11606,"713c7ec4b6f4ba0c31fb18a0ebef3d943c038081c1cbf38cf34020478c59e1b3",9.917710196779964],[16677,"982cd68228d9012172dfe7cfe7cd8fea0580bf562bf3f0acb0ecb90e29352059",27.151515151515152],[13728,"8d07cbb635073521d0557ad3fe3f4ad9746d87ccbf1206f1b9970dce5cd4d99a",9.317957166392093],[2593,"7899c1b600df8fedf36ff0350204463012c72ca82d6d619078cd4905094c32ef",9.917710196779964],[6018,"85cef5377f98d9fc7e500cae0703730e9400c85ef5027b913891b7d8fa75f3d8",9.917710196779964],[6212,"1840102a1913997e0fc6d7d743fe245d7b0e0d68df810bfaa5b73fb431bfabd7",9.917710196779964],[13612,"d3afb5735e84cd1fc6f6370e76442fdac69ed901f9092c47720501d3663a219d",37],[12496,"77639c5714a06bdc3fc4444068b4c3be1a423412863f7f5bf8df1cfea6a2f9ad",9.917710196779964],[7586,"463d4ac1fe7070e40167b114bd5e2ede11b4773d73492e3cc2aac9da7b4c45ce",9.917710196779964],[5324,"ea1c0d5646ea169a9cf41c2e2492b3616234a9493108ddf7634c5feb0af445dd",69.53931203931204],[12500,"45c2ec4db0d0532b2b28628e6ba19c2e1672d28c1c75cb76de520cc9f618f5ad",9.917710196779964],[4271,"44eb4f46637b05a869e8f6dd006a9cc8db21979bdfc0bcc36ed768239bb0f0e3",9.917710196779964],[1748,"bff04b40f844df9425914361d39099b26c093425906e6ce65aa8d4b01d07a0f4",9.917710196779964],[2553,"31c837d0237f4a511a2473001d549b91be39d9871163a2a7fd0747216f0886ef",9.317957166392093],[25,"40ede1f4bf10ae88328ae00fb56a2d5c26431d316fd7419f7661648c5879deff",9.917710196779964],[8697,"501b2a7ece618c68a40a9b84a67fa5a206d83514db84e630b4ee4ac07549b9c6",9.917710196779964],[17250,"807c53aeaca0d00f5c13a3e5fe04124cf95191bc4314b62e4b9b6c5892a7004d",9.317957166392093],[10892,"b91f43ed34b039725cd57cecb9b4ea407da4e923cd00855309a1ab0f126eb7b8",9.317957166392093],[11370,"85e09c6e57749900358b517da7f73b45ff7c44abdba871344033ecc85c6492b5",28],[3792,"bb3184aee209f8f9a0a8128c43cf621f24e84cc4789587229f6f65fd8d3202e7",9.917710196779964],[11592,"b68c73c41173a4539d59ad88cb704661b88a36479b5ec0a514060f26d3a8f2b3",37.936094674556216],[1236,"6795d6c912f3e2e05623e822522bb94550995721ef03b9c1ebd0c08d63f9caf7",9.317957166392093],[3253,"9329c1c57ec0818ea528617ca1613c9362e64e781b225736f0ce8133b5cfa5ea",9.317957166392093],[2412,"363456f8754c2a03f67e9df5b0f92797f27c739cd9a516e0dc11a2e11c7460f0",9.917710196779964],[17599,"1ea465619f74c7076da2521f59874a87b0bdebf9451c73e159ea08f5dda61845",9.317957166392093],[3308,"b021d6cdfd83ae4219b298b2bee3b506ed6ce8c0d0db88d9f36c3fa5ae3154ea",9.917710196779964],[10299,"c58073a5641b5e8ae7ebce6750e9f5a9cc7350e2d93b912a162c1541227060bc",9.917710196779964],[8155,"14d8e5b9c18a3bd8e4542a9f5d89754a016ede83704c459ba03f7baf7bdb51ca",9.317957166392093],[3322,"ad882a6c7766498c2a47177194cfb78f63e1e07c757709f43eadb4a5ae523aea",9.917710196779964],[13956,"f071b66f9190704f338fab565bc96f30dce61230cdd2556aa46c91875731dc95",16.97508896797153],[7414,"476e8038590b3046fcb07335e2b40ea881e3a0a616bb5f24543b5f1f08cd4acf",9.317957166392093],[5162,"37f97ee1fc9c230a980c37491402e5ea67c05214a4a1c5a1487d658429e832de",9.917710196779964],[10047,"c71a8e0ac38a834a30ea7b895f59ba81afa9eb053ff1faa13533e8eef63910be",9.917710196779964],[5751,"a14d66e1eb2d2638cb1c292c684e79bac7debb829f826eb4b86d0b011645c6da",9.917710196779964],[12614,"e53631dd38fe4e479c138a1b7bb301705fafb48b06335ec057b60bdf848c2aad",9.917710196779964],[19715,"603a75fbe5ea69ef32489575df3811cd141a7303474ab1550ea0f363273b3b06",9.317957166392093],[15222,"59d39a8e185488d861315027b19832a3751728fcf91eb2758ab8bde37e99067a",9.533923303834808],[15927,"c6c0a85960eb72e6cad84f198246ca647574e0bb46a39ef43db84f049e52936a",9.317957166392093],[10670,"f75942c31bfa3ad4daf0865d93525ba848ca37a81a4c1ccac786fe485a403cba",9.917710196779964],[3439,"c68601cd369930a72c35f9d2ac6175bee52a516eebb9de67d2a4c4e7777970e9",9.317957166392093],[11225,"afb279ebb4e956146745fa5275cb4dc985d006bd9415bb2cee5f8f87e9808bb6",9.917710196779964],[3596,"b4777281460b4098ec94e827e3f7b3245ce36d9975eb327fcbedd372cf3c4de8",29.822064056939503],[13231,"7f50710c0a62f351c9f58f63ea01f70a2ad3804c83f643d5248a015d683c51a6",9.647446457990116],[18537,"0e35935dcb736a5847f8e5a6b7f2dc089280dacf2d9e2eae8c1834e88fa9c030",9.317957166392093],[11594,"e6f2aedc49e60e02c9f21fdaf84f4521860f00041888b0240f259a8edba5edb3",9.647446457990116],[2116,"49625e6aaeaf3fba327135006714325427ab8decb35c5ce812136d5bd62320f2",9.917710196779964],[11737,"a5136b237a45e60ba16a72ad40df060eac3bc58f0775c737dcb16ba35a2f15b3",9.317957166392093],[15647,"da35dd7505109cd37ceb3a1e8002353a1ed6573539b290e3aecb420253d46670",9.317957166392093],[2696,"8260e13428ebf940c5e2546268be593979ee99f12c66a4992a225df96fed7eee",9.917710196779964],[19672,"235188e2ab763c193b949672804a3334ca059e282b15592846a49c6fbb068907",9.317957166392093],[8881,"98cb23dffe84b5b0763385022f330789cec41f83a2431c6234969aa75df38ec5",9.917710196779964],[2090,"8345e8fef1fdb05bf9dcf05646682d1e493ba5b86981f69430d98e1934af4af2",9.917710196779964],[13490,"6fa3c5b9845da748ab59a949c094384559e51c7587cc668833380a5d9a2e15a0",9.317957166392093],[1477,"6c49133b9793b317495c0b946b3a529bc911adb60f6c24cc1a53a7eb1bde47f6",9.917710196779964],[8603,"d29651fcfd99e1a3c56d13454c92d8665f6ac44045e6dff89a6c982bd2196cc7",9.917710196779964],[13773,"2541a2fa095cb5126eb111150f2e5258059f7074bbc7d1fe776ca8c29185e599",28.124444444444446],[9948,"43784141eb7b1cde01f00712a304ac02254a91e2a3a04b9adbc86deebd8da4be",9.917710196779964],[2676,"a7de08ad463c327e562998bc1c18e5e8aeb6b6c5b9047285edcf7429da11abee",9.317957166392093],[19338,"febe91c05a41fcfe25114b32bc39a53264abf507164d632c1346f304447bed13",9.317957166392093],[18807,"77e6e617c3afb2ac680d9574bf0afee85b6bd297da2188945b754cc39a8c6b26",9.317957166392093],[1566,"23b437fae014ff3ed32d9870a485c67dfb7804bca1d3cb71bf1de888b0e6b8f5",9.917710196779964],[16810,"34007cde20cd36d999852577979426618ca5b41a6b2789864bf9584534290b56",9.317957166392093],[3698,"e4040f67cc91f0b10f05164c1e5e299e1b949b0a17836e3f111d9836f35e99e7",9.317957166392093],[3221,"886804bc8b1bc9f37f15ff9b944617d2fc7fb9a3b39b176c9e3545bcfbdeeeea",9.917710196779964],[12098,"6e0d033233ae433fbb5f7501f44360f725ce1725e807f0122deb83977a85b8b0",9.917710196779964],[12879,"785e249bc131e2657ff68f2547a9d4b962f34c707cb93e302a3eab61238368ab",9.917710196779964],[7469,"61767da3ed2be06cbb91a53fc91b9cfca869fb6b7021763ca489abd64c23e3ce",9.917710196779964],[9749,"e9f809c5aac6051722936eefcb3caa2badb2c0b0bc4958f2ff4e6770071603c0",9.317957166392093],[11215,"fa4c6996cb841ed695ee3c50c5511ec05222ed77b550639845e46e0743c899b6",9.317957166392093],[15828,"2d6c378306d75d49c0c3c1bccca02ffc972cc7bf347a24e2dfc07eac7e6dde6c",28.848056537102472],[13486,"4f667d9e4a762aeaf7332adeb7d860fc28a66466aebd180fcb140202b06532a0",9.317957166392093],[215,"ab4ea053ece2e77456016121a31e00e1e120cc0a2a8f5960fe08a2e37b6d89fe",9.317957166392093],[10066,"5f643b8e3b783c975529c3ffbc774805bbc4b1df2ccfcb2f7305974d290ff5bd",9.651245551601424],[17083,"305d5215b126dc1e849f60a7ca10a92f3a2b858cb137e4d7bd3ad1a34c6a4350",9.317957166392093],[4317,"4796103aeeecee3d5a0e6c4101ea74f82fc6be0e7733c879b47ecd470c2aa2e3",9.397642257991386],[12669,"23f1a51f64286b8a94c786f8284477d5134269ff010826ed212efca373f1caac",9.917710196779964],[11022,"32530d5362eb7bbaf94dec7072430fe3ed837e7a1bc150f0cba4f57f1aa8ddb7",9.917710196779964],[9862,"31d191268a00d488386ba439235bed2d27d19ee10e55f6a7085ae111ac4531bf",9.917710196779964],[6341,"4eaabf9a0fbcd90f0c5100bac50f72d3b52deabeaa364d84df866313e2e4bbd6",9.317957166392093],[10879,"d9cf2d98f4330c339c18648fc3ac6d58e66d862b64a428465cbd7118e039c4b8",9.917710196779964],[15661,"367afbfeb82caeb8c4a17870e97486a9edd65d3be84c08869d61ba35f1e02770",9.317957166392093],[3940,"ddaaa39f41b0689530f902c737001ee88885cd4ad72003d890588b93447613e6",9.917710196779964],[2217,"154650e7b0b041eec8bc9d907e1c1f37b16d83dcf286cee5ec35bd2ee5b365f1",9.917710196779964],[18748,"9b4439978ac14447fe0885990fdf707ddf01ceaedecefa71965abd26986fb928",9.317957166392093],[999,"c5f291668fdc9c795ab87fe003c8cb4377ff724a4b4624c4e3dbf99938ad3ef9",9.917710196779964],[12109,"63b8e12c2ad06d50640eae834f55844b224401f73c244c47a2de902b5e26abb0",9.917710196779964],[7438,"ae52da1331662fa135b094270bd81f098a399a41dfcf71a4d5abd2845f3525cf",9.917710196779964],[10613,"804b323960ed7a12af7806c04cbd3c604474cf3bbbf80d9e9656cdd360f795ba",9.647446457990116],[17227,"5b651e04f6593fd2b7ba3ec9f3c2896380c7b494e375cdd10300beabb8595d4d",9.317957166392093],[17674,"a018878e012c8333518333d9936f20006f50f527b528c52122ecc1bb1fd4a943",20],[1708,"37ae3977a09c33aeb9957d8c329e2c666171404d963f4ff2b4a0d410f5c6dff4",9.917710196779964],[3595,"d34b6bd824be1f8b50b08cb68b93bf9eb9b1e43692361328b319bef25d9e55e8",9.917710196779964],[19577,"f44746e3427333fd2cf137b6fa7651d5f1287c1fda2f7e5b3c3f559784a7430b",9.317957166392093],[11879,"fd811f85f5883481dad71c82b40d487552a29f596cd814dbde3fa7e346ec2db2",39.20855614973262],[5620,"3de90c50595319071fccfeaeaf7535115c498219a3dd4441a8b20a1944538edb",9.917710196779964],[5675,"cec4b1a55b4769dc41e8b8bc9df4e048cd296ac228fc64de79d81252dfc12cdb",21.863917525773196],[7382,"f8056d81fc4e5208e17b6ac3351b8e9aac467d842c414ecd004cb280f3ea89cf",9.917710196779964],[16354,"530e62d6811337c3b414b3a20059329141d2de3f38050f8ef9bf0edf41a0f95f",9.317957166392093],[10312,"ed5fdc4bd26dcefcbc05686f71a3b8bb0e33ea90a3343142ed3effd24c3d43bc",9.917710196779964],[169,"75b9e568ac502e9ea8647e0891cb33839fbc4c920c6a11b98820b998a264dafe",9.317957166392093],[15,"d1d94f1e7ec647708f8f2486efa40bcb7d6ecb3d96a86b30c68efb79cc23efff",9.317957166392093],[11889,"f69230017cd2f7cbd35dc099fbf2c1210f0a622e925ae7e0028151e8925b12b2",9.917710196779964],[795,"5ef48a248a7483cf813467a9e32b54655b447911eba76117c2d2c312aa7c8ffa",9.917710196779964],[9089,"a19a4ca44c75eb7b60e5bdd6567572b73833ee4dee508b842259501cd9143cc4",9.917710196779964],[17115,"a7d491b17acb06080e7bafc0eb8eb76ce2b1b5c3bbc4350f078ec629d3ebac4f",9.317957166392093],[994,"bab3973e51063d68423f0c0e8ac493c2fc8c5dbadb9b2d77a960b0eb9ae043f9",9.917710196779964],[19514,"527d323a6c7ca5afec12d3ebcd8777aed9ac12bb04282e60220513920e1ee20d",9.317957166392093],[2310,"159c21b077a99f2aba9db47bfdb4b5917599743e301479206b187a502aabf9f0",9.917710196779964],[9215,"dea58542a4474a36e138c2e8ee2fe2945f845a936c3b606ed66b6f55138c5ec3",9.317957166392093],[3352,"c2dff0b697d542c8d6325cdb33495990ae8c396a9ab1bddf1d45ac05cf9101ea",25.968141592920354],[4201,"3518a7f01b3d427a054765278590e62b2141c9f54f5f3e65ce54367fdc0a6be4",9.317957166392093],[3533,"af29acedd691e6ff5b98457dc3ac059c5019e1e6e7afea316d6fcf696bbabde8",9.917710196779964],[8026,"acc8882e3be4e1bd0893c5837f1a91243fc1c4aac2b7dde425de6fed321065cb",9.917710196779964],[10746,"87fea94d8215b891cc829ac2055c5fe78f34f91ec82f3c4d3a24334bc74cb8b9",9.317957166392093],[16794,"f2a33aec0375b00913f8ebd17ed296678843e9c4e2893e838575156ca2c86f56",9.317957166392093],[7494,"fff53dffc06baf610c038717bb598079fd61e550ea61f8731f6508565a91c6ce",9.917710196779964],[19454,"b93142cd0e8937e82e247211167bbaa883826475f0e8a2f882b162d3789fd10f",29.32959326788219],[12069,"a06fcba9f2aca3428c5ca765032fc8117b1cda4bfd2fab235f7f40eeab51e2b0",9.317957166392093],[17581,"d01ad65105e2ad80e156e6ec08b1d7a2a4ac5aa8eb2fc988ad158714f5cab245",9.317957166392093],[7555,"644d3f823c3750bf3bd789a8e1386718b23786fe663f1a0b686fa698b27477ce",9.917710196779964],[16953,"0ff8cc51de895b0c8835e337df6950868f0b29c5ce46f2d97f56141381631a53",10.052724077328646],[14866,"34b7a664694a1bdfd331552ddb1ae6ab7ac55c5f05d0177c8efb789996a07a81",9.317957166392093],[6181,"4b65c4ec132386f07ce22f60ee96737a1e5d39c0da871394804918062a1aedd7",9.317957166392093],[7727,"d03eaef1ef91a2866d4510649c3ca832f3e8f3d7c03e9249dbbeec30c4d94fcd",9.317957166392093],[5732,"59bef7f73a5a0718212ff57c9e9536149ec80a130f62a1597222431509badcda",9.317957166392093],[12613,"b226cdcd5815bc360f30c216e7aa10e281447819e62162b4c267e73faa8c2bad",9.317957166392093],[11686,"b5f7e02939f27e2fea68ec73242ba137df28ed047986525d759a719ac0ad64b3",9.917710196779964],[4736,"5aea97fa4288f8553c6dcbea9802832db1571247a1bcc52dbfd9109ddadcbbe0",9.917710196779964],[8846,"ec937be5ca54dcbfc3ef10a0fb0b80aeb9f94f533a901a00180505800f7dcfc5",9.917710196779964],[4402,"ec715fe2ca9b9d72d1fd27c8319fdd87bac99f4a1c593df58ba8884dbaf70fe3",100.68649885583524],[18252,"86306d221d7067aa08439c4afc6a29cf328588ab3c8d6aa2c0023bdd0d2bfe36",9.317957166392093],[15432,"35e78d3076c36c9db1c191b96c5a06a0162f91e8c23e1d5febc6120f0b178775",9.317957166392093],[19707,"bd11cdb0c5c908b2d4458d321efa602f65bf3da7364aba07e719c06e1ad38d06",9.317957166392093],[19371,"87d479b1e4e92272204ba360294649c4417dfadc119c3a91aff4254f80bc0413",100.14197823000474],[7865,"2c00983b03958b4431ec8faed08a8d4deceeacb00b12ec31f579bdf5c50b76cc",9.317957166392093],[10971,"08fbde8314136d4e20799bfd26551c40d7218699c1df7116403f71452ec234b8",9.917710196779964],[14862,"99cd5b66a3f1d2c7a21fe02c37323d17a6cf7581cf9ec858e71afa9d31f78381",9.317957166392093],[12053,"c1cf551b309a351ce0a120167e1d430ebef4f794d00647dded45cbd8c5e5f7b0",9.317957166392093],[7789,"6f28ca98cccff6195db27d8a85de34fe9468e6c1eca8ec8a7ba110f854e9e2cc",9.917710196779964],[5746,"3bb418e264786ff284109fe64be600e833a5107bb0d0cccb839d0269814fccda",9.917710196779964],[16239,"0d5635a9cca74022d8971d3f4f1c1fadf65e72844bce4a455507319b66a6c562",10.052724077328646],[15334,"d4bd4e244613daa96f184465c272712e75c81fa2c32445f09d62380680f4a977",10.033847820200378],[14196,"5d27ec593a3001c4a17b135f4c737b756b76a57ffefcf7ea5ca9f98eef185b90",9.317957166392093],[13509,"430399c3173312164070f189e5db572f00ffdf3b0be49b2f21b225a33b239a9f",9.317957166392093],[16072,"414418153a0f0723f94efd2514c41bbc2d2a0d0b833781aad91fd36af5f9c266",9.317957166392093],[18383,"fac93b62900b32e3f33d52958b189090b6bf35e42d90aed3503626ced188e533",9.317957166392093],[372,"5550e407d15f37215466007d98c86c336f090fa814941c43ecda9f248dd893fd",9.917710196779964],[12694,"d05da2f0bfb210afe011a8b685f132adcd8457a218828167226f5f8b62759fac",9.317957166392093],[3778,"a2b005cbbe153fd21517727c923319612d99a64f0ee02961dfa5c6da77ca1ae7",16.412848867825172],[2245,"318823ce08b1e319e2feed5107f9c03461dab433022f2eb8c24b6e3f818147f1",9.917710196779964],[17371,"08b3954a0702f40ad4154118c80d38e32fdcc012779425bc42bc2403ef3a754a",9.317957166392093],[18742,"516d0d6bd2788bff44e40292d298b13283508183ec7e2496c7fb1e562559e628",9.647446457990116],[10622,"69cbdf4fb17d1757f8f59a2d16fff64f24fc94906cb3e9268d5889fea4f58bba",9.917710196779964],[6432,"d63749606dd6e301ff55987ae69c167783284d23fb17573b0bbbac1f40b710d6",9.317957166392093],[9563,"135b75fed17e8c4613d43042e81422f7424c2410f7cd9e7624bb99e0a3e838c1",9.317957166392093],[9924,"ad972a87640ac12f93f73c323933a650689d86e9edee1b94ff2da1098be3d0be",28.14867256637168],[10533,"31ccab0f01ce4e4ed45f70b472fd67b93acba729d549ca38b364004090f3fbba",9.317957166392093],[10574,"ddfa6345e6e9c151c1aaa9892732e743830042be25ff24e0558e8e2e3fb1c4ba",9.917710196779964],[14959,"23058e6f733f74f5f645238a31704d19bdf05e6a3694aaec8462d0b0a1d07d7f",9.317957166392093],[6431,"a45c6fc06d30135f73d320f275aae894f3f4394ff9cf8230fae41f745c0b11d6",9.917710196779964],[17525,"4e2bc0364302b7baaa560e1f763ce31379c68529bd2de2d2ae21d37a5b1f0647",9.317957166392093],[15666,"008cf90e32e69904ed006d6dec186d1848f4089cd73a23e60b0649bf56b21470",9.317957166392093],[12767,"2de8cd7ddfc80569ef471c9347e25d4c4e12b4e2b4106f4844b61c2dca7420ac",9.917710196779964],[11730,"c4531c1856a33ca9288a643022c529a41ea9b763345826c94d9d7e3f941118b3",9.917710196779964],[4630,"da34361e3c8c1ca365580fe9e415c6d362e0fab94bb8ac6d7a9dcc0b120e70e1",9.917710196779964],[19068,"5bda0404458a5437c69f344809fa89469677f2a6a7a9ead2ed8045795a53041e",9.317957166392093],[12413,"7129201fb30b38b0d682a5dc6147fa9fe2c1e8c718c02ad99530b6ec81cd84ae",9.317957166392093],[6761,"91af291795fdb8c88ecd79f5034d2c0d639c839483f6068aff2a35cd335a83d3",9.917710196779964],[15195,"98743601666f65c0d6daed34f774497fb17e42d0f0805986021d14e01b9b997a",9.647446457990116],[6829,"5176b462fe5097a94f73dae7f9df2f1e68921ed96b01bc014f10335da20d11d3",9.917710196779964],[7190,"d793d372f40b95069721175231488349c91f041f9624faade1da68a99802c4d0",9.917710196779964],[3501,"af8a3be9326ff58427b047391a921a86d5cd9e6720bd7f779c6247521af0fbe8",9.917710196779964],[8010,"014cf0330d8b36bbc398db3a639f3d500fba94768dcec974bc6dfecbfb3279cb",18.091370558375633],[959,"895aaf71ac0a0424375b5cc4704f947176ccc96fe97bccb1f7e60573ec8f71f9",9.747997086671523],[3459,"5a5c006afe676235f6d06cf727c755d3799b05993293d03f6b614aac786c53e9",9.917710196779964],[6883,"bf11506768979ae2d064e414e302fccdcc52b405c833c46b1b55a113a6d4b6d2",9.917710196779964],[12073,"5879af39392c7fa8a872b7ab635624206f030d88f9c8419ffade9c69325addb0",9.917710196779964],[5411,"63688f903188b5c96610eb36d67b20e527c03f9a79d431bdbf9ac19a85aabedc",9.917710196779964],[19297,"d72503bba386ba83a18d27e74972880fa93e200f3e6c37c3df5cd3982e80fc14",9.317957166392093],[16668,"971a67dbf675fbb39287e79db6082e845bfb1d6b23637052f1744832e1585659",9.317957166392093],[9715,"d3e813082ad32da254fb10bcb9c93ea437543a087d4c5b411085d7f4d4c73ec0",9.917710196779964],[15223,"601c66c9d923540b607782b809049610a89c381de0c8719f15d22d54b8f4047a",9.359398496240601],[11579,"426fd078f64465945ae0b4b7efe94c0c1bdd347b8ffc8736e47e8ed409fe00b4",9.917710196779964],[8172,"c1a59a16ead8cdfed02aa61c647b5b650999834d76f31d46c72289d93e542bca",9.917710196779964],[7368,"c5ca189b7a20ca19ab360b474e504426cb6e969a8e8184992fee0928533498cf",9.317957166392093],[1437,"5fc77f43aff3971e2effbf133af9ccc2c7461b130f49ba5fa4a84c05baf196f6",9.917710196779964],[16076,"15655fb1f801b3ff725369cb05f5bc29c84cf534ae1920bd9a418a9a0f07ba66",9.317957166392093],[19104,"15862b5cfbd30fa3cc6e61260b15e0aad98ac2267af3541c78c87bd49ee2931c",9.317957166392093],[19680,"8ee8f316e88e0c1570456b6268f5bb9375232f11807440716b6f42c21bcf5f07",9.317957166392093],[15002,"e29bbea9fbd1f0ef34e97896b95e3f29d5c72d8414151f5d9ea4be85967d597e",9.317957166392093],[17585,"f5a2b8a671beda8f06d269ef7b2384295592622314b3d1ce48d36a3a8b568e45",9.317957166392093],[1868,"343d83b09b875f9a9758b3107ec5e95f0d909e14aca1777ec13df051ea86d1f3",9.917710196779964],[5794,"2f09624e9d6b182733bd63eae1cad21e5d3077c7c8836f39b7f00cc790e477da",9.917710196779964],[6936,"f699e1900516048b9af35c2e563d5e0fefc2776cf9f7c8ed89b809dcfa2d67d2",9.317957166392093],[5501,"e772296bb49c52941a28b5e449b338ef71623187c132a2b502506ba5a9ee38dc",9.317957166392093],[10256,"e6b973ffc6f65665f18694d1ce224265b84670572e160679e880eeb18beea8bc",9.917710196779964],[18337,"f6857d55b9698b8b0d6dfb89b7a9f3406a5e3d19fe42cfd94854277c55cb1f35",9.317957166392093],[10419,"a75bda6b697be112009fdf9ffbf11e7b7ca35b3dad3e7b2f4f4aa100fe6dadbb",9.917710196779964],[8015,"a6463f468ea409e681eb2bdf3cb9e6330f423587b83ca27300321861565173cb",43.67736883320282],[13652,"eb74b1221eac95acc6ff56dbe0d6e205ce487008b71545dc35ce3d8d5c1b259c",9.317957166392093],[521,"c8de37b0b76baf094960b1f7676c729085a33958a7857f8e8dba167945e288fc",9.917710196779964],[9232,"252a9378f167f322173f0c42c174f786897470dce69cfbff1cb5162fd3c537c3",9.917710196779964],[7666,"2366131b5ccc821eda7016b716720c7ab5659ade8446ee4cd3be41e67014d1cd",9.917710196779964],[8087,"6681d8e849e98a262fe3aff0dea189b08b3ca524daa43bbf3c7b0264a804e0ca",9.917710196779964],[19762,"060bda3f4072b4e7406f8fadeffeeb8fbce383f2d8e507aa4a492c65d0f43104",26.093862815884478],[16800,"7eafad09158f84c3fec9fa0bdeb6c86d1cc56c4f4d1c084ea21f9a9c05244556",9.317957166392093],[16782,"df609eb8140c4d855459233c146bc074a4f97d2d578846a98cb084864dfebc56",9.317957166392093],[1030,"80132ec1348898a6cc77157cf52a694b38be2c8c31ef4788c5e31745759311f9",9.917710196779964],[14837,"02080923fa3d62a4461bbc2b709bfc7189da0a752a54922af5c8faac45c13082",9.317957166392093],[6633,"0f518fa0b0237bfad96f11684b26a529a0a4d7e899c6da7dc82dd1ca78e270d4",9.917710196779964],[16224,"df62d4c8b8133f02a6a373d428f2f0fe199745219045b6b5bcea54081f783a63",9.317957166392093],[5426,"ff7122bfae4aceb21d765385e24bbdd5c21f5d2ea0b6013dd5f2e827eb6fa3dc",9.497326203208557],[222,"64f0b258bd4745097aa28c37737ebe490814394df1240b429a503162b3227efe",9.917710196779964],[8956,"5e97f11b629b899b88648845d932692e6ae4fac8303ad7dd85df59a2e44414c5",29.112403100775193],[338,"3f33a73c83101a57406b425bdb0a48b55dd39a6aa0b65a372e75c566d340c7fd",9.917710196779964],[10224,"461ae97b4142dc9a3705cd7241fbd9a24eb66df56308489a04b48c18e652d0bc",9.917710196779964],[10111,"74655d081df5ed33fe3c9647a19238131c995d98bf77d0a2aad5c4111e829fbd",9.317957166392093],[4789,"40acdd9399662a63dac7f0935488fe95eabe057d92b48ab8289e7bb1a9ea79e0",9.317957166392093],[308,"0ba5224df71d11110ce2c5501caa83b12162ecac87a32ce76131a9fb3ea3eefd",9.317957166392093],[12586,"d13d207ace69f120aff699b4850ef402c1d1a9491b1ce8d0cc66e5d36a4159ad",9.917710196779964],[2285,"90bcf442dafb00747e127132a965490d1a926809a5665301498eb92876af12f1",9.917710196779964],[11833,"eaa8ca551b0172bd7c5bfe02d2389fb46d548d155e3f7ae64e6667847cf882b2",9.317957166392093],[14447,"899bed49665cb76403ccf551549b4676302e241f73e4fbe654bea25e2cdc4f8a",9.317957166392093],[18593,"c4de5809868ad034a18971662784a9ba0a5d891dd1f06769ee84c4c64e81032f",25.35410764872521],[1204,"a46ba082b63909dcbfa3dc35a71d78db714a1f726f28023295bd92c77b73fcf7",9.317957166392093],[14663,"9e4b6382646c38ae7351f83acc8afa67c803c468c3f50369b74cb5baa48dac85",10],[5264,"56145843ca8e41c0b0219e2ebcfd60b6bbec913de8e1bee56166cc92361998dd",9.917710196779964],[2880,"240d816f328296153940e8705fd2b3499802e670973b9ac45fd3223114a53fed",9.317957166392093],[559,"358c34a40b2f6e60063f173a91d36c506fccf53d30798ebcbfd14e405ca63cfc",9.917710196779964],[1813,"448796669b6c385800e16e9f600c3a86c63bc25f13118f615114b31f14c025f4",9.917710196779964],[4677,"0c35678a247a4912d00773694ca21ad8d38d7fd0d265ef5ac00584629c2d24e1",9.917710196779964],[1394,"26d033fbe0a1191658987fd17880d74fe8dd25f7d192ce8398e10580f08bd2f6",9.917710196779964],[11070,"bedf644bced4b512c360a80f554d32d16e41d4286844f14d73f80886b60587b7",9.917710196779964],[5761,"21feb2712612eb7346a4799ce7d29283bfa286999b7a33496fb4873bbedab5da",9.917710196779964],[6206,"596773591e026171f6edcbf09e81b497e42f4826009be0059feddbeeb77ab7d7",9.917710196779964],[13764,"5555706a681767eb6db3c8636623ce8c1231d8e135f68d462fd1e7812373129a",9.317957166392093],[14019,"6a7a189e45620b4d97f4f4f6796b2e211c3fcd670f43446d39a1e54a64c86994",9.317957166392093],[9009,"fcae7f72b0d639ec758a41f81e61b0c00a85663c6be0db8157e7777ac68abfc4",9.917710196779964],[6527,"273d624101a829af44d91e8a95816bf8a804ef9937aa50ece86fcfd440163fd5",9.917710196779964],[11196,"91f9dde524d2539f5f963e12f3c96fee02909b24f33042cabcdc6631eedfb1b6",9.917710196779964],[18648,"34b4b1f31ee52f9337679f343801078f71bb3acf9d3935d8a7869f955ea8c12c",10.052724077328646],[1740,"c033cf2bdf0f2d07dfeca8bad030dbded39610ead76a95064c473dd0304ca8f4",9.317957166392093],[5384,"34bc7263fe409043cb269613f5cf319ed6627f5595a8fa8a1cc21cf52bf5ebdc",9.317957166392093],[8800,"cccb8eebee5a4f2913391e91182b8ab47cab69167d32032aeb83fdde5d3a14c6",9.917710196779964],[8606,"779f7cbad0620c4b7bc63ace9769d3f358e1ebb64a60a5f0828226339d9561c7",9.917710196779964],[18101,"f7b34107e6e66094359d9935532d76734623398541c27baadd1115325153e83a",9.317957166392093],[15350,"bb5674e7463e34830a1347c20e2fe610285ea7bbb9418d37c76fe70b56c45c77",9.317957166392093],[6900,"95c0a399fe9edafd491f34d3a7f222e225195defea3437b0195a62c6d9149fd2",9.917710196779964],[8331,"f7cb9fd7ee0dc8791dbf75fe9c3888064ca072ac7ccf17c6c13e476740a81ec9",9.317957166392093],[12511,"f6938d89a471927a26c3fdf4b92ccee6b3527465021ec9885fb116818f8de7ad",9.917710196779964],[18193,"ac462ca7df6ac3e6c377d502113ede8dffae151cf709b304d647d1621fc25a38",9.317957166392093],[12006,"baa603427e2c40252745697bf9be5bf236860d4179d8e682423e4347067f47b1",9.917710196779964],[15870,"76fcb936c5082c0a1caf49c77a6197aeb730bdb1dfda445feabcc5e788c0b66b",9.317957166392093],[709,"71fbdce3d0c2c7ed43d8b380104dbfe481589162ec62e8f6da3d84b757d62cfb",9.917710196779964],[19842,"6955ed766402624c61101bb11cad5400302a0b06299aef35f9027feb30b51201",9.317957166392093],[3876,"87109c0d4ddc84a7aa329db2b2c2a0adf58d83c6bd5ecd67e47c67e5321988e6",9.917710196779964],[3072,"b793f73b61138a6275ad276cbb96833f88ab64dcc096a19020cae1c5255bd3eb",9.917710196779964],[19184,"9f4c64984306f7454da36db510a0cba829f01f0a6c191a52e1716aba37223819",10.030959752321982],[15104,"c9f153020729f6492230642a2653041c926441dc69c91ada2fc6b33be587897c",9.317957166392093],[3179,"57fb05067e71d02583f67349e59d746fa2526b6b19294e9dfcc66010584d28eb",9.917710196779964],[15188,"cde25e0d9ce04db50287350f2dbd1fc4de78d28116d020baa9c2d348e584bf7a",10.00375234521576],[12012,"63bb2ea172df0415cdb58d8b2452ee2b14414991a9c7d25978ac26d248963fb1",9.317957166392093],[9605,"5a1f58cc76810437f8b95b6f8f09088684fd76ec573f3b92ec5e4eb2765e03c1",9.317957166392093],[3432,"c8300c7f645cf325f7bb7636f6b9240942e283215f414553cc596fc75e7479e9",9.917710196779964],[6530,"0d8e7da2fcdbc9e1d6b1f115c3d739c0d7a6d1067fccd09892744703fdcb39d5",9.917710196779964],[18606,"33a3496167636774e62ff0342e71259725b39204a183109c8ee104d209867e2e",9.647446457990116],[3842,"6e0ee5449fab8dfc0f99910a3a5c94201f140c5215dbafdb9271485b2c1dc6e6",9.917710196779964],[4476,"7a811745fab5670148dfcd61bdccd337670fef1f1b818bf178b8d77910918fe2",9.917710196779964],[1446,"d47cd8ab8691543578e527a025851f49065d30a0829bf660829eab6c8cb888f6",9.917710196779964],[14626,"664365e9d79d3b250eb015178c260ddefdf7b618228dd0114efcde9fd2ec7a86",9.31549501337874],[14403,"49fb495069b8ec61c8453a1a5359427518e82aa3246fe51897cfee09e16b358b",27.149153625039922],[7630,"fd70d8e1fd83ac596473770604a71b1f9ab163f1e073c57d96b5d3f8391107ce",25],[12808,"9e1237712e120ca7b9da5d02851b8a7227a1c4427c60666b16d512c9b474e1ab",9.917710196779964],[15395,"5cbbcde81c031471153adc1c3bdf8eda3f9b6fe105128db31cf51d15ae846376",9.317957166392093],[6147,"7db33a6158608de9cc94d031ff71b8a6382884d0893854a054a8809615f128d8",9.917710196779964],[16936,"5265a7bc182c3f5103b36f7d3a8c7f3381d2e27380f27889a8060c415c336353",9.317957166392093],[13602,"a2fa26314a71582d1002b191a2797abc3ce4d5dd82683369c099424b291f5c9d",9.317957166392093],[18283,"94171af7b916e928c34406c67ffff24c2d795ec1f9101ae7d41e906ebc6f3436",9.317957166392093],[9537,"74abe8df0e4445378c2e1e9384e9f444e0e48dcde53aeab00fa2be16076c75c1",9.917710196779964],[19695,"4af7dc9f2d8851cf51f5b76b2013229034c80e9bb7801bd6370bd9927f81f706",27.004807692307693],[13393,"a5eea0afbceddf6829f4afe4f1fc3f86f9dff83ba03cd10689c3524f84e07ca2",9.317957166392093],[17367,"45a64f6f8248d6c6c9dfff1a7fb75c91f8de57b08eb16a79b350b41b3bcf8a4a",53.97276853252647],[8880,"4cb84af7b9554f5206f7a76b8c11138db61e3eaee407e82fc3097eb21b0d91c5",9.917710196779964],[6940,"2c4c980067af3f50f858ed59f9175c2972fa1acad578f02116a1694cef185ed2",9.917710196779964],[2652,"ae3b7cfd7a2c461f4c679a5aa71e31fe48789f64cdc18a9079aae4b10182d7ee",10.052724077328646],[10712,"bc49920f39b2aac122aa94f7dba2920983c577e7d82d8aafc2ae505b067bf1b9",9.917710196779964],[14190,"fe6fbd53291009969272f598a10e74412e758784a68148e8f962d74714a59090",26.090592334494772],[14350,"e24d45060b3c578721d8374a0c0b72bc9492eab84b3311c4660717dc2d1b578c",9.317957166392093],[3557,"5faad45f0d46b7f49d49979860efd49e412c71a3fdc3cfbdd495d3f860148be8",9.917710196779964],[5405,"ac2d13381373f8e30fc65b10a6dc36df56d3b4c47f8ebb4ea2c833d2ac4cc9dc",9.647446457990116],[6239,"750fe5eb97857fb70774e83d9117630ab454c42da543a9a2fa37b3dc7db67ad7",9.917710196779964],[5228,"50f48e0a9826ba62126c163f2be21f5cea4427338c7b550a8bba8e782ad2cedd",9.917710196779964],[15101,"4cb419d10450f612f74efc17a1457e707d0b2ce20812d686a92fbec808fd947c",9.317957166392093],[10499,"8ea12f7c267d1dced256d6bfa2b77e8cfaf9a10b9c6e98610439bfbbdc862dbb",9.917710196779964],[6349,"2745327e90be659b0271614340bdcb032283ef232a995e1fc9ac90833807add6",9.317957166392093],[1945,"13e03ee598f36225a51acf24c83e53fff96ca0f5956a6daf6fa2f19365aa65f3",9.317957166392093],[17787,"3d22e18e6966f0b3790845a68e675309f07902ff869758c74353c142464e9441",18.130434782608695],[8455,"97d1a0dec833656f896d675aae9057e1598c0517b2667d7621a5fa78e1aa4bc8",9.917710196779964],[14763,"85d3dc9043996456ef04152dd5a255bb4f0e575959467039cffd97d91c1db183",9.317957166392093],[6171,"eca2844638368229531cc0e6f92369b88db510fe098793d59aa0b9fb6756fdd7",9.917710196779964],[5989,"c56d6ec93ced82a82936de30b9bbcaa492df399aca6fbff8616a17196d5027d9",9.317957166392093],[6968,"649a749210e014c1fa7f1e4a3b71f132a40748d454e457383f8410b226c72bd2",9.317957166392093],[19804,"bb34641f78a6dd3813c2dfd5288faebc3464e3078cb94803283d196d6d705902",9.317957166392093],[11117,"75d3c2cd3f498da5f8f463d65590aa3964cd019505e9aa7dc12ebf8cc68f25b7",9.917710196779964],[7064,"da92b0f770a97e9f931f6147c4645030c9acf03cd2a801e232acbd52d24a91d1",9.917710196779964],[1839,"cef4f982f98db3ea2868de2217edcb7b026fe00db2ec36bcd910d9017db1fef3",9.917710196779964],[16949,"7be1be3ea502e0de0d5636d4c85b7bf7e096e4445cad801c927cafbe11912b53",51.21107266435986],[3396,"706488836fb9402dc4c38ffdddb14d259744a4d78a2532e981fa78eb2fc4b2e9",9.917710196779964],[12892,"8ce8dd653a216fcb73a0c8a36a120422acbb2ff088bf19f9dc4edb1fe2e356ab",9.917710196779964],[2751,"2ce64fd0fdc86d4da3c08f8b3ac13c16ab769617b02b0f19b5b37aa87d7017ee",9.917710196779964],[5477,"954bf398a5838461c412ff75871904098a79f951cda93268f716621ea4455bdc",9.917710196779964],[15669,"67a139d7c9d608774c99b25e61fd37d91f67868fcb55e8faf1659656f47f0870",11.058407079646019],[17423,"c12adfdcdeaaaf9e3689a77f955f5b511382ffc6f76b447a58588bbd315a5649",9.317957166392093],[18837,"003e9643158fa25f7baeb9b9db56fa7367d7dc16342ce923c62adcf6b2197b25",9.647446457990116],[16449,"1b7ca5fecc985a97d06fb3b0abed1483b5d99c6a2ad80c335b4a92a7b9ec3f5e",10.044313146233383],[18203,"852c32ae26be80e11fc602d34c3c1decb0bf917d2c5b2996d92285f3409b1638",29],[6765,"4ea2118399ad994fedabbb966c4e22b45788b7237f57bcb488ea48405f3582d3",10.052724077328646],[5361,"777a66775495d10ffd3735f402e15ede75e2cbdb9fa33bd8404c822c549a13dd",9.317957166392093],[698,"9f914701bd235509e9e31830788b7f40f9e7bd66494caae4dacde7a1224543fb",9.317957166392093],[11828,"4ccbcfb5b02ee8faadc5620a68409908fd82da7a9bc101a2daf426dfb44988b2",9.917710196779964],[9778,"41915a7ec078abf258b5385de43f95611f011003cfb13f98c02f5a72e478d0bf",9.917710196779964],[10855,"ffaa83fbb5e134e702b2c981ea024527a454723013d404be25e55aab958bf6b8",9.917710196779964],[1627,"a8d1fea75cfb2eadea6b03992c3e5e018458c4df133c06e16cec010d958b6cf5",9.917710196779964],[1504,"f187a7cf40b653d697915bec0840eab21c5be5d29d3e5112b6b2efe4f20714f6",24.022222222222222],[12672,"4e54914806da244df660456e1110942580af3550c802ce505dbbe08c7142c7ac",9.917710196779964],[15611,"15d17f32ac5e02a18107ce3853f4656ffdc9b8e69419f2d967b839aff40d3271",9.317957166392093],[5007,"e727aed6cb0b6e96dd19b1215d07669f0b7d7b8693886a3e6d15cd4144ad1fdf",9.917710196779964],[14691,"f8e5890ec78186557eb59274fdef97c96f34437bb5e5d3d756acaf9aaf030985",9.317957166392093],[3690,"7d7f1b3feceecbac37977b172fe6c27123b4e61aa07e8922dc185afeca82a7e7",9.317957166392093],[14826,"fb3aa1c491de6375ca47ec77b33912f05c60732aea1720ca873b3c63b4e45482",9.647446457990116],[10714,"4faf8ba290a73e67891686fb15a45ed4c4f7ecae3ff78ad3aa9957f4cf53edb9",11.036158065599462],[9170,"a098e3b151df2ee655fcc9b22196b0dc58341845d8a0b1011097cfcb467eb5c3",10.052724077328646],[13952,"0e6a388727918b3ee60b0608dde7278c426b09cabdcb38ca0fab3dadefc8e995",9.647446457990116],[16735,"7d33f9e6a016a37affbd885f9834ed6d38a44538b08f4e6c64d7bcdf8904b157",9.317957166392093],[3243,"4ed0cd8406cb3b75abc92c1cd576302ca124a00f27361be4c722b720c4a9b3ea",9.917710196779964],[19643,"918d81099c73041c9a9d7c0a2884b598280ce50af3fe8b8b03c653de0d392808",9.317957166392093],[15605,"bab08c1c6777d050ac3c8738203153a0ad9333c4d5624c5be566c9444d184f71",9.317957166392093],[13193,"e32882366abfd19bdffbbc79f52ea659b86889b5927cc7f8ed56538203adfda6",9.317957166392093],[11387,"562953d9713dfd5feaa5059e1a68feadbc98aa80fe47da3cc74cd02038b96eb5",9.917710196779964],[10711,"b27d503f03639e3a2f4af90cb063032cb898aa3494b28224b2ce044f7a1bf2b9",9.317957166392093],[13060,"67b2a88940edd3224a0ae90b2d0d946034af9a9139d76fb243072c2722853aaa",9.647446457990116],[16423,"bd1cc02ab6a2d80fa21154966bd99590987f3a0a20c8383e7816bb3040c4a65e",9.317957166392093],[3423,"4f23b066397af5de67dd9a1e38fdf9fb559c88f17130bc824516f8c0185781e9",9.317957166392093],[5296,"d9f09f19f183034e8bca7d1906535c83b16e6263de638f4f8e47bc624d0c70dd",9.917710196779964],[17497,"294a56587f95adcded6452a54ec309e3a67422ad06daec3b1bb744590da6a647",9.317957166392093],[1465,"2dc227d98024895d2089e3ede7b84ac662f9d212414e059df22c9487d90864f6",9.647446457990116],[19139,"28d71769781bc20631957c442138510f510fd946d5f6db3097c56a8cd600e21a",9.317957166392093],[7421,"526cc5c03eed31dba7fee693850f575dc3c02983f3a53ba39dae643ebdb342cf",9.917710196779964],[6680,"e8c4f49314907541ffa7e2315eaa06b2b6770e7b72c0105e53801b8c26251ad4",9.917710196779964],[10177,"37dbb7b0675e4aaa182588d8659e1ca21b43b3b472995cb364cb24a8b53730bd",9.917710196779964],[9975,"5f9f636ea276164d91a594b4c863fbc89aff2964fd74e6186e104f91070d79be",9.317957166392093],[11230,"bb5a468829a73d38ef509b86bbaadd9d4d4306ff3877ac5d78af38b9a6f481b6",9.917710196779964],[11563,"6f096c419370116dc2ee4cdf4f1dcaa5e3b7bf02785a1f9cf483ca9b461b27b4",9.917710196779964],[2517,"508f7ad460ad0c0bafa4849791a2bcdfac2b18448736d871c91f646ecf54b1ef",9.917710196779964],[2290,"1b7d266b8ba388d58e8555278ad0e25c7e01cbe677e114b211098ac624260ef1",9.917710196779964],[17849,"6c60d90f4c52034848f9de494ccdcd54eec98d4eb1a8430d9c74868cca0c3c40",9.647446457990116],[2093,"07feb529046401e35299716f380ae4604e3efb07ee1696f9078740cd8b5e48f2",9.917710196779964],[10754,"2e005e1e881cae7fc4edf7d579ff02ccb13fbfb6d1fb3a2b666c45503a80a4b9",9.917710196779964],[14382,"2400f4f5abec562f8168e4d61fe637546b11c54ab9a3b312db5f4cac5881b28b",10.052724077328646],[4047,"1ad041edbaa4035f6d8f44067825572e0e5fc3be73050b7fd09e6e74058c74e5",9.917710196779964],[15353,"1917c7cf8bde8fb07611312b021db3df910378adb9a613480c31370a0dcb5377",9.317957166392093],[19660,"558ed5f72ada65a7907019bf94670b1e8d4e6d22ca7a8d454cabb5e3520cc407",19.427814569536423],[9531,"d779797160a15e452ff89c9db9251e98b5a9b83629f313e6fd360bf3e0397ec1",9.317957166392093],[11139,"cbff27a478768d50d2c0007f01be41a6e05b55aeeebe20186ebe070c9fff06b7",9.917710196779964],[13028,"9a7c059fe44300f0c356bfe8645ef625bf7f7011ac79f65936771f4dcc8b66aa",9.917710196779964],[14731,"ce0572eeb14196a2e446ee00a028d88c03cce94d00f0b6851b6f6c5140204584",25],[11016,"dc0d28dc13b013e8108c0f699a7a51b2ff03f269ecf68093a3fde9ff0324e7b7",10.052724077328646],[10841,"982a0db9af98a8f347d80445dfdead7f487049121ac49c0b200d6bb128f60ab9",9.317957166392093],[5791,"da38cb43fc74f6076e5791774d941603d85b633d3d6fbe287c768f24ee217ada",9.917710196779964],[6001,"93fec21971742698a8c8968822d80e1075ea5bf42506aa5472ae746bdffb0fd9",9.917710196779964],[18370,"7de7286fbaa9bf6a21a916578526342c4597aa4beab48e7503de469f9f134934",9.317957166392093],[9772,"58ec88f42998a2b2d86558b58a2f7273b9cc5ce7a8276783100393152e4ed5bf",9.317957166392093],[6290,"cc75d36b70117fa66d294bc681205cb29d979ac581431bd3713f30b034021ed7",9.917710196779964],[7841,"70e3ea1e9ec29e89d5721eacbfc31931584697eecaad5fa190ee7f90b0008ecc",9.917710196779964],[11683,"c2c82825191ec1185ac958db7f3623ab7b0c77f9e2fce90057d8c5dbec1569b3",9.917710196779964],[7888,"8197d8a1267d4ab90c00d8323707a10dea9597aac494bc4269735a778ecc55cc",9.917710196779964],[7981,"e43ce2a44a4cfe57cfbd7a99759af517ae0bf7f74605a08927ffc5810043a5cb",9.917710196779964],[17239,"db62883761dd6d8560970f9f04ddf32c4a45307b22d95aa7eaea7108c584184d",9.317957166392093],[10495,"2121a2526508f7e35232dcd89e5df1ae29af399afe95f3c2135c83fa993631bb",9.917710196779964],[15649,"281fd9ba79aa7d4fee341ad17f608ecb71b063bd96151aa6322fbb4f45285470",9.647446457990116],[17112,"7f0be11a5ff71dbd76b3a60390573953c2c8c5dffd22e6726db75f50855ec14f",9.317957166392093],[4643,"14ef3100c6be8d8e1d2dba0e324ac8b8f06d5003d0d13e228f033996ace15ae1",9.917710196779964],[1299,"25480d9cae5746e70b8949e1059e0d6ec8468bcddc69b49f63ffc81cfadb61f7",9.917710196779964],[3798,"b16b27263afbb775f6dd344afc5604f0a75cdc04ce41e19644cdae47105ff8e6",9.917710196779964],[18875,"99912d20a0d9e0b78922e7092b85ed56e4d6c7de9f3331ccb1782cb311d33d24",9.317957166392093],[10290,"a64fbf0bcf4a30f24a41eb1d458bbcae22287df1559c8632fc490231d62f72bc",9.317957166392093],[8315,"1c1db462d7fc29700396322446acc5fb15e8597370b0329e0f6c6f8188d73bc9",9.917710196779964],[10932,"0820fa8047462c85c88324245121aec692515af7e54c6c98907d5a34c5e17bb8",9.917710196779964],[15735,"ecc47cdca1db338e4f6361eadf7b8905ce096101bf446778767e490ad208b76e",19.216323131376225],[17725,"961cc75d562bb48390879f2bf6d469a09329435a259977aaeff5b5df6800b942",9.317957166392093],[3194,"c1c01783894e62236972cddd994707300566ec15b35598ddb5221c53fc2315eb",20.848484848484848],[6696,"55781f2515469aec90f8538852cc6afcc9b1689e83e1c4743f595a6ecd8cfbd3",9.497326203208557],[13253,"dd65c5bff09cbf1c0236e0dad61e228ed42ad241e6f3e705073fd3718fef9aa5",9.317957166392093],[17669,"b8d8947b58f8d32704a41269fe5c620857be620b4e151bf5b111901b6071bf43",9.317957166392093],[10958,"f840cff7e2dbd886d616c02c96f2faf97b4d69fc860e77e00df7a40dfcb84bb8",9.917710196779964],[9670,"2c0f2514dfe0b12f3869352d494c2339c015dcc4797e2c7f772afd21d7de93c0",9.917710196779964],[3912,"a76609586e62eaa592011b92fa97082f047b45db83003312ba4c6e449d8047e6",9.917710196779964],[13992,"b65cbaf305e4e693ff4e615b5e444169049f3bb146c20443b7bd3e76c72a2195",9.317957166392093],[17212,"056ffc07bff14ab4cf711289a163ba30cea1e3accd693c5a57088cf42a69974d",10.052724077328646],[8942,"6f0cee8f4d8fea88cd3dbb598329d3e952ce1ab554870d4a5381d0a6b03c2fc5",9.917710196779964],[5217,"9a0c12dc197a41d8dc16a2e6887645afcd00f48e712b329cdd4867600ddbdedd",9.917710196779964],[3303,"e788166e2da9d66f4e39954ae152999875392eca583689d535b6167221355cea",9.917710196779964],[11649,"747c58aeca15570cba7701b68b3d8c7565fd853b81cabea8e3f9817e96d49eb3",9.917710196779964],[6619,"46761d46239ffaa1ff597267351891622d4d2f255003401c23515437361583d4",10.052724077328646],[13167,"63b5bae702bd97d4e2540700c09aad90cf725a157d8393c43413233d0419ada7",9.317957166392093],[6208,"99a23291e8edf2c5e2d01e43239a62d7054b74c88ac90b45cd81a2c41f54b1d7",9.917710196779964],[17850,"be75175eb91fdf55a32da4741155cf8e524c48c15bfee0f1012e043ec18e3840",9.317957166392093],[15368,"01545880cfb4fed70b34fe75d0dd7be2800226650561a8b4dec5f352975efa76",9.317957166392093],[2778,"0b8f1b40cb032e13f4768b8003efccadc2f569059c0868021c92cc498edbeded",9.317957166392093],[3869,"df7ebfb7d2e959c71b4b172d018222d42d68d5d9d4f598a0681ec08a1ebe8ee6",9.917710196779964],[18894,"2723ef45f17b52b0a55af611ab8d667caadaa24abaeb103455d34e13853ea323",9.317957166392093],[19557,"8d6e4f7ebc271751fe51e3140188d007ac6e6b66b4af61c17af2cc78a91d600c",9.317957166392093],[3092,"b6fe7224195eafcf76ae10fa6842bbb113da088eb9127e121b9727fb8f86b1eb",9.917710196779964],[3897,"9b7784e3eb8274c9679d4d1a4db3395dc031c19d143a9c0d499c767d3cc060e6",15.04117108874657],[12337,"40817092505e3e5df608f33ea9b239b5b5ea511ae83721cb204b82bec1f5f4ae",9.917710196779964],[15138,"0701ba8dbfaea542c9272185b71e2db4de517e41f6ae63b1b5ce10e689afe17b",18.09625668449198],[17418,"79833141f0c203eaa93ee1a1c83eede0c1144928dd507a9bb8497fa2ecd06949",9.854867256637169],[4733,"96103d744ea226d23ad483bf5a7caf1a9b567cee18d881e6801da22a1204c8e0",9.317957166392093],[17175,"cf1642ae4ef52dc55a9d46ee4c1618117fc2fe645a8b15470bd0d5c919ee4d4e",9.647446457990116],[16029,"3ecba42504e771f36f77bb8bc3f8824409ae53a20b2f218601d9a1e0fe39ea67",9.317957166392093],[8003,"0b5563ae6fcfc0ca5c7a6f1c669090ef8201b2b7fcd134429bee82f897e482cb",9.997888067581837],[1149,"7414d78951ef7cf0157364a268b23c77a4eaf4e7775f4d0c6beb11c66b1251f8",9.917710196779964],[2528,"10f076e8b165cd14d0cf62b0c546caa60092a9b68cc5963e2e4a25d3fef19fef",9.917710196779964],[13539,"44d1d78f65100cc5f213a82dd1e6ed861b358a430826c0067d1ffb63bdecf29e",9.317957166392093],[10962,"4d8503843e3cc07bebcd98d283ea07267b89c8b0344fdc740d7024ee76d841b8",9.917710196779964],[8792,"8c7b36fe959a04556e02eb7a6b2ad9d674d6ca5d0f9cd6fd71e65810982e19c6",9.317957166392093],[4843,"29c007ceecce75a3cedeeb8a5edf9d2e38f3bd21a4bfb52a8c70d44c4a842be0",9.917710196779964],[11795,"e8be077bda7ac13530713dfbd556eb658995bc969cb5c285f174d2332c62c0b2",9.317957166392093],[4760,"a2be87dc58f7b5bfde572037a2873c12e0ec9acbf0688db70c803863980e91e0",9.917710196779964],[17138,"decf4514d202b819a29bd69685e0c6c99498ed30b381b10bc2fc19cd9802564f",9.317957166392093],[15806,"a391ed9f1f9c3310c76da50eca7fc0d93c05af74c70144f41ff550eeb759416d",9.317957166392093],[9640,"241b8ac1be26b760434cd5d6230cbd65e91f7ab820163396023f358a92f8c4c0",9.619607843137254],[6648,"36783e99caaa3683f29dcd053b9aa175d6c90080d357f1a78748a803e58556d4",9.917710196779964],[13446,"dd7f530f4eac52bcbdc2a390afd4f60022d179edfc2ccb6b5bff3afef7e918a1",9.317957166392093],[9634,"e97455a95e9fd268fe210965f0fc520288096c8cab7e6d5c1c76301233a0d4c0",9.917710196779964],[12683,"b989774fcbb13df4a555753ecd1f7921997a25b84140cd6a0c1ae5157c26acac",9.917710196779964],[13792,"57ff536b65a17b5abcd2b2967402c690a43f7d19b8fee193c885dada070c8899",9.317957166392093],[6822,"3ab3d0aa76a9a9bad6e6bee7fbd6870987b97541d3f52d74625f6ee6780520d3",9.917710196779964],[1128,"9f45929f078bdb4e6d59501ad9fe6a6db31b3006e4626bf2f51eb34116bd6af8",9.917710196779964],[12953,"cd0fface488ae13e51095346eeec9629283ba52d5ed0cac338ca6bce8a86e5aa",9.917710196779964],[3312,"ae84785075e42b2c1a1c054ff6515a21d219dd32b04bae1a05631411e0544aea",9.317957166392093],[13075,"e634278cb0854140d2a300dab6249fb1b483b15d1af66d5b21a702c6e56a16aa",9.317957166392093],[17809,"ed83d9f712eac397ff5cea8452c51b4dabe95938d4772dee201b073fc49d0f41",9.317957166392093],[4845,"e17582d858461da95258df95836465213efacdb9083d5eb671e9aaaceab829e0",9.917710196779964],[2539,"9f05f0cea5d65ced8654fa2253fabf444ae0c979d124d001bc4d1bd7acde94ef",9.917710196779964],[7247,"33aea470182d0d1349c4cb8f6163830be70a167e84a18f24bf41f12d94b664d0",9.647446457990116],[3618,"5705f08fc7aefc0b30a0fc1d6081ded8bef4d9e3082a1dcad2bffc49fc611ee8",9.317957166392093],[17665,"8f46fd98445c6d8bd32f1db6f1c5ab51f377b99c05769b29750dc851dc8ad843",9.317957166392093],[1918,"7fcebb42b4164698e427fb40005735b81ea73acf9cf2df846dfaf428d24e91f3",9.917710196779964],[7257,"d5accd936aa7e6503d174f5edab4a8a9c653b7d304d0aacb9658958e6b4451d0",9.917710196779964],[2919,"e76afd12fa3b14cde3eb04fc44dfea2af55bb007b20380073ff142a301e3edec",9.917710196779964],[700,"959cd9d9d99d5476025e5d0f2836808fa3c8f01898cd0f0deaa8ce6f56ff3ffb",27.11946902654867],[19712,"ac47c907f5f6455a447c80027fadb216fd0dd3c9963c649d6a5f36bdb61f4b06",10.012158054711247],[16750,"d3207fe69bde35d1a4e34ae6533b81abaaa6603a3290897afbb462ad54e67b57",9.375],[8222,"23000accfb0aa8651e186ecbf6251b28aa8215eca6e916916075be419ce3c9c9",9.917710196779964],[2717,"f2f0df3535a440c72cad626ff506725f6d59f619ccba14c6f978d1b058f954ee",9.917710196779964],[12898,"08b7d211f3aa600335fa113c57cceddaadbde8f77e1da6266c72315848e44fab",9.917710196779964],[17678,"bd8c4d2392ef8736abd38f0fde6129bbeb66823379c61b6a90a46dc3f9589b43",9.317957166392093],[2914,"8150c08044183ddc32dcdbb0b3020d284b634a5df4a809f0647875f4e180fbec",10.032489508596182],[16328,"abb5a34963db4e1bbcbe0a637ab8ae05ef6409acadff7866a1b4d048770d6a60",9.317957166392093],[16419,"9f1a02fbf32a369b93bd08a579e5b313a78cc8033ceaf5e3bb0b58455e2fb35e",9.317957166392093],[18721,"53cd58136cc86f48ea0273459134a4b65952bbcc97de46d759e938180bedab29",9.317957166392093],[16921,"d14beb97fc91c35b168a5c0c9371a4f7b835c3caaf3566b0d758c3488c9fba53",10.052724077328646],[8129,"c47b9d8d5b4dc5d6b6788c17205c9f83faad5af2e98d82a13137e489d5638eca",9.917710196779964],[5765,"1ec5da85df874c8e072256108765a91219df191a04ba15ccecb2656e18f3aeda",9.917710196779964],[15097,"04d9f47dd46cb306fcbaa74e31a2ab52815f2ff7caeb2294f978a1a365bda87c",23.027027027027028],[14516,"2fddaf22a6a653d97f808701057e0a8d3aa61419146c2b65571d4690d17ed188",15.026455026455027],[11031,"7049f58ef6e3cdc23063b1002bdb66d7ea81aaa766919569702eb44d5070d5b7",9.917710196779964],[1207,"c34dbe30f13ff8072346c186aae8d7b6133c6a502732c62ac4b8537f351af8f7",9.917710196779964],[3975,"cc77dea7d502130bf5217ace8fbc43386f9610ec9b283614bd2df4fb7688e6e5",9.917710196779964],[14950,"fe75a395a5c5685d8e2e0db6c18993ac5b262c9e4bb345b5f309bee86117c07f",9.317957166392093],[6837,"a744c49fef4fbf22e60e0cd61dca720bc4bb61749a6f60c00e681924bfbb04d3",9.917710196779964],[18099,"98ec3280c13963a824db8d99d970da0d38d8f9be172d808a447493082e98fe3a",9.317957166392093],[14992,"f1598cacd44ffc970eed133714329ef4ad98c2764c15ec45ce3de286d9f2ab7e",9.317957166392093],[2000,"7fcfa4d9e2c1f6b149535da76e36d69f0f7d119adbe61b90252e0d54f15b06f3",9.917710196779964],[11115,"775a6023115723226a114ddb3318552c5c6606e6e8d9d210d71b445b5c5129b7",9.917710196779964],[9321,"9776758dd166662420e7bd256fc98ab48e9b3d5cbe0069698c5f8ce675f7c0c2",9.917710196779964],[7147,"cb065c97350e01cdf83c334399f88f959cae4c9b18b3896a24f07057fdda08d1",10.052724077328646],[8169,"f816f83205a5515b231e931d8af281b92362d5fb7a61ddf577452635175a2dca",9.917710196779964],[11354,"d75f69fcd478ae75df1da6fe3d1f6f2542880d4990c25894dc3e8f4066fba2b5",9.917710196779964],[6515,"c1b618feeb265c87231b056296297befb85adc74e5938867a65db062d1354fd5",9.917710196779964],[5484,"a70f819b4ea530cb9bb95044ef0ec9a3d404dbdfb098a9aff095bd0309694edc",9.917710196779964],[15981,"97649f8a0ac03c02078bac1a9427a6261cdce254a639da438f012c4c2e3cf268",49.146268656716416],[2942,"fa8649ad2397750562b3cbf79370c9105b2f038fc34fe24544537acbecebb9ec",36.056752496058856],[15162,"e6bf7c46734196b55c87ecfad5a9d6769510282ab09bf88ec2c2963df8423a7b",9.317957166392093],[9281,"af3fb4a71a16332fd3bb8fb3e7517871e455eb27df4679228e8523c530a5efc2",9.917710196779964],[6881,"e09954f3eb3463e0509b7f7f9b78750220a993b29aec0065c8b41992bd35b9d2",19.066666666666666],[19023,"c36d6baeb0a707f12e3aa6a1b2e759c883775d2f1ffdae445454931a06d3ca1f",9.317957166392093],[2349,"6a5a3cf215ec610201c800bdd56cd631a4167d7a95024bdb10ec5a86b49ebff0",9.917710196779964],[11566,"f9052266f6d29bdd5959c801e4a0cc6ea05c254a85708adce55173b40bb624b4",9.917710196779964],[10089,"0ea5c457d6cdb8e6b39addbc785f08a76e95daeeaf023fb48291bbb04fcac7bd",9.917710196779964],[3567,"d4ff0ba11e801f9e81928d12a9397e4e0e6f52b98c8b680c4ffaa6b661ae7ce8",10.052724077328646],[10028,"c53b0525b69b15da6f5a810bc5844d2fe4830f6b30793ed5f1f2d638175724be",9.317957166392093],[19509,"a028e4d4b32c818e0a7f490357bd4beb00ed76563b3010a12f6ce3273fd3010e",9.317957166392093],[183,"2347736123f57f75354ea7cd42b7990988b655411224d4cefbb19211733dcafe",9.917710196779964],[15580,"f56e66609aac47efd688123f202ea606fc4cd8ddf85618ac322c8bf7b0e3e271",9.317957166392093],[12825,"366865e05856f29087b286136a712cae21016ec5b4da7cb4f711dc59893ecdab",9.917710196779964],[8072,"cffefaa6f02056d466ab3904cedb24fb87947eb1c122514af44864c233c5f2ca",9.317957166392093],[10451,"3066f5bb92af4162d3a4a6377b8f7a7024962a222a4f889ed4f11770c6286abb",9.317957166392093],[9420,"c7aac577f20f9e653c157872efe6319c2bdad29a6457c44c0aadb7681bfb2ec2",9.917710196779964],[11740,"9ae9188bce993503d184467b0d19f013ff708ea70e40c0b6e17c35cd6fb110b3",9.917710196779964],[16177,"ebb61373a1209773b2bbb439afc3e690571c535bcba9e7640109efef13486c64",9.776021080368906],[15638,"07aa17dd7ba6f0e4a6ddb2e1d90ee305b8a817ff98ee9f3b060a408866368e70",9.317957166392093],[354,"596c4405802b0b4ab24cd1bbfad59dc0209df56217a5d9782c3ec129efceb5fd",9.317957166392093],[15592,"0ea7eccd92567061bd69fd04199716e8876957e5bcd1fa0cbc76155cfb138071",9.317957166392093],[15879,"9066bd80f6e05ae6a6c2cdfbeef59b37e73e675c9d2698c82c233e31ff89636b",9.317957166392093],[17757,"491d5b8ca1f477649da94bd6fb19898aab0dbe17e706dbaabbcf982775c01942",9.317957166392093],[9603,"a3f377c75932bc3986a5cdc3ef739c3ff2f0f0a2068e2da0ca8c9182609c04c1",9.917710196779964],[10149,"db47197bcdb41456d5ad19af7226f2886f3fdeb9e21399f605e11a6458af63bd",9.917710196779964],[11081,"053115669317038258f55997c36d13794642a0da39b7575a538171867a0465b7",9.917710196779964],[16337,"f6c9f53b797dc0430bb2a7cdfa0fef035a75b8466ab04b015a1f69df619b5860",9.317957166392093],[6241,"c44156c17d2a76410c383ecaba215bcef804e9f6494cf620801bb6ecda487ad7",9.917710196779964],[4418,"bf73ede06d681aa3ab814f1ad6c867dfba486244aefe7162e7ba6f6f64cbf6e2",9.917710196779964],[8451,"ff75a82b6afbd17a4e54f3f51851bf7f5f1b1723b906c791cb51b87090aa50c8",10.052724077328646],[3826,"edc53036bd4ae46fefa40a6d4ae7d8ba0fe6c612e4211fa8ccb9affeca02d9e6",9.917710196779964],[5550,"b9a9ef2849973025208f6004438a9794824c6b5659ae13da01834b98eb9ff3db",9.317957166392093],[8985,"cb73c369723e418dbb9bde9e9505493cd6bc1b6036a8ad46dd2a5e9752fde2c4",25.829596412556054],[5904,"694947b4420082e4f7accf0eedd2326bc5c4311ec24bb3fc42ddf34c222fabd9",9.917710196779964],[34,"794f976a49c81e1101000b29f74733558014b974ba4ee82b41fa9d6456fdcfff",9.917710196779964],[5687,"f4d42a2b9ab63f056b33a2a65e6e673bed00a6dcad7490a697987a145a9e1edb",9.917710196779964],[5268,"921d1c80e3c8cadccd3368cc0d96f189238c68294b4ad01a8fa678c9395394dd",9.917710196779964],[11365,"3c5eaed98ca7950bc2f7fd4a8524370235bdb8b9d5dfc333b8b1956f0f339ab5",9.917710196779964],[4314,"1b5f1d657f925a46f7eb7d0a927afa5190527fb60d65f7d300032b233517aae3",9.317957166392093],[10063,"704278f936097ceab5b8f75bf52813f2732fea6f525411904b5e231a7429f9bd",9.917710196779964],[16292,"2368c48fdfe03db46a80a0e6f0eba2d8f6ea7b6fc3a77d0b25bf68730ae35861",9.317957166392093],[1495,"6af1182259f4dc51dcffbd3b85c5349f60a91b3888c19728c957840f5d0f29f6",9.917710196779964],[6860,"062e4ce0daabcefb2151b1ac98045352b9a3e2d8e8b5d2a0cec7a1177489e5d2",9.917710196779964],[14311,"7dd7fcb52c3ae35595e4279b7dfda8d9536b9a388eb9f5c4b42992385d4a5f8d",9.317957166392093],[18501,"6b51f0e7ff36ec5dd7f5e2977cf17d21ca4db898c354056a45e5844dfed46631",9.317957166392093],[11372,"2f638e38643464509d3c11e68686142cd1ac297f606fa9b1a75d539d8e8490b5",9.917710196779964],[234,"3209ccc3bf73440518136e17508d6012efb10e1ea5864de88e3f492e47916cfe",9.917710196779964],[4682,"c7d024eb0a294288fa26e5b83e4c7320b248aa1b6ad2e7b00d9ef6b77a9e1ae1",9.917710196779964],[19340,"6655676bbfd882f4bfe36e7b5a0588906c0ca925b971da5dea4e4f51f553cb13",9.317957166392093],[8897,"9bfb3ccc88f63b5a6abcd84dceb9bf702eda0e6bb957b496a9812d2378c475c5",9.917710196779964],[13488,"900668bd85d658355d0d004f4773f1ca2a84cfc548dedbbe207e0d81c4e21ea0",9.317957166392093],[11010,"9836a496cd23b8bf7c4919be81c89c22502ed67a596ccd8102fa91326027eeb7",9.917710196779964],[7791,"461f2137a8d928e3d2b50db110ed7c908f7989a3bb299cd15b66acaf3047e2cc",9.917710196779964],[2060,"fc596051a65137b5e78c612c60334b16726dbcb33f255cc52e14830e3c7580f2",10],[19161,"3361a5b65626314840662a0fa124c135976c587aaf79cbcf6cac0f71a039171a",15.964365256124722],[3218,"a498bd1e2a5b9d3bba850d689e40a334c29ea705a8332b6d8223315f8941f1ea",9.917710196779964],[3264,"adb3f69057c24a57aad2e174cfc634b6ab8ad0f40be8c3ff1e500ded9a4998ea",9.917710196779964],[4505,"650970d5ff39bcc46b4479ccbf865d2eed672b7740f9c4aa5534428bce9051e2",9.317957166392093],[11781,"d6c3fa1ec564b4cb0dff1469fa788606151843b2168e3004b518b934ee92d5b2",9.917710196779964],[18850,"d47af70ccbfea29f493e7b7f0e280c0d3351215add9546330478728986d50c25",10.052724077328646],[8667,"523aff83d8c03428e7aeca274199f89c394d0da3f58dce609c344d327f94ddc6",9.917710196779964],[18730,"646ba27cfe17049c2c2084e5ac94c2fac7d1243743067dd748463d8ed5d45b29",30.331550802139038],[1784,"8e565da3134c6a169ca91f90c6b2097a85845ca5f9001db82a4a2c4b3c7256f4",9.917710196779964],[4205,"140b1db719b88cbd1cd2afb124c60f2c8e1f99169c7daf1ad39a1304e6fe61e4",9.917710196779964],[12282,"d4a57e2f062c541fb87da291d1fcf8971b29a8eca6bdafe58e8b0a69c1bc65af",9.917710196779964],[15755,"e206a4f391f0d0800aad66514dc57599df8b1fe2559ebe3f9f714282f5cb446e",33.23625557206538],[3692,"a8e72d087d084dbc7897e23a81606538f29923944d2aa96cf761693a88f3a2e7",9.917710196779964],[13318,"b4a233138ffecc0a76581bfc1a644990d68b17f8146165bee0e8c7eed34647a4",9.317957166392093],[15832,"9511ce1a22154b3c7645a58797968be931db0ef40aaa16196828f03adf7cb36c",9.317957166392093],[7781,"351a3d16e945fc514c21f0b70931b74b0d67789cbf80ba8f064d1cc21a02f1cc",9.917710196779964],[17970,"f2d2bcecb25cb7e51b5c5f64eebc397379ae5b5aeb42ed61c793f48df12abd3d",9.317957166392093],[3473,"457220ac619d6da84b8b2a8f3dcbcffd4d13d639609d8a0b2d6f75c3cffb34e9",9.917710196779964],[71,"daa48a2e7a61bf8f43f3a4d4126af57cefaa1a3aed5fbaf12378fe2dbdc988ff",9.917710196779964],[1075,"6bc079966d7d7242883a6293a8d8db244d02f024d61204ee546576af87d5c0f8",9.917710196779964],[9729,"68069de4a66cff2bef5cb19ec97f4a3adacd6beb8911e78f4cd1501b46be1cc0",9.917710196779964],[9243,"297ba5e20a66e8e9bbc601a84c735b855fe54be2c69ca3d7d3d5f5865a3829c3",9.917710196779964],[11491,"0af8f436037845091f97e484df97afac4cc66fadf3af33de3e83d629b87a92b4",9.317957166392093],[15948,"69ef672c18d694522a6e78b25f01e78a18052189aaf234c1c290fa3b3d1afa69",9.317957166392093],[11956,"a392aae49b7342681fe257feb68bf066ffb20822080b634937cd977e90e6a0b1",9.917710196779964],[17165,"7171a7fc2d8e37a3876eeb26cf774a0084bc1a25eef49d2d9834aa889d719a4e",9.317957166392093],[2415,"59ba04d6b027427c34f18e1fba169bea3fee63e1ff6451de39bfa40e85825ef0",9.917710196779964],[12794,"91335b74062fc002ceb6fa8bde34639a5eb1acac3deffc6a82cda98e1844f5ab",9.917710196779964],[17883,"0c839d3a402575bc24f05357ca7d6dddc12d6fd7bb68ae81d2bf492fa163983f",9.317957166392093],[9456,"3d3e4eaba2018c0ecbbf3c90a931c7befa5cbe281faab05835a383c95265fdc1",9.917710196779964],[18105,"e7886a1f85b56c569859e23310e9a7f73e00d8eaf262f4ae7687349740ceca3a",9.317957166392093],[18319,"23c2bcf0937fadaee6478401e6bde9255cfbaff0f4405a440ce72924069c7f35",9.647446457990116],[9780,"d2974ed5b66b26b1cfcc8543afbcb72feb1359071a03aa831f57c60b8ebfcebf",9.917710196779964],[12537,"770d728eef92263ffa8ff6cba3122f6ce65f5c986273401b1247619b17f8afad",9.917710196779964],[6271,"ee477d5a9b2758bb60e001c87bd823a1c72ddbf78ffeddde50a50309c7e045d7",9.917710196779964],[4877,"4b3a0402403be5bbfdf1ec22e1e816cd736d2ad3f2f59c64ac9f5dc3e121ffdf",9.317957166392093],[18043,"936a759c745fc1db571d719bf4438ffbf7c3414eba5c15edf95bf8066f36693c",9.317957166392093],[13710,"c8269416455c9d831001d7c0fa569b3aa6b3ec00eb5818e3da1427e4433b2a9b",9.317957166392093],[19814,"ef143b025a71d1379941aaee3092ec1c4b8001dd3f32a373adcc46c2dc102e02",10.052724077328646],[10544,"55a7705c89fb86ce489358ffbfe6ccf5e2fb36e0eb447e10c6e5048e1ed7f1ba",9.917710196779964],[9441,"f3b1e2d9cba142a841953e0be83b2832862d37eb8f24e2262e399146469e13c2",9.317957166392093],[14871,"1c6d75ec31614f2d6b39cbc23c10b07c459f6c0249cd2235d4631d3fa9565f81",9.317957166392093],[8179,"b1cab6c6697467061e7d9ee66047dc700e3e7cacdc481a7ec1f448a7aca31cca",9.917710196779964],[10941,"7715500ef6440abd88c7801e25852ef154be8c88c238ff050a842cec06fd70b8",9.917710196779964],[1645,"6db239dbe0b0b7c28ca0738ecacf3833d0bae78cb6d8ec152096392cfad450f5",9.317957166392093],[4490,"3789b484c6694a8a5244b94b06c5f8036b31f140b69995cc44997fc437cd7be2",9.917710196779964],[17526,"1e987a390c43b7dfef931646838cdfac8059b0b2f72e114c8c676ce243a1f946",9.317957166392093],[3555,"83fded0f3fb9c7d1640f7f9e6963debb47259b9d5a057e716e2df16add158ee8",9.917710196779964],[9373,"ae3df703baf3690a24e7942df1ca18af84ebf0a3dbfae88a7075eccb953066c2",9.917710196779964],[7473,"8f352b4add59875fc0e951e6c8efa2558cc466559b3d8b689c6838e38bf0e0ce",9.917710196779964],[12634,"2e2039c0905855a1bea44ed8cba8f0749c1c036297337b8c3ed4fef21c830bad",9.917710196779964],[5924,"e2dc7c9e8b773db1679a3eadaf6704a7481521098ff7c14907bed38d570688d9",9.917710196779964],[1278,"0e63d78e26e08c3005187d123872b3c1dde683910d13e488844b9c89b15d84f7",9.917710196779964],[19844,"af08d0f3fdc497c3342d27d4e8c3092a928c99f7d83898de5f69a16e2217f800",9.317957166392093],[17502,"4356fdac4cd1d5ec4c6a4095187879ef7fd268001bfa7208d7f36b966cae8247",9.317957166392093],[12453,"a26c16382dbb27d83647bff00f4ed0583f1050827cadc9c5392ee0fcad2942ae",9.917710196779964],[11549,"b9c4f4827fce8fe7d4e7a5b58283e0f8cb5c1ebb520e5aa1125f75f634b53fb4",9.917710196779964],[11585,"a0d968ac625d949994fa020a2c604dae3619e6fd3294a86021fb593bb568f9b3",9.317957166392093],[15388,"ef450ebc3b1b04415a7caed65873cef46273035659c3bc1591996bbf5f9b7976",16.07335760473836],[18299,"89b6c2de79e8fd5f924b96d0a439db2850e4b98013cb7c679d51eb3229f4d435",9.647446457990116],[8093,"08c3404e3a21ff658e5b6c7906d7c4a534ecde5fcd363b6eee8f420e1f7fd1ca",9.917710196779964],[4453,"2c6a9754751299bf52331b7c87d65fe436c1c6297ac74a845fae258f576bb7e2",9.917710196779964],[15622,"9cb51401e787a10fd0034be5c4ed56ada6df1448fe8d1507924d52c2abe7ea70",9.317957166392093],[14279,"e9c2db437527f01331d419467976fbc17d84b65695aa302e74f2b68f3de53d8e",10.034207525655644],[10314,"3ac7c824c3983535da48e9931ed6c65b88985ca83bb00196eff0025e392441bc",9.317957166392093],[14889,"6bb7ab3d13b41bc72b985b00c6304c82ce91b1810f888908d832722021280481",9.647446457990116],[10448,"7162c360be482491d8815ae6fa8299024dc8f57c6007e1718ae8ef1d0e576fbb",9.917710196779964],[7811,"804e21b303c9465f712b60a9134271a8bbc12e7b6de4057cfd17cd60bfb2b0cc",37.1689497716895],[935,"8bb1b41e34fed79ff477e210102f080534b9fb287b997b6a923503e223f398f9",9.917710196779964],[9229,"a416de2055e0112325d6360eaea72a4aca0aedf31c16e6fea6e9f7f8fa9043c3",9.917710196779964],[19368,"97de8d92d9df83b85fbcb4dc7c7724d8e2b1ff45fb1a67e51f317e96bcc02613",9.317957166392093],[6292,"b85620bd7f24ebcda371fda4810928d198dc460f0d650015b864d268fa1e1ad7",9.917710196779964],[18921,"624edb0558c0c4d9c80acdcc8522b0471fdd0ac03141a2b16963cc8e5722c222",9.317957166392093],[14228,"d1f6c95b8dbc274329e43ddfcb396e6444bfab3734ad4bef4e318e64aff07b8f",9.317957166392093],[12143,"07ed72dad76064f96d54c6ef12a03c9e3a7273c8ed3ad144d6667e6a0f0264b0",9.317957166392093],[1348,"0286680e27ad0a475104f8e635892243ef71d960a8ee4414ebc921848cfc14f7",9.917710196779964],[6505,"f9ed96e2b761c6f5cda83464cf5774364a4868eeaef771d91e0732e8218a68d5",9.317957166392093],[5307,"31da581b1aa765433b86b365e9c846c527225fff318bff3f4bd7d7657daf57dd",9.917710196779964],[10633,"8e0ba33b58ed699584117967b935ae4517d36d7de126edd971d27cacb70d7dba",9.317957166392093],[15902,"a69f4e65e4387292fe8d76f3502dde11dac4f32f5e99abbb08f982400cf4f96a",25],[19704,"9506e5efb0a39900226f415aeaaff00044c9bf0525dc4829de6e68b261ecab06",25],[14492,"31961f2b9c780717d2f4bde9ff7a78d2fd4a4766e11b49c4b0b6d4126eec6989",9.647446457990116],[6252,"7836c9dc02b985a4eae5216b02f882143a7bb4c8c52441e54a69e62e222964d7",9.317957166392093],[13057,"cc29d2ac9c94ea3b06e99b7b77defd617324d09f43680c3e64442aa8432e3daa",9.917710196779964],[19029,"9fe558984c233d4338cb63c9d737a64377a3d6301b21ccf9b9c9f9f238a9a81f",9.317957166392093],[12444,"488f801d6516b00836510c4807f95550e9d397799bf0d26ac995430e1b9d4eae",9.917710196779964],[4784,"513087e3f1a5a5a1287f62a9bfde1685da246cc7e11f1c983d8fbf59d73281e0",9.917710196779964],[7599,"0a8380b1263048726db152ccf095f387dcd99b9fdf0c01ee86d329c0ef7e2fce",9.917710196779964],[11582,"18ba158731d4512a0d6b6eed4305c9aeaeda9d3643bdeab16e9cbe6b8f26ffb3",9.317957166392093],[13243,"1583b181689ff6a092dd42afba63aecb10b33cb6b1c9e8ada8cf49b9034503a6",9.317957166392093],[18291,"e8196e20bfcc70dbe792bdb9d5d3400d628cce049e8771c867092f93605efd35",9.317957166392093],[1144,"14e488de65c0930f2bdd2b01fe82c0be47f35947bad544e2073dc14fc9c656f8",9.917710196779964],[14706,"50ce87fbe2e8dcffbe7cea297b924dbc709cc9fc23451e907f8a6df9e901c884",10],[10145,"902664b4d6db5acfdd0d58ac5bf71ab2eafbd3c53ac9b084f1187df95dcb69bd",9.917710196779964],[12788,"d75d3c9037bd9633f5a27be92ad9fc51b44696b42aa4e12c7057821f8856f9ab",9.917710196779964],[16657,"1a8af56c405c7e0cb5cc12f8b72646048c70cc61a554d89d2fcf7c637bef8b59",9.317957166392093],[13381,"1d9612ba66bda3dc59fafed63bb3988197a51591609a4ee02c3ccbfd0d31c1a2",9.317957166392093],[879,"98cc554c47963f7f1d58ef1ca193fd872afcf2cd335e4bd5f7b7079569310afa",9.917710196779964],[10112,"4f0b7062fad7af551b689f732bd06942338d788f1b82dfa2dcc3eac50a519fbd",9.317957166392093],[2289,"7bf0576dc17c9263c605439e826009d362e0f8f61419e44de61bf00e38490ef1",9.917710196779964],[18436,"cb4380d432a234e8214f60ce91f3a4abf53157e631e04d1b61ca2850f027e932",9.317957166392093],[9028,"50551afd57ef098f77d66b2fa0fe2320a9e9a15b51d9e65620c0e78c0b099dc4",9.917710196779964],[12696,"b218f6b9e5bdfbc241367a23c5cba2eb8eed6c1c563c76fc5dc1e58689089bac",9.917710196779964],[7294,"3ac19595a7b84b54da908f37bae8658c03c0bacbe642613b7febaaadcad01bd0",9.317957166392093],[6115,"4f2ea03fd9cbe46593f305a01fceffc64ba4cbde6006db1c3faef92af6b253d8",9.317957166392093],[18215,"6ff82200d7c5135536f3cd376c1953900f113edd3fd9d45a6a94022d643fba37",38.08577878103837],[18061,"536cc2b1747b243f26d218619b2f3fa062d3246588110f4981f3c82dbc8cf63b",9.317957166392093],[17431,"380e708fb141ab29c2d1406486eaa67b5b37ad8bd66b24a646415a4e89771c49",9.317957166392093],[9996,"462fa490d6c55a7ee64145072314d110a9e1f99c5ba5c9814b98e3f13d465cbe",9.917710196779964],[11998,"91bbdac25b4a6033dcd843dabb7aca66167f1f620ec8e2c626a44ae7abbb57b1",9.917710196779964],[19353,"416ba2b4a961829f2fac92eb21384826141c4696820a8519dee1e431f60e8913",17.027642276422764],[7074,"8621d49d8be2c1ee5212a8bf9df20ef9a7f091b8296fbb47229bb9fff3e47ed1",9.917710196779964],[2373,"ebe6b71322366133f7b2fe7c7387b1fd7b3dbc935fe3a4ec5d60b1d4f8ada0f0",9.917710196779964],[15537,"f8ea6dbcd78051a625f814adc3490b6b7d9f120d0928596ed04c564ca9b13973",28],[2016,"ddd5b31e7c690cf340d592586c43125a84c40c08e5f5c61cddd20e015f64e7f2",9.317957166392093],[18458,"16699c82430adb4067e5da26b4a6461cce92b10b2f0031b2c018c64804556d32",9.317957166392093],[4876,"d155da6b43f2f39907993ea10f825b9ea9854182a3557d3cf38f595a2fd8ffdf",9.917710196779964],[3235,"5f1b7b5ca1fa0015545a4898829edaf9c93cb4fdcdbc0bca044555c9efefc5ea",9.917710196779964],[243,"f9389fd17dd818f1ab3f71b791a3494d786a1f4e78007c39bf2492ed092359fe",9.317957166392093],[6708,"5e2928084e0992ae7ec3976d46c023e59025b301e3866ca77a5c8fe9c4afe5d3",9.917710196779964],[8757,"5da33cdc957b50904524ae7dd4350f11b26fb5f8a43006604657846ec66f4cc6",9.917710196779964],[18624,"8e0915bfd1a98f7f0702e11d0b9ebab8aa102a873c0a649622a771cdcb71102e",9.317957166392093],[2608,"24dc3c8175c6e9d6ebe409c8d88fbe3febac9e487ed49d7c9060b916dcf21aef",9.917710196779964],[8874,"e2b8e0c406c1f06b920e8007922b86bb0cc7a92fabc6aabaf0815446915b99c5",9.917710196779964],[12079,"d891ad0c3fe6161b4734afd3e76d418e5d267dce15ec99aff4f29b12a0c3d3b0",9.917710196779964],[592,"f1b9b69f9b1c377edd7b7a3c0df8571d7ce1f7fd8bd894ae156b389bdfe4f5fb",9.917710196779964],[3838,"e0b0b8f3f22ce4c23579622de3886b30b4b117773d897e2838c461c8cc4acce6",9.917710196779964],[17,"5901d830d0cbcf993532936072ef2d1c4f39dfccb11b9f2ef97595d13c96ebff",9.917710196779964],[2293,"976ece1ae6bfefe43e550adbe199310ca359d9f2790687f108646f8a336c0bf1",9.917710196779964],[18032,"90ef2ebcd7cbc8589f2dd3575e1fe508192abb561ffe4c64eff14acc34dab63c",9.317957166392093],[16563,"5e808a914ba050165ef8344e18fa9dbeb37cf12752a8c2747ce792e718c7d15b",9.317957166392093],[14445,"237466862c35149a214e5753db7d1125af511b6d6584681b4d5b14bce0ae568a",9.317957166392093],[1435,"15ad44c53895279c02471dc74f012c444186523b6d03156c7c6df6be62019af6",9.917710196779964],[11058,"41b775aa800cbf41798a4207b408846ee8394fa9548de2e3d0215e30d5139cb7",9.917710196779964],[2772,"baf2d7e46e8a2e35e48e31631d899a92a20f256bdacb5f26079ce968983bf7ed",9.317957166392093],[1039,"c073a73a3a5f52ae4c6512915cb442693ef634a7caa465b51325f9841cfe09f9",9.317957166392093],[11089,"90f44239885d6de494e60e93896fb7be751a468b75ba28db60aa8c3faeab50b7",9.917710196779964],[1417,"dca649fff50b635093562a776bafa9e1ac2755ef813a93342087718b2a8ab8f6",9.917710196779964],[5944,"25250e6f4d03a7862716b7f971cf8e0d9f388d0b3121958b43fd536ac4706dd9",9.917710196779964],[261,"8275346708700560bc1e768cefd089e7a46398b5b1a89424204923380eb932fe",9.317957166392093],[8472,"df1d3a5b2f041038c9ebf5994fef49a340f74bf18bd6ba511227b575634531c8",9.917710196779964],[19310,"a3a0fdb0247c764c9c12384dccceed065399c466547bae80725fffdceabf9b14",9.317957166392093],[5043,"7c437a527dfbca6e0ffd71ee90c491888c158627322c33c8683b010aa1eceede",9.317957166392093],[11037,"7c86e534d418af8c7098f1f658e249a688606e8672a6ad5d8226c7102c00d0b7",9.917710196779964],[17584,"94bb635993e88dbf09bda52aaf805675c96a5ee127223af6d081034257589d45",9.317957166392093],[19015,"67abaff72fdb665be5e0a79a6023d51d9e9d6b5fd7aaec744ad5f9454a65f51f",9.317957166392093],[3259,"4b4631d3d0f32f3fab0a1a22dc018db45c02340a868bac8d9c0d2534a2089fea",9.917710196779964],[5093,"0e84ca56ce29f5482e644db942a6e09e58490bae9006158159d726a56be99ede",10.052724077328646],[678,"db813703767db0cbccbe36e86842778b10dfa40aec436af253c27283e1c163fb",9.317957166392093],[14974,"9fc25ac7807243dce64cc56f8b2c8bddc4d31ada69b57b3604bc3bc442091b7f",9.493150684931507],[846,"f6199d77dd7107edb429bd013c128eda0fdc30a6f61ab97266a3df82d45a3ffa",9.317957166392093],[16658,"f6572c4e5408f8bd6091928d412da2c4e0e64b8886a1ff6a812c9e81ff968959",9.317957166392093],[10585,"91c2a7716ff87bca4c753f60e1c7559812950cc2cf3f8a57eea5302b9b9eb5ba",9.917710196779964],[266,"816530709ce77546c0608c2afff66a25cabe4847f3b9f9ecdec32bf195f027fe",9.917710196779964],[19713,"70fc22d3f870fd34314e0128d0783caa804e393d14d8b5307eaac92b71144006",9.317957166392093],[353,"7dcca8a13ec21796c331a2fb3f4e204032f8f4109c796d333cfd8d704eb1b6fd",9.917710196779964],[6366,"90f4b9c7ae77a87ed01dd76d94e63aa5029ee2b064d7744fcdcd47ce1da18bd6",9.917710196779964],[11581,"6bba77037ac40d3b4c7ddcc1f94ea071903adfb2e937ec494a630a42f268ffb3",9.917710196779964],[4305,"645299f8a439d3fa168df54fc29362abc303e772f4df6a60be205d6421dcb5e3",9.917710196779964],[2644,"dff239c096fe565b28107a0c1b6ae8b3a6c3fc58bde9f8341ef9c908c3cce1ee",9.917710196779964],[7525,"41bf90b1e5b865b43c7f4fb59ae17295cab62fa45bad042e0f535d520e5d9cce",9.917710196779964],[12749,"796e72e5c3ac723279df959e4809e9273238d02ac38a44a5d124254e2b6640ac",9.917710196779964],[1971,"b97ddcef05044aad6a434a48de48c024d18ba09f837944c7ab2c175072b231f3",9.917710196779964],[13433,"3f7e8b1e0668b1a5eabf42ae410db1b942d7b5b05cb829ecf7dc930c7216bba1",10.052724077328646],[9511,"1988048c94af19211e97ef50c76885ae676a1fd0d1910103d18e886d20079fc1",9.917710196779964],[9860,"17b9f3578e089432d8b22a3bd94cb355a2a953eb0d61c8896a791f4c2fbb36bf",9.917710196779964],[15895,"c5cae938fcf2373a9ff11d35851f172c2c752a5e7a18fbb748a4ac1c9b5c1a6b",50.34324942791762],[14462,"90c74da131ebba98e8ed3092044e5d53c00760467ab68449c3b332228633068a",9.317957166392093],[11119,"21cfe0f8e9d9185992e1405e3ebdfe05053c43ff9fe807c010ca3ae980ea23b7",9.917710196779964],[5468,"1a03e0931498c82495c9e53a4466309f1b280936cb22f7d4bdd1bd28400a69dc",9.917710196779964],[464,"bb81aae72d0854332d4d27a163750947124d1cb9316e5f5370071ec320c8e3fc",16.142857142857142],[1439,"46fbed2d5925da80d127b99bb13d5b3121333342939789a37809d916c68c92f6",9.317957166392093],[7039,"34d36a82fa6dbd293c870537bc15e92917e16dfcd6b91bd9897e951177f0bbd1",9.917710196779964],[2188,"751c8e347954fb1201154827da24f49b680932fc124ebff3d6562278767fa2f1",9.917710196779964],[17361,"d30bfefa6dc04bdb7d1d064b17d992398b6398ab73727f56771dfba926dda24a",9.317957166392093],[4268,"250af13c5de709e5f39c600f5d98e72418ed75ce20dc8a57a9b7379e0893fae3",9.917710196779964],[15054,"9854c35a619ec155815bd2ef615838cf43b5e24666e3170b8b3d6114d61b737d",9.317957166392093],[6814,"231378c616da8b87e88554dd67c01f8719fed10a79a84725f3542f5596dc30d3",9.317957166392093],[14461,"1375c00a5f8c58bea46fe4acfa29b6238bcd1901d27247b7896f931a4666078a",9.317957166392093],[9338,"f2978292fd05737c48366d7258d9e068130b6db8accb7dd65734a0029120a6c2",9.317957166392093],[12935,"dc0e8ac82dc137fa91e1757abb7d9326ffd3f7bd90c9492e538bd36dfb3a02ab",9.317957166392093],[1586,"abd70383c9a9e2d96cdd9676144350983a62d7a566ea72bdd1acc3fb869b9cf5",9.917710196779964],[3730,"188f095b2870cf8c14622896f710a43fda0120a485b2a3c5b1d9d66e78e167e7",9.917710196779964],[15199,"92934ad22380746c9c21e089a1bb1c0d9351c29d663f8c4eec676fec03138f7a",9.317957166392093],[12517,"d77efae6734669824e73bfc99f84d2e7c0f27c295e9109cfbddae7b5a630d8ad",9.917710196779964],[17199,"474c006129189beb13cbe6da3c88262a99f60ae9f14c9e5c6e70e6510c51c84d",9.317957166392093],[12562,"434f0175102a6f59ccce0f3d1bde1268e1c42f0bb57a00e571ec6b4ac4e88fad",9.917710196779964],[12800,"7982884657c6c9b642c52c4ab430e2c5664bcbd33b21ce1b202407678697edab",9.917710196779964],[17554,"7a64d64682114fee411966e8cb65362091b5b5231ed830228d6350a154a36346",9.317957166392093],[6310,"f4b15f5239d702b4eb2d71ddf181751485b8e114345fc4b3c947c7a5e2b7eed6",9.317957166392093],[3954,"480bcc2732d13926070e3d74c6e3f7e24b18ee17f502f12eb8d68efd324bfbe5",9.917710196779964],[18604,"aba020405364ff24795c98d44de6457b1c9cc940d384041215d28d9277ad8e2e",20.08888888888889],[13913,"473c24283ab37cd32f03048d448765b05e824a34235f8c01465d0340b156b696",9.317957166392093],[1827,"83e8ff2df421f62ff13eb91474f3cc5e5422e20c2870f14bedeb412ad9bf11f4",9.317957166392093],[3958,"36e4f2c8c14a0b82444c5d6f3a0d527e48470365d1bc8733bea3a508d68ef7e5",9.317957166392093],[14981,"024c5b7fac8f3f89b05a5fb6b3c1b48e2238d4b58b32ebb603f9d1afd839ea7e",9.436992738146092],[3282,"f4c9cce8cce0c988ed2db8144a41761efbd18030763eb4c82dc9917eb8a583ea",9.917710196779964],[8418,"ca1dd219a33564f2aa661e5bef0f8ad2e8e3ee52bdebc72e16488c213e9784c8",9.317957166392093],[11652,"49be9a1a3873cf636c66fd4f0c29d08c8cc3a8316ef0761a3dee170755d694b3",9.917710196779964],[18818,"1ccb9f9492c466133138a7d8af3ebee15d6187c14680031121c362d9fe9e1026",38.61187214611872],[2086,"499756048415741bfb171cecbc8263fe0f05f6944661de7dc9dcfdddd02353f2",9.317957166392093],[2617,"bdcace9f67cd48d7ed3876682d9ace14457534a9f41bb57fb7d1faa24e1210ef",9.317957166392093],[14508,"44bd3badf089e36f43be3bd695a822677c258e69881b8fe388ac93d4dbcbf588",10.052724077328646],[17941,"155e9cb36682136f7dba28c5064d6f9cf251d42272a3a2bb5f89a9752ad8653e",9.317957166392093],[14128,"1ea0ebf55ffbdd7658e61372f2ba0498388274b9a21a83cbabb155b110a6f091",9.317957166392093],[8339,"0480840b098cfe81b4e377d1f3f883ceeacf0af2d565f7ef02acd998977b13c9",9.917710196779964],[11069,"e1e254c9683e7a32a9c89d25c58cd07ddbe7d7c332dd1fa69c1038b67d2987b7",9.917710196779964],[7498,"4f737123568fca684ba8d5ebc14b16a709f59a4e14c2c458955853011157c4ce",9.317957166392093],[19410,"ea80367f796a21c9e22798efe083311c137f7f4e251b688254411b3bc1872d11",9.317957166392093],[10906,"d319a093c31685093b55e4307562064d0870a6779ec12e07d149b8626ad0a0b8",9.317957166392093],[987,"4e8d46c92c3b7b2ecddc6bb0a401c23b6d9e362ec033e7a016904506098548f9",9.917710196779964],[2227,"d2fa0b66371e59ada7273abd920d964dfe33994402d9f45101072766c9315df1",9.317957166392093],[200,"68598439c064d29c31b7a7801a253ea910421a0c5b83fb6465f111feafcca7fe",9.917710196779964],[17312,"8e94d04d233b2533cce5437347c414e9ef8522a722837f4530459d3c2eeaac4b",9.317957166392093],[1688,"2e5c6998be0e7757e6ece5a7a3917407fa96b9decf33145049349b6ba0fc01f5",9.917710196779964],[10134,"bac676f81087451af68feeb9dfa7c8a3f2a194f4b6fdebdf4b9382debe2e7abd",9.917710196779964],[9055,"b0071bac740d1219d6a5aa8e3d25cb771bb45c84f0de3f08c32fc04b7e9a6cc4",9.917710196779964],[16570,"248c6447ec5f3c5624bff8b10da059b99358d8bf5759ea078bc177e1d5e1c35b",41.35472370766488],[7474,"be3d69b6ddf769b63f9b6cb15819127ce1a34b4cb78541c42fb006695090dfce",9.317957166392093],[14061,"f0bffb9fe5f79c6718cc8b0b86eb397cd4bc45238d469fdbe7a4bde5e44a6993",9.317957166392093],[5036,"0994cdfb96e5a22be03f20386e3b6100bd4ef45ee689e1c5f7d21932f3e1f6de",9.917710196779964],[12467,"0d0e6f75287c6f36cdf2b63a50b65e91e642ff5de1a8e315d961bbb4b20234ae",9.317957166392093],[9056,"75cdfdfab64950fe0b480eb335ad39aa1db71f30b446530043b3d85565546bc4",10.052724077328646],[18566,"e9171c2e2580f5ce59414517514ff9bbc18c294f0d46b2f8082b279477f3fe2f",9.317957166392093],[5671,"5d24c0be7c4a2d52b24a9f62744129afe1b65f9a96209be9fff9754268e32edb",9.917710196779964],[18556,"83f8a0acaaf976b7b2ce124ceeab9568d0b835cd98865f707364247e0afe5530",9.317957166392093],[13067,"06e427430234895cb52e732169c8fb712e6178a3498fe4027f53f457522c31aa",10.052724077328646],[649,"813ee056eecb83e83b58cc7fcd6ca7a3e573b549a859b1696ff85dda279499fb",9.317957166392093],[5018,"cb562f78adfe9974cdf608da4a54d1992b0462a56f71fa432ee8f055e6060edf",9.917710196779964],[1741,"93c7d054dc2919912ce579abb8857c0c6295e3eeff0a706083f6f2a09dada7f4",9.317957166392093],[16642,"34869e4250723b5e036a7cd1d59561f4312e7a309c3d5a5e3d08f580c961ef59",9.317957166392093],[14524,"c8b5ff0a69c7f4d50e2126bf9540bdbb5d5cfbc564663f5e8eddf7158333b188",9.317957166392093],[18200,"211eb999838c8a7ec9319c46f3705f1f881ff7899111d3e936adb7304a362038",25.916376306620208],[4962,"24d3441dca457d63a87bf9a9bbfdb7b1ab85878a236191454884b6838d2a78df",9.917710196779964],[4178,"6321cb95c3b800de14d00646b582865baf8403c5dc8c2c89e8dcb15d71b495e4",9.317957166392093],[18912,"44f0490fe733a9fbb7ca094a14fdc320713cd6c51283ac37ec3b6f77da5d0323",9.317957166392093],[15347,"223ef7d78c3987db6046d95cc9e2e41324e46832bfa8b4a003669027281d6577",9.472566371681417],[2787,"7a631fc4f3d9264297b875fcac217979523974e226586c7d5f0568ff5fc3d6ed",9.917710196779964],[8504,"522612a781a731887c3eaa6d138127f22a4fed944844b8796ea4bc023409ffc7",9.917710196779964],[9699,"c663f3eefd627f1d441992005cc7028f9a0b7cab0e423ec5c5176ce5ecef61c0",9.917710196779964],[14630,"68427e7797c3dbcb326111d389498afa50793ee7f7e8d398cf81dc7d3a9b6386",21.654135338345863],[11819,"58d399bb188e255a6f41f7b9a0211f0a4ee48a7628cc46ed3aa86669fee096b2",9.917710196779964],[15507,"8d375e4e7587bc6ceac4f7cc947c841795fa621429fe1a47c805f15d92daf773",28],[11469,"6aa8dc0c80145456d48493d3a7635cd7b1210c463cd684ef4b97add1599ec1b4",9.917710196779964],[18162,"f72dbd80201b2d796fd910050ab368c3360cb06780af1f04d3ee2e4f446a1539",9.317957166392093],[9279,"fe5e9e69e77752606887e45d72f5c1c8b191a5f7bd6264f2c721dce228aff1c2",9.917710196779964],[3651,"aba0d9f54600fc174a45178ec51dc0d5c0789ea02a568acd4594fb7a4182f0e7",9.917710196779964],[16480,"e02f704378ffba5121d188571729c0adc98e87b6c55a6d36dafea533c9eda45d",9.317957166392093],[6320,"9472061c4ff02348a805c5fd17ec4b6bcd11297c6ac4358fb7158f9e2d93dbd6",9.917710196779964],[18938,"b56de655df8bc2cb0ecd0ffdd398078f81e08314553cea71d1fa01a6bea77622",28.150537634408604],[7992,"6f1bc04f2070c8c10534970a93544a4f80d3f948c34b90cd91ed2edbc37f92cb",9.917710196779964],[9122,"5cbce54f919708a8839290dcb32b21260da98c7876fba231180013066ec802c4",9.917710196779964],[14877,"081dee5186ee9c131f340aa9ab2f4de054e900d337b3316d2491d9cf56e14281",9.317957166392093],[16900,"62eae1d17ad231dee86dc0a3886356192e0f518ea881f3c4d608298868623254",9.317957166392093],[19002,"15f5f29e049a61a388df1a4e099459169421e6b8f68ecc348041701ce3457e20",9.317957166392093],[13181,"97540bfe1bb2e9106b6e514f8bdec15eea20d801f1368396649f24ebe11564a7",9.647446457990116],[9189,"69d2ad6f1356e156f5394a761e81ef6a20f42c33079bca26573f77cb88ec8ec3",9.917710196779964],[262,"914ea516a4ad47cfe888ddf6e14645fa860ca4747f69978c384d989422c031fe",9.917710196779964],[15125,"e3fcf860b71280d518d5e5ab24bd5d978adc0ca07ab4f7114538e8a64db2317c",9.317957166392093],[5251,"edd646a7caab0f538d9c98101ad730b8611badd8e2a5afe969b96c6e1613b4dd",9.647446457990116],[8518,"d3cdadd03a89dd17681ab13c9634f6a7fb799297f0fbb1f70e75aa2e00f7f0c7",9.917710196779964],[16958,"ca9afa00f0e44f7ca545567abacfebd9413c19a597871823348514b1a823ff52",12.018662519440124],[6603,"671b8a5fba72a6787e1cf1a538610564fe7dbceee2114e3673a1e3390eaca2d4",9.317957166392093],[11944,"ecf0d5dd93781ffefadda478e8a07eaf06b080061726895abe9c166af510b1b1",9.917710196779964],[12429,"d2c7a698a3fc29b4f83e6b92aad7766071e19c3754e975f33cd2feccf3e362ae",9.917710196779964],[5822,"ab0ca8d57c08bd3673efd20a6cd57958f90f2f5fe07ab1a8dccdbaee45273eda",9.917710196779964],[16749,"f29c5b068b608b099de952db4f048f15840cf2a132c16491525536742d8b7e57",9.317957166392093],[256,"3b71165eecdef95a044255b14e6325dde7be441868b1037f432d33e7ed3a3ffe",9.917710196779964],[17991,"fa0bab8fc2ef69544ca73fdec7bbd1af3bb96833d9e530cb4f89d84c8a38643d",9.317957166392093],[17971,"99849cf76acdc97a9a5afa976eb2300bbf6525b7e133e7da0456c4554ab8bb3d",25.003537568982594],[15234,"eef2097ca36685d31ab9fc2a74e894ae635f3979c2a8150479a3d22dd5bec979",9.317957166392093],[4817,"f8c75f78a1a8683787169fe2483f3f8c1d33f2c17786deb64965b3ea552253e0",9.317957166392093],[9292,"bb6d2a1c71eff002e1fa24766f0cdea5c024ce64999434bc765bb2ddd1b8dfc2",9.917710196779964],[15374,"41af934dadc39902f70df0d3c77bedcea56057c8d3b896f0c51087a880eedf76",25.359430604982208],[18578,"6316816af814b6a9661df496e9495ae6b851f3846636767130967b89031e762f",23.003533568904594],[16217,"ef171ee3cb24e7076e488bec7f905f79aa9ee6040fb7ea11a6c36dd436fa7763",9.317957166392093],[4753,"6b3a9eb50e9f9152c7e5c65c3f4ad270496dbccef79ca8549a1b6681547aa0e0",9.317957166392093],[16517,"a7a5d63670b9fff3cfdc3f499c8a70aa997bf722e1081284d806e5978180e25c",9.317957166392093],[5126,"af69fd8e4cccb2450705bc1054a62b0056d542d57c7ac7c5d0edcec6c7b072de",9.317957166392093],[14096,"926f9e20d0dec038115bc25b2bc5a72a1933e68a048503cdd0b998d43ce89f92",9.317957166392093],[3391,"2a21368e6df5a25430db1ace11f71cc1901867b13fc25e3842385de9272bc1e9",9.917710196779964],[15553,"372e4fe80b0e203e940bf44086845a74b866c7090edd488b40953fa353d4c372",37.89021479713604],[18320,"89c949b629f7dbc4b5c2432d9bf57478b5063621b62a388ecbc4b6ae967d7a35",9.317957166392093],[282,"17aa6b5f9ec20717ae3ee7000d85a1dc036cb061717ea4f77a71bfd656f210fe",9.917710196779964],[5823,"071508522594e4975c1d0f1e6c74292ae3136ccc398de6c626fc0329e94139da",9.917710196779964],[5108,"add03f8f6a9196cdec2161773e8ac6502d3fde1a378e3d912ac8c3885b3886de",9.917710196779964],[1621,"60178fc0d08d63ec6aa6168eb4f095583dd71d265d48f6b7bb2818ff2bf371f5",9.917710196779964],[18406,"a26ce0d51b082b971c0c572ce7b2b49970c407d228d150b33b7593db28bd4f33",9.317957166392093],[16651,"be99b42458c3c43e5078c65318efc84c41b2f42bea08ae6255959e3986b4c059",9.317957166392093],[6543,"ce7bc340fc947ef2b2224f21c2474124bcfbf9d63023c32df6b5df92de460ed5",9.917710196779964],[19617,"0c066570ba2964a05b3595a6cdd8cfe00f95dd29bb1a13395a16cfd24abc2709",9.317957166392093],[15547,"03ab6bdf473e255a4834c8b5b9a368a5b880b69f1cf20ab1b0f74bf2506c0873",34.77580071174377],[11682,"e4639356f86d2225ed09ca63ab7232e039a7c13b2626f23f3b27f5fd42dd6bb3",9.917710196779964],[2106,"8cad638ebc5ce0bad2fcbbab73423a0c42347c12b02ddcd8d103552ed9f432f2",9.917710196779964],[6656,"d701f3b71946c7584db7c8915e10ea8ab7d71a22faa08946513a5f1b37c248d4",9.917710196779964],[1756,"ec9b6630c6cb9a48338d63d03e25501f6a26f757ddfe7bca4bee812ab5a18df4",9.917710196779964],[18831,"30d0f424b7183111995458b4dbc6864eaa6a49922098870d3840def1d916ab25",9.317957166392093],[7068,"c49fffa55a87641c5f95598de541b8a5fb3d895674ce0fcee118d19296ab89d1",26.13612565445026],[14740,"fdc6e63fe491c3f078875678d26855a065cf9d20ea3cf1569ec178780f801584",9.317957166392093],[19612,"91dc485c96c9eabc71d9b37be2e4c4db16cb29b1855af1390fb97bbf09276809",10.040927694406548],[2897,"90bee63e9197a8233c1a14c196639570756e28fb96e5dd2e5958912fc72626ed",9.917710196779964],[15880,"22fb74bf13f04c88f86a21f1f54f1f51093c0019c09bebc00ddb83957d7a636b",9.317957166392093],[3725,"a3f92f837bf72909cb2751778322ad51cc57738c5442207539db2a01265e6be7",9.317957166392093],[16601,"ba72315f305ad5580fc0edf8d2d0f17bf22fb988aefdea7e60eeafec7afcd55a",9.647446457990116],[19528,"6788db0b75fa33090173304d980af6723bc36847e5fe21ee3ade0f3febbc8e0d",9.317957166392093],[14924,"11c58db18c5b5b05d1afa7028ebce8ee013e802ab9a7c5c45b17133ae6217980",9.317957166392093],[4237,"4ba674c4bab152927a3817dd450c7455b6869e653bce21478bb50f1977fc30e4",9.917710196779964],[11034,"ce76343772336b12d870b9572171453dcf54040b60a4524b67ec605d3b19d2b7",9.761273209549072],[5932,"d35f65185bd98b4c387f102970037970a239b9a9a1344d163c213b929f917ed9",9.317957166392093],[16620,"df488aea4a2f5244d165b4d9d50c415207ebb20e168934b618c37b0ac15e735a",297.30593607305934],[4836,"3b918ac3ec25cbcb61a1dd49ba3c3d99060c6834ce13fb6b00906e7e9b4e35e0",9.917710196779964],[5566,"87e17f2c1a3754a8180c0c774caed5ec04bf362b2df4bc12c2a5e50a1acdd3db",9.317957166392093],[651,"72bac6e52d42ea49f2c777e1803ebf44da8177ae6988b58ee1be7a448a648ffb",9.317957166392093],[1091,"bc47036ccff1f408e5b87b3ed11bb91fb07bd05adf4ea091f622805c01b09bf8",9.917710196779964],[8722,"788ae3ae4ad88bde916efd731d4d85edc696a16c98ca6eaa57b2bf211ab98dc6",9.917710196779964],[3719,"06c5e093bc0e2cb4492e20f679ab53af733798d070f23cbcf4c4aa28c63977e7",9.491525423728813],[9427,"d3ca23c308692e88508ab2b4c2d1271ef089d401dde473a525eb02f83a712bc2",9.917710196779964],[14319,"34740c65bb97167b1f05d9b6e4cc664baa88059d025cc872004d71a0371b318d",9.317957166392093],[13545,"3cdc6699b4b33c1d66b08d2a7667c7a3efda9d82945c2cc38323da144908db9e",9.317957166392093],[52,"77c4913d0b6f9ab9136c36e153d69f69458d2c53b654bc7fd8b4b01e8a01a4ff",9.317957166392093],[2197,"56dba58a2c176e4f24d43037975e1c99f6e09ef8fae224e74c4b2529b5448ef1",9.317957166392093],[417,"d131bb4f91d042eddc6074e46b8d777a846ac75cc9d33f18a5dda981956043fd",9.317957166392093],[7492,"34d8484f6daf61f206f6199924044277317725a92f01b616fd22410119c3c7ce",9.917710196779964],[1292,"316195fded70c0ecca86b8e924a3048e293f8d66d7d2b9865f259aae26386df7",9.917710196779964],[17476,"9ebd3af0512f78ebb001c2419beb5061002ea656535a98ec965e82952db72648",9.317957166392093],[7900,"647bd6433abc4beaa003aed2cc73c50a75e81cf2de1ad6eabe2d5383e9873bcc",9.917710196779964],[9506,"9bf625d6f4cd855c9a5d94b438a73b373a904de1873577042740edaaa699aac1",9.917710196779964],[1666,"40dea0fe3abc9781a6ef01e1968a2cf09850b865096211f4b20e7bab1b9923f5",14.188948306595366],[10591,"7d0d42552a3232404b3a8c93640551a386406764e8921d951be4c0063a95aeba",9.917710196779964],[16678,"a43f5c52c297f6fab24ba0156a671be8b9568d0005ebf430d3ce5e7921531c59",10.052724077328646],[5718,"280b12ae7bda7113568e2b1650269c9fe90ea7738cebab548784c21ac9d7f2da",9.917710196779964],[6356,"47ce4d0527345cc5bdf8c3864c18acdc6a57a3fb111d7221375eaf27f7fea5d6",17.129770992366414],[6698,"a39070b1571066c0e5c2c8f309d450d5e533ec4db3bfcbe5feca34d62992fad3",10.052724077328646],[401,"b62ae97e9e723be827fc666a8915aa0be7b169fb8c6e7abc3eeb6a02a3c454fd",9.917710196779964],[15700,"8d2f16d5949b0a2986e3f270a26cad6dcca7891bf578f6f1bdb31655efca816f",9.946524064171124],[77,"c8f462d756cab1417845dff5a14590e2193099d696f73054caa2ba0a03a87eff",9.917710196779964],[11971,"5c3b9062593bf68ee78ea8c3d9012586827e7cc512f06cc47f3ce8f6888c80b1",9.917710196779964],[16661,"a880e501bd3e409438e9530ef5a04dde1368a864dc9202b1528a0ffa1ce47d59",10.052724077328646],[19176,"85f8498edd73fffd68e6814be8840dbfae44a7787ed13263878e0e507dcf7d19",9.317957166392093],[9097,"0cd4610c521ead0357ed4cd7f69a12d4f844ba005572357dc837b15dad3f2dc4",28.899115044247786],[16,"8a7da6f84c7db1c7944b16601504d8622d94267e26e573250bf1d2bb7c42eeff",9.6],[19586,"e0a234bcda8f346a0c6c30fea3ae8962fe175c4e28614fca5f13839be266a40a",10.042553191489361],[6963,"fe74914eb5abf3c8b93ec90aff547f89e4c0e4294c6b18894919d18e667e32d2",9.917710196779964],[8104,"8e565648a9537b5ae9ed7f910925c67aa2592b142b813fa5af3220a9883abbca",9.317957166392093],[394,"ce4a23855cd66a2731c5d42ef877ef074b32d35d4ca52d3768bd2f84f74e64fd",9.317957166392093],[11890,"307933bdd327f47532b50b5309fb2f7d1dc3d2c693273e3584c5d3521e1312b2",9.917710196779964],[2822,"48428fe62ca715205b7b798510fb445283d0ae7ce7cd43c9949c6230323d8aed",9.917710196779964],[12213,"764f8b2ea4701881afc3d94e87a054b6aa4c553c8bf6705ddc2690a9c7ba01b0",9.917710196779964],[9165,"262fe06f2f9a35624ffc538c93c6c2daa03c9a6b95b86fdee5969ad9f145bcc3",9.317957166392093],[3681,"bcb0e02d50d7adfdf6530d44821e34177c2994b1b974f4f2af9c95378ee3bae7",9.317957166392093],[8528,"c9686fbc748f2ee6e755bcedbc0d3274a82bae8396d8a960d74c8f640253d4c7",9.917710196779964],[4957,"21f60878f2867cb2851000693386d4aa35faa4010de5d9e9be5f8bf2a77e82df",9.917710196779964],[13345,"17fb757a9d351059b34df912face545ee08e01755ed819fc12fa5847564398a3",9.317957166392093],[1202,"c14cf2011b16fd615b57cbca6c01b07b19edb388965fa9ae4e010b08473901f8",9.917710196779964],[304,"6beb0fced35af5b4e9abb9b8121a316a21d4085b9db019d95d273920f4a9f0fd",9.917710196779964],[10067,"84440b65e46952b8c62039feb0a9ddcdcf59ae15db1968b8e4679ac33200f5bd",15.105633802816902],[3334,"60316d38a6b9348d8ecdb54fdb92f7b9c6abf985b3fe4868e2fe82cfd02e1fea",9.317957166392093],[7224,"5c71585ffb2b4803a2f8194d2c3ad7dc4060f211afdf8d4d1d35eb75cba180d0",9.917710196779964],[5934,"c48be2164d903fdb6ec8cff2846e001fbd67d8b84b7f90ee2e1605c896f27ad9",9.917710196779964],[1570,"4a578d15c6c68a010d27eb9a05846b788115d4804afa80f3ee5db7643cdbb4f5",9.917710196779964],[7456,"5e307fd3b28b63b668561444608fd6bf300144de9081eba1639fe82c6f3f09cf",9.917710196779964],[19156,"744c3f06132da9382319d979daeeb1e1cca8c2f5fc9d28cc44cfe3782e5d551a",35],[16820,"bf92fd69b9bd01be0d160902c224ae051404bc36ccee485319220a928822dc55",9.317957166392093],[6736,"5ee65879f389a5e446c1fcab2eb066e7e65606f852b9a7f6ee254d99b300afd3",9.317957166392093],[5618,"f4ddaf719a5ddcf6a9a07356b9517c945f3a72940d8b9f2c74a28a6ed89390db",9.917710196779964],[19536,"b0ce27958b11740cd6399ab39970539fd304941b0b87ba4c0a8a6ef0ab4e440d",9.317957166392093],[4694,"74eb13e0bbe35fc1369ba1799f29b8264b35664048603630b8bc0ece9efe08e1",9.917710196779964],[18190,"b96ef02c9e3c2f9d108bd81aea294df10fcbb0de3bcf7c63cdbd18710de26738",10.052724077328646],[1172,"e33b18aa1c0c84ccc989a8d7b021658dd1697aa390abc3f7ffe1ba89696929f8",9.917710196779964],[12217,"593d2b65875c01086796d3e81a5f7ffbeb343ef53b84de4630cb1ab80d45f6af",9.917710196779964],[7521,"4aec1f0bb45b4c273c473bcae786ef415ae94e271ec8a7c248cddcde7d62a3ce",9.917710196779964],[18096,"991429ed5b09f75833cb6971e7076ca090e6426258c4fedd091267cc1ccd063b",9.317957166392093],[13799,"a96bccf5a7a5aeba74f1e333e75b679d1aebf3d79fa54f6399d536e963d15b99",9.349552444342438],[17791,"de27e3d244d775394dc3cfa30eec7942776f2fcd642f3732142dfb0562ed8541",9.317957166392093],[1093,"f61f17efce2bdec51a666229ca5c71d159747c02528b5cfce62585e1bbb599f8",9.917710196779964],[19644,"2cfec4c3a1a47f48265a36b29e4155b67f324c92ec0ea1cc2bfe20bc2c812708",9.647446457990116],[15088,"23856791031b12dd94b7ed5d826c1c4dd2bdcf27af8a4b5269f875987589e67c",9.317957166392093],[14893,"c2f2c999949b9425c5045dd81af737f7ec8f4f4ff740981038844882fa520081",9.317957166392093],[3408,"7bb2e32f7a3f4f7a337538c37c035b8c73afc5da85ae74862e1d393f5c6da0e9",9.917710196779964],[17434,"3e9d31482c28cf93a4bfc06723ccc1b206b87551bc7c36fbeb9f9fc6f1280049",9.317957166392093],[1609,"92d17ed193a56717a2c36bc4e18da8eea6ff1a1c76e9f5c4fae06fd05bd285f5",9.917710196779964],[291,"d3f6df15631ca80a9de93533ce74b330557e64a4ec7bdd0c45c0e6b4ec3002fe",9.917710196779964],[11754,"3a4d1e7f95ecc1a108fc76b9c01e9974b1d2f0b1fd4c81d96cda0398b0e4f7b2",9.917710196779964],[10262,"a4130b0f90e0a119140d2260d2c4f494cdb22e85d26caa2f4cde693c334ba3bc",9.917710196779964],[16173,"efdb88bf3fac97331574e2300218a65de437aeb6a514d74d84a4193b297d8464",9.317957166392093],[15434,"a733f2bd2445eedb08b43a0910250aadbe18ec59bd747f6f0a0e50ea1ac27375",9.317957166392093],[992,"0abd9c4b42814b5f1693bbe0de0ae74a9af9de7a84dd135058e51eae382c44f9",9.917710196779964],[9324,"7308e7001f0da0517076fa2bac475fc1fe3a196bd3fbbdae64722a297a27bec2",9.917710196779964],[6901,"dfdb665b29a51afa8932f8ffb3cd9850a86749da5e491ad9f35de90bf7ce9bd2",9.917710196779964],[7219,"0a3d26ce29551b67ef072318424e020b46202983ea4e60fa8b146cfcd4008ed0",9.917710196779964],[19821,"f0a7a879514a8c369a5223ac6d1dca84cb1e54102cd1fe71e5a11868a3c5ce01",9.317957166392093],[19803,"0e1eaf59f86054e84681ad536f92ddd893a596491501fb64645171eddaec6a02",9.317957166392093],[12884,"4662cc89eaff1cef7a18a94c7aa6031e83d93e434a3c05d17ec5ea5329585fab",9.317957166392093],[19811,"915537b03b651196ebe91ac5969a44a1f5e9bb3c1ab6bd82ba8597a3c20d3d02",9.317957166392093],[18216,"58b3b9cd1f7de4d91580fd922c5f32cb4ce3c14e5da8e95327fc55632b76b837",9.997888067581837],[8760,"da9134eac2398202c2f682a04f4d4f1131a21f3af05b61227b2ba36b273846c6",9.317957166392093],[12538,"c99fa5d160718074e5c887ba817546071542069c31b1ec41494074add21dafad",9.917710196779964],[15683,"2040d0817ba9dc2be2cb46cd1f319e84a0022e489b630f81882f71857400c76f",9.317957166392093],[1275,"7de8116285d8ddf08de0acab95443757f08bb3db786cff2a5417f8de22c885f7",9.917710196779964],[18195,"238fc0f545ba9a000ffaf52670b4268f4e5f87b83fed0dc182a2e6599f4f4f38",10.014471780028943],[16083,"f6856c4734d073f0582149aa4a245f777eb5e4942682b5043914d0b62acea066",9.317957166392093],[14124,"ac46df91fea7cccd3b3709fb51fa1b401f35563524dd04e8352771d9b83c0692",9.647446457990116],[1661,"75872a3bd4af5f041cba8dde611da195e6e9f5c485303ec8e2a49bc5ba232cf5",9.917710196779964],[17432,"e09c750712e52326c01d2e60debdc66fbd034816eeb307642fc92f3abde41349",9.317957166392093],[17492,"d41fbc858a01ab8fa7ed3e2c6fa3dffc48dd314919118533459a11cbbd5cc747",9.317957166392093],[17735,"8bd08af5ff81d0e9462d93c734ccb7e23a0e6ec63dbabc45a654a7b4706b8442",9.317957166392093],[12049,"80bd8f7680413825065e11fc9360b298257e4b92feabeb61ca54797172d7fdb0",9.917710196779964],[7321,"2de34678e933b48af742971cffcefdb98e799b6e255c1de814c40e0b5ae2efcf",9.917710196779964],[4190,"9ecd7854c327cc1a513fd7b6dbb64d41175e7754b276cb57cafdf43c46c17ae4",9.647446457990116],[13428,"bbeeb5648fa231ac872fa7025ad9f136b3d18d89a9582d52331b4bff06d1e0a1",9.317957166392093],[19134,"c9e586370ea8ccbda65a67e159ef327ae89f4520efc7cc13cd651875ce34021b",27.123367198838896],[14822,"67ffcec8943baee3cda05e33cb270de2092b402fbfb10930a4ae845360bb6082",17.09090909090909],[5238,"b98bee3552c5c7b18554417d4fc464d3b09f07ebe568aaa20f0486757093c2dd",9.317957166392093],[16989,"f7868411ee2d3d8418adae6f33b54ed0557a5f6f2ccc647f54dfdd54a7c24852",25.100591715976332],[8151,"844fe3f093b485450118717d24701c9ee2ce16d2bfc6d991dd58cbe0f89f56ca",9.317957166392093],[3326,"a29fc9f14cb8367743b9b2cd3e527f9708ed936281003e005b5aeda050aa34ea",9.917710196779964],[1851,"30e75ed904abbfd29ca85fbc441ce786aa87b8b570f22b4482ad95d3ee8dedf3",9.917710196779964],[17480,"88ce4ac182763c982fbb07074614c069c7a733ad69bd2d781f6163f4f3951748",9.317957166392093],[14015,"d3b4f2c6d5b5cca7e4202f97fafe6fefe596ac403a6d77aedab2acb0a0ea8394",9.317957166392093],[5643,"44d212044d4daaf3963e63f17e666d4c3afb2e64d582aec886fd5b5213575fdb",9.917710196779964],[2929,"e5774226faecd6eed8862511c879a5ca712b1d8b56f5a2938c88bb88a434daec",9.317957166392093],[15262,"d6710f1cbfa5da5b91567b016f2d369c26ab3b278797c725f65b57a39ba13779",9.317957166392093],[15098,"02a8ba8a8727720c7e33bb93276795df9b5fe7ca6db73cdb52e3ee0f9a59a87c",9.317957166392093],[9817,"10f7de4f24e2d9ca8bee0e87c5fb905f19a46a878d352cc83f26a684225689bf",9.917710196779964],[15641,"511df058e3056129a0eaa61f5ec4a8736977f1381d9a9b14e1c924ffafa88170",9.317957166392093],[5505,"6a62658a23991876beda503df3fdfecf55f77ad9654761029ae72fe8a6b52ddc",9.917710196779964],[10620,"84e2043d98681b488ba9d0bc5005e31337675f5b4c45b21f82a681b7e1488cba",9.917710196779964],[7261,"9202523639f2f0251a39d294e48e6f39fc9ff2d206243faa72482995732a46d0",9.917710196779964],[7142,"7b8a6cc7d189226ed736b5954ada11e0230c2e23b3f26885c4ae07c9487811d1",9.917710196779964],[6469,"69d876f044e082d7e0a7276f148221d2e979d075064b1967fad101f2f4f1abd5",9.917710196779964],[12901,"5851e40228a71f8c090049868b67b460fa242adcd1637671de4f74d7a1614eab",9.917710196779964],[11997,"bb541af12f94ce776e13238545856c69a932b9cba322e2d2bc6496d63ec057b1",9.317957166392093],[6918,"dd95ac94f6ee3d6b9a4fd99a936ed9306eefeda182fcb1f3e8950147cb2d7bd2",9.917710196779964],[3431,"033ea422eceb8e6ba6e9a8b6e2089b916313c21f0848be9c15f2258f21c579e9",10.052724077328646],[15221,"d1b68ffc458126cf4b5ae12ab5b28fe674efd8f1034d62f46120ed5d1b17087a",9.317957166392093],[6804,"82b3cd06049aa1f70e70448dcffa54b396df0d3ee8aa4c3cfd7e3acaddf63ad3",9.917710196779964],[7612,"647c83e2f1db4f44408660281153743bbbd45bdd43b891cfa256b8f198b520ce",9.917710196779964],[19008,"884dd9ef88c390b8ca16dcef3b76e9369bb5781a2ff396e3a5e5d90f4ca54a20",10.052724077328646],[10644,"7392bedd6cf1983a0e837aee60497e9bfce8e645eb349c9daaaf66fdaecd65ba",9.917710196779964],[18822,"7cce70035c953b45ad87842c7de03dc786ac3a2bf61b63452733af415821fb25",15.07908611599297],[8227,"36d7583624bf3b0dd1ebccd0cffcf4fdc77e1aecc4f4181d220bfb7963aac3c9",9.917710196779964],[14645,"0ea35e61250d82e6860071e59ffbfad7ad913d6169c4408cc8a9a27cc0650286",9.647446457990116],[14241,"e8f7eb2d77cf01170c50f6b135d30b48245062bdc2d84c9f18ecf0b98a872b8f",19],[16221,"af4f371c6bcf9e0eba9cee3bee9f1c1d8f54e6ea658c9056db847b85034b5563",10.052724077328646],[9986,"d065c480d4c7e54cd70fce7238977485f5481e20fab1bc43d73ead033d2469be",9.647446457990116],[15601,"fd634ce71179397e7f8735aefde300833c0f22d8c72221d6d6e82c9c6d306671",9.317957166392093],[11866,"28d414163ca7ecb1c35658526f39ca5f44f01ef2ef0d0fced2b8b27888d147b2",9.917710196779964],[17261,"070d63b3d3fb01d4afdb5e8fc0e4237d160eba1399f721f77c82781ca315e94c",9.317957166392093],[15228,"bee3befe6ba761ea0cc788cf86175e228e001da88850a9354313188d6f4eec79",9.647446457990116],[3320,"9bd4c1f0536974a902acafaac7c2af845ad749013b7d95c0acf6613d86903dea",9.917710196779964],[11108,"94859713193065b405615df1d4eb40bc263fb3fba2e66ab44a6dfd3ae80734b7",9.317957166392093],[18481,"cacdfdc891504315ea215535de3e73b6e6e30f094927ef81c289729ab54ce331",9.317957166392093],[1884,"415e14f21b261af92d69560c3c33cbb4b1f077be30918f02cd2c2cf3fcc2b9f3",9.317957166392093],[427,"b859c4c59e62b1ec8494b13df1bf7083e6942b2549b44ee07a559201972433fd",9.917710196779964],[16063,"6540ac6b9c8fc9efadd521b10835f1dedd7c90ff7c1736d2a9a84a0ed8821867",9.317957166392093],[4820,"e092be836859b4edb200b096d8e067053bba7f13e0624c056a37f8f94df54ee0",9.317957166392093],[11170,"5b9e244dd47509e7accfb5946e702b24f0be94f2b11ff7d096e0c40947e2dfb6",9.317957166392093],[8083,"c10deee9126578ad41896de766f60dbd7466becb157173d446bd5f8e22fee3ca",9.917710196779964],[13033,"d6d950a2bd739f8b0c77d51fe6d874852d3e1e63ab5f01743a4905fba7d263aa",9.917710196779964],[12099,"ece0091d299981a02ba955d08079c9356e049e6359e377dca35a8613663ab2b0",9.917710196779964],[9020,"48160e7f6aaa49615298704470e5f71e6aeca826bf537a145748b7dd7b7ba5c4",9.917710196779964],[3610,"351058d46cb93a0d2448628900ee1da82f42f81e896d1b1a9e86678fb94d27e8",39.05061082024433],[4757,"7796307c906aca3ede0121c7b874781cfdf6b860341c8617bb936a4aeba797e0",9.917710196779964],[12311,"5f0702dd5c3988c0c31df54acbb96b1e2f1e6d28ac1b83d4298c4bcbf99a2baf",9.917710196779964],[9617,"0ddffada5d86baacb043c7f2bbea01a04dd39a23d3cef4920013ec122fb5ebc0",9.917710196779964],[15606,"93bc2a1225ac9cae00524b29491563ed6827ee72e128958be742d56b584f4a71",9.317957166392093],[13867,"910d5750505edb6ed5a3ae270e145fd6ac4ddbaf75eb48b706fafbb25bd5f497",10.052724077328646],[18952,"278873cc033943ed3c2913ba4a43150cc4813fc295c937b037b2092b299a0b22",19.20212765957447],[5136,"42d969de27268be9c675970c98ad4dcf6071fca433d1e14ec0f76357e4ce67de",9.917710196779964],[4748,"d3bab19f242deaa420793b40f619077a8aaff78804b2081c398b3c0ca7a9a7e0",9.917710196779964],[17569,"45e6d5fec52c520b78f59b9fe69853a9bfe28a36a2db4d84c51c9aa3b0a4e345",9.647446457990116],[9993,"cba88a2ef51a43870e9c5cf6a548108ae1bb34d4c937e1664a1e1023aacd5ebe",9.917710196779964],[14660,"49e00187c33fdd54f824ad617c9130c68da1fb626eaac9eb03fbbcb579d8b485",18.779456193353475],[2369,"7a44e6d07f6a8b5b8f18fc2401a710604b099aea19fe48312aea3b4efadaa3f0",9.317957166392093],[19074,"48c71023ae7dff49c88e25a39759122630859e06f9fda860f8ac39924fddc31d",27.151515151515152],[784,"cf996f0148452bea4538239dd6274fb1c6aadba1e685012e4dd473c9f52fa1fa",9.917710196779964],[13038,"2d79eeaef3ec3ed93192be2a244e0c0fb39d46079bfd88bf1d780b72733a54aa",20.0734394124847],[18560,"55c1667bdd892788b38dd893e7d8b016a59bf1b85701d2ced4d12f4907c73430",9.317957166392093],[7897,"ec6778de0ec3f345502a36fa78be057c72c65e50cebe6a02fe83f513f5e842cc",9.917710196779964],[6441,"364e01e5b4a1cd093d20018dc0a67571f8a903616e393bec18e05cf37e68f7d5",9.917710196779964],[12752,"92923ed3ac0b71af3ecb8032d23ce6df76462b9b58450bcbe1aff3757a8e3bac",9.917710196779964],[17251,"a88caf9fa3d1bd4dcece04e8aa649846ee80de9ab08ba104c48364ef7875fc4c",9.317957166392093],[12664,"b8d28353909843e8aae4fc1cd48ecd89d40a4a330171e8b1f8423d33cb43d7ac",9.317957166392093],[1596,"c98a87c92e96b068b77aefca8a74ae99d966b6561896bff0b6e067c7496792f5",9.917710196779964],[5005,"0fbbe8d7bda1885fcac531f107a6b8cf85236add093395af2b023f1c6aae20df",19.32116589485154],[12085,"0f0f8cee8c8bf54138ad056eee4e956544f041c3e476d4bb5722f13d9ed0d1b0",9.317957166392093],[18248,"1baeeb3400b08482ce0c43d106918d8972808e6ef8245e6f14d014d978a90537",9.317957166392093],[14250,"9ce80d455b0ce9e6a1e4c85c73f96de6fab251edd18b073b3e6ae37cca1ff98e",9.317957166392093],[7075,"171522b9f00faff668efcf538d2016121aab8452b28acf0ca2a8a42c346e7ed1",9.917710196779964],[12717,"7da2c3b4bce59e4952c4f3dc19612407528121f3d898c64b0f9ff2712c1c7eac",9.317957166392093],[7130,"5ca6f311559afc65105baed7940403d4a427c1d4e78d7ebb1fef0e1f80a51fd1",9.917710196779964],[424,"3d4796348754fe0fe64bab1615e4ab496564fedb23666bb42fb31f350de734fd",9.317957166392093],[7455,"534e7cc7d7491b1ce39fe2cb9782c44b69354cf612eae7d4d1502e90d7a10ccf",9.917710196779964],[5158,"b483a3323c7a2a6efb9642a1dc93c11ae99007c7cc8d003d4fed5e5aefb73ade",9.317957166392093],[18580,"7af06008084f7512d7c21cd06024eec0ca1bbf590c1090c063f9c23ae7e9602f",9.317957166392093],[3087,"cf213cc970ce165765beeb16c2dfb4d34d5e9e10aaeed04c6b51be329edfbbeb",9.917710196779964],[3850,"67f3fcd7881870a6582d49473b154794070444597a7d44f11fb87586c25cb9e6",254.0192926045016],[10393,"2e9aec0e7882cd0c21d585f865555e1f0e676eaf4ff0d5e386e373b2ee2bd7bb",9.917710196779964],[13071,"02bbb59efab70d44f67ce789dcabf277ade335315e9aabbac2860385687026aa",9.317957166392093],[6234,"7d26ff4a9a55eeb193267befac64f9348e875a21b5ce5ad592b9b09b927985d7",9.917710196779964],[15555,"d0b2da0135a3cfbf468fc22fc7ab5db2e57fa6033368fd45d13539c345adba72",9.317957166392093],[10929,"21b5ff74b893685fc4355a80b5fe7fb7352c27a19983ae0f483432761b0183b8",25.961605584642236],[9661,"7f6919c7c31d4419d665bd46907516a79cbc405fed50a25e33574e0161e9a4c0",33.926940639269404],[15608,"86a63e5fb765d60ccbce353def56c66817aad0f68c584123542638e571994471",9.317957166392093],[7329,"4d46ae01f82bc96a0ffed2310a4335d132e4e29f61ff8832659200a35235decf",9.917710196779964],[7597,"1259c420227d43b6e90b10f695359082e7ea58dc0d973aa0a36b0a63e9b431ce",9.917710196779964],[19733,"5ec13c12f440b071ba19ffbde995b8db26e18d869e89578644843833df77a405",9.317957166392093],[5712,"5d3bc832e80171e295fc389746d25af1af4a961b0b3a0bb6bb5cedeaf96d00db",9.917710196779964],[2169,"4341d1cbdc1625f11035456a0716398d5a0cc71c1ad5899738e2a99b69dacbf1",9.917710196779964],[12916,"2e3071197cd40c1bf5f5be425c4b26e4cdb6145b7bd7e6bfc00cf3470d0237ab",9.317957166392093],[8330,"8684c84a81f048664b10110a473f6665e966789c1be08f92cd574b33135d21c9",9.317957166392093],[7143,"f3fe069e6b9f7a4674ef61801002d46897c7f2ea9a2a979d5ebbddfc00340fd1",9.317957166392093],[9046,"3058ddcdb75015f614f2b90853d7260101309d156cae77a23979bb0f0e307ac4",9.917710196779964],[1196,"88664435eff0619e11305b09a7ab995f07b0b005dcfbd35de888fca1e11108f8",9.917710196779964],[3871,"2dabfa095f673c12a4a7b96a994cf699449fa1bb33d00ad4ac78948dd0218ee6",9.917710196779964],[5606,"a24f98ee96e0d302d75054f958bfc0b79bb608f294b7a91479f5ce34516f9ddb",9.917710196779964],[4495,"040309c3b8e18484a01e87972b31f21aad1647d2274fbf337ee727bc11eb6fe2",9.317957166392093],[3712,"faa845e460ebae5506e1121eea16c3b836659684339d607a7e44da898d0584e7",9.917710196779964],[7375,"7b61bdb40014193ca53ae30ef19c766d8873323232860b6353bc9f26c9b28fcf",9.917710196779964],[18373,"a6e4b60f05b71ce710952c3c3e6e28f0c057b49654d8c0f18dd221e7aa2a4034",9.317957166392093],[3323,"76f388e9956d716ad5f63a5eff39a850cdaa34bd404c0258f66d8b4bfc6e39ea",9.424083769633508],[6400,"98df6c6fb79378c89623cfe625508c0245a67c8068d4fc8b7803f18c398b5ad6",9.917710196779964],[7258,"cd2406900bdec92731c43b9ec8583a48e5d5032569f61eae1bbabf96f1c64bd0",9.917710196779964],[19098,"83eb44a6cbf6292c6fca38ebdbe04f0d65818be5986d16d42bb4632ef285db1c",28.899408284023668],[13645,"271b1c19abfe6f5a5e2d49e7b1ab04e07dff4729f05ae68705294e57ed85549c",9.317957166392093],[7773,"f73d26d97054f3bb4707789a5b9b26364d526bb059fd0fa3ec374480ec2cfbcc",9.317957166392093],[2833,"4290f2c5edccbd96255b7c3273a5e7ea001902b24734554660da70c4f1a372ed",9.917710196779964],[17366,"adcd3562308080ca8f647fd53c4c9c6fb4ecca43fdb7e20858abd3b90e368b4a",22.150943396226417],[17830,"de5959f98c2ac6c20023df509208dfa495c9480e3cdb20ec6d0347618fd39e40",9.317957166392093],[8988,"b326f3f20eafb452c886270bcfc181907f78edc53145aee76ae94a5333d9d5c4",9.317957166392093],[8448,"c81d21d7ca950d8ab0b72d1592182006193272d14d1692f0524150405fa156c8",9.917710196779964],[10828,"b3ace72df65034ae5ffdb922769ecf618a603eb4012a9bdca5df42ec42d81cb9",9.317957166392093],[10251,"ecd33dd11dac09ef6041c3275b6c81db0bf3a42a51fcbe2f440872e74494b4bc",9.917710196779964],[11903,"c33e912e1582e0870d21ba7f9437f59ff4ef9491d59a6aba9a291d5c6adb03b2",9.917710196779964],[3656,"f864a86b7a1698001026e1866f4586bdab9ba2f98370917a56ec65b3096ce3e7",9.917710196779964],[16506,"d1a78d6ae1482fc9c1666b02e9bdfeeffa7b9243d2a7695e070e36cd67df1c5d",9.647446457990116],[10492,"dfe904378821a7a2abde7ed7c18ad4a2d4dbea8c08c29ae932af3b26647935bb",9.917710196779964],[12926,"de54087c32af3d6136ad5ab07e7da9b50efbae089757ff677f90ff1da93a1cab",9.317957166392093],[13923,"48eb84a376ff79727af1e323a6148cae7e8226f3cef05832e15fab3a889b7796",9.317957166392093],[7154,"826c8e385a475b12951ee483070b85bdd8ba6938481794bf17b703501553fdd0",9.917710196779964],[19602,"eb79487fa637fc21e4f16f499589aed732256b80b41bcd38f9d42bd99eb6010a",19],[15840,"bc9ec1fa1de8e786c34ba9729a7004e8b20237200f53d57763515178b699886c",9.317957166392093],[14083,"5d68dc82e8359844e6370f91aaa212cdde8792a260dbc375e44856272ddbf792",9.317957166392093],[14112,"2491dcbf1b379df0cfa67b40d0ceddb950706fe4d08928865cd1933a32844192",34.301686746987954],[13954,"b6a21d2982a14c683d8c01088fc6500c25ad25571b1d340e56ee690db154e395",9.317957166392093],[11723,"0de76ea32df9503ac1d7c076df21cb3783bf7f175a6ed3e229b9913d611927b3",9.917710196779964],[1021,"457604cb4dea46bc875f68a5c3fed790d388eff230f13816144dfe1bf25e1af9",9.917710196779964],[19167,"53d9754bb11d966494463bf13dd1d4ba02412bce277de10776b40fb430aae019",15.073529411764707],[12176,"3a289d2592bd4ac61c4b6d5c88a1fefa49dc04ade28cb042b1d14529a94037b0",9.317957166392093],[6416,"7d12046bcc4019b12d190b3371d2e10d8ef1f1132fe41a38c6f0dc62d13230d6",9.917710196779964],[1507,"f496c1ba750837d29ee19f976966266568872dea4dfe4625c7e482d2fa7111f6",9.917710196779964],[4866,"5d6b3ac46b6e73e6638ebc437d72dd5077d8904f6a2cd359859ee3a10f4c07e0",9.917710196779964],[8201,"1c75f542e49ef820e72535086799b6dfee574aa331fb4c3deb23cf545fcdf8c9",9.917710196779964],[3689,"9305a894a0320e7096eacad71ceca6bbcb992a63dd96a65f45348ec39c12afe7",9.917710196779964],[19144,"118f3b1ea919cf1d9298e070b7e76646df09aa22d51da310fe6a00c03f0cab1a",9.317957166392093],[7814,"593bef85c74ae33d2c975b623f07b5e084e1fe8de94cfd66954c5ca6ff65abcc",9.917710196779964],[3216,"8435347d294156a12d1a4f439761e99808670d68caa156952c756ba98812f5ea",9.917710196779964],[17221,"7b1edf093f596c68bd7ed791a9ddee0903d24734bd315921165f9f9d5eb4824d",9.317957166392093],[1796,"9ba5b23f04defbfcea2b364e211994b97ab82f9720cdfe0e991592dd8fa045f4",9.917710196779964],[12210,"a9941013ab309d4e3f2cfa1b7db42c83c22040bcc6f524b89ec3e22f247006b0",9.917710196779964],[13876,"8cec15929b8a1a80324b6a4e791dbfc281024239f3d43d99cad109b4f707be97",9.317957166392093],[8703,"6b2980c36d96f86a0e2cd3e811453821e7a451cea0d96c3059b03fbb308db0c6",9.917710196779964],[14936,"2b4e85b4edf5d827a726cdb262005804f766b44e15e9080b2959249bed401880",9.317957166392093],[1831,"2eac3cf49e7e60dfed7ee5f67db2ec428966c9b396f1584b27c3876599fe0cf4",9.917710196779964],[16366,"78a0254434133a95b6ba2a685c14faa2b5567b579bdb685f6496b8a7f943bc5f",9.317957166392093],[3304,"77024ca5ca9ba732381971cab7ed998e30ac007697edef46c6307487329f59ea",9.917710196779964],[6725,"ea366151ebf610f1d623203d099185a33751fc5020229808ab512044075bcad3",9.917710196779964],[8323,"5d75f33bdfb9b0112a9bed77ef23da39f77d670318ab309d5bfacb18896b2fc9",9.917710196779964],[8270,"b3ebb65090aa8386099a130aaa982128147c902074e9439f4055c378b08d84c9",9.917710196779964],[3655,"dd844deb5d2924262c10639639ee08767013ef54bb873b6aec4c795d9bfee6e7",9.917710196779964],[3936,"347195e7bccd1cb7f8f68a8f0fb19e1ef66764ad61ccf288e1a12848602c1ee6",9.917710196779964],[15645,"50e214d0bd383adaaa452a36f648def798730139ce81c4f64eb621d359c37370",9.317957166392093],[11838,"617696eb85591717070a7561024a2f9bb0d160139237903b8559d9d70da07bb2",9.917710196779964],[18054,"0c6dd3db06fb0dd3b41844a646833ebed36f90d8b95f5f83df7cbd67f25e253c",9.317957166392093],[4206,"ce53524a275626161e1856871fd76e370d7bb92798d66011121e9020026260e4",9.917710196779964],[4280,"747d6154313f3750b330e6e60872511bef7fbb6be722d390f9dad8e0d6f6e8e3",9.917710196779964],[1646,"2a760356541a55ee0079af6e77aa37e68409ba9d007e3c95db1e46ed1ee349f5",25.968141592920354],[3827,"14415e266eaa9527ace54c7c3c1fe8fb38ce136f69e1d0216a8f353cf388d7e6",9.917710196779964],[18724,"5a42c75bc74db2fc99bacf7d75267e9925947bad2bc98bfa28dc142ee75f7d29",9.317957166392093],[2368,"319843fc5eac450b2718e079352f6eab5be50464bae280a85c009ae6428ba6f0",9.917710196779964],[10931,"5ffbad40ab3f5100677bc6464c0d3d754d0ae1aea1fad597efd2b15964bb7cb8",851.3004484304932],[13649,"d8bf9a374217302ef83aedeef1c45278e71553486005423b29c4ce50a8413d9c",9.317957166392093],[2990,"8d42a27110ea693085ae4d505ea5a019c308d05a783c5138ccf65c93550b5aec",9.917710196779964],[19625,"e9d46cae3c53fbf8759e29eead51e4f80147e9fcdb47df69b73ff0b9a4e5be08",9.317957166392093],[6691,"3398d910212fce2604f87d822f3de80852ed3c00dcc6bb4ce8453bbb16a202d4",9.917710196779964],[16732,"fd659900cd2c6f3f844ecf7906ff5b6a9aed2bf0fb527ff838e0c7e15d4eca57",40.57627118644068],[18074,"3f998776598971ab08a8e1fc77b3a7a1d70bee7d5fc8da65c7cd721f88c2a33b",9.317957166392093],[16929,"dd46dc1e62bcae900e8d32ecba3f6fb623f004c35cfe5796b5b5b90d44a88353",9.317957166392093],[1913,"6ba9a514eee291ae0f76fecf5c033e926168fbaa70d61e1ee1fc7fbb8e2593f3",9.917710196779964],[5111,"4f57b98cc0fa374287f494a7dd1b6507ebcfaf060c494da3358b6df3aee982de",9.317957166392093],[7186,"54fe5850174827c5354fa670cabec84646ca805a0109614aef1a2f3d0ae3c9d0",19.11401151631478],[10901,"42423e40b75698831cb286f6c6344badf5b7975334f3b50ae5a9d97791f8abb8",9.917710196779964],[1514,"87cee4394190102477d6ecb53b5ff10865eb0d0451cd1b86bd63cfa50efa00f6",9.917710196779964],[6941,"bffd3b8dd2d58fab20dd3a7ca9f3603789c9a067f3acfdef13084c3a40ba5dd2",9.917710196779964],[7465,"cafc20542e5a0eb9533f0724b7ff015fe53a3f94a10bef900fafa1e7d321f5ce",9.917710196779964],[12149,"f3cd37aad9ab23f0d8e8066a1098186e65d4f91f85c1af719996ae632a695cb0",9.917710196779964],[6105,"c34e5954db20618047f373d9a96649131c35da0886ad80fa4023149a2eda65d8",9.917710196779964],[12298,"11eb10f0f9e4e1b4a164c3383ac54ceb9781a310be47c956e20ec703f15839af",9.917710196779964],[14829,"69422bc03e89869bf669eb14dcb51a1f9b5a3fcd8d72f6eb8834f0357fc64b82",9.317957166392093],[19202,"0af6f4146cf29c77e8616afe36a2c8e81a6fe1cdc4fae376b8d4c7f2029d8518",9.317957166392093],[13850,"403d6939fdf2a734796fdd154b91b1a1c697140eb1fb94facf1cee8403d66a98",26.128113879003557],[78,"ec2955accadac5901613860cea39ee141937d47095d1b04f4967a4deab787cff",9.917710196779964],[12844,"a23ef077ef49872becf73a698088ebb96c98feedf1cae98dc0194a2d489da2ab",9.917710196779964],[6216,"f14e9f182d8d8875761401c91d459f44e81b2609b782921cca56d939c74ea1d7",9.317957166392093],[5631,"3b7152d60b9a4f577a3770968b8a5b664b977a2298226f3b1e3e66c566f570db",9.917710196779964],[17357,"e2a464c519e7e0c49f73ae31ed16640a435d03a17cf199ce139373844783c34a",9.317957166392093],[19416,"374dec54189564adbc013506625f2b6fc9db0c1afc7347342d63afd8e479ea10",9.647446457990116],[7010,"dc83cab92a4e1ecbf6b5a752bb42f4ff2feaa529e689a3850a7191d4d397f0d1",9.917710196779964],[19309,"1182e88a510c325d1b9ae6c11adf03bce34628dbc8e6d63b0558815ebcdea014",9.317957166392093],[696,"81dbebbe9dfa2a0d59128c15b3b2681c74f204604df2c83172d7a44bb43d44fb",9.917710196779964],[12434,"888fac3854a76e6bbc7d0adb823211d82a1a8eb426bfa5fc2b0bc87b7f365eae",22.385887541345095],[631,"f84f836148dc745e5b9b5b48624c8d6f43e33c94cf9613701cbaa57a321ab4fb",9.917710196779964],[481,"5c6e5d608d7961b23d6011395653ce59aa435f5e4c3b3380298cbba22d8fc5fc",9.917710196779964],[16836,"1b9497477ec727f2858518db5d218f687fe786fa40c13e7c8a0d76eda18f9155",9.317957166392093],[19607,"074712160646d6787ec40a721b3c1b975480c36182d85e6fbfbb93e70831c809",14],[198,"b3043b07b24255a7c1ca57edc08399d92568930907fad7428979ec805bdca9fe",9.917710196779964],[4723,"a88dda10fb6fc13fd6600c5fc103288277b1ea6fad027226784d7f73ba0ae8e0",9.917710196779964],[6939,"c673968ff562b2a33c58fd21697f7c32f92b765097788afca2047c2b7ae55ed2",10],[17417,"6ae4411a2b41286e06ac3036edbd8b24db449656a3a2f106734c2583c9f26b49",9.317957166392093],[5863,"6a907c77b81ae3c8a05d69fcaa1b33da61a7889435ad6e14aee095ae0ae0dfd9",9.917710196779964],[8699,"4400fbca956fe35a9b742b7d737886c4a6fea60ec101cec05c8bb6ee60ecb6c6",9.917710196779964],[1769,"d524da19011a03720ed5b4dd4d1e9257f5874df5a05ad33e07dea81967e578f4",9.917710196779964],[19174,"ec63700eba95f8e19d4112ab748473f910b9a5aeaf7c7aa4b59877eb702ba019",10.052724077328646],[1124,"73f171a0816bc800bcedcfcf834769c21b495550b92e36846aff7cd5afc970f8",9.917710196779964],[9892,"6f515b4744178407939ec77099ef451a1b1d9edda9d6638234fa40c7343efbbe",9.917710196779964],[5215,"ac7126ed986150a1a8f2e416195e47d636ecd18ca44f6fa7f229bb717f36dfdd",9.317957166392093],[494,"92c211dbe043e1d4406a571cba4f878a51f099bea9db035c0e5c0ad03267b5fc",9.917710196779964],[14970,"5ba0e06bade98463ce4d674cd8c0db3dd31645b6641887a3b3af51e5ab2d347f",9.317957166392093],[10995,"0c9b258a16c4fa6b8a7b9407e3c67ac42bade091d59d2fbc6d741e83d96405b8",9.917710196779964],[7540,"c3ca8ad62f5f283db2c8d035033df192c557cfeb9adb0ebd1248f80db61091ce",9.917710196779964],[16421,"45406498e22f27bcfe00a2ce71db770e32d1d0496aea65e1fe5ad3e04f6faf5e",9.317957166392093],[8804,"19961f7729d76d9a4d3c47ff454e0d4ca1960d7e050af7509949b968f9f00dc6",9.317957166392093],[10813,"b76d4fcdb6e45255ba6befb06aff03acc29a90ecfe71011de718946f939f34b9",9.917710196779964],[14282,"53db6fc0c0b3e4f1c8e1164d393557ea69a5c6b56fc00db0d4f2eb489d14108e",9.317957166392093],[13164,"5ab20aacc4da62c2cf3dfbbc74ff7457502bea5acd9d61f8413ffa4f5ce5b5a7",9.317957166392093],[14883,"489ff98e24fd7589617b15bf42555592a2a06178b4834963764afed9825d1281",9.317957166392093],[10108,"a1c60f610c6f8ab5916b4774685ffdcb13f77702c408060d7ccfb74ba835a3bd",9.317957166392093],[2031,"3d940b40bc3a5e0c74abdcfe6f51f3175b5577f5677ac3c43e8d79029701c1f2",9.917710196779964],[14225,"53364527a2e1a2278d0d968a7efa69994d7139ad663afcd3c56ed203d525918f",20.027063599458728],[4823,"aa70bde0986d06411aa3aeeb0b35f0a45507df115f8cd84ac54835050bd141e0",9.917710196779964],[16934,"3f891bc63febd1ccef7b5ced9147243e8837e1e041445aa389ccc27f9a336a53",9.317957166392093],[14081,"d5612784d86b6961ac72ddcea8c2324b41656b9ed79adcbdbb64e52274310493",10.052724077328646],[18156,"a6229fbe867b091fdcc5291f09bbeae90aded0075008fa1b8902a5dcf5e73239",9.786848072562359],[15145,"f39d0956cea7b7699cb5ff070c2b411e77bb948e27eae3b7f880d054d0a4a17b",9.317957166392093],[11871,"e153cc4a2f15ec7f8104643fa32a40251b84eb5bacaa20fce1733657e3c140b2",9.917710196779964],[18568,"287c4113763ecb2a41c7903f6214a7f7dc3cb671116e1d60f46347cae317f52f",9.317957166392093],[268,"b65105775e980b0dba6aa74c719282be77090dd3d989dd64e49dd3f1ec4325fe",9.917710196779964],[10477,"725ac1170c537fb25a1de4e9c6a8372b7ce8f03e290c516812a6694a7eac48bb",9.917710196779964],[19482,"851b182aa6de4647de32b3f33d11caf50834022f9c58ad71ae061715fba2190f",9.317957166392093],[5211,"38f5b3163b5dbb9f347b7bae8a56f16b1e3832ac8f2b739287ec4f14bf2ceadd",9.317957166392093],[510,"75c988ce2a74f584353b6a012ff5c53627e2858357039d6fcc6e86a5fea19dfc",9.917710196779964],[9889,"cef7d26b4d0c34ae56009aaf7fe3e354cb6e1bca0cf79f008b2a647ca24cffbe",9.917710196779964],[1170,"385223c2396ce6785eb1bf38eb1eb6a16c4e2f1db60a5c670341c9fc534b2af8",9.917710196779964],[13240,"0664853f93d507efb2ae7f723f8e93238937192934ba905b2340aeb791c116a6",9.317957166392093],[2348,"797ca7aff78427814bfc344d4d8a446f96c5e0de14b2c2cd181b40188db9bff0",9.917710196779964],[10655,"d8b47650f8ac3207c54af0a030cde3ae1b6ac47df01e5e1c77b0efde03bc56ba",9.917710196779964],[3149,"a6fd85e4f7d65eed49ef0a685620c68e56330fa679a58d297d60876ee4995beb",9.917710196779964],[3364,"e5323be2a2a3b362208368ea183f8defcfb1625ce32b45623f015c852baff3e9",9.917710196779964],[7898,"db5d1b1d959c3ce67f58b70b70d494fe542fa0788826168433abf258fb1542cc",9.917710196779964],[18496,"6e3db274a753b0e8f2502421d7b6e14370f874361549913fde67776987457c31",9.317957166392093],[4887,"112bdd8fe32e35160aad22e5447d95e0ccf64a7f95027c6d51ae4061417be9df",9.917710196779964],[12553,"b307bce9f8e3fb5bb6eb3cdbd471a926dd0ca38fe4cfb7bc4eb96c7e7c0b9dad",9.917710196779964],[2893,"415a7dc9dea8b74013d5469c9131666c44f84ddf27375e95b12ba3f99e632eed",9.917710196779964],[19132,"e2cea0df8761daa82ba6a1bf1f0b31fa23925d211e0f2d6f5549e1e210e01b1b",9.317957166392093],[15972,"d4dc172a38645212ebe7d15a6e8487e581ab59fa6425615326f598a8f3b65469",9.317957166392093],[19870,"e78bb56e891d239da15f1282920057d2d33ff45aef8330090bdefd1c0a562d00",10.052724077328646],[5291,"c954ea22a32d81c754e876f774d1ed54d8b1dfc8f1df0fa4743e3f18e92273dd",9.917710196779964],[14426,"016b03efacf6d017caaaf13ddcd39c807753ad294244ca27578af54f72ebbb8a",9.317957166392093],[17156,"6711de634cb8a2d4c3b87128cc17a71e059416875990f594dd442bd59f65ee4e",9.317957166392093],[2419,"2ecbf1ab8481582cc524234f2ad773d2222116c3ecfd8f06def605ea03d357f0",9.917710196779964],[18860,"67260440a2c68d709d9db4157553168250fbaa8e3d94cf9ab3267bdf2a92c124",9.317957166392093],[15032,"df2c80f23dbec3dec9190cdd9c7516c4fdd4257c0c29cfbf86473c7df369cc7d",9.317957166392093],[4024,"abeac91fb0e697b62038bf979a3b954586a57045e861490ef17f0df0e25c9be5",9.317957166392093],[9151,"ac41fd25eb5d7ee648567a34b4f69846009010e63e1625cacd46a4b9f55fcfc3",9.917710196779964],[10318,"bd2a5fa6f00db56717d9e0fcd00a8f6cea519866a7723127d28ee2f1808239bc",9.917710196779964],[17507,"ead40534b9e5b82642956ab4a4c6681030a82c6b0e79fd3f4c1f745db5e34d47",9.317957166392093],[6645,"b06ee49299767a3b5f35c50753337626bd6c13770213194dea6e9148d5c95ad4",9.917710196779964],[9418,"117a8d7b6ae1789f8d8d9c50f24dc0999d6f0d4569a5173f55bf5f23448230c2",9.917710196779964],[1841,"428d59696138bfb836b37357b009da90644e7f15fd53037c41101b9e00c7f6f3",9.917710196779964],[355,"848b6eea9b4ba56c40d208ff51336c2e7fec247f61337c27d1b178b46d68b5fd",9.917710196779964],[12703,"d8be7f2c6a289124daa994ed30128bb5495524bec7bac16be33c6bf405ab94ac",9.317957166392093],[625,"ae6e1c7d0389f2d0c772f97f57722767758c4b875c9320de15f027d384d3c0fb",9.317957166392093],[8652,"feeb9e185dc2b5d2786790c76ea9a798f2c5269066709cda7c3cd36f2fd804c7",9.917710196779964],[3418,"74186044adfe5273aa51325986c3d5a5e223240fa50c75ee8e49cfebd9e08ae9",9.647446457990116],[7119,"917b0cb6110efb53ba73566a3ed245090d67f13647dc9cdf93e8760d5c5334d1",9.317957166392093],[18085,"fc4768cf647fa4241e83b31ff07fb5913af1f0c342750b7c72d52f14ae26613b",9.317957166392093],[2814,"3932bdd26f82f6fb1dfbf371f11c8e732582faa653caed6623cb3d928b8995ed",9.917710196779964],[5619,"6bb0f4ec6d6bd3ad7f3eab55090a5e594b64a436969e712bbaf95a2fb53190db",9.917710196779964],[1608,"9e2c0e128cad52e55e344b2f9f19345df995ebcfd8e05d8428e782511aec85f5",9.917710196779964],[6435,"4e96dd1c3757a4c6318170244cdf27312936552c04525cea9149a9bef66806d6",9.917710196779964],[16141,"ff8bb32e1f853d0385a7c9ec1841441cf453d2a4337a889db947f73906883365",9.317957166392093],[14275,"3abdebb52209c1debb082d47eb0e14ec49c5e265422ea97b3339339bfb23788e",9.317957166392093],[13227,"826b7710d0edd2137524d26f927c4eb6763deb160822852cc4f9f6042fec57a6",9.317957166392093],[2599,"0efa4848266fd1512b57aad145e45d1e56059224020c5391943dd1ef831929ef",9.317957166392093],[9132,"933f4bee61ff8b9efc1deaa1c13994ba5b82f6f6c8e359a31a45848eb984e6c3",9.917710196779964],[16275,"32890eedf05f9777ba479ec42c440fd318de022c2f62fdc604b7e8a214b1ba61",28.870307167235495],[10384,"79cf4b27a7c91c24c9d3568590797a6fe343b36ab14fbecadf9ddd553caee4bb",9.917710196779964],[9178,"0a3b7cde99dcea3b913c71222a910d21f474354f04c140043bda789c7309a1c3",9.917710196779964],[5920,"0cda36f2f706d8276b8c9e2727770337acc0e0beda2e2a7dca16bc899aa194d9",9.917710196779964],[5949,"0d60da893707161222c2c73171c194e21e5296d8a20c5e8aae38e85ab3d86ad9",9.317957166392093],[6017,"d4fe9a119e56c8204a571b25481f4d88d243a2a6ed13a98c22fdd0f4bf18f4d8",9.917710196779964],[16054,"aae8f207f549d2f73da9484fe9210fb7bdaca1ba118a079f3985cd58268e4d67",9.317957166392093],[3636,"e4d3acd318111ac5d37dad732c05f2b1fa1729b572d657df31d1a0c4574406e8",9.917710196779964],[13873,"3f82517f5ae2d3ace2c82a2f09ecc5fb46750da51526c12b50ff014e98e4c897",9.317957166392093],[8042,"ad820ceb47d00b23ea83b8e32b43989185b28442cda31f920cc6a772e6c04acb",9.917710196779964],[19815,"6c3ad30342982930a4b34578b8d00081c0b6ffa69e8d3956a7acd9f920092702",25.84024988844266],[18082,"fdf7774df05fa8e4699c4e40ca8fafddc90329276c6a5d3000ffe87374c9783b",9.317957166392093],[16896,"76958861bdf550dfd1d8e3e50a63b3d5a46449b78c3f8d28facd5c25f72b4654",9.497392881432782],[17841,"23c0789c2e5c24f95782a2090ef92a16567f492d21f0d739f35c158847267340",9.317957166392093],[17467,"e81296f63c168564dade21f4d06a1f67795714a446fc751297338f9765535848",9.317957166392093],[3456,"f065505b4bdf3460eb47e57d10331ad16c50f3f447f8f07e3da5dc780ae956e9",9.317957166392093],[7587,"007ebc734567ec9b12782d3bf88a05d2e0e72e3ef7878ca232dcc1029a3e43ce",9.317957166392093],[7058,"a4336cc4fa37ecc9234bc61f15ca21648066e4ce2f85f9582a99d1cf22129bd1",9.917710196779964],[3846,"f01110568118ed7dab10f4d28cbf5ce6ea3f69f1bf460e5614c750a28db0c0e6",9.917710196779964],[10667,"76e77a1b083f53980e14c55e4305db0356b46b0acfa6725aa8402a68e1353eba",10.052724077328646],[19700,"0cfceb75a161a7f576bda3fe899150e77028cd41580c2df6d5a9070236e3cb06",25],[16999,"ccde38a92c4fa59bcce045964be2bc6200cccb08fceca1e21cafd053a6df0552",9.317957166392093],[14192,"1d9e0ebf33f2a447d90eec21c7a7ea8be5aeafb57b169f12fd34af487d6c7490",9.317957166392093],[1584,"ebbefcca1a1242b76250e397d68e63c042bd146aa12dedc6b2f934c4bdeda0f5",9.917710196779964],[1674,"848851b32dce383b29cccf656c0dadd6ac0cc71fdb89a915e1b026b3c74116f5",9.917710196779964],[10675,"1ea9972022f1b2e6cf2a6b54bfe12422dfba56ebcc6aff13876704178b5533ba",9.917710196779964],[9652,"e1de370ea7c80da83d71d4389450d2390d9411243a3371dca26ae40683dfb3c0",9.917710196779964],[5255,"f03ab5f75d18f57b8f6b989b3a36b25b5d9b1ef6eb35c80dc212a5eb2affacdd",9.917710196779964],[11862,"c1dfadb918450cb37f6861a73ac4bbcd02b7c2c372ffdd780eea25a148454ab2",9.317957166392093],[10382,"7743ede84f614cfec144dad17ffb8eee564a22655fffe04bf0bd29bbc63fe8bb",9.917710196779964],[58,"c243ca0af7ca8bec1b9221dc85edad8600ab97e28ec7e5a23e3fa4b0f04796ff",9.917710196779964],[10027,"05993c43d0fdfd17dfa05880a6aeedc48cb051daad12424508e0a6ad793e25be",9.917710196779964],[13870,"5de26e91a5e8a762ed3a4a75a2085290b9c0f48dd21a4053d090f6445d25d897",10.052724077328646],[15192,"45b8f81f24bae1fdbb4708e1bc9d378def66ece2e2be89c60fde76410c99b17a",9.317957166392093],[11988,"3fcc000c93a6a87d903c5419c062862a8073a39b3b473d336e9b179b47b763b1",9.917710196779964],[9102,"63ddd9b5e32386ec907699e4c871a5b5f310d38fad9c902c1c6386dfdc2a29c4",9.917710196779964],[591,"0e5b7dbb84fec96d2b1b43a8663a8d2b0abee3847a16300f99b75ff35b07f8fb",9.647446457990116],[4939,"49b3482b5548f007afba1886f2e58cffc9ecda269198cfc247a93f70986c96df",9.917710196779964],[1525,"a3376cfa56fe9419a9dbcbb3b37543ec7744c64ec07b5de2637bc1923d7af5f5",9.917710196779964],[14028,"fd0c07faafc4a7c7f80670f7d5859ecf4b701f1c7c3a4931b8fbfa1a1c772794",9.317957166392093],[9723,"6c2669104f081e2f992b3a6ec57a043f8886dbe24b6a4125f1fe8f89f26d31c0",9.317957166392093],[12584,"73cec336bf9fad2e0e6e9994e08a9ab4fb7c04c09936c89601edd8e5856561ad",9.917710196779964],[403,"a854d23dc6600ca8a6ee892645b874b4bd2a29709475af832a1ac8159bbc50fd",9.917710196779964],[19317,"95b9bc420029e8d307627d49950a38b89914964af1d7b5186d6b8371ff6f7114",9.317957166392093],[5692,"8f6768fdadba701535af07d0d9097d87594281167bf21add0c4108de118716db",9.917710196779964],[2853,"930938ec80ae3918350e358041a5d044a88c8f603495b94c2817722488735bed",9.317957166392093],[15849,"13a6b36cac84090e8eb317fd22a504e0783c29bc6111a273c5d15350ea343d6c",9.317957166392093],[1863,"7b735ed7f10fda9808e6f1074bf6cf53daedbef39f2107218c2a523101bfd7f3",9.917710196779964],[2572,"46bfe93fe51dfa38483c23d5b37b7897e058127b25cb924e1c9c1ce8973867ef",9.917710196779964],[9621,"f5f33c373f440a07b7d23783ab1a40a85a6159fad3453cb4c55161ca4e3ae7c0",9.317957166392093],[11200,"d001d0800b59f9fbe857f40037870af96868350e0620e9eafa28130c760bafb6",9.917710196779964],[3609,"b59fe1216cd142a178d66b898febc8e642d5b87e55845b40d3c3de9d722b2ae8",9.317957166392093],[17559,"cb8ce5b053378e471c016aa87ee9aa6cec5d78c2318407fc6526d9a235695846",9.317957166392093],[5872,"70cb06cee0a17da163da1b6179c6424804aac7d74263127eed01c5af2ff0d9d9",9.317957166392093],[5360,"6788f9972fc3f1449a06b41023100b663aa7c97a1c1919786228239b104916dd",9.317957166392093],[7395,"9cdf03d2d6bf86abf0c6b4c05dba94880fd7cf706e015f6075e857b5494272cf",9.917710196779964],[6329,"4b6e558aaf7dd1e21500534e1fc9bf4b5900b9753bfcc006a8bb9f51d49ac8d6",9.917710196779964],[4910,"c62939e4f89a4529c8e662927fd34cf5b1f0c3adf1646db380558f7edf0fccdf",9.917710196779964],[4008,"512c59d0ad7ae3ae1299327807491f76b14c5db79e69148782b5cd08fe9cade5",9.917710196779964],[15938,"3eb0dfde0c3be47cb5f599eb9d650e7d3518537d074913276ea402348f6a3e6a",33.78010471204188],[11823,"37096f48379cc38af536079174849b3a1fab407a6d2d83a1df54df856eb68eb2",9.917710196779964],[6861,"894d5726dc9719fa1df6bd710312738837288a55b719b860dac6825d4b9de3d2",9.917710196779964],[5022,"164c43f3af83f6cd68b57eb476e9a0930d2dbd0852ab22959e13400a52ed09df",9.917710196779964],[12658,"bd5c815700fbe03d2e59c33f6dff9d272c8119059093749f9fde1fb7ea49e4ac",9.917710196779964],[5959,"e81da48f556b83d47ad9f3a4026318823cff67f327efba4c92b199b6222d5ad9",9.917710196779964],[9217,"4f5938d06342a33d6cafa7e6ae0b513534ad69ed020c8b706c0ed46bac3a5dc3",9.917710196779964],[7863,"153da0bf44c8f15c5bf5ef3428a3e7924d05ec0c1ed29265e8f68188b3cc76cc",9.917710196779964],[14728,"fd06f6a45f519c138ebac7684fe5d548a40452e80a665efcdb15ac71ab726484",9.317957166392093],[9900,"0e98a629b7b0003970ef142832927653aa4d4b2bba62f54e35d04a499a5feebe",9.917710196779964],[18034,"c903bdc509ad3355ae6f3e8d51953a4d4521929b8a2c26d5a55e9ef56aa1b33c",9.317957166392093],[6545,"353b11333d372123401b74f850f1dd9aebfc48aa3cfb2e1cd3d187c25fe90cd5",9.317957166392093],[10911,"6fb7b1f897deb618fde77fd169ceddc7529a19629519150b9f1218e598ae9cb8",9.917710196779964],[6787,"8dcca7f785caa71eeb53aa7474c0f15e7f836e4474968ba2774011beb6f260d3",9.317957166392093],[8111,"6ae16a286c3f475ee2110979a49c4ad383a4f2bd30ed502dc8a538bb79bdb0ca",9.917710196779964],[15804,"7def39126c0a525436debc0eaf1d01710a76e2d94565fa1d3f8d4e3fb7a7476d",9.317957166392093],[1199,"602094ca23d8a75a6c0718c78949416cb101ce0dddb6f4e4567bfba4daf305f8",9.917710196779964],[19096,"1065289496643785985041838cac3ceb0d24214cd7ddfd3067e9e97140daeb1c",31.333333333333332],[2295,"6dc313f4145a8ac843faefb41d31a7d901ae38fa9772493ece39fb0c0bdb09f1",9.917710196779964],[3267,"b267f90ed54a295dc98f890fe106da8747e858a9a70dc84be19adf5bbf2194ea",9.917710196779964],[11212,"61cd0e150205dbf458401cecc77fa050d32c8559ee94bd4482e55c2056cd9cb6",9.917710196779964],[15250,"09c2e57c95fb65fe00f6f11d2c2f888c3054d83ef4e4ceaaa8abc13ae0586f79",9.317957166392093],[16097,"a171b857e01b0416022761a061882ef9714bfe13e21dca2658d325a1213c3166",14],[4407,"469cdebc93440d444c3c1524c42f3f4e53ba74bb6b60666d6dffa956ccec08e3",9.917710196779964],[12268,"cd244a6ba7adeead737c9b49885f59ddf915f31f5bfaca4ec9e0d9c71bea8aaf",9.917710196779964],[8758,"5ed497a8544d2789863805674cfc8db075b8f61566451af60db2ea5cdb8348c6",38.00356506238859],[15112,"166d0802d8caa07039094d92b2531572f75c66bf0d2307459899320e61965e7c",27.141361256544503],[1148,"82114b7ab04d455bf15c6445602301632a42d328ee7754d8ec60b292e48352f8",9.917710196779964],[4537,"3076157ac64b0212d9b0bec1c5f2f9eb52e7ad70b886c0090796f53713d81de2",10.052724077328646],[13080,"96712839aff92ef418c4a1e5df25e28a9da0bcc2bbc6fb588125ac885c08e8a9",9.317957166392093],[15049,"5a963f22bb1f16dee10df63e40889690306fb59e57f982f0c48f79ec460a8b7d",9.317957166392093],[6375,"fcaebf38f3d8b35ea4c54a201f2af2d67368afdb682aadc623e39af63a7277d6",9.917710196779964],[1238,"8b65f8d50b2c6dbdb08c34f2b0a71e4e2440b9707a016c9b6ee6513d1669c6f7",9.917710196779964],[13212,"116104944e6370df72f07d3ce361bca0d725e8c01ee6996e39002b436a31aca6",9.317957166392093],[14760,"caee008d922495e1d06cd2db7166bfdf071cc0e7474a90caa045ec776ff1bd83",9.317957166392093],[15041,"bc41cc404d23cf664356b03937164f5944746d13aa6af38d02326522cca6b77d",9.317957166392093],[17644,"6de1d1bf3f03c3ee2b89322f8ebd3cbd25330c1da6594bd14b5d91b0ae9d5544",9.317957166392093],[17870,"f0bbc5ec02c6000cf590aee7a3930687e4173271f6f84a24f6c49a3324a9ca3f",9.317957166392093],[6228,"15408723cb61820d49381a917c3cd48df6b9e658a2f3d99273d299c7611b8fd7",9.917710196779964],[7603,"729a4fb382b57e5524f176df87f811232e9e63ca5f9542ad555f5aab74362cce",9.917710196779964],[18240,"f9070e83d10fc43b93082cc64c62412b50fe3ee84d775f2987c204da7cc02a37",9.317957166392093],[8321,"88fdcc3e1b734f5dd05352d444940deeaf78ae0cc40722772fee3cdb016534c9",9.917710196779964],[18286,"2c9f3e54c5ff9489bec32900bfba9f4b4c4b85695d7b3e1fc0fd510a2bfa1b36",9.317957166392093],[3062,"663cf6a1e38ce29ac53edcce1ef6bd784d5c26553a2c9d56be6e5f4e6796e5eb",9.917710196779964],[18810,"ae495fb1d57f191d2a3a3acbac6b0ad02a67a53f8f41082aa04c295059f96226",9.317957166392093],[5520,"672d54d6255270f41bb0d22e4cdef9e51e3cb9d6622dcf1bc5a7fa14b02820dc",9.917710196779964],[12814,"f6938011e3f2943c9e8f97a66612ca152bfa775bd2dfd236715aba81380ddcab",9.917710196779964],[1441,"7f3d34828bb194f9755e92c0581f3df98c5bcc224df8fc704c77a93dd8ae91f6",9.647446457990116],[16945,"6bda02232f6bd5ba44f7616692000c40f2b0f191327145f217d2f652a45c3c53",9.317957166392093],[9159,"e988a3a85f0615bfe924afe4b5179b97c40b01b55fed2d73917991cbaf6fc5c3",9.917710196779964],[2622,"af2386a40078ab1bc358dca82c460f6e05d9e806065ce0833addeec28d440bef",9.917710196779964],[4129,"c104300a92380325aa72dadbe6b4bc9ad0241965137178c9dc5cd7a6b5a8dde4",9.917710196779964],[728,"f8bb61579436717ae351724bfbfd8dddd6e226c59b31ff182be8de3f895006fb",9.917710196779964],[17931,"d4aa9554a40609f5f4747a221eaa0dbd75bea9ebd9a710f329291e3b2432aa3e",9.317957166392093],[2129,"98e97f654466682ac455710f15cfcfab9eb908c53bfea845dc565e1b75220cf2",9.317957166392093],[8088,"61e27a4ef0bc6e2c4e473d934b28e21b8442a31bf8ff550bb145bf19438cd7ca",9.917710196779964],[17205,"822cf2ac5db0eb3cd49b86f797b49905bd1105a7ea38aa777a02be7dd951ac4d",9.317957166392093],[9675,"c1fd7a195d1c46c163c6cd18914af9b5ca048fe8b899db820e75953736a08ec0",9.317957166392093],[8054,"50646f2028987c4a89e7c2597c4a7673e4c27d823c65b97aa0f184d64e0423cb",9.917710196779964],[10105,"4a69500563514f856737a4f848f7307f254fcc788546a3f8fc28cc4a3d9daabd",9.917710196779964],[10126,"33f31f484ea3bdcf68ac066fd93699c109fe2d0495c47fb9d912936aaa0483bd",9.917710196779964],[8150,"e04d9bb8b68e253cfb2f0cc0e5f6db0aba0113339ec5605d53d18fb8f5cf59ca",9.917710196779964],[19030,"c0854c37681a8ebfda9083777e9ce94a5c3d48429cd3c82055165f44922da61f",9.317957166392093],[17191,"7599d9e23200d7f27c781f00965854fe0239bd23cdbe6f04638f741d5895f04d",9.317957166392093],[11780,"abcc88ea5d6f6856dee78b71c8a7b0e6ec8dddb3df53663ab72e5f14dbc6d5b2",9.917710196779964],[2439,"18eb704376f377f6cd0e8487745edcbb3d0fb5a7f21f8aa94e75c47c5a6b3cf0",9.917710196779964],[11199,"86a828ad40b3232a05183e44779ac29b39797ec4bfa06efd12a93f84c74eafb6",10],[10219,"48262527491a18faa4fd1ff13c1fce7bbfb291ef9d898f0a078da4be5c20d7bc",9.317957166392093],[4604,"b56cd5923a0f2af65da20664935d7f564545eee7eb6542dcaaed7547121d9ae1",9.917710196779964],[13950,"cea4c4b01111fa62db058874be3d38d70edd6c52502e2f24ea4f80b57aaaf295",10.02375296912114],[18900,"afe749943915ceda3355379cfcd89b59b95e846be6dfb9965baffd867f5d8023",16.884955752212388],[2689,"c30db1c446066275fba0f45cb5397e05a3e5790dd4a4060c853aa4c8eec48bee",9.917710196779964],[10891,"79facee009d61993e6d34605600ad0e99f1afa04963e1143080836a73cb8b7b8",9.917710196779964],[170,"517f18ed0e5ed3d3f6ffc1f832476683f5b9372f28ccd69d59f19c5be9bcd9fe",9.917710196779964],[19244,"2bd5f829f42ec16be651043ccd6df284c8817c19add525ebf4d714ebbccb1317",9.317957166392093],[14682,"23ddac1f22ae8aee055a6fb6bb9ee99102029ef05954b7792eaee8b8feee3b85",9.317957166392093],[8596,"744917cf2f84034380a5175d25a8e5bd9aae5c324f3ee055fa074f0ee64f79c7",9.917710196779964],[10496,"88eb3fb14f8a4c1dd4cbae5e09e30daf684f7d8323911b6845bab86101fd2dbb",15],[12384,"f97c27dda92c5a559adcbfbe37479b4f4f16cef21a5e5b8930d3fc415dcdbdae",20.016246953696182],[11543,"23eac7bc7e2d5f6b53b0f080a3d6af681f15c5d58368bf5ad3088909352845b4",9.917710196779964],[1790,"aba1042afbc218f5f648cfa61e25e4fe7ff884f7f8f08f2c4f5b350da8d54df4",9.917710196779964],[9269,"694eec6554acbe5c3f91e44a4c47004a53a6cb543b28ac7e43a2f4da72460ac3",9.917710196779964],[2974,"0e0890ee47341770faa786bba80ba2633be6242a64021c483f0af4fd76e97cec",9.917710196779964],[17272,"a99d48faf09714f637485b0657febe757ef6f061f7e0a93c00ad413998cab94c",37.936395759717314],[14299,"2453fb8f54214359afeec6c9ac9d7dfb7780f504ff39d41b17d10113eff3a08d",10.052724077328646],[9134,"3b35e0538a9bd049259fadd6b74a6e87a689fe2356ceffb96afff45780e8e4c3",9.917710196779964],[18881,"1425d7b4aafdb87d770b2232e19434960f35d9e54a22ce5156a307f0ec2d1624",9.317957166392093],[9809,"d7fbf46465105acc2de8962e7922304bd32157ac374f256f7b6c137da84a93bf",9.317957166392093],[16694,"13a2b914f043d461bfde84338e44516e386e9fa73bc3a07f03459443ce829c58",9.317957166392093],[16775,"241cf26d7efd7deb09a3b284ea69f0c539ba91315df52bd0ae69f6ed914af356",9.317957166392093],[10641,"5d2ea36bd97ad353059f16ca072e262c32ad1f51ac50867895adf5ebb49e68ba",9.917710196779964],[15855,"684743ac2a4c336eb0f7ddcc3b97ec360dfa5c36d6c4c17e35f504aaba1b076c",9.317957166392093],[15800,"82695e2f46305ceba26c868ef5179fdf59e94dd33945c3dd8684f44c32b6616d",9.317957166392093],[1230,"19ff93132cbf951020a0b8c40b54dd038056389cfdfb65cc8e22724f7024d1f7",9.917710196779964],[14489,"819b7456e687224a33d95ea227951c8f7f0e19e2a2254a816a07e51503f86f89",9.317957166392093],[6369,"4176f6516ecf1aa09365edc610dded7945ab2055e0eae5d9ef89834886d88ad6",9.917710196779964],[9087,"cd42f95792de5e1e29fcc90c80bd789d8bd2ea7084e378ba585660199af73dc4",9.317957166392093],[18309,"1b747d5d28be21fff03718ab42bd35f91315363c735f9f5955009ef9f149b835",10.013531799729364],[16253,"8698b3a38007b12a41d4d58dde02b2791a11d85f4fdc4b81a7cfae3e106e3c62",9.32825880114177],[17435,"6f117ae8f3f21acd812e9d5b183544840f29eeb414f349622559af0b2c10f548",28.970558375634518],[17805,"6912468457243054bc0fa87d68460d1a5fd2648c86e79ad627ee18ada2402d41",10.052724077328646],[824,"7207b0f793e1c044415aaf7a506f350cd6d3cfada257605db6fa3ba0c9bb5dfa",9.917710196779964],[19148,"168b080efea52c247de282cb13067c8b73f8ce6fb6dd5bf9e376142971a98c1a",28.187082405345212],[18515,"eb493a326db78f77cf485efc62b5d84a0b540adcc20ee2e6d6e165381fb51d31",31.05169340463458],[3209,"4c9f017c9109e85bcabfa6ac834c4c5ece396605f06abd8f1ef74116d8fdfbea",9.317957166392093],[7425,"cf3d1c7739190ada0fcaf6858a1501d7029693346427858399ed410b81223acf",9.917710196779964],[11101,"f765b552a5b2f897d596afe1e73ffd0c941385bd0305874006cfd086fc493eb7",9.317957166392093],[12284,"3ead42d8a3f579b4a6d99cc36c7c8283f63e8570d759ed429fb00c30a45a5eaf",9.917710196779964],[11930,"dea7767b897a53f1c18340dfefdb657c8a33b7898044d5994c4ca91ff300d0b1",9.317957166392093],[19300,"04a096af5782e208fa674649babab5826275c56a4a35f565908300353665f514",9.647446457990116],[15505,"c1310d2a1d8c635a9db6aa9c91088ab2ec2b5a4225111e36e5f5cdf1784a0774",9.317957166392093],[5534,"dc7d8fdadcee0acd59366aa7a4b2ffccdef7876ee7cadd1b303cb6f8984501dc",9.317957166392093],[9137,"2b856ac7dc252ea3e38893b9af68db729801f308221f51113874a50041c7e1c3",9.917710196779964],[16513,"0909e5bc2cc0313e8eec3b613ac6d63598e46ba700050c80f386f58348d6f05c",9.317957166392093],[12748,"06d131b534cbab5967f9aa33d612b4b955881d80a64e13bc69afd7fa5bc740ac",9.917710196779964],[7496,"ff2c2e39ac8ff85b5a082bd1d80d1b2773f2baaa83c8eaa1dd1e51f2e112c5ce",9.917710196779964],[18932,"69641ac41d79e4305a1dff16e6fa9bbc933a422aac6762861580660137657d22",9.647446457990116],[10086,"f0e3b431ab3fb4b2d920603ebe06cefb1040c49e8757114aa94cc3802703cdbd",9.917710196779964],[10488,"6ecc6114415fdc764931a168b3a7709d34fb5ec24ba668c45bc92fa92e763abb",9.647446457990116],[2831,"5ddf593f193326eb8ba5f62ccd9ce46ad9e351f744ff745827271216bee07aed",9.917710196779964],[11091,"62e395ddc41f949dfdfe6238b70450e9c38470b4af756032b20aa3c415d94eb7",9.917710196779964],[12299,"5d3702245306896c6ec7ea0fba5fcf0605fa41b9771f82039a73a64a712537af",9.917710196779964],[14554,"cd0ddd428e5119d94d53daed8b4cd78bbb23d911213d5110074a08f96fad0288",25.403141361256544],[17958,"1ccf82e934a94c25e79f46d04b13f700a241bad7ae1f16eaa5e5d9297df9fb3d",9.317957166392093],[4589,"8bf1799f1f533b37e143db538766b2ef6e2db18066a03c831a9c2aebcb89aae1",9.917710196779964],[16405,"54590beea2c6b683f6eaa019b318698303c7e11d5c1d8fa8a4c5eef26bf5045f",9.317957166392093],[5780,"55d98aa90e42d6c7cc6e776f1cddb6ac1865637b4c709f513c5df46456678fda",9.917710196779964],[12513,"88555c7b8a51c284d18fcbc9e739bd0588531b7d127cb670d542ec59efedddad",9.917710196779964],[17875,"bc9a88ea264e46e7e5a6f8a7e931f3ff3b8148cfeef91a494d0c7c4d3148b93f",9.647446457990116],[11493,"044a7ef3d908520cfcef6a03eae709af189531c8ed9eb370be755054c7998fb4",9.917710196779964],[5614,"6a62d9251ac1354b5ba6e632258611c89fbe7a08c6a6db762a63e7228d8693db",9.647446457990116],[11488,"2c99604923c34ac4f0ae8389005d420215119c34581ede61eeea04136e4598b4",9.917710196779964],[10429,"ab17ef44439edb9a601edaa48d99b7d9111a97eed3be381c8fd133bd8ec19ebb",9.647446457990116],[8251,"0b1bf162f222deb2a9ae9f710950ca751d929742026573927ecd63d0a95ca6c9",9.917710196779964],[1896,"4f61b3a086cd0dc5649c020358b30d807e04c622e884cf458ccfb5ebfdfba2f3",9.917710196779964],[11332,"007591f1d9a7bae33cbf3f89d9608b6da9225af7e9a1a49dea7a40949915c2b5",9.917710196779964],[12219,"ace515e56a3d2df35d0abecb1749b4ef157c2fd67c464ebe3eea88a7a705f2af",9.317957166392093],[18553,"5ab7e5aa3ed4ec03a24886a85119162ea5d25a88161830b30c5a134eff156330",10.052724077328646],[1407,"3191ce782a2bc614c77ed06496b2812024ea538cae6d36f37eda3228f0d1c8f6",9.917710196779964],[1603,"c6e3cb6cfea02b88bbffb20500bd028f58803b4f1bdc8e462868157f2cd987f5",9.917710196779964],[2750,"5c5d019ca35f0c753f37e9090bf79635c00d7691b98f427bf4e7b9fa63361bee",9.917710196779964],[4177,"0de551ba07d721e806695773233951b949176aec62bb51e90f4cf44a94e095e4",9.317957166392093],[11333,"adf5510f32be7bf1bf1385cce56f792738c591b6ac34844b817adabb28fac0b5",9.917710196779964],[14713,"a17d06039e7e6ebd3a585124ee7fe12b95b04583bf697d58504e13e846f69e84",9.317957166392093],[8125,"0fae421e4c7ec79a85af533a8ab99c4fabbce93730e121c0cba6de58097597ca",9.917710196779964],[8440,"42e10502d12896aaee8b21ecf3ce191b1f27fdb4ac81aca8964303f5956962c8",9.917710196779964],[15871,"426835f5805fc13bfc068649b8161cbd6e65213a167c91616b1c005d1196a36b",9.317957166392093],[2705,"17bdaf0be419124ca81bb0730b6b606edafe0ac4b5a1a3f3d7323989763470ee",9.317957166392093],[5642,"b4ff0656d90c646bdef6fbe2ed61a883b1862c7b9be65e6139dbfc6d7d4d62db",9.917710196779964],[471,"eba496d2aa878d6a2f4dd6f68ee768c72befbb369e8c7fc420ab8b9bc779d4fc",9.917710196779964],[17804,"3c6e43eb90ae7d690e4332cdafcdea9bd4364508eed376e990e5d08928622e41",9.317957166392093],[11000,"7b38745ee64c69b4525b09d0894c078d1ff5b591cd65d20177c422f03f4bfbb7",9.317957166392093],[9473,"a8cc46b64f607296a8b768b35679ce8c51d09d39083d22e5fb51d78032cfddc1",9.917710196779964],[16954,"522d1ea2e72b8b34ac143779e3cb9fde28a2b0b59e1df1fc00a6ea8cf1261653",9.317957166392093],[2048,"bd6ab9884d04e6536968c76ad40016eab85258c7e0d3155008dd7667dd97a2f2",9.917710196779964],[17118,"339f72dea1f85a900586424966cda255e8f504a2c3ecbb7a09f31bbd0dec9b4f",9.317957166392093],[9665,"21b9bb87c92688df0bb4e2e93769e39a1903fb3f513d835d719c6ca6feec9ac0",9.917710196779964],[1289,"9bb533f1c8142623cda1e4c1b956292ddefd2556f02e7f43ef0757a6a70670f7",9.917710196779964],[8477,"7ff4022574ef304544998d9b226ac92b33ec74ffdeebb8fb5e18f3f670672ac8",9.917710196779964],[18540,"756ce7d409b945a9745a92c22b3a0e9e8fccb4f6e2821a0faf7dc28369e8a330",9.317957166392093],[4511,"978df1340ed0cb0334eceb00ebb28d0be6a5ba870ddfac92aa76e36cebe148e2",9.917710196779964],[7895,"46b41164708b6cc4ebb57b94ada76b3332323572d4a3fe6a2e4bccabddf447cc",9.917710196779964],[5933,"7cff5366b390d5cb17904742b19ff9326bd6c8ad9eb8a1fd0e17b44558f67bd9",9.997888067581837],[8893,"4f9d8101ad2a96d790225ef9c5f292b2154e51ea2956bf1aea11f2a17b2b78c5",9.917710196779964],[16154,"7ef4d263aa068eded0b00077c53777ac7cebbee133506ba5b4b3876db6f4f364",10.052724077328646],[9797,"5ab8e68d7e3b619fe674939473384d3e822700258ad8c72447ff832bc1b7aabf",9.917710196779964],[12368,"239b5cbb0f3d0a0e53f06d9368bc4c6e1d11ed8d93c71db511c9523ef1c7d0ae",9.917710196779964],[9668,"90d8afdd59bcee2751a7080709172145a40e4b14c7e8a5648dedb62a960e97c0",9.917710196779964],[12174,"fd3b5755cbdcdced2b78b12cd836506757cb7341b3c990c91b0df205d9713ab0",9.917710196779964],[7319,"f410c7dbc40ef36351a149447c34eff678bb0b45d9496503db9499e02734f5cf",9.917710196779964],[11260,"904cc93d75666892faf59061ae264f88250bde18fb8e6a9d974d36f3a7a849b6",9.917710196779964],[18363,"4c31b53b929ff9324657222dd9d1b039db1814f91b5fff2fa4260c9add486834",9.317957166392093],[1909,"721588490659115f2edb9947c00cb7f9a67c29cc955cd720a409027a405295f3",9.917710196779964],[1369,"65d500775e30b754296cb2fdd3055fff1a9d44e786227bdded390e702a7beef6",9.917710196779964],[17933,"7f86d0a5fff0b08710f368c37a4d79760912da08f658a0689e9d9256eca09d3e",9.317957166392093],[13599,"2dcdb958e9c9136f5b831c2e5e7aa76031ce7143735569e7c26c2681a5a5709d",9.317957166392093],[18115,"3e81478f59fecd0e348ec66ac0c78b7adad9c9ac7cafc3110f84f1c9b9b58a3a",9.317957166392093],[14758,"348d91bc4f3878ae4974573682fa50e8092ae4bf80915be115276df6984bc383",9.317957166392093],[10315,"0ba8c78d2cd809cd246f06153947829c75d3e36a88236d18f8fd00226b973ebc",9.317957166392093],[8359,"c147320d269efce81b8978954bada3356e7705b06b15e4d2bab4c1a3984ceac8",9.917710196779964],[9438,"9e35dd3baa8e6db868b6ec5587aec35213ed14a94c70c2e8194362284cd317c2",9.917710196779964],[5132,"ba5f2431c1bc9d937c2ade5dbc65c572e395aa30dabac42220cfd24188e569de",9.917710196779964],[17260,"80ca1cae86d29ab95f99e11e13791a0bc537432ce4c3ca64965067955bd5ea4c",9.317957166392093],[14506,"69c666e72bf89922755980c71efd4a4914e17464cebb2d1da7ba1193c329f988",9.647446457990116],[9200,"967e32e898391df6238e53ae7c0bf65f49b1365ff7d3d749154e0fa7975970c3",9.317957166392093],[19178,"ecbb2ca443992f2db3d950f0e266f46a5e1d2bcb50ab3c52056c6733c3425e19",9.317957166392093],[15742,"7c768d6b23d561ff317b34de7a0115197a228487802e211ec924f7b134928a6e",9.317957166392093],[8952,"8b4abe418a7031623687db5931f440e09c34f0d998f24548802f0501f5f51cc5",9.917710196779964],[18783,"faa5556dea326fdb65bf14aba91d7ebfc35686fb7f8bd26f491f8271d3b19d27",9.317957166392093],[10701,"a1c160b4af99ec1b5887d8e7d07c127d8c52d8f4fde62b748c0661425261fdb9",9.917710196779964],[11298,"e92f9a78e7242d27ba21c659b3b82f19dcb20aeef80044afe5de4e6311c311b6",9.917710196779964],[14491,"91effab1d13246382428ff7fe6a056cf57ead45e4f64c7d4a4347a98c0d76c89",9.317957166392093],[10649,"142490bec42d1a23fb4337181eab23ab8b7c84653a95f07961946795b0b363ba",10.052724077328646],[7798,"337a096e3fa85481d77f7caede18d43dfd76fe60dc6d4ac90af6f0ba56c8d1cc",9.917710196779964],[3053,"18a1f87620fbec24ea3939cd9ac3345d9b837e1a4872986d7d60b1972f87f5eb",9.917710196779964],[1015,"16259c9c3ca7b36e955778c0d4c5461b03eef3c1892abc885760265963aa1ff9",9.917710196779964],[5354,"4faca500ddcdb2a3591e4c8a7829ebef41a47e9052369eb7ff94648bc62e21dd",9.917710196779964],[19843,"edd66acbb3e07d1ce3ef7ea6167750061360fb56f07053cbd9959e93ccb60301",9.317957166392093],[4947,"6c9608233ba04e047dd7bcca9028a6cb6ca44a14518c3ed14b9919dfcab98ddf",9.917710196779964],[5224,"61e5faeb1710475782d7961b5e9b952a2dbaf54230a3b0a4d97968187e92d4dd",16.941176470588236],[9012,"de93111eafc5950630cb2199498c60d472da681fb70b9bf16fe9bee290d7b8c4",9.917710196779964],[6983,"3f97c1c1c2c63c8f804c782077107af0c6ea562fd4158d44cea7aad5a8ad18d2",9.917710196779964],[7482,"fe85b00a355be3c74959b44f4c702d6a30803aac150bc1e6654c68c7f8e2cfce",9.917710196779964],[15585,"c0383b576ceac3ba37b1a38f1ce338f1588b567d1158fd3b19ea10cc961bb071",9.317957166392093],[9812,"742797158ca32ceb1e9b419d6f4db6016172e5c68e5ed72133aff35de6998dbf",9.917710196779964],[4538,"f5b207f1976afe2fc1e02f5104cce5bd9a99e1b89dd449a9ef411fc486331be2",9.759637188208616],[18668,"a6f7e1997451fd6978680675736ea1a59d7977ccf0e9a96e55493ec61725e02b",9.317957166392093],[782,"6c9997c973f672347c86fd0f38523076b8428949615515a1b59f4427aff7a2fa",9.647446457990116],[14951,"1b0f6f0708aa86a1a1b007a8c6f2b2a366e9038844732211f0cbe9952c4cbf7f",10.052724077328646],[2733,"94628f32e73164f281351624cde37cf5706122fec96149fdfa80ec01e90d36ee",9.917710196779964],[5242,"faea4aef414bb6477c6a49fd6b645755dd0669546c33ae474f3fcf25a049badd",9.317957166392093],[13004,"09a70cc44aad6b3c3c0c9006f6862edd071a6ad8e8ac3ec099f5ef3c992b95aa",9.917710196779964],[7113,"b4e699f76f32a521e22ae6788e18849eaeb257a9947f4567b9f264472b0446d1",9.917710196779964],[13951,"8ce714141ebe912f093fb70e0f224499b096d90690430243f9aed35da420eb95",28.846975088967973],[6541,"4ca808111ea5dbb663101502209e8f28e49e199e230d0d92c017f5d0600715d5",9.917710196779964],[12777,"e21918c8f16aa049d6b02a31de8d8ee6b0ec5943de32f4caa84a64cadf0210ac",9.917710196779964],[1569,"a4228cf56a41276fa6eb34d14eccd48aa3ed4e4639f9f521f2de29a5262bb7f5",9.917710196779964],[12552,"677d17890203b0e86829e366ec0a0b0dfca8b24ca306369af5bd32bf869d9ead",35.881773399014776],[16977,"706d76a0f1c7eb4bdb7c46ec117f155098d7ce350188a7ef5b03558c1fb78752",9.317957166392093],[14953,"fd3458e037d6cd7c6185f5ce27b10aa7537e951411c753a1a53089dad6d9a17f",9.317957166392093],[14454,"02d4c42735ea003832a8b505bcb1dd5c115daa10ad585a1ea072940b5b3f258a",28.099408284023667],[2174,"7951e0bfb926264c433af4c224003d574a4b59f581db11b28a64d8992f33c3f1",9.917710196779964],[4861,"a7314126d3eb234e8deb5ca62c99b6453c5c2f4ae4f6d384b1c8cc0335e611e0",9.917710196779964],[12594,"dc3cf6e91c1b33c9716e4441216e4359c3fad6aa92c94c5e0a1ceed8edbf4bad",9.317957166392093],[17046,"466edab5581eb1d23c44fb855e3e0bf4a07ef555b4f2b11665d0d436b8302151",9.317957166392093],[2074,"fad970f2505a96bbb4a2e82bd03a8ad58c14f5a41ba306adadb8c59825686bf2",9.917710196779964],[11088,"80064922539e4fad46904a2d980d7c1a0083d7bcce8642cec1d6756cdd2853b7",9.917710196779964],[3810,"e6e36ff8c0ac171c9e1e74984a2916d7bef7eac77c1901a9e92317454e56e7e6",25.4421768707483],[10730,"65a11b0b6b89f6a0cd5ac3553455ae861eba7c2999044c588df3c67e0b2accb9",9.917710196779964],[13686,"62e71a1b85b097013a256b33fda38e6dd2d6e838325c50c3bb59a06f54697f9b",9.317957166392093],[15921,"3ff26311242d1e300964acd48d3b00ea9dccf815e05bf094d319aa9605d2ad6a",9.317957166392093],[9858,"bc36f479dcc1d9ef0a5f53b983aa9f193e0fecce86adf6b65e2b297ebd6437bf",9.317957166392093],[13079,"411e50511034daae1ef0d512b6e34b7bdaf273f74ac716e75265a8dba73aeaa9",40.76518585675431],[15346,"b38c42a3df2096640e64b4819d8c678a3243e005e52916819ded9b4733d67077",9.317957166392093],[17739,"417f67dbe1cbd317beb631f46ebae1684c9082f04ecb05c30df4544677957542",9.317957166392093],[10361,"8dd9e72e2cf81cca46a0cc31175cb33a3840e15d5b5d3d4a36ff5c7f366afebb",9.917710196779964],[5851,"1d984f75930c2eb03a550d1d0cb5fa5429285d915898e7446b8a51ac4186fad9",9.317957166392093],[9266,"ac1b693cfe086a2329ebd8881911febd99d69a545c0e8878e72c8d5722a80dc3",9.917710196779964],[954,"4b0561449a226323af1a55c6caba4d6b252c5f8465304ef9db795f136e237af9",9.317957166392093],[12802,"b245855c3547cb8aa66297bb1c30124fe63c1116875ffd4de42b4ddd0723e8ab",16.056140350877193],[5221,"c182c877e0ae347ee4d59f813a98b0a4255008ea4aac8d3be7e60686ab02d7dd",9.917710196779964],[18525,"596afff568c2dc537312d26125071fd5cb627dbe559504534d2b1a177b54fb30",9.317957166392093],[11051,"545ebf41e45fe21fe4fb1f4302dc28907c84c02b01d1c203d3ba4616aaeea8b7",9.917710196779964],[4313,"cf61d1e1c171a01e01f37766d7cf0ef90e05e2daaf696c1b7622d73bcb22ade3",9.917710196779964],[4192,"4039b87559569825aca13136d048f19aceeac9a6da1c1d4987b7201d50fa77e4",9.917710196779964],[438,"7ba39649acf712af425988a45cda23505a551cea06972bd133fe1f81194f1ffd",9.917710196779964],[6727,"56f589ecb4a0462e38a05cd26c6b94d8ad998ce67fadacac24be6ef58d35c9d3",9.317957166392093],[8228,"086b01b5a29fb3182c45fafb4e848319b569fcd75a9c3f6161547f8de226bfc9",9.917710196779964],[7724,"8eb495c22d0ea8cc485aa5aa8f41b2e3748a974a6eee9c8bb477357b329457cd",9.917710196779964],[8662,"f5537918bb799c356bf53dbb3c315b37a6885e26dd29a42afbaeaa3ccb08f0c6",9.917710196779964],[8326,"58e1b65d8423c5578b4fccdc15eb6317a4284191825f435b14c675aff19d24c9",9.917710196779964],[17006,"81bdbee430593fc51a3db8e0b00eee6d3d15c8c35b84e63d6c8b43c11e4ce551",9.317957166392093],[14023,"b538f4eed642d42949f2f3b998b8c1b45d613499f40bbb6706178c5f914d3a94",9.317957166392093],[13208,"6671f0eb883229de8248cbbbce6840079258567d35eabf5667d01362be3abea6",9.317957166392093],[19791,"c9b1651d30c72ee6afba40fab143f14a22e61b6425cd4e6f3e13d96bfae3f202",9.317957166392093],[19447,"4ce2abc121fde997424364a3af5a1b8cdd1f55b4960579fcf493c6fa4c0cf00f",34.83778966131907],[7000,"8698e3d92dbdc3c776666cca37d2d6b02b3cc3a3e03cb9a31b012aab53e3fbd1",9.917710196779964],[4903,"4b91ad190a326bda7f239d7f627ed9b8f94df581e5e8e84e77e72570c0a4dcdf",9.317957166392093],[8307,"765f9c0d0810c63c8d8f657001dd62fe2c06dbc26bfd707e16978224be1548c9",9.917710196779964],[17745,"28a5d006b618a323598adafbc322148de8de65c6ba1bea2ddecff1dbc5154242",9.317957166392093],[7115,"e52a48391fcdf0d53de10adde9fb5f113a2944bf74247c996bc22d01296c42d1",9.917710196779964],[3782,"7c51d43e414200fa6094cc258faeac1019c330ee4db89e81d5dffe76cd080fe7",9.917710196779964],[19251,"b699e785ab3bc998f1b6b7ab55e58156329a77cd15dccf6c752a496e61a78e16",9.317957166392093],[1751,"0ea48e69e6061275ad364220402e238c5ced2db8c003bf09dac87a5f63ef9af4",9.317957166392093],[5071,"d3c2cd1c7e0bd444328c721aa3569f470f66a71318f7b4d33ea719da403cb8de",9.317957166392093],[9035,"b49803e248eed5e4ebeaa6285e42908abf1d0d6f9c53a0130a3dd38b189e8ec4",9.917710196779964],[12243,"d7c9b6c398555bca63b68ce95de71a44d645375714bcbc50ad75d09ae10abaaf",9.917710196779964],[6097,"c6343f4759558c08669541d701259044757c90115cbb8006798d1686e5856cd8",9.917710196779964],[17652,"917b0d61c9100f1ef771b5e4e77540c754ad12a95682fc051f31c14d94232744",10.052724077328646],[2249,"a6026b4c5242fea3cd24f4f8b49ea497e29802f0b6cf2c16e822c845305241f1",9.917710196779964],[13665,"8a31bd9be7e032b0f1486ac01e92f4a1d59ee576920e62f633d00f53164af59b",9.317957166392093],[6456,"84a12d34866a542f070bc68b9147253ba2499b7f641569351f20435e62b7dad5",9.917710196779964],[3714,"0fac8ee8cb05bb68fab366b5293b95510e97b1bbbbfd5bb527572ea6ed1082e7",9.317957166392093],[15462,"c300bb284b8b3d613cf5b3e7d077f9f3c6cbbc55b06a446029ead1d64c66ed74",15.078534031413612],[5168,"3f1ad78fb4dba97c6434a75a5fa94752b5faced6d5d470adab7b77ac5b032bde",27.026519596338886],[7993,"9e2356d5a55dd11a7da0749d53b8aec6d6e3d357ddc87329dde3f14452b291cb",9.917710196779964],[13862,"6fe6d61cdf06e18dac2b1c7a079e7027d198a402713cb057f2402d6b05e32198",9.317957166392093],[1600,"44f1614ad57a776c8049d49bc825657c2488b9b995519b48f242f2e4ba208ff5",9.917710196779964],[11842,"7f9313a3e49fbbef6970ef359157209768ad93aebcab2727ee5005f21d5772b2",9.917710196779964],[9066,"578074716d44701a15df05f4f4a1d47a7d3b7a3b9c84e061b34a0d1eb45f5dc4",9.917710196779964],[13255,"ac573b359e717d5a300327f5e38e1f8e196c00d9dd072a50e1534bca98cf90a5",9.317957166392093],[14027,"92e14f9ccf4a3204996848d9e8bf31643bb0176cdf5d54b447c67c83b1932894",9.317957166392093],[8161,"5e707631a6f98beaf4ea12767aedbc3663b04d30427ea4b2a2f5b02c868b43ca",9.917710196779964],[8205,"c46ffbada0aff76f4b78cc77604b7a2ea137e520be0be56d9c26a1d21be8eec9",9.917710196779964],[8097,"968b1bf926ebeb72fcef5b17d67597be0a8bf59896aecfde83af9af047e2c6ca",9.917710196779964],[9481,"735912bbe8c3bf6eb41e0a521dd5e9358848bcd510aae61f953a559f00c8cdc1",10.052724077328646],[2935,"770f2a0615f2fdc11f35a8cc11060d78e9515816c50c84fd1fb5f15d1b24ccec",9.917710196779964],[13197,"38bc9a47d513ad36001eed1e32e4ef131c929bd37a947f0c75c9ced8116dfaa6",9.317957166392093],[5713,"3c86448a59ce7fb3f17af4619f08050da9863eb64a47c54e24d347b114d8ffda",9.917710196779964],[14587,"f0e6432389cbcd51c8cd4eb6352a36911b3a065fb083db362e01eec3d2326c87",9.317957166392093],[5070,"35d9269a0640cc14ce04da213f6db67c8847663d297d5458897e348fa56ab8de",9.917710196779964],[2318,"8671956be4240fc1edf4b4f9ce168a87bd16adcdac816a7b74afe76ab8c3ebf0",9.917710196779964],[8412,"1b935d532015d031b1ca8d8302b2ac21b95acbcab4094b438bd2193624258ac8",9.917710196779964],[12039,"0120c0aefd86e8c46d5e883666c85b24dc094571c7c699d15e5411a2758b0db1",39.13879003558719],[13423,"8758fc1dd5521efc9bf7a6a5a19ef69c3f2675357e609f776237e5d18b43f0a1",9.317957166392093],[3155,"12dd48c3dbf4f8a5dcff675d55e436c41da37ef9cb38f1779e4c79daad8e54eb",9.917710196779964],[8197,"fe3384cb7e456acd681a7b14981712458a32c20dd7fcdb60684da9d6e137fcc9",9.917710196779964],[4473,"5e59dd22b4fd1cf8e6a498744bc2c50d99dd2c80635b28f6e2c7ad016c4b91e2",9.917710196779964],[15977,"fbd1f1bbee26b40883a4f88b4897da9a6ee9c52b4ed4ff8cbc421d1733cc1a69",9.317957166392093],[11527,"de2963893f5c9ea8868c22ea09ee21cf93ff3ddd0977855fadf977d49a245bb4",9.917710196779964],[9246,"ad40bffe4a690d120415d20005ecd7331430194de5bc7bf8ac12394c6c1e25c3",9.317957166392093],[18816,"112fe319df196ed9c6fcb86646f818dd123b9de2ad4989e05825ef68d3003226",9.647446457990116],[12940,"7f1c03f511e478518b7de3488d1ce72f174b2b7e8c367bbd80f54ebd6eccfdaa",9.917710196779964],[14409,"fa3f7128c63cfc85a0c72052a6ca5b6918acb7d6101f689a6f68c2315ddc278b",9.317957166392093],[8186,"6770682f908444eb0b9d33f77f632884fb00cd189538e7b444eb71eb159716ca",9.917710196779964],[13094,"7fc4ef2563b3686da4cbe66b1232cb95df75f69a6a429f109a6f1022d6eb90a9",12.064171122994653],[13689,"ad7cb0ae5a8e9949334a5db8903d730ab6ffc3e567ba8f5bfba95cdbe938649b",9.317957166392093],[2934,"689919bfd66732d3ccaabfa3a8496524efdcf2fbdd180ea47143915bc0e3cfec",9.917710196779964],[14859,"5db43ca4ed837d1f8d1519fa8bc85115f0348aa682447ced3ccd173278789381",9.317957166392093],[3255,"d41561169b4b37b89d65c2f684aa30b93cff5d2b22019ed8dd5bb035ca31a4ea",9.917710196779964],[3765,"63bac497f57d67e3708227cf0126d4628956cdf1cec8f5e624ce497bf1ff2ce7",9.917710196779964],[12479,"c6d27825fef18d90726bc0369c2fdccdb8c376a04d725879f204bba4093312ae",9.917710196779964],[3047,"c878ec6cd164ab14c6187739b8a7ca43ec4f0c7b83696db101fa18a58ee900ec",9.917710196779964],[1781,"07bab28d4eff5d8b7ab0262012147fc67ac52aed16d89218b0c6d8f19bb159f4",9.317957166392093],[17416,"af1e08c04c11e608faf7c21828d2ca9506b2edf5e02ca8b89baeded2df8c6d49",9.317957166392093],[14129,"8c90ab94b49ec8ee654f11a8f6c56e94a3ccbf2bf1185ba0196ae0498d7eed91",9.317957166392093],[16369,"c74ba909333c6b54a249e8f3a92da28a7d207caed9ae0a23f885088bcdd0a45f",9.317957166392093],[15587,"317b23ee7fbee7ee3a5fa1e6b48b7495e0bc2cfa223903af3d2c6e500a9e9671",9.317957166392093],[405,"25ce9d60e8fe3152efb58beb35ddc4e426c1871914852a65ffdcecbfab6d50fd",9.917710196779964],[9867,"fb619256388715daf43529c2bdcb5f3fc5dd3ecda331d7edb55578c4c9291fbf",9.917710196779964],[17548,"85a21ca0c1be91788daa820a174307839575871b713651f8b2955690c60a8246",9.317957166392093],[19862,"289b75a65ae6e9d6c478b8404a5831f675a2805d7e3e79b1e1f611a53e3c7200",9.317957166392093],[19083,"9fef031c24a95342ed2532a50f92e417c4418d892843528c9cd8a1d0b9df7f1d",9.317957166392093],[16743,"a5d254d1a44410f0b5c858d912c9870ecb111274e35d343b696a9c5bd0f69257",9.317957166392093],[1861,"6a499c6eeb29fc0bef8e1ecc6dc0e033d4e06129cf7e631cb029e80ee6c1dcf3",9.917710196779964],[6263,"50f1a27ea1d3821648458a833113f3abc7968a7d668190df36f377b7e0ac4fd7",9.917710196779964],[2186,"e6913837be9ba82bf756221f6c7e4d1d5b1a8d9f38dd600f9ef4e65d2daca5f1",9.317957166392093],[14105,"7b9cfe60f5bd97f77a351a78697dbe538f8138d7b0bd58c8187eefae25106e92",16.040774719673802],[5249,"8a0eb472152495ede1d04739935ca2968a7609d88b444f93a853b7fce79fb4dd",9.917710196779964],[4512,"d184cd5f5b7984c5ba739a89fb853dc42b43373258d6b60ae079a479c9a048e2",9.917710196779964],[4573,"434ec8f4ec821ed77f4daf144408cba017b0cc87ef5223d9cd7bbe5e0377cce1",9.917710196779964],[16202,"9aca3affcac35a8f27c64dd5c1f78fc6efa38a1bb4ed26cd213c0d2ebe6df663",11.07482993197279],[13817,"59fd34ac5f9f0b9141a65e9fe6938828c7a55ca537f2d75786cc13ed7a4a2499",35.830388692579504],[9,"5c8157e56e4879bae9d8048a3351e579a2af94f40c738ad1bb66b5275f95f7ff",9.917710196779964],[35,"16ef0e84ebe956d9fbbde12bac1460f5b34174ad189a942d493cf07839a8c9ff",9.917710196779964],[13975,"f90093c4e5c801f4e73032ba4f8e70ef39846d8592b09e4326c5b8de73758b95",9.317957166392093],[8525,"2103744d7224dbaa3e81af876317791b43294f8544a4bf368f693a02f3eddac7",9.917710196779964],[14347,"e0e060e55c45d3178b9b4efdd083f3a7ffa8b953867a9023047bf4df6a1f648c",9.317957166392093],[9290,"469770b9c6a559c5565f849da63c0f0099faf94e324ec2d70a6bc328db83e2c2",9.917710196779964],[13591,"2e4ca5eb92637aab8be2c8f9a605b4fc5d0bd2abf9a082c29df6f76ad7a4af9d",9.317957166392093],[724,"c72134ccae58202a80e236dd8e4928d622023c10ecef90d40c14c2ea06330cfb",9.917710196779964],[2907,"8185fe0700b89e497852982bd6c714df775313438d846e64ea5a52a3010f10ed",9.917710196779964],[5857,"a1f3eb0d04dd9e3fa9874507a41918833d3f5aae1d6b5f5b8057a4c1b80ef6d9",9.317957166392093],[17297,"6f909409508b96e8c5e331cc7c1bdb7783645e29df4c8b2fe72725527c2e164c",9.317957166392093],[8045,"5721df7eaa150ef21724d197551c505ced0bf9ba9435759ef22f4fae7ddc3ccb",9.917710196779964],[13314,"46f0b947e4c160aea968320e2f95c6451092ccf1af29ef50f0d37e97dfc154a4",9.317957166392093],[40,"45ca87732e08bb2d7798d2f549cdea1d96ffd38a9a3f3fab9b3495af89e2bfff",14.787682333873581],[12627,"497b0e8d55ed1b1e177e54d628cac88cd42f49c4b76e2f84112eb808a07d1bad",15],[17679,"31007a1c60df0eecd06650215d34398b0996df8190d2c3decf91499eba029443",9.317957166392093],[457,"2c9e6705697eb41925136738ef60a345e4fb914857eb2c9ae1c2e0079d5afdfc",9.917710196779964],[17333,"15f3e2033e9a74008d797261889b9452403ae9596a42a7c893afe0d38bb33a4b",9.317957166392093],[16282,"2fd7241161d6a0870ac4c8852c84c64b70348cf955e82064f418cfcc08139561",25],[7044,"04adde8f8404b290153672c075bc9d28e6293c20879f6df98d2d014b7df9b1d1",9.917710196779964],[15122,"3bdcddb459c5bc6156322f80309605b70240789f0b03c7349574d2e98794357c",9.317957166392093],[19734,"b8c88254ec6940c8e455c5b60e43b5ed430037e57a78835cca4837bebd709c05",10.052724077328646],[4492,"4360814bc9edb2229aa5eb56f971c4db580adcb5f002daab03ba6c2f306e74e2",9.917710196779964],[3751,"2de6b09b1637107280bca284c43732c940973be739066507878d463b89b63ee7",9.917710196779964],[9784,"05c0839b9dc13cd6038e8e5fdbba12e0706c81cff6945bfd3f64042536d5cbbf",9.917710196779964],[11887,"2e5111c3eda294cf3b1fab76c321980b566d3a0ab1432ff7e157f65c42ff18b2",9.917710196779964],[886,"75e505012b7c0eaee358fc4c7e6dfb3f4d94a33d8fe2173b3caf0e1aa576fef9",9.917710196779964],[11865,"a06d092ac5ea036493a95ba3bd2ed55ca8c57f0d6401188ed21937d6d7ae48b2",9.917710196779964],[2094,"d9ee8916bbd8e37de2a945df9360a9383ba540f84b85e3082935e5dee9df46f2",9.917710196779964],[17378,"51c99c0c5cbee2c8a67b2d37c8fe6d480b3048bb06b357a468077302be8a384a",9.317957166392093],[1763,"4cb722e78ccd1bf11c9dbfc246b628de3241035170ce97a0c5da4422f00084f4",9.317957166392093],[14438,"34cd60accb2202418544a35fb3d3b0376c1c8de951adc7127019f0a37d33828a",20.07662835249042],[16490,"3fdfc77c74e0e3bbe86408ae68295a4e8babab1fc69f5e63c5e35b21e2617b5d",9.317957166392093],[12579,"ddd9339482f00dfac582044f8ba95e351f4bb93fdaa0b2d7b0987b85de1c67ad",9.917710196779964],[19822,"408b7735116df5aa2b588813bf56622dbcffda178b450c4290a6fef9009cc701",45.648],[19418,"bf0eef0e4bf41a1f90e0ff15e12b13211c2d7dab771d5648beabfb88b018dd10",24.261248185776488],[13449,"6afc28ead708b65a42c873d060cee8f14a7861631bf5337b0de012cb0d9d14a1",9.317957166392093],[9142,"4eb98557d8a472916e25559a7fc741d85644c57c00d2323aa2c75b8b10bbd9c3",9.317957166392093],[8937,"76b2a82e8888bfa68d1fd5d8106883d0b5bd470069a6c61259e2646014b546c5",9.917710196779964],[5538,"f65f5bf8cd8a28b7a558602fdeaf834e4591e63e89947a484cd157bfdb8bfddb",9.917710196779964],[8562,"cd587e8cc1164cdb9b22b839742f5d7d792b6297ac5c8084738b42651b1da5c7",9.317957166392093],[16536,"2cd7eaabfbcaec9f5fd348ed97a56ea41c7d3bf8ba8622305b41cbaed6ae5d5c",17.083197389885807],[15512,"8a890d1d637287e571107c29a254ae1a37cb7a4b31bd659df3da71fb6c8ed073",9.317957166392093],[4629,"7da0ef5ce9fd2a2cc114b59d1bbe41e1a82b219596b98579a290661f26f371e1",10.052724077328646],[11855,"e663ede03cf4b6a5f4aec4cfa42aec2ff3dfd19c54abddf070da52b7a6d754b2",9.917710196779964],[4057,"ea643d7a3f43bf211ee11d8477e042760cb26e2bdf4cf4906a669796a83463e5",9.917710196779964],[6450,"7642f70b0ac8d357c2df0ac7539e671314057b7cce66c1508e84168e31c2e5d5",9.917710196779964],[3737,"7a9c485b16bff4450a98a3c783ec705c8590dc0e2eafad43838e0caf4e9458e7",9.917710196779964],[8957,"e3222bd9197e5e7a4bbd235a3819600dc241c076910b2f78eb007dee564813c5",9.917710196779964],[2311,"064b6232b8115fff85500a9ed5464897d67547ea70ceb3d905c8f68ee7b4f5f0",9.917710196779964],[4781,"0f0d149b0b226d5c3f4d28b2ab0ceeb1f17dc810a4cb1513948c6d1ce09f83e0",9.917710196779964],[12447,"64bd1ca6c7b07a6e5bb1983d3d1bf25be85a7bdb6802acbfb8a25649e31f4cae",9.317957166392093],[848,"ad749362f11fd14af04a9518dfdcf8b2f1d07af1e99b359b9679323daffb3dfa",9.917710196779964],[7618,"94c1b3beb0ebac21d42c9be9850df505a6240557c2dafc3fc821553c9ecb1bce",9.917710196779964],[12918,"57ae374d0bf81afcf0ba91f192b1f11981462fca27cbd9517ad3759ba53c36ab",9.317957166392093],[882,"97aad5fea849a7145b6f20ada93454ba67caf1763f455563a794e0fd793303fa",9.917710196779964],[4561,"3c6b912951641a8afa0e227f0150ce4a8b4feb8c98ca325cf09bcef3bb9de7e1",9.917710196779964],[15827,"b0c095e830bc238b5618d63d4c54ec3fdb6b26424fc5e4eb004924149a43df6c",9.317957166392093],[10927,"e4bff34825bc7d2dda132d715b32faac8c2a46e9f2e1ca2af68d97d0916d85b8",9.917710196779964],[17736,"23665012f2efa8e242458e26c6c74d80ca393b1ea536739cfd2175d7ff4e7942",9.317957166392093],[10785,"71a0efea48d083d567e06f502f1ec29c22caeb6bcfc087fcf1d643276e8868b9",9.317957166392093],[3531,"523fff0378cd4cdab4e59cbfb0652176cde9afabce241b91171c55306474c2e8",9.317957166392093],[1849,"0c665313497254920ea27a85f356e13220e828d95470c16f7bb5175b1b0ceff3",9.917710196779964],[13621,"24fe09ba03de6f83745dbbc9f4677da16abbc5d5c22654e6128e1ab742eee39c",9.317957166392093],[14938,"6aca92cdd3a7afcd2fc0c9c9400f06f4210fe8078be583bed1eba3be1f0c1180",9.317957166392093],[13600,"89715d48b1b0947362355bea67a1f9d0294ec789860b650231054fb82526699d",9.317957166392093],[10726,"b044a036d101dc333b169f2a71561003c9f8cf3f162cae3842bb4ef31f13d2b9",9.917710196779964],[4905,"61b8b155a08393643b629d3454230481c83c6f773889cfbf6a20765b3f87dadf",9.917710196779964],[2067,"b13c42774144117a447e68221a5565e903a820b7f16bbd2b7a8707e47fc874f2",9.917710196779964],[15631,"2a42a5bc4c8c849aac7fc4b00e536a0f344be3cff362aa1ee8036a5a9c4eb470",26.093637454981994],[15665,"2e24ebe194d27708efed803715065254855049a861a7b8018ceaae9919601570",14.023972602739725],[6799,"853d01dfb250d90c5515288cb38905b7bd79a3e0c781eb169ab4bbbb007b47d3",9.917710196779964],[19345,"12d3e8e0d548177f98379de47a774efb77f79b1bd96bd3aac7b7bacb2dc6af13",10.052724077328646],[7032,"6417492d77b8757a38a67b23595667892989e8f350fac83dcbf37a1f0590cdd1",9.917710196779964],[8706,"8bf3b37ba238b6668b79bd3db820439046573c67bafaeb6e41327b3261eeabc6",9.917710196779964],[16923,"2d03212a704043ba6ad6a07d6577ddcad4ef4016007e6fbbd9ac8c94e109b953",9.317957166392093],[16294,"4e37b8e576e36512e97058e1b0f0f5ae3530e2aff85f3519deec67bb50774761",21.057471264367816],[17608,"4b81243ca197d18b6405d8243ad06d825bb12bc6e79ad5375d87118243d4f544",36.57627118644068],[4109,"f03045f73deca178281087ce68c05cc1b12d11d06f3973886b695d00e498fde4",9.917710196779964],[5622,"6cf89e8dc416be45e94075863f946077149975b268b536dd4745823c933387db",9.917710196779964],[12422,"c8c7a4b1d0db5d93c1882a529763d0831048e271053c698b35fcbb89965070ae",9.917710196779964],[15060,"39785ddcd3f1057119ff3ccffa6653fc8e029b6a90a030b9ed8d3a47f719607d",9.317957166392093],[19720,"4731d35bc131f8c49a687b5896884d05a3f90eed1c1876152f90b1bf83b60806",45.694736842105264],[14665,"9688925f0a3bc7e73db220bcb52c9b35963bb8038c512a95e8f8d0b06df09b85",9.317957166392093],[13313,"b56b9cb9213aeb218fbb6c2ab695e7213100bf556868a82185634d64d45b65a4",9.317957166392093],[10091,"f11ca248070b5002a8afeef6c1e2d915c40afbea121d92d16086aea44675c6bd",9.917710196779964],[5981,"d5c2b03c52efb0dca166daf88f2b2f8fbafeaa7dd4d2e99a17eabd83829832d9",9.917710196779964],[3847,"46883ef978ced90327e4043cdc3a8a5c0294720549dbfd5bd5c43f064cfebbe6",9.317957166392093],[154,"fc404cb784e14b62e64016b76591d1507007bba2c0b4d545b47b49eb1857f4fe",9.917710196779964],[4547,"6f5f88e191d9e2cf42b9fe9b259b6349da813125ee48e7c70cd9f2904c420ae2",9.917710196779964],[8366,"f6d284477633df97a7dc04b5940d8d683fdc983be00d5e49b24d30380c1eddc8",9.917710196779964],[16546,"1d41d3c15321cbe82e7d6573c1c2536f4391912d6e7de4195b954676eec5165c",9.386620330147698],[10540,"721fd90bc1058b9dd3a8907140ab13b36a1ab53691ced1df4247efc493acf4ba",9.917710196779964],[482,"b978b473cd9f4e01a2634e21f5a3bf717c31d443c7b7384f044a59559669c4fc",9.917710196779964],[14783,"2e579ab71a3a7ad55214ef4447b80c0ef58f724c217dd19c80108d1695d83483",9.317957166392093],[11213,"d20f2e436bedd4f1df5c336bc7d71b377bc6eca23589aa3378291ea48dab9bb6",9.917710196779964],[3319,"9d60f7bef0c8cf9cdd33bb89c8df359e5ea4983d271eedf66c5e7243f89a3dea",9.917710196779964],[12539,"5b2325fc59b3b06f01a1e795afbcc536f34954e6cb8a7d8b99419d0a10ddaead",9.317957166392093],[17897,"7881d5326e44374f941f34236e7676e83e69d3bec22ab9279f929d955c93383f",9.317957166392093],[269,"5a2da5e7ef2e73137433ac5b740f5a47663359af1b1b9e3c38df1408878824fe",9.317957166392093],[18315,"10a6330b100ec1d2b3c3d32a2703500abd1eb8fa5fea5d0bc5a1975c2ceb8b35",9.317957166392093],[1468,"a91731ab68b09b8c459b8c51c3082dd0ce513adf3f6197bc04aa70cf11e45bf6",9.317957166392093],[5582,"9d485bf7509dfdc68efa6e4d68434589faa69cc87363f3b855743a40cf9fb7db",9.858123569794051],[9228,"a6e56dda0962f4ce41937564fc453e7e0174547c881dfa4649b48445d41346c3",9.917710196779964],[507,"863465ae618e91440636632a14e576876f1742ee221a6676b3732487e622a1fc",9.917710196779964],[14331,"fb0448fa5abad4d96756cec3a5cf1f9d610acfbfe321c240c0c817750aa1b58c",9.317957166392093],[11994,"9a019936d443ca0513f5ef96bf94c578a559e8d258fe80b59bb96826ad885eb1",9.917710196779964],[11973,"1d6d0749012523ab96fd8010229299ab68e20a54663ee1b0ed4c7accf2cf7fb1",9.917710196779964],[17694,"91633c656ee7ca875dab3cb5551de6a33ed9de279c00dd70c884e780c7b25043",9.317957166392093],[19017,"180575a107b4de653371d94ac9ffbfca7c4514194e53b393fbb98a12bbb6e61f",10.052724077328646],[18461,"24050478e3dff0bd9ba5dc94d58e5695b090b2e06fbbbaedb5770c0a102f6232",9.317957166392093],[385,"00c3c862de372bed273b1ebab922ce90879c9b5a8d68bddeb2b3da182c2c74fd",9.917710196779964],[9014,"fd85a2133e0585de6fc0744cfd5ee8f6b70a3d065c9ba18ae1b975354733afc4",9.917710196779964],[12066,"ad9aada1849100fc909cc0a8ae1f200af03f66d68885ba21c4dc61bdab61e5b0",9.317957166392093],[4012,"1edff661efce733aca4c7797c251bcba6d390749cceaa6a72e43e29478c5aae5",36.92788461538461],[10704,"c0afb34066a34224d8c9f66012ada3940588f429ab04040c934c252330aff9b9",9.917710196779964],[8735,"adc652206c9b2f5e0308b91c549dbba8cf91414c4b31ffc6f8e7750492407cc6",9.917710196779964],[13991,"c57736a6e6cd651bf0f25408452525a24f91994e08e11b51f7aeaa600a2b2c95",9.317957166392093],[4783,"5a6c798152f198bc1ac0cd5f8f3ee4e1ac9a1e5d519abe53fb3a5bbb865082e0",9.917710196779964],[15177,"06964c752cbd427cf5493eda0482c587a98f957695da672a6fbc25a5a2b6ff7a",10],[17222,"fc799cd5af442dde914c435d50b2a5648d8fb5c0b6a84945b6bcc555419f824d",9.317957166392093],[7517,"57bd7134c87fcd89de6e863247348e8e539f0ddeee88929abd9e3d6a3a95aace",9.917710196779964],[5188,"5c5749c671075d556a3b2bddd7a91ede8a550e8c929f5479eb3e72e45d320dde",9.917710196779964],[1138,"fd9230bd15b1a68f2b114503c270eabf22169ab94854fc92dce63d2606985ff8",9.917710196779964],[15390,"9cf958e94393daf06395bffc613b14312abb1ca19706835c0b88daf696477576",9.424083769633508],[2319,"a4dcec488268d6e102f4dece9624c71277c77b1d9bf41d2130269a091e2bebf0",9.917710196779964],[4791,"dea36c7ce97234afbee99c5a498143951aadf95f63a9d6a10e1bd74c323170e0",9.917710196779964],[15615,"a228839db3e255bb9113b238835b3ff9b5dfff4cc4070b67776fe1cd5c291771",9.317957166392093],[10458,"c2130d2ecd27cc817f13bdbeef8db06ac073d23d10fd392d460cfe13094f61bb",9.917710196779964],[19800,"3bc139a1c4cbd085c39aa000442e9b49ca67e2c954aaf04e746e5fecb6b17c02",10.013531799729364],[6870,"e33109301ce5a16d51258c9f1e73a7a389b9fdf43ff2e611599779e26718d0d2",9.917710196779964],[43,"2ebc18abc7eba638cd1c542b4ac2785259b435050ddfb02aebe0197ebe2dbbff",38.61187214611872],[15736,"00753ab897a8b7f271193919dd4ca8d1fc97d9f00e17a53ee28229bbf2a9b66e",9.647446457990116],[10645,"fb471ee19a7893afa5ed95edd84239478756db134cf9dfaebc237b558e9e65ba",9.917710196779964],[628,"8a11771d9d3a59eb7f33552e9c7d1c58eeb9ffca2c5b7243eb5ab95c8edabafb",9.917710196779964],[5785,"072c2422702d2f75592da3db67c074705271a1d697162aaad3fc9b720da184da",9.317957166392093],[15248,"802af1e588da54a29703f9b65a07f8993a477bfe312b48f440d243077df57479",9.317957166392093],[18300,"9d3f27b6c08d3f6d01a7f76b5fbad65f65bc0fdb4db9f14d441ca7d37c8cd135",9.876543209876543],[1118,"dde3971193562fee5574e6b411fc5e57574b35385fd41109ceae6f4abe6e7af8",9.917710196779964],[11083,"6f5c5909ca5aa42cfb3ddfb8cc36b65c4d14c8f520ca08c7dc9536e8f8e762b7",9.917710196779964],[7165,"7447526214a8db0430c241fa0061a9bc388f4c66f2b97ff59c218ed64d1cecd0",9.917710196779964],[14642,"6a722bc9c65e75b7c04a64d9f50eaad29203205d74f380f5867865c76d041686",9.317957166392093],[11670,"15e092b25ca3719cc65442aa56613e4a78ef27cbf9ae1c04827001d36fee77b3",9.917710196779964],[6259,"af53137209aeaf0a64dbf721747438bc304a4d12391fa33bc1bce2c309d15ad7",9.917710196779964],[16647,"3391e7a9f495ccf184943da762be788e298b242bc5b308d07daa2b8fb9c2d259",9.317957166392093],[17396,"2bc626a7c01860669da715587b469b0480adc69053887ccea83d1f137af3d949",9.317957166392093],[9666,"882ff0f1e2f0f25061b8c3537d047b29d993be29c0a7a4814780432b8b9898c0",9.917710196779964],[2259,"9b59715f8b04170d9e387e8fa3a7be780c59524226b1d000493e1a7ecc3434f1",9.317957166392093],[12379,"b4bb75fe57dfec1ad0788955a9bb9b4fe5af1ca146e0c766924250cf63edc4ae",9.917710196779964],[802,"d3bf34f4b7933a0cda0bc96e75b2fff13a68cfe5479b931bf712a3a24b1387fa",9.317957166392093],[13630,"b70178f6c7049b077060fc49fc8da47d5ed0c09762e29005888dbaa4b070b69c",9.317957166392093],[14503,"debfbbb890fb1de28ee3ca72f8695280b6f800b097bf9f6a2c781ac5c1e70889",9.317957166392093],[19421,"865c512d057d41cce4b7b51559f486c3cc46324abb2a88ca4b796507bf34c710",36],[10018,"df6415d5a19067eb87ffcd908281ca2c8a811c543c7031b22c0ff192083e37be",9.917710196779964],[2828,"4cbf2e15d150dd7feff152e8cb20f927fe0af3bc61bf753c1551d4deadcf83ed",9.917710196779964],[15618,"41a523a5aeb987c888531b75fd7d186146064a7df12f5a095af040995fe20271",9.317957166392093],[3050,"4e149605857e18a7ac16165887a7414ba3d4e29619400699b96597f05036fbeb",9.317957166392093],[13995,"f362475c168d319c91e7325bb2cb1b88a1c3266a19cba0b453900bdf29da1295",18.09625668449198],[11253,"7bbf3bc7272b8edc1722f47b34d8c8a058b4291fd9cc9ea5ccb2f824b05b56b6",9.917710196779964],[8854,"0265b4f73f2f3cc57b5704df52198f3c871f8f300dc849d95f77dd1ed2afc1c5",9.917710196779964],[16362,"5802b2e941ed8a243b26a7075bbffb28720dac5dbc3387ac0048aeca2ebbce5f",9.317957166392093],[2158,"9d640a36cbab5ad400bc04d860d171c7530d19f2f2a8972f8defa3a50ad0d9f1",9.917710196779964],[8842,"23bda64865292d0dcc1d8bc8da85c2db1e7760332660d5da0efa091f5fe1d1c5",9.917710196779964],[18192,"9e57e7f40400ab24e73d3e46d24b5728eacbb71ad3f098e6498c152381396638",9.317957166392093],[54,"f44777804d6c4cedbfe737fb5bbef06656316f0b9e6ba1571eaf107ad7cb9eff",9.917710196779964],[8702,"8ecf76cd29e786c4171040e55f3d5f984febf8c4b3930dac964d1f5a9b3fb1c6",9.317957166392093],[1068,"d27db89e1083695e3c1084d9cd3cde7bda7f8ff1f3a6ccd1d1bc03b89f16cef8",9.917710196779964],[17155,"58c7947f877765255aaef277933b47cef3df3c506c47ac187b7b5a2f11d5f44e",9.317957166392093],[736,"152ebdad980890a3be9c5d217b26525e814716c1ff78a4a85472dc2a01ea01fb",9.917710196779964],[4617,"4b66b15d6cde95f6bc49b079ed996da661e8afef39625183ec067cb60a927fe1",9.917710196779964],[12294,"72f914e9dad82ddfa9b0b8966158cb501352654c9bc3c4416c5adb19dc8b47af",9.317957166392093],[7871,"8c5b605dfff3b8b4946a86bf61c4a049db6038f39d3102874f68dc795bdb6fcc",9.917710196779964],[2686,"2bdfa841757c06bac7a618191e5dc69878d9fbbfe15a793efacf86d692b593ee",9.917710196779964],[16348,"c5d344bd7c5cbe2ec255e353b2c88d1a4dfc8aa43f3fc6d3c60660b4e31b2060",19.093184979137693],[6754,"f8d7f0bb18fface5246ab9c0dca15d606d4488a58f732157f9ea7a972c0491d3",9.917710196779964],[9406,"41b7d3f15da84b161158f12f140218025d20a28cc0ebd27608fe2985209c40c2",41.35472370766488],[6695,"56926d27aa36c8f078ab365579eba550b403348f447c747c4098d9267640fcd3",9.917710196779964],[10001,"6496a429e81f75aee471db1b0372a94892c3d7faebddc8c343d9dbd859a252be",9.917710196779964],[11046,"533ed0a9b964954ac6e1a3645772e0c2a91e450dfd5d3e3ce9d3372b2e41bab7",9.917710196779964],[16747,"5546865bbc5f34a9ae4079051820fd6e44495d1a138b35388205e310e2048857",9.317957166392093],[2297,"3d942b02859d57d3d52778654085238efb514348e286dce6011868c554f606f1",9.917710196779964],[17511,"9755667d588ac68013d460cea5b8b28dc242adcb7bd38093fcd1f01e1c984147",9.317957166392093],[79,"d460274df1a0f5d77c76804ecef54f04f9991b0e86a419b174b9f66b6f437cff",9.917710196779964],[16301,"a69abe8544f8f102e37a4ecdd967b27d7712022d963de95df123759a193f1a61",9.317957166392093],[8313,"2969b254153260460e18a67eba57982471fcce27104231a0c30925437f5640c9",9.917710196779964],[19732,"83bbb41fda94fa6b5e972746afed82780d130c5fc708820b7816b45f9e79b705",9.647446457990116],[19714,"3b43bb583ed1eb634d85aa14912bdb101bfe765eca1df437fbcfd21cf7d63b06",24.228163992869874],[2167,"491fd14411570046bdd74256af7e8c783fd39fa17875a23c30303f833cfbccf1",9.917710196779964],[19448,"9f847b5c211f8d2710120588082ea28a1e389ef2417daad22c7f92f92e1eec0f",9.317957166392093],[17133,"f3281ee842d81a5d8db755d5f69670f02c768359f1fc63321e38c68ef0a25e4f",9.317957166392093],[13171,"be5a02d5d8739447545a1cddbbc86f9c2bcb5eb9b1dec62b8b89ed1cf0cb8ca7",9.317957166392093],[17949,"6d4f69306e3f83284323cb85046c426436a3dd5677f70e43ca601995377d4a3e",9.317957166392093],[9033,"593cc33be49793d7717c4c3fe672fd0f7343fad2f2645334fb5989bfd3e491c4",9.317957166392093],[2430,"b1bff2f41650e82f538ff35a17ea95b7dbc3846a37c5145ba272e1f640a543f0",9.917710196779964],[6443,"e894ffd141c722981a346548a26e3df787de288bdc58e97a0fa591c42594f2d5",9.917710196779964],[18440,"6434041454a7cb387ed59a8189fc59484b757408036ff1f27ca560ce77b7d932",9.997888067581837],[1245,"d686ada96d74555cb2902542b32065f4b1694ea138c0554670a4dfa637f9b6f7",9.917710196779964],[14203,"66c353b7533ac0c7a85a73c6767d42af2f1fb935d2e6815706f6a009eebe1f90",9.317957166392093],[14875,"5c4b5b58690ffcfc1d42a230547d25fb9882ea6f43373a3b58726c1c58d64781",9.317957166392093],[18158,"2cad79550182fe7163481a445a54922dd642d3bca4f24217e30b58fdd0322639",9.317957166392093],[1052,"8fbd10a9192e05995fc8ecb567bb29dda1fa0e7e5f07497cf57e2a76de04eef8",9.917710196779964],[794,"cb3432e85948fec24c74001d9668e919281ed54fdae5daba76b27d28b0e191fa",9.917710196779964],[2932,"c915a5fa432f1b5c13d419628be3a19840f9cfcafc6542e99fe8744676a7d4ec",9.917710196779964],[14804,"5c615580a16b5b883157dd33fc9d07059b05ab8b690c1eb4d997f2e339f1c982",9.317957166392093],[3447,"b9653f67763c5ae02128f036e64a89c15fd2046e18d13d300e078127b6bd65e9",9.917710196779964],[171,"a0b1c2d06a3438748c3f46d558f61f3cec968b0805d78312885f28ebf981d8fe",9.317957166392093],[19872,"f6f717b7bbd66ff65f0e1634741f35361e6cc4be199ebda95f61c17246411300",9.317957166392093],[8840,"db9a770c45b88f1dc7057d6581039044c28e000ce5cdccf3ce985e752706d5c5",9.317957166392093],[13319,"998e82d4cb6b49e1329627c5551b9e554a836c1c08a809c0a03211d3374447a4",9.317957166392093],[15713,"6186cc740aeb26de068f05e328e0b201b8d86e6d64034a294cde6b75d79f326f",9.647446457990116],[10983,"5b834a575589863e45b0cf7ba253bdc07123a690b0536120ee82def702921bb8",9.917710196779964],[16355,"c19611566fcb367a8efd0683e43ffea3f2349b0a929d303b041305476146f85f",9.317957166392093],[6428,"9571e6a6391f62aad20df195c39d8ee81fc32b22632551eac3c4d82d16f714d6",9.317957166392093],[4204,"3fed6067903ffd0864a861e8341e88fbd3af1733f4c33e761f7b18d8563f64e4",9.317957166392093],[6177,"5bab033e0ecbbc72f2b12bd0454120ff45036306033bee8db621a372c56ef1d7",9.317957166392093],[17030,"f98914cd4813b5dd8e3efec457cb668b5f5a68768c961f7bd321a98626846651",9.317957166392093],[2674,"ab95e6067960bfcb303c0e67ba5aa451d4e69c70bda92007043465b2c8d4acee",9.917710196779964],[7832,"5163a0a2477883f4c0f753621fb74c616190b215161da31d7d9ff7cf7b9795cc",9.917710196779964],[4899,"af97375fe976a58a2d8e9ee1a11455c42cf73ef05ba05920a64ca3c1c797dfdf",9.317957166392093],[14103,"5323dd88effff9e17178bcee1ae97625ee10dfb2ccaa7bca456b354474cc8892",9.317957166392093],[11852,"41a209a52a8702020af21a5c2c7b50395725879c3800f3c54869f90f31f157b2",9.917710196779964],[10186,"64f95a3f2f468205a8016c63d48ed8683ff707b7596e91b79c5a96e210ac1bbd",9.917710196779964],[6483,"313de985e5d3ac19e34d56c02673c3286b754d6f9cb9887a9844fdd7ab3798d5",9.917710196779964],[12662,"5adcc18e6f5e91b1a1ef9000eb47926d0eb491967e876713537289a7179cd7ac",9.317957166392093],[7997,"f154c16f50c49604141da10df91951bff26e741f9638641aee090265518486cb",31.63101604278075],[17252,"40ae415395d1864e98b29d1a06eb313343a486e77b80f63189add5d9ea6efc4c",9.317957166392093],[2957,"3f3bec7f5fe06f7901c750168ea5d08a178a62725efda133199405e86a3499ec",9.917710196779964],[18772,"cf6cbd814ca68ac86d37c6093d048d018a4f315701368efcb6ca07cb360e0828",9.317957166392093],[17948,"9402afde6f32ce4f5e23a1d6d88aa9504011e6ecd3a68802e2d32e199d9e4c3e",9.647446457990116],[10476,"41298d6c217b4d931ab1918defdba99678c21c01c9830f0cfd1c1388ebd84abb",9.917710196779964],[1183,"417a990031d70c7fc23e5476f390ef8705bd51fabafea7212f732c1022a71cf8",9.917710196779964],[6972,"f71e87d9e0d91956622cab1f4e8b06a196fe97c1a7f1dbbcfe2dc652dff528d2",9.917710196779964],[12485,"f93e9cef23e5cb8313348fa24660358c9134d63cc52228784c9450d245a108ae",9.317957166392093],[6404,"72ea6ac123cf49653bda3f608574105d12bd8868a91100bef10ce9cd110a4ed6",9.917710196779964],[14123,"447b61146218d356e04bac78f474679ed57a687149541349dcb78872ac020792",9.317957166392093],[629,"8a8b0e4feb2f00fff2b912b36b8ca8119b8f6dbac993ca3d9198c0e2f1f9b7fb",9.917710196779964],[1812,"45ab11637f162f6e3c144112fb0a816ac432bd168a6eee016f27d78aed7327f4",9.917710196779964],[3208,"9e7bc681a2339680f2e8fa60c4a21133dd300a0c59d67e1e2e19525b8428feea",9.317957166392093],[13413,"bcf6a4d012d8cdddb8008e159031cd319f0d75a432d71d5e6eddedb00cdb11a2",9.317957166392093],[6887,"a92ac90bdbd62452456ceb4e0136fb46ab7b4cc1f555e23a2c275947c5e5b2d2",9.317957166392093],[775,"8356495537fa8497c9964f36d9d4828f69a9f0f39d2bab0991d7e660115cb6fa",9.917710196779964],[1845,"86a5e7de4ac80d7bf8accd20b2da480867be59304d03af0b22ff3f1cc451f1f3",9.917710196779964],[8059,"5343b64090ecf1bf84f621a50e91db4f396c2a98ef3a362361622f13a4a30dcb",9.917710196779964],[8352,"7f29dab746013fe016abc38580343c91569d5adf5a2fba8b32149e2bc2e8f9c8",9.917710196779964],[7023,"7d628a238475ffc8119a3ffad32091b01583eed0f6e19154d2880d55ed69dcd1",9.917710196779964],[12921,"d673fd1eb9e3a88561f268de3db74d99342ecfcd868cd06ca43b1f062b3429ab",9.917710196779964],[6986,"8b4406aa705d6ab002826cfaf3db8f3ff1f47c6d2b0e7337bc6a16f06e1917d2",9.917710196779964],[16624,"6b2c4f5eea50f6bf1bdf2881080b09b735f9ec168f41dedbd97a928ac39c525a",16.013852813852814],[6756,"c4b6c04a9fe86d8a0b575e69b5e320f608bcc9aafeac7f187caf8ce78d538ad3",9.917710196779964],[8696,"0f3051c0cf4c6ac66965582fc58188fb0573a014cc3d93506d5396595b95b9c6",9.917710196779964],[16849,"8d79b849deca33a97b6041664a0bc802ae31bb3e37136c4b8772d032f8234555",38.21408450704225],[3066,"2b40d4ea1d698afb020466927c926b89ffec61aa9b237dcf9405bb5c7607e2eb",9.917710196779964],[11923,"8761be63c20f6154a99d462218e6322ee824ba45676844dd0b532826fa22deb1",9.917710196779964],[18879,"3b0b79a1b1eb58f1a707fcf620f916f01e176b3f44c40e9482c8b67f89262a24",15.079646017699115],[9989,"738083ad0125974556195c03c46ca55fb68befb2ef65bbbaf4625b3d326d62be",9.917710196779964],[9270,"6b649cbd485b7070cb8cacea0a749469bfbd6d99f128aaf1ef4b5cd2678808c3",9.917710196779964],[11843,"25943d42f2119baa58d71750981a82c7594416c60b3e63262a10c214e67f6fb2",9.917710196779964],[15031,"0c4dc2e3c57b9f23cd3dccaa9eb8a3c2a5bdc85c07107407c8702985e6accc7d",12.057692307692308],[14654,"480221993e10ce13755d430236619c83b4e3932d3984b0a0200ac259c607d385",9.721518987341772],[12354,"5f5884314127de629d0ac5f039dd61513f2187a16d6d9f8c89927fc22f27e3ae",9.917710196779964],[10756,"f6577a05167ceceb20a35862426cf18fe2e1f4f2ec30484d7d0048370535a2b9",9.317957166392093],[6781,"b1db130ee0b089becde40b046fba4ea57c1c6f9d6d176a11966ab1dff75b66d3",9.917710196779964],[7352,"fea39047b4d0e9cf65b3897e6982d2d976ad5e1434c656a6de3f37a310fcaecf",9.917710196779964],[11030,"e73e0bb22083e0296fe25bb6b4510ae66626e9ef051f123e4c1e0e6b38a3d5b7",9.317957166392093],[10316,"e333db008926e6e578d6c48cfd04e7369644c88c966ee06a5a43cdad53793ebc",9.917710196779964],[10700,"aea2960b2f00bd0c43e7a1b2909600b676583f970217f57a0b90eaa3a6cbfdb9",9.917710196779964],[16916,"0b540d81f7e44e930949ea2d41d69130c408110794204de747cc58a8de2fca53",9.756272401433693],[2407,"cc2ab23debf7fb7be05ffd7de6d514f125d1457dedd1e111b53fcfb7f3226df0",9.917710196779964],[12138,"62c81d1af2effb6b72d209a24fd1d1ab1ced2d60a5615c31ebd77c0dd97b6ab0",9.917710196779964],[5541,"32cba56067a1c6bf6f9db78d7a196cc3cbe2b6f175abc294e6df62dcba59f9db",9.317957166392093],[12409,"44762b3d91d9355e7bedc53e41a949deb413140d59494c5d5724df982a338eae",10.052724077328646],[18379,"a74e8feef1e65873335949fb68ec9a18a3cec09ffeb443f7aac57002ec491434",9.317957166392093],[14016,"e891f66a2ea23360bcca3bbd7d0df792f677e14cba6eddc1ea13033441d88094",9.317957166392093],[8958,"f890cba12937147e074accab20a4e859565135af80cde7ac79daf0facb8512c5",9.917710196779964],[13828,"e93c4099031833253e72bc5a46147892dcf38451c7c838492ac9dc3e5009cf98",9.317957166392093],[10617,"2a981f1bf29cc6472015459f977d592f9567749b3cecfbad516d52af3f5e93ba",9.917710196779964],[2695,"1d8b9dab47a01bcb08498612b8e3f2f62067e47f4e3582efde951830d52c81ee",9.917710196779964],[101,"bc4ec63616235f6896ef88704fe1ebf9fe29270f0d800e77fd5ef9e98bf65dff",9.317957166392093],[1551,"a2a65ba7814fe19fa9f9b0b0fc19ce9decf8c76b10d6d68d7bc844646814d3f5",9.917710196779964],[2813,"6cda66984b0fcee04c1af156b9bab1336f3591fad27ad58b2fb9c3a0f47997ed",9.917710196779964],[1319,"9595c0d9320a52d4192faf91a45bd107dfdd363d5a59625fd49de53b9c0f4bf7",9.487528344671201],[16865,"10ee76c29ca2c560a03c234a214cfb8188ef618493fe421bd9d582bd3f7fe554",9.317957166392093],[7175,"8f421d1a2c7c35ef7e30d11ff0deda836eeeb4fed153fb6c60bf7df2d5cddad0",9.917710196779964],[12872,"2894c8a1aa8664f3934bbc76dbefd0b79517207b811615827ca93c174bae6fab",9.917710196779964],[8712,"1fc1c0db956c5396454747c6aae05426e956d852d020c380d6ce7b394e6d9bc6",28.155555555555555],[11463,"365817cfd1d2e151572f0f09dc34cf9a838d3481b8fd6eb9a720a01963cbd3b4",9.917710196779964],[10832,"88e39eb365f2722003a1180fc2a844015acc53827f717039438bf05fca861ab9",9.317957166392093],[10801,"4a2ccb1ea404f1ef0e8abd1cd9a0ca316d8389141981f7f9ef74b582502a49b9",10.052724077328646],[18885,"0462e10a0fd3e176d6f2338d91d0f2a8f17e199cab58b67b2e1010a7d1d2de23",9.317957166392093],[4437,"be96528ad4db12a9d736ab65565ae351574d8afb74022b58325f5a21a013d7e2",9.917710196779964],[11769,"24f5f303dfbf41d6fdc6e69dd7e024e3f10235367e5287dc5f25f10dd007e5b2",9.317957166392093],[11358,"0ec7af2e9246b249836c9f27388c52661b07bfdd252d6c09cb9c8e37d20a9eb5",9.917710196779964],[17601,"3a031c6a95ea52f328baff4268998ac5809be44c0f7d1b7e7c7d74e6a7440645",9.317957166392093],[11468,"2aa97b43a922f9960eca5b6df3c7f861d449229a047bf757e6bb2e48f0bac2b4",9.917710196779964],[431,"a207f0aa7c9f816deae89ed1470b5e08318844a4ff897bf557990fa99c1926fd",9.317957166392093],[16087,"76555bbaba9bbccee264e0064b1990154b3dd9b58f9bbfebc6179264e84f9666",9.892183288409704],[19816,"201af7052144c2330ea1b6b700dcc04156c8c393c0d9b85e7ad4af19dcad1f02",9.317957166392093],[6969,"66bca98a5ed383f6d1e183d4184dd73c749c9583c5aa9181c454646ef6102ad2",9.917710196779964],[2961,"7de3690371f6d6a12eb13c9bce866bf20a5d07aef9bccd161cc9462b2f1993ec",9.917710196779964],[7174,"e3a6bd6cb6be9f08a9a0af4037faac1897be4e97fd571b8aca10cd1e0d09dcd0",9.917710196779964],[5917,"18611169274377c61aaac2b2021a12ae668865c6258ac5bac0c33023777297d9",9.917710196779964],[390,"f880c6d8380effdb6c6a2a17d19c35ade192378f8749abd3683ed5b191446bfd",9.917710196779964],[17923,"2908c858937960982551e981fde7cc04a583a6b9a42fb865e62f3be9945ec13e",10.034187455573232],[16017,"3d40595f922feb79f49b29cd887d139c7281492b52b42980f8150024aafb1268",9.317957166392093],[7957,"a18f58508daea96b090d58f926d01b50c8e6beea736b44355e3a7f00e957dbcb",9.917710196779964],[16281,"71ae4b761d5b74d5d36f41656dfcc7aaf8753b9b5e0e6b904dd04e4937519661",9.338112305854242],[4273,"33cc6c267a7ecadff92b000b5256cebab36e9a20cc1d23c4e2e412962b59f0e3",9.317957166392093],[7797,"113d7c4af131629f9919bedb72c228997657e984f096292491f89ed9e053d5cc",9.917710196779964],[10876,"9c3c6098f2e0d88d7484fbc1d423e14eab743f041c31a128b75bcae71889cab8",9.917710196779964],[14912,"7c0e8f39aae5eca4e4fa23637f7e958c9b12be7e7ef8d2a5555cab35d403c680",9.647446457990116],[16935,"a5f7f931c92a280bc9e5b8960fdf7a3c0e91542b8c86858f0e7ca711c1ed6353",9.745222929936306],[11239,"144709f727311e2fdbd8ff50809dc254e45aa5a1a3f880d7e59b34b7d28d71b6",9.917710196779964],[11776,"bbba0e3b4a754963fdbca31f6649ddd38fd48a80245909f8751833b67042dcb2",9.917710196779964],[12793,"a61156c6b2a3f85f81d99b3368d398d71c267d248293c75c1798f761eb73f5ab",9.317957166392093],[6385,"d2561dec46450ee01a2fd67941b2d75fbd87c8f73d630d6718f3db00ff366ad6",9.317957166392093],[9515,"011c9f3616cf347528afd4026f8efc792a5a2ea0206ccaffd7df16d140f298c1",9.317957166392093],[6711,"46fd3f44b6961147c38e4999cc36bd091700ddfdd72578c77e5944421013dfd3",9.917710196779964],[10331,"b1a5f483d0715559c638f6c28c504ca5def711d50410a2507418c6ee768921bc",9.917710196779964],[13450,"5d691c1fe3d7e8fe9a683ee533ba0b9a2456de137ba8ebd9b254adb4226503a1",9.326683291770573],[1582,"9dd3f279f18c54cc1688afa2969f8893d2c3348e31247ef576e4e7a4e6cfa4f5",9.917710196779964],[14591,"7f2f0e815dd570408aa9868e47b378e0be1ed9d48ee07a5a886788ef99d04287",9.317957166392093],[601,"e526f50545e1dcbb3475d998f46194b1671ada494d178be6b399634c3663ebfb",9.917710196779964],[10504,"7b6f8f18ca4a74212c82591ed553515960e3965bef3592e296e369468d8728bb",9.317957166392093],[11576,"83087777ee886519ef320e7e2c8cfef064c10d15ca8ad31db94f472d75ec17b4",9.917710196779964],[19066,"c04cc5f48ce7623d9752d3c5ce812af85ba21cf8b08fff4b9c4958881623191e",9.619607843137254],[17380,"f2c5bf735220aae0658ab55c6c6cb6032b3910045562aead8fbfe95d7f22304a",15.609756097560975],[12713,"058f65ff81ef915ea680825c2e2cc71ce80075413a6e8fcfcff213012bc683ac",9.917710196779964],[7111,"35f767eb3334550f40e59f0355929cebf889719f7c412eb3cf900704e7d746d1",9.917710196779964],[717,"6e61cfcaaea3e3ca61719b1d27196732333610535f65830621e8545f634d17fb",9.917710196779964],[16344,"bc3fe0dc8d83884f901c8e3525b49f45fc52397cb002c4cc28e800b2a9d02c60",15.012366034624897],[15410,"b00b11939705de762645b8046b0aa84637850e0893f2ef97512bce33bb420b76",25.311942959001783],[17685,"0fec53ca7af66d991f89d5d539f83a6ae6e4fdd1553e7d546f0e3521d9827343",9.317957166392093],[12475,"766b83a9002d2d3b51f45d66b7c7579901599bc451729e621530fcf7d35c1cae",9.917710196779964],[19277,"8532b71893b4618e408b307994f4bf18e99131a3366b1422a9b684708ae2a915",9.647446457990116],[488,"414d1b634609f8cd3e756fd9a8375d554633ef6918ff3db1cfab0e424095bafc",9.917710196779964],[5711,"fb399572e7918dfd4dc932c1a50caf5cdb98a5f5019db5ace201f0e39fed00db",9.917710196779964],[17893,"6311a1627a3b9740c74287c4894a22fd8da77fe520988206056d18e8f219603f",9.317957166392093],[10933,"b42ff5decf4fba43e2801b17484f9039acc458e6eae2fd5875fd500b01947ab8",9.317957166392093],[1925,"9607a40228195155296e316c06d0b8f45334af49e2a1bd4c3190d8a5f70184f3",9.917710196779964],[19048,"074c0fec42b73cbe2ed1104f4a2a70484c66954c16e21fdd07380da6bb3cdb1e",10.052724077328646],[3172,"be59745e445b48f013b06ca74b05856d4c734a7918b4e603a2b4f9ed758733eb",9.917710196779964],[16114,"fdd59f3080acb4bd73bc14a424a7de8cc7dac1848a0a0ee8b162bb7e5b86b865",26.003559985760056],[9737,"e44344a5ab9d7ef6c85250336872b9027a5def544f093936dac32d552c9210c0",9.917710196779964],[16481,"9b5778355c0ab87896aa4ba85bac89b2079139f25d4d1ced44099cfda8c2a45d",9.317957166392093],[13925,"f04682a0fcf462c970bd0ecdb10a6c2cf67da6dd74ea17599fc38c1a11b87196",9.317957166392093],[11075,"f37810bed4ab4bbaa23c7798baf8bb8547d5efa2b1d40f1908c72bfc8e6a7cb7",9.917710196779964],[19106,"7d507c36d92700e65472a6a0ce58ec86ac07c3a59eefdb573fc588052099641c",9.317957166392093],[11061,"9850914def575deaa91ec739942b7f95718cecfdfc96ab66790eab2111de99b7",9.917710196779964],[16484,"5acf559568b663f6743b079ed83b9d1500bc4da191df5320c59d2c999666905d",9.317957166392093],[3196,"dd572f7ebe140d4a691afb301f4befb92d100eee4700a27f141a7c1e0e9d11eb",9.917710196779964],[18597,"a624be0a076b58109086c393b1d88e69245711fccb101f38089922acefaadc2e",9.317957166392093],[13198,"51dab507fef537ed254e668280b442225cc5b0323e4208c80714b7e1ce7cf6a6",9.317957166392093],[19497,"db4bcb5899ccb8c86a044e6a3a76a3f7d0ed322f82c0734e7988649b13db630e",9.647446457990116],[14569,"e849582e4083f706de71fa859d27f918cdaba4fddc4ce67a1ef5a301e56bb987",16.056140350877193],[9343,"df722d2c21c19c023bdc8ee6a0f5150354c99fd8fe5d145211ae091c98e09ec2",9.917710196779964],[13438,"88d7a5b1a66f61a493a4bc10620055de464630a1138e6751650f849bbcfd8ca1",9.317957166392093],[11617,"00ff1425f597253c3d8a3035ed5be1cc6f2ddecc3181ea025757132fb6f3c9b3",9.917710196779964],[11767,"853ebafb126024cd58158d55aaa9dc46323d4308e7ccdf70ade0397b2f27e6b2",9.917710196779964],[12302,"615e86f378261cf774ed34fb2d965b140674461a983a216ed727dfaede7534af",15.942959001782532],[8495,"2a39310610a1347d317bbde9dcee4166ac622540d5006736f111cd1b08910bc8",9.917710196779964],[9693,"3f93fd4e0fa759884c488242c1c07875da2125f634b334d254cecd9148be73c0",29.96679841897233],[4414,"f3fee5095357b820ca7a1b2fb551af9106a5b9decdf161fff7ecfa309738f9e2",9.917710196779964],[14546,"c506aa8e49a3fb011cff866c042eb976c7348f8be1a47eb93bb7da8022e43088",9.317957166392093],[10360,"9302e65ee6068f5e93554efbe295e52d67d6f34ef6f60073bfbb923e050902bc",9.317957166392093],[4058,"820500b22f3330bccc3d911ea47f76dbece7168baeb57eab9903fcbd266461e5",9.317957166392093],[595,"beb0993c096cddd2414a7e51eb9ba5e9d8561f2bcbf148d415b5672d7523f3fb",9.317957166392093],[16304,"c453df0219c9304a215d7fc6c268a9f9d50d1ad8e73ee7e999b061f06f970761",9.317957166392093],[14687,"9788f537ed8d65382d72928f97bd0c3dc094906869e0e920a2e197df4ad51985",9.317957166392093],[12247,"2b9a7b0de795fd0a88007f2b8df6b270463e5d5c9ee47b40dc5f964f9a60b7af",9.917710196779964],[18150,"1affc21daf6dd14d7e12518eec31247381f5baa7fbb027ccb59162040a016b39",28.19047619047619],[11084,"c748986f75e924fee5a6205b9a16e1435510a4b4ae7afcc8a71f636ae87c5eb7",9.917710196779964],[14371,"cd2e35a850357ab3bc8bdb852ee6c0eaa286c61344b17567155f1f642eb5f48b",9.317957166392093],[18088,"dec1a014a1ce8bf4116b37c4dc932b17b2d9ba78dcbcd5ac0e6f752599664f3b",9.317957166392093],[10070,"7953c525c9276e30a9b6677435ef457bce85a92c2616da1276bb01a3c986f1bd",9.917710196779964],[3175,"8caf8c2f11c5f30db7dcec9f55d61a4b7a51025dd0ccee1030d22d4e33102feb",9.917710196779964],[14281,"731fc8977bf6110feb465c298b4167bee2ce2acbb04a9fc40ecb6c7faabc118e",9.317957166392093],[605,"a315c1b61eb3522c0c9856148d7b14cfb7b798a0ec803f0dd1cc81fecd7ce7fb",9.917710196779964],[8181,"7a4c4e38add5ce3249de095fc7e9e61b80645bba0c5a47200751cd8a80331cca",9.917710196779964],[4610,"b5f4e624d81c8259413c2c590ee8fc19e5cb2c732afa18e4bd53e504bd3d90e1",9.317957166392093],[18529,"65d39c1b0beabdff96077d8b13f832fc2c4d39d1691cbb6cea20ce4c6560e430",9.317957166392093],[19388,"ec55836178e6e30e6de433151e65fe725bf94c7ca91b060536f59eb693d04912",9.317957166392093],[4523,"e990841264f0d5830a9cc375f039070182b1de60d749397043e60b45e7dc35e2",9.317957166392093],[13476,"581475ba9bfed092745200b719f2efcda2ccc81f0730b98222aba401eda16da0",9.317957166392093],[3099,"d4dbf08d6097466c3b163290720fee74f1c2bd1fe83a8998a9d702a98d22a4eb",9.917710196779964],[12551,"6af2196790197bce6cbb0f7a20d8fd4dcb9c9fff8850a2b26e6a90ae15ee9fad",9.317957166392093],[3349,"3f7168a9f3e3a3054d3afa0b7b01f7b2d2c756035847260d7c9a3b2e1cfe03ea",9.917710196779964],[11140,"2305e08e2310a67ead4d59b26780e18cb765656e8c9929abc5e3d5b3df7d04b7",9.917710196779964],[10765,"87b6eb0171db5964951baaec80c4f8cd257351a0398113fe867c18f7295a90b9",9.917710196779964],[15495,"cd70660a61dc03b7006bfeec33a2688bbac46c2937af9ad5d63fddd179242c74",9.317957166392093],[19481,"0b07b8fb05e5e903948b40a70b188e18c1ab734a7fe86a2f00869bc70ee5210f",9.317957166392093],[11883,"fce1c11c30cc078beaf23407ce1584d14d69e445ccf94319a552406da56f1fb2",9.317957166392093],[1988,"7b3801e3741c9a846c0af22780e537fda95d08c6b8bb915c7dbfc82e27ca11f3",9.917710196779964],[11319,"0b74489a46a4917f14dc2944c500341ebfb32879685ab54068510c7f43c8ddb5",9.317957166392093],[1593,"855db972c37ed3d0f0ce3cb1995ca97ea9d66bd09fd96f578efb01a2dcf895f5",9.917710196779964],[9764,"9f73534aef6ea0eb4f17bae5c2a65e6c1a2a3199d797b4a7d3599e6717fde7bf",9.917710196779964],[1356,"e41dd036c8010b578b2b10630e1a9fa71b497567e3bde9c24ed33a362c0f04f7",9.917710196779964],[18654,"155b2523f308905bf7a79fe4ad4ec33736dbad78cc0e5015223edc00e7327c2c",10.052724077328646],[5522,"8da999008cdafc2cd364e05e96d34b7b3fe80635ecd769534335a82b8df619dc",9.917710196779964],[19274,"ea6a05e93bfff03c6b8d8686bf3ebbd6b8b14c15e37b266c7e44b4d447a6d015",9.342789598108746],[4033,"4ded70a0ae1270d1e6b2fc3e2a975c54174ab0743a56ad1254961bd418d88ce5",9.317957166392093],[7720,"6d6355d0289633dc8c4464cdb4772f0506fb6d61f2c9437b10a95b79e84067cd",9.317957166392093],[9906,"cd4da63d785be84b3f8726fecbba215fc5118de76f79937be6d6a1c62014e9be",9.917710196779964],[12893,"c9613ac3aef065366bae464ad227a3c785122f3ddfbaa4d8e366bc91537f56ab",9.917710196779964],[7844,"fe5ae00ffae55a44ff0324fdb5b1398d26973fad6aa1ddc1c1f85b944c6d8bcc",9.317957166392093],[4886,"82e24bbd8cf0ed18c3cc2a262c9cf1a1847a437be184d32cb06a66b5daefe9df",9.917710196779964],[1108,"ee72f65aa12557d8e7b0c64ca497cd3ea22382341fdf0634df827cf11a3784f8",9.917710196779964],[13125,"7b9fae5c5fba9da7ff968cf9357421bc84becdc8efff76a0e395c9d8c1657ba8",9.317957166392093],[18574,"26683faa3ad4ce3ade4b0b563fa4f01cf934e2f52d700fa99d512ae8e2c3902f",9.317957166392093],[4808,"2575b2b0c34565a5170feae7c0513a57e4afaf4dcfe1b1717722af895fa759e0",9.917710196779964],[2524,"adff2e17185ebb9a1a786ee1fe96f1151140282754a121fa2353bbfc085ea8ef",9.917710196779964],[5062,"44498c427fd0096296b7467fdcaf4caf6c2a38862abe2429fca4ad7c3dc0c6de",9.917710196779964],[18019,"c831caeafa55d1ccbb3597535c234d500519c657389d09194c1d45b7c94ade3c",23],[7040,"1f4155af8626c83fc2c8b9deb1a226c3a62dca507f2fb3383be68e0ffacdbad1",28.064697609001406],[16322,"0ce64045c5fb614e470f7ff4ad556fa96301f5238e1074880b4e09eeca299d60",9.317957166392093],[12525,"ca617a8d33fde071ae2bd4dbfdc1896f6a7daaa6ce365bcdbb86ea193714c6ad",9.917710196779964],[5846,"41ab6a3dc692a2689fc89e327532d42d18290a02a77e479e2ff62729004807da",9.917710196779964],[786,"917be52aa203014809b5f157e99a3e8d21ce57e421b0aed7627ead7f355298fa",9.647446457990116],[6891,"aa9513b7ad36eb6c20585d20b5793b5020974cfb647d15f9a8e7e52fdbfeabd2",9.917710196779964],[13761,"bf5b1047013a0ab128cbd3fd3936414ab46df2bcfad7249ce22ffe1b0cec189a",9.317957166392093],[10640,"92dcfdd2ddb9c8d669f10c0f455eedcf028e6ef072c6374371894e1372ac6bba",9.917710196779964],[289,"80962d9aa07eaac5f0d9bdaf40b5bd795567c5a02debe2d04993c7078d9a03fe",9.917710196779964],[16131,"ce4335e4f2e5a0985553229f2afb548727a2e1c082f736e59c9e8efacda06465",9.317957166392093],[13574,"f492c68cef083d4f4bbc90ef5f71f836ab06fbd034dbdfcd13be5228085a179e",16],[3454,"8ae45242fce5d2fe6f261ff732b51c193836720c0224abf7349b06f2102158e9",9.917710196779964],[4322,"792b0264ec5aee541166c813c4d63345a2c43b7ac13a45951cac9edd585a9ee3",9.917710196779964],[8277,"e10c9d41d488a13ab76abad5677630c8e614fe5e064dd751a5724a79d1d47cc9",9.917710196779964],[6728,"2f86d027ff754556be71ce3d3f2f5a79339de3a48d04d6702d0b89d4efe0c1d3",9.917710196779964],[7857,"c5de21ed7bb83382967d841d9f76e66abe929b98dde27c3b941a5521d5117bcc",9.917710196779964],[11078,"067b4c50c70270faa249dee568c67128c0985b0c8fcb0d9c6a710c35aaf06fb7",9.917710196779964],[19836,"ff1afebc85fd5d39f2ba3927e38a13bb7c53e3b114c6a06e25988a942a7f5201",9.317957166392093],[17779,"b399010d12995faaa6ec2de4949b1a360a3396bcc121b265bac36631f34dc541",9.317957166392093],[8393,"f6a4b85c5f6c855e4cd32efd91c8f92784a55586dca8ce1940a050efe45ea2c8",9.917710196779964],[9042,"b005f6e2dac3d324414c80a50ae9e940933661dd4727a905dff2c9367dfe81c4",9.917710196779964],[12461,"3c82fa7fcff36bcf73ec1536d012e404c3cfaae56b733252af28bfada3a93cae",9.317957166392093],[12281,"c7de70b29fe995bfb9f4b8018745649d0e265322dc7da72f73c4e8ed6e9969af",9.317957166392093],[14989,"53278493a69cc40510347dc34eabd66804f11efb198162497c890d6e4c30b67e",9.317957166392093],[18669,"ad4703270ac93a6d839819576b7d76c6f5957b0e42b9276bb40a7c8dd259d12b",9.317957166392093],[8156,"ccbc2037567ce4aefdc583b52b301747b3a7047220adbe230c64e7819e8151ca",9.917710196779964],[17602,"13e2aa1be1578fb77ca1e659bd334e95ea3115a152d7eb5a2db4901ebcf10445",9.317957166392093],[2265,"60dfe39b91c5a1509570357e0353f2662f298e2e86b6fa7b200b2c8c73df2df1",9.317957166392093],[4888,"3a1a88a959b6a2d7554d5890627cd6dea88c31da3c1f62f1ec81a0901f84e6df",27.15],[4711,"d67c0a2bd26bae8b435e85d1a11bed8fbead5d3fd993068638e242082a4cf3e0",9.917710196779964],[13669,"742340f0d03690dfa57ec49e7efbfeabd89b1a4ae733d28b5020ad4e9531e39b",10.052724077328646],[9248,"174bd2ac7b29aad9b8b61ca36b181c6c2a9a443eed6fb6a46769d80ddda122c3",9.917710196779964],[11759,"332728b6491096e0d724e7b3d8b93d4273b17a3dda70648cb096140ac25aefb2",9.917710196779964],[10181,"e0efd5b61723274eb80ef31877eff1bd79555ee594dac3fff328bdbe996924bd",9.317957166392093],[485,"50b3b63fc751644439ef683f17d4a555784d41db37f99a88c6f1ec4ec61fbdfc",9.917710196779964],[6911,"de3dac9a7fbcf8e45ad10698d08f5bb27853b36131035b904daebdaf406d7ed2",9.917710196779964],[18285,"0b90c812f8f7c6f37ec434c6f40c24557fa9bb41ff978ee5b246375841142036",9.317957166392093],[17200,"b06444dfe30dc692690e600ee652c684364876e28c59e7de8b328e69e637c54d",9.317957166392093],[2552,"e153a5020f579ededf13ad59820521c512d2becc545c5e11405f020db0f386ef",9.917710196779964],[9721,"4e7ac18131925eb751bcbfab2da7e1a68d51cc89a9024f22537af17c892d38c0",9.917710196779964],[18655,"404f7360ec6e06a49c40ac87b4b7476a8aa82b5c9b58b1b70cc05386b837782c",9.317957166392093],[1587,"641054002af5165a158711dc64c1aab8bba6fd18fc070b0a78b1079b90ea9bf5",9.917710196779964],[18433,"05ac27f062be70012bc87363dc48be28f2d37794771810e2beab8be93e2ef732",9.317957166392093],[10530,"ac8d00fe00ae344edd570f43a5537bb6a19c0b28ae1b4ff22c150ac17ba3ffba",9.917710196779964],[8695,"1617d6e2f0377e2f61b93fbc13b02dd326af4ea877ee705a21d7cb1d3ff6b9c6",9.917710196779964],[13968,"755d5f9edeb965c4cc49c6f3d1e98b71e01d639ebb46f87b38b0ada0fcfaa495",28.19221967963387],[11014,"4662c3455b03a82641bca2fda20154b039d3e19e3fb1044fc79ab0584447e9b7",9.317957166392093],[14827,"a40ab8c0df05949c27e098e616b41c48e66d22d5ca8dba3572c6809671925282",26.00755857898715],[19160,"0923cb9db94bfdf2baa1cc8f61475a00f44d097cf6797f752e380b6a0ad4291a",9.317957166392093],[13271,"6742163370a7043fef2cc563e15dfd896a7891d71f04054127741c61fc4249a5",9.317957166392093],[10095,"b4bc40ae173c18dc9661a9e56cdd59fef6a4eaf27294858d6e1c38c42ae5bfbd",9.917710196779964],[4065,"a8ca396c90cb082273eb6549e8d9f6b1a64b994042c41a53cb74ab6195f055e5",9.917710196779964],[3488,"d1f23d26f5070e853e1613a3b59ab09a43a10197c3de4b3358366f4bd28219e9",9.917710196779964],[6985,"c282ee15116de5237fc8075d6cf2e4c57b5cf2e22ddc86eaf577d38c4b2a17d2",9.917710196779964],[17253,"24b70f7fd7a281609732f6157e63acb2e9a35f5abcf9dcf5bcbbcf084612fa4c",9.317957166392093],[18191,"2a7c465355a39b676c205149c041d564e14cd903e438ef3a588aa5d30c686738",10.052724077328646],[15885,"c4d979632983074d884a2adcf8b90ffe0cabbc9d44677ef47bc7ad83b2194a6b",28.5158371040724],[4598,"7ce8c38b684670407be8cb6110514139e1a5287e0cc4c9b48022bad5487ba1e1",9.917710196779964],[8078,"77abbe0d86418c24aa1d72614dfa4cd450672a5ef795dee3e006c2adcb8be7ca",9.917710196779964],[7060,"583324465f105ada2140cabd355336443d5622fe6a33dce492fd775a9ead99d1",9.917710196779964],[9070,"99d5849cfc599d61a04d500218e60bffe20a3af238279b177b749a4f575a55c4",9.317957166392093],[18755,"b0720084a4d319be9b580b3a1e06a6f72ad2ecaededf7b54a89fa0e06f7c5828",9.647446457990116],[18180,"674f2a84f6754ab93c914d125412f3b9070d38d3d34032b0a874932e2740af38",9.317957166392093],[16679,"2c0a434260a9dfc76cf5f274ccfa301fd8d3c5cd686534907d76597a85a11459",19.25423728813559],[8177,"81aea5a66cbf5cbe1e574e66bfa4fd2883f143437a607c67179fc8e79c2021ca",9.317957166392093],[15030,"feaf48d395e91a3c8cf6ec5f71f40ae686f698d58e5acb28a6835002122fcd7d",9.317957166392093],[15289,"ec8d7099c924a57ba9fa4699cb773beb1f5bfb6fe5157769a552eb1457ac9f78",26.135593220338983],[3660,"2fea89103c694a01153ac975961be7ff3d974b9c74de257726bdcc01b257e0e7",9.917710196779964],[15193,"eafaea6140c67bc3115869a2b0da9fa2557cc3fe57773dcb919f8a9cdfaaa47a",9.647446457990116],[2364,"e3d1ba0ef2cf04968f057c3f1637eba8fd3823f6c3c97d1da9bc98846928acf0",9.917710196779964],[18726,"51431e898e965e2e4742475c76c9fa44c21e6811c6d61d0a9b011c8900de6f29",9.472566371681417],[4518,"3d8014bb1727f05cf1d60ca7707c0cc854d0e9b41077650b4ea41cdbd7a83de2",9.917710196779964],[17912,"fa60563de98e8217fe4a999af7220b3f1c75dd6982d5efee0b1a444e1a88093f",9.317957166392093],[6096,"6612c748590619116854cea6b5536035252dc158a52577bbd87315ca13bc6cd8",9.917710196779964],[2360,"adae0d202f7272e762e00c387aa40e87317315886b4e43e2e35d62fe8ea6b1f0",9.317957166392093],[7233,"0b3d4d86e9d788e2b3b8ab200991d8bf9f7776443221c126764d8f3b66df7ad0",26.090592334494772],[16564,"5985959f3e309035fda07221a1ccd8ce44b1befdabdddcb3242e015819d7cd5b",9.647446457990116],[11342,"e8f534738ed974eab8221a2e80c6681a79fa07104a823ec85caf8b165f63b3b5",9.917710196779964],[13860,"5520227404fda8f4671a18d52da8d28b8b3c2e2ec0236321b36d2cf8d2f33398",9.317957166392093],[7677,"5af1e7b6afd97d8691715ff588c9bc0ed771b773d6d2c100e505226dfb22bacd",9.647446457990116],[7179,"a42f128bfb4b788d67f65acebcba889dbc3932dcec9b151f7ef8560832a0d4d0",9.917710196779964],[17768,"843ead855219f24667065c01e77532be294fe043173e7a5675b25ec7b1b7e541",9.317957166392093],[4667,"8f3e9e486995cbd33b9ddf4b89f8212f3aaffe218d5184b44e59c6961d5f33e1",9.917710196779964],[11299,"9319f8bb744d834ff26575d8ab1b2250324a6a39bbda59f2fdc9142f3b6710b6",14.051915945611867],[3653,"bf6f652fbdec270fdcf7a1529c198a998f6f79b61eba665142d8b0ec3239ece7",9.917710196779964],[18417,"2034b8764cddbfff68e1a4517612c506aa3ba3ac78e4297901ef73afdb603233",9.317957166392093],[1097,"558b918dcff2f3ad36b8b7cedd31d1155658176e45dd00b3da057bbae9df94f8",9.317957166392093],[15194,"38fd8f6a57e1d01ae9a123e710a3dbc4b3556371dfe50537cbbd1302b1e1a17a",9.317957166392093],[9701,"46b8eae695c91f787c20bed4f5b462ef0e4c5c3530a2647161f88c42d49a5ec0",9.917710196779964],[19622,"c0fbfe24d878d431584529b475f56c7ba4261c1d48db29c85041a47da167e808",9.317957166392093],[8004,"45e5bf6a82ab3fe25a9a6bf2e1afb81b047cf44ee89ca6b93224b85af74d81cb",9.917710196779964],[14628,"e243780a4269a52e083a737533e89b868d63c6c0482a2993f9b8bb329e9d7886",9.986576933544288],[18146,"261c385f02e85a3a400a02f735be92d544c35b5e4395f298395e4850aaec9439",9.317957166392093],[11618,"55d011e95e01bb32f0e349c5c25edd3a5a41d2d01d6486e80373e0e7b9a8c8b3",9.917710196779964],[2559,"b0e359d474e01f6f4f3d3253e12f2270db026227122346299318d51c88a97fef",9.317957166392093],[8632,"865af64b8193c033325e8e516ed8037be36a93de2f94519ef463c0a8682136c7",9.917710196779964],[17294,"5013c1f0e620d4895e6bc95c203b1e718bf21565529d2ae92027b503434d534c",9.317957166392093],[4146,"7bb5fa23e6b68cd614b075db33cc3fa1d5f11a9caede7614ccbf0eb27f96c1e4",9.51504424778761],[19706,"4e6d2a3f9d50a04fc47cac301106c4df3661e1b555b2d8cf4a99a306e0109506",9.317957166392093],[3530,"b0edbf646a0d1af35c0ecc342426dc6313d9503d086cbc943004712b6baac3e8",9.317957166392093],[18686,"74e1da38eebd7eb45dff3708e900a4544c400cb4b289e2fc477cd56a3e8cee2a",28.89679715302491],[1994,"bd23ddfa93071ba54d36b5e44d5b11f0bfd77d718ceb1dcc8735fb8544c60ef3",9.917710196779964],[16285,"864f11c01e36e7ee747e38304e1e3984e338d5ecfabf23023d85cd44961a8c61",18.185567010309278],[8821,"32d4ff44b91d1fdde26adff1f8261f045d737f1931190cb7e5a8187d3798f7c5",9.917710196779964],[3525,"f7b7b7dcc6e42a21962e566c06cf50fa3ee7b7cedd975697ce38a4e35264c7e8",9.917710196779964],[14525,"8c78fb7d50054f671b28d9d30c5b93d13efcc0d0f85781d27eb869b23583ab88",9.317957166392093],[13717,"e5a41df33f3544cbf5c4b3517130308c5c3ed57fc59a8854c777b458b437049b",32.37202241421651],[3244,"e1bef73a72bcd247f98fd3227a8837cc5e1ddce2ddb1e3c421dbdc518a77b3ea",9.917710196779964],[11796,"2205239e5ae3b59c877b3fa4788178e836075ca6718fb59b67c20e151d53bfb2",9.917710196779964],[5929,"4be7ed10445b00d99c0a943fc70ba3dd99d77968f75626dc686cf21a620080d9",9.917710196779964],[15602,"1bd54aeff90c2154c214799998ab4334c8019a005c60c1b370909642c8836071",10.052724077328646],[11836,"3fdc2b1f1b457cb342930f91e1bf45137dea371ea67cd55816ea2310c2eb80b2",9.917710196779964],[10286,"e34d443af998f78131dfa6563a90b9236617c9bb65fb5d5d967b5be230de79bc",9.917710196779964],[19839,"a412b7301a3ccae5979c0776009bce21c6c43249162e95670bd52e1826f23001",28.087636932707355],[2694,"1faf2c7c8d3f69c44ba0468a05349c5bed7029f404dc22bb81f67200e14f82ee",9.917710196779964],[17256,"8b858b3c1898730c7ad22a9a25f68877e7e6c161a356c8a6474e08108736f44c",9.317957166392093],[400,"692c1ed28ac4150d03d1ea7c5381a1b92eb72db767226be1cc00b9dc3a1a56fd",9.317957166392093],[2437,"98d35e2a1c2caed95aa5ac0722b909783551c3d41e4eb389dafbc44aac353ef0",9.317957166392093],[11383,"86caa50ae00141729517e109a39c025111bd8a7defb0d524dd018d61cc927eb5",9.917710196779964],[2538,"9aaa0a5f0e3833c9ba902640908e07186ec7380309fcdb8341fa4a42180c95ef",9.317957166392093],[1325,"21521f0b5082041e89d1013bb3d38276d88517cf1d701d0c486dd192ba8540f7",9.917710196779964],[16079,"8568da49f957f48c212a7878fcbd16913dc5d53772aac50b168691495b1fb566",9.317957166392093],[6178,"74f68117aa7d5da229cb898076cb5a1b361a8d31869746d0ad48a4a0074cf0d7",9.917710196779964],[6352,"39c50a90b188188a01db29e06135df7cf05554c4fa0f0b7041171395df60aad6",9.317957166392093],[14395,"2e9e1d8b52bb834c627c215ec1aad9dec48836b640d0b3a58b1f1febd28e578b",9.45537757437071],[819,"9c493031f77158c091cd56f096585b8aa63b9f5c7f74276a49e50b0dbd9168fa",9.917710196779964],[2947,"60b8ae36474ece5ffbaf5352991fe481badcc26af8cd0d07c863187a9c35b6ec",9.917710196779964],[2516,"b5db99bc9515494a0bbf614a2e488943908a8cc43af36d8c871a3f14fad2b2ef",9.317957166392093],[18911,"481075150fa4f516b301a47a6f6f980f619adaee9aea01ba984dda1f1c170423",9.317957166392093],[16978,"51dc806446567460117fbc61f4b57f392f091c66b6d4067c2d7ca49db0c98552",34.7773851590106],[18815,"0239841f96eeabd5d74d4e71023059b26778b2a253ca445c676b85e0ce133a26",16.056140350877193],[15268,"2491a98e4c88f64deb3407536aa72100a37ef6758fdc7c2dbcb0d6fd73290079",9.317957166392093],[2427,"7cb255969f14453d9a8be5b802ef7878fc9e7bcff443698994c4b3e970fc49f0",9.317957166392093],[17234,"c579bfa5fd519198284711f1ecce598d5810ab09a50f47b8f7d6c3f8a58b394d",9.317957166392093],[17547,"a5bb8ec6654df609e11b13b25d89c9afb04907007f6ef101bf2fef12d0188e46",9.317957166392093],[1750,"fc49ce059d1449929b8036117ec0fda6c56d9c46e1cf7eb584b5d344c9259df4",9.917710196779964],[4063,"4f978a99ae8e074b66f6e457aefcde482edc8e085a4821533ad081d2a9ee57e5",9.917710196779964],[9866,"ea3b66796539da45f5dba1da4bac0ba29463ec1d9b59808c89c68d9f071823bf",9.917710196779964],[8090,"c875232b0a560fc9daeaa40c89fa4e71a42d00fdff8e6504af0afea97579d3ca",9.917710196779964],[7582,"67744159e1606b008d91b59376ac92977837e7c2bfd3855f48316f4ea25249ce",9.917710196779964],[7592,"2d396df642b2081afe3194f6880096b9b9002879861a25364e01cf4a1a8f3bce",9.917710196779964],[18478,"a6c5a3b462fd782cd284fd26590db5ce7ab5a63caef61d93bc7da255adccf631",9.317957166392093],[13305,"b920cf8cef48ff89a55c38f91dabc2cf13fc2fd6b889e21b299c9f96d0eb76a4",9.317957166392093],[8733,"174c5f13a67af7f7d4f7d9c5323e0822ce7bc9aecb351def6e99ef32e17681c6",9.917710196779964],[3298,"1cca5c7410428199fe3cabfb6c353beebb79a2b271fecd34dfc520b5b52869ea",9.917710196779964],[4307,"8642c8df02d2a06a434b2c173ff3c07609b66da4e5a5c93a7f7104cd3a15b5e3",9.917710196779964],[6568,"93105efeb19e5719780fdf118fbd8bd882d12319e0cbda47b81b04211e01ead4",9.917710196779964],[5518,"e1c51d944b569ee440c2a7f635d209bb31c4b0275c8855d58df6ecdd4adf21dc",9.917710196779964],[17102,"bfd605afb60f5a85090c8225b8f103f08cf20f51e7ce7223895b2adff3f1f44f",9.317957166392093],[7608,"f9aaf821c20e51149720e17de0d23d802ac2e76121a925d9103fd09572f729ce",9.917710196779964],[12516,"e1aa54e087f50a5f4d27ca8683e1a91cd7b172d5e47e558af8060fb5b0dfd8ad",9.917710196779964],[3602,"560b79fc6cde42938a3453adbea5b538d9aaa78041adc3820a66f2ce575433e8",9.917710196779964],[670,"0f94f588274a004d883bfa9b07fa0d29cfe435f15e7626e5fc649b4199f66dfb",9.917710196779964],[17019,"f1f98d2086155c2031a4cd25bdbf808bf477c95e74ea9a4ec0eaa2d7f0b79b51",32.512455516014235],[9782,"039ec663dbfe886a8537833d2eac9c08ce32ed2822968487abf75d240b2ecdbf",9.917710196779964],[18759,"6832a153ad329e26d2ef5bec28126ce21f535e19b48e6888d799719c7a943c28",10.021505376344086],[14446,"bf781100ab1928ea9cfaa9f7a966c82b6e6dd793156aba2228ec62ad5e6f518a",9.317957166392093],[10729,"374ea56a5ffafb2e1b5049af5fbf4432560228a820c4462caa2cc127c339cdb9",9.647446457990116],[3362,"0f9578f5bf5aa4be5acb107e758961820938217e3be8e167786b67b382a3f4e9",9.917710196779964],[14430,"d54d1e09b81c146b18cbc936fd7236fc0cf90e12ddd516ba17b67da2f8e7aa8a",27.24],[10229,"08a35edcd1d26be9f2631c3df9af2684db013e0999b26975943f43f01f87cabc",9.917710196779964],[17353,"1ea47c11a56e379b84426ae230167680d1650990c07be769bb84ca344d4ed24a",9.317957166392093],[18351,"7e85cec3753d01024e9ea98e479ab0f87e993715ff91bbc5b1bb2491e5c9cc34",9.317957166392093],[7162,"aacb88ede6873af8f36b31fd9699e4c9b99d27fc801fed693e7a851537cbf1d0",19.20142602495544],[10889,"214be6e0d9cd6d78cbf97ffdd088e1d866cf7a74a4f7ec97e31c5dc35e3cb8b8",9.317957166392093],[10758,"081884901428baf44f755f1f30b832d220ce0358bd0c1de594b282eaa7e59eb9",9.917710196779964],[230,"c11f085e0ac1710499fa7d242457da647cbbc92bbcdc4d0faa4d0ba2f0ef72fe",9.917710196779964],[11003,"a272983858e6bc3bf7fd415d65c675e806cbc4d02361754a8b5bb322113ef4b7",9.917710196779964],[1836,"bdbc80a30110cb6bef74d899b8aed15429bded601104e9f6fb35e450168606f4",9.917710196779964],[17748,"266f51aeac7ad70fa5afec7403fe960bf5c917dd22dda1142948896cda4e3742",9.317957166392093],[17306,"630e75f4adbbcb2e7ef1e2c546c6e19cb80ed85c3f4e779094dc060a57f1de4b",9.317957166392093],[7637,"4a30b13abfed1a7bf7fefa354dc17f85e3fc89e07f0103ecfbe224b9dc23f9cd",9.917710196779964],[6274,"082b0035a9d98ad08bdf4850418384c12ca445e7cc9dc2c9f5cb420978953fd7",9.917710196779964],[75,"2b4799893daefd47dd21832b174d76aaf6d42e1f7232a17d1f6394f63c4a80ff",9.917710196779964],[8308,"da6e5304dfbb4165828d9fe5ade516b5f5a99e80d0dfc88a339a20799b0547c9",9.917710196779964],[1698,"cb23df60703f5fa3800a69f7d0a5383916350dcbf86492355a882c34a427f1f4",9.917710196779964],[778,"dc43a68fa373feb34de9f5bfb9153c781fcf169167389e2d992614cd68a8abfa",9.317957166392093],[3920,"a7290d7ee700c2cb2b2864f1b0a06069b17873c23083d771b7f9c313bba135e6",9.317957166392093],[5694,"d8b7281d8bc0056a2a333b04f4bad8439da11e6f7953b9572ce1cb01d90d16db",9.917710196779964],[13474,"8e564464f45c63612cea8e61eaec930728b8fc95801a009fcf4e1f7d7d0a8aa0",9.317957166392093],[512,"b00e2c345ab94ff6eccc40f22a8236d19ac11cfa19f4ba317494f142f4a79bfc",9.917710196779964],[19125,"5ea0dcbbe9eeb14fe7594ccd9f5b822275063e12b6658f36b11541fb7510521b",9.317957166392093],[13417,"a25013fc53e4425253738df9a72c668e07942c0b07ae722bee612a72209204a2",15.003322259136212],[12838,"01665d4951fb5f4ad3268a9bcdc2c4f29c99a31e3c8a851cc523af9fa62ab2ab",9.917710196779964],[5474,"02ad6afd9fcf3294a02d600202401d10b5941cebc75e8a3f5afdaa255fdc5fdc",10.052724077328646],[11907,"e24dc01edba6af6a101ab14798887fec9ec285d3d367badc365eb850144bf8b1",9.917710196779964],[15541,"c4cbbee477125cc4e51fcf8d6f56f691d1d22856fe13e0053f9d7cb851fb2973",9.317957166392093],[1313,"42e03a41a27eface802263442160de4fbebb9fe4b937eb23c997e60a83ad53f7",27.151515151515152],[15597,"9115e1ea09d3901ebc3b374ab3e5c03b9856de21f0a84ec66b49714e5c4f6971",9.647446457990116],[969,"1e271d9bddcfa3c08b46504185fc60c6ca8c812de82beaa234a13b86222d63f9",10.03257328990228],[15782,"10cced4dc8900710c2d299e48e0255fc6f0bd090f22d51ca554fd2653b80a36d",9.317957166392093],[12045,"1e250460fc5784c48db5e9ea0ddf198eefd46eb379e33e28c6372e2999f903b1",9.317957166392093],[1063,"9a67cabf6adf1d396620a797d9bc7b43609db2576e75a7824ea1e8c243bcd6f8",9.317957166392093],[10213,"4fc88e16cf6ab09fcd0eecec18ae7e776e98c1d139178a47916dc0f5dbfce1bc",9.917710196779964],[13659,"a16859a5fc1c9d1ab12f62f8a3ac68d8b1c42e67a023f58b896713a3b2f2119c",9.317957166392093],[8716,"a6a0e9e04c7d017ca9f216c996f8ffcd621aa3a49fa5a6babfb9d3a7bf9c98c6",9.917710196779964],[7668,"b483aca4c4ceed3c4b83b7404eca46a1ecb6278a4ccf4c0f40d54cf5aacbcdcd",9.917710196779964],[16425,"b4ad449752ab7316d65ffb896dcfe3281300dab42bf26be11ffb7aab61749f5e",10.052724077328646],[4046,"e1722dff0bc07ec4a6a8fa01354e0ed2510105084347327ca062dbb541aa74e5",9.917710196779964],[989,"4301306a07154733eba46586148491be09a3bb02b4afc64ff95458b6e11c47f9",9.917710196779964],[15176,"5a98d57f9bed15ee16484c32230175d663453c5b4d01c8046dc3f057e9f3017b",9.317957166392093],[12469,"a23dd703f8e77bb96be932d6adcdda69a998b2e7cb844b8b29874449f63e2fae",9.917710196779964],[2791,"d8256c219127de30a01e63dd44ae3a494ba8fb4f6a0bbb439c79fecb761ac9ed",9.917710196779964],[583,"ff568b4cd21a939a6f5d5d5198838baf3767e7e9d88d54f1cc3a292d910708fc",9.917710196779964],[9280,"b7282ce35ccd5c1312c8ac7aa0aafbb93d6770ab36b32ca185a079b72bd6efc2",9.917710196779964],[14931,"7d43992ee48148cafd1fe3077e7e352ed81e380d032c6186bf8a04d8cde72380",9.317957166392093],[5078,"11804fdb1b6c97bfab1f9d2929c383019e6ad5ac8fd754935c8375deb936afde",9.917710196779964],[13111,"d93d4822abfd309428adb37a5ddb3565d70b1f9bf52e382671cfdce94fc8c7a8",14.074866310160427],[6889,"dc2925a868c702e9e59015c2e21abce435478b9daf0fdc4c0ccb087ad60fb2d2",14],[7410,"ff7d0ed737f7a6b6e6c51b1e864d69e0a42d0cad222c4f41105b6c24a0d850cf",9.917710196779964],[18714,"1bcf5ade94975965031f224c7d50746ed81c97c737ce220065fbdf8de0ffc729",9.317957166392093],[11114,"e3506c1c4156c61aa983d4896ecece5a9182401b3460d0bca6bed88f208f2eb7",10.052724077328646],[11487,"95e9f1dda230bfd36e31196216f3f49fe4e0b0bd8864e1b113ec899dcfba98b4",9.917710196779964],[11378,"d93f8a62f7dc5b9abacdc36151a8575df7abfc3f1c6e89a23604ef23e4b288b5",9.917710196779964],[18824,"2b03f1b1910df35808dcee9679b472f5812c99dff7a844f801887c30e978f525",9.647446457990116],[3499,"a4e3794199ca5a280fce335affb9f1c0aa5444f243c13a0ba1f05975acbefee8",9.917710196779964],[16408,"7a45d85bcf064d0c5a26ea9695ce14efa6f5631ab24cee99533c685406e7fc5e",9.317957166392093],[7890,"bed2db35dbf673f2914cbddc7610c5c543ba0e7712f354b12fac7afb123452cc",28.126696832579185],[14898,"24619547cf6fb1cc0c48b5226164deeeab3cc915ba33c736db0e7d3436bbe880",9.317957166392093],[5482,"46ac7816de9a92cfb6a0a806cf7f6bd6d44f6f6a3acc22c5213779e225084fdc",9.917710196779964],[5170,"de03bb079bbb7c1df69d6e2c730ae87646ea4267737673903f0d09846f6226de",9.917710196779964],[10686,"5af1c72e4a5688ee59c1b7829a5a4fe42b9fadb4c8383c89e338e5c8d4fe24ba",9.917710196779964],[7829,"4a874ab5d55a4233e14929cd4f1b3298adee6178e148ea540868a97622d596cc",35.82958579881657],[15913,"a04c61f60f5115add57e34ca73eb957b71a13bf394d19f1c07820482f8c7c36a",9.317957166392093],[14099,"ecb85689a8a2e6707a71c26dca49f0cac9a6a6bc42652a6222b91edc5b6c9392",9.317957166392093],[1825,"ad9850289a545c3a1c82e4b54c0f9bb1c4b76cb63f70c4dd03053d06787412f4",9.917710196779964],[13982,"a1a12eb0d03e60a8072319a0c377f8c67e639462a0ba3df75636cf1622fd4c95",9.317957166392093],[18295,"1decbec18fb61a7cbaa55790cca53bc290a2365c71b5f2669d21b0ae0e13ee35",19.066666666666666],[6337,"a20aa8e9c20fd95f87c2f458723b3f17d987675dec1ace297b4dacf56c4ac1d6",9.917710196779964],[8192,"d7ad91151e103e0d2787e56545a6684e066cf311678942e212fdd5172d0709ca",9.317957166392093],[9017,"e49f497346395cb428a367a5662b2b2e58dd3b5a9beab7c5d5c3e7c2743ea7c4",9.317957166392093],[14036,"4699a92a9a4c422524d5a98e6a981a84f160766ca20edafe15db049f5089ef93",9.647446457990116],[19556,"584f47a82642b6cbc0cf25a2a8f025f781e1846bbf9f7298f80871279d7c690c",10.052724077328646],[1934,"d15854b66515ed957590772edb497bd58f224debdbd480cbcbfac214084375f3",9.917710196779964],[14810,"d032d4c24a689b88446c3c6cde9493fb8b0511ec8d9ecadfbc90897d44c39282",9.317957166392093],[3377,"b858e0ce0eac7c1b6ec4acf78662aa10311467e38f26e4113ed7c8ddd74edce9",9.917710196779964],[9509,"84e0df7e49571af857dcd80699f8071351a5ff5325fb0ec9176685168914a3c1",9.317957166392093],[15893,"ccd8734dfab61bf8ae109ac230fd95bfabeddb46eb509fe41bc4d439b735256b",9.317957166392093],[15183,"87c5214ae0491b9fc92d87659febf1466aba0f0e85928ca3b675d1e28c2ae97a",9.317957166392093],[162,"e39abc2588c3ef48483ffbc417cee3cc6abd028b8fbd5926e1470410862aebfe",9.917710196779964],[12660,"51d7f3c5f66a7506df7c8ff7d26f65ded523ed945a2fe9159acf9353a29fe2ac",9.317957166392093],[6222,"3345351ace0b8ff6cf26c6a955498e175b08e089551f941c1196a24e136d9ad7",9.917710196779964],[14746,"7fa4748aaa0d46769071f8e7c7d059becca2077838d3cd8a8c21691a89e7f683",9.317957166392093],[14604,"2ebca6209ebe9ef3ca7fbc00b6d04150bdaa8bae2a664b8779f894df14d50c87",26.115555555555556],[5506,"6819856ef81de831629c970c27ad693d51fd493b3e631226fbeb1c5dcba72cdc",9.917710196779964],[13120,"c3a78e37384bbfdd91ea32aebb9f477f17040e54a008c551380fa2bea4429fa8",9.317957166392093],[14579,"64b46e94441d2017449d8f86799f718e3e7211f6507c0026f7bc849ddb818487",9.317957166392093],[4831,"9b02834cd36fd48e91ac3768799c2e21b3e83640a8456eff98ac33ce08f33be0",9.917710196779964],[9679,"bbaffc7025b2229a58191980dc48964813e22d5056609435f1257370aac185c0",9.917710196779964],[16368,"a4e866a2aee125a396632e2bdb66488e5e390091d1df25fd75a6744cce0faa5f",9.647446457990116],[7344,"bb678639074e78481e9053d3a4ee4dd8661910ae97da0d82efaf44b74a72bdcf",9.317957166392093],[14372,"a3ad5410cbcca2cf19a57c696f33a6e97e523a69548d6a1f211317dd94dee88b",16.16724738675958],[2446,"abc2c3a7a4baa00a29794630124c545849ec27461c5f01240a70595f909635f0",9.917710196779964],[3202,"bd44d9f3a7bd7d4d5078c192249e11431ff0ad3158c1b8482e1cb28874c909eb",9.917710196779964],[13332,"2d0faff9d4f1faaadb6317bd3249a8fb4e66f8207bcc22a619327f963e0001a4",9.317957166392093],[17301,"29490b0734395c689c81ac9ea839125e8ef398505edd35fee6ec2a8f0cd5034c",9.317957166392093],[8076,"459c7aa9b0cf797fff486c577511e9fb1545962a73f4b42f4c79c47b6a35ebca",9.917710196779964],[7808,"025d1b21eb49579628a7cefb2b0e8db0712d36d605189230f2993f31cdd3bccc",9.917710196779964],[11924,"1939baece8d53511b053605fc7a199209d6980c93083afcdfcb10f4715c5ddb1",9.917710196779964],[2002,"9361a418fa5d2cbab4c7ab852e8f07a63c0852f7426165c0fe6db96640e504f3",9.917710196779964],[1231,"5927596ca4291303594ebc50df5b517d36d906de95718ecf8c959ea81164cff7",9.917710196779964],[4721,"c6c36083c9471ea098fe373321f7880164030e7d91d233b943713d2ef723ebe0",9.317957166392093],[7295,"7339daa7849a1bcac85dadd7a6603970e08114dd16c279a27f45c5c24ab319d0",9.917710196779964],[16213,"c406b5de5ddab6c2a56e50d94b958887913fe35eff026b53f59e15cbffa48463",9.317957166392093],[14010,"15a1e654d729c31377495201627f54c9e6e2078a0cef1cc50c889b5740549394",9.317957166392093],[10738,"66d4110ce14d0e0e4c2010a69c8a93e92db1401b94c1ad9cf3176fa1c307c0b9",9.917710196779964],[4020,"50cac68b1017b0b5d11aac13d2f8c4afbc72f75f8a0ba9e09c0106640b44a0e5",9.344947735191637],[17459,"6b96e078a8109a106b42fcbd16302540cb7462480c9befa11167904058ec9c48",10.014641288433381],[1434,"84b9b7e75d2e207b470a6f605f955ce548a4448fd70ab13eae7a256dc1119cf6",9.917710196779964],[19585,"45529cfdb0fba815f9d17b96963cdacdbd8357e0b66180e83a12c3cda14dcd0a",10.052724077328646],[547,"bf41e803598bf7e89ce9a68c1003b149d1c1eba271e7090caaf1c007282b4cfc",9.917710196779964],[5898,"4c9e9234cdd1d93bde3f49a07a1041e5baf743fb6d589009097a9186f99db8d9",9.317957166392093],[18382,"518328abef51f80e0b0b77bb3613426a8575331ca2948da3e69e6f3d84e8f033",9.317957166392093],[8782,"e578b54417474402474807a63757038f9c443463d9f7f7232934823c0d8c2dc6",9.917710196779964],[3073,"71478a627bb8575d2a2751cc2273cb8e8e1723e3c2f3ae68cf3cb9a1dc1ad3eb",9.917710196779964],[9459,"730a2bf23b251ff82b53ace3d99b0e27ae54d4ede7b4fd306d7d7f60f24af7c1",9.317957166392093],[15087,"87831bc13038ff9d22ce99d80262b6d347580e519a91077338c6dadc7fd8ea7c",9.317957166392093],[19725,"f0dd6ab293b4e0af07927c86da80ff6ca27cb723886b935ff0ecd15280add505",10.052724077328646],[18420,"5db6e43a41ef05066c83e8f7fad8414b7e48f34ff97e2b3167254df358e62433",9.317957166392093],[14354,"ad685e8287793d86452fd66685d3149b6dd8bd7408a3976db64da6a453324a8c",19],[3997,"fd235d4adc1a54b6022b1ea95c9fcd9916e78eb56b65d35c0fddfe892dd2bfe5",9.317957166392093],[18128,"57b9298b1f2c5eca5d9b95da2aa3a3efaaa234fce66a6b5ffa1ad182ecbd473a",9.317957166392093],[5985,"4037602a816ba8cbe88fe0dcd0445e307c4fa131cd80bf07d17ab17353ac2dd9",9.317957166392093],[8233,"f6b74bfc5b6a9587cf5af534fd784193291413f9260f07d99fae9fe1c54dbbc9",9.917710196779964],[5189,"e3aff4c4486ce26d5ba408b80f576ec06abe01f76cccfbc5a280a38ae22d0dde",9.317957166392093],[697,"c3e10891d1e31b3d242acbcae5e3e7ffb73a623e1eacc3476315a9e3a79d43fb",9.917710196779964],[6679,"dde7748822a3a48339f99dea9a78b70e8c8da1f42bef5316960e967a83c41dd4",9.917710196779964],[14418,"5fc69d121eb858615d668d1d712a94fa5546fa54f251088f8ebafcdb31f8f18a",9.317957166392093],[7952,"9436e51528e6f1224f1bd4bacd5051c05237b26e117c43b1bbda6c15cfa7ddcb",9.917710196779964],[17781,"5ccc13f81320e8f28b26239560a4ec65963ca960e9a9737b7b524bb227bfb441",10.052724077328646],[12077,"51acb7cf9650d2e582406a35396d380c742b96a136b261676047cb7deab4d4b0",9.917710196779964],[1944,"3dc4b962cc775263c348f0aa284400a9032a28c1e246626c8cc272cf47cf65f3",10.052724077328646],[3476,"4ba38d170bcb6900d12a81f13f7d6692f1e4fed72cf64fb4c7c022e8854f32e9",9.917710196779964],[19499,"d3f23f029181feeddbac5903895fe560cb9c5e17df96cb2622693bdd0bab5c0e",20.106194690265486],[13774,"125c6959658450066a62078eb4767e3a5f3915ca2b847081cd6287ffd81ce499",25.98428290766208],[552,"980258a3726c67aeb4f5cdf98180e30b07cc72e7b5dd1050187362f64e8244fc",9.917710196779964],[3502,"8fa9af830476d6ef6d3edd14a96b563ebed2f1e7f03f1deb357da1d3adedf7e8",9.917710196779964],[19826,"08e3f575acf42be76a642301c98a66e13a8a572dc486a6a6c0577cadd97bbd01",9.317957166392093],[6202,"cdc11e7febcd1d356d7ec47fd8dba07b9c26e2fd67d38ab1124bd0b826d5bcd7",9.917710196779964],[17705,"32af75684ad4c196f4c81594180c874f81d2668daed693306a96efdc94601d43",9.317957166392093],[511,"5cb36b2018f81acdaf47ecb71e21b58ad3f789c74f3e91f93bb171d0806d9cfc",9.917710196779964],[8304,"02a15fede9dbedd4c9347117637add7772bd2ebf970799716a68d49d3fac4cc9",9.917710196779964],[7700,"7c84ade63ae9f2171610f5a5539b1e59506d80eef5e0d574a9addf033e078dcd",9.917710196779964],[19597,"beb06be877e8b166ff7d286c872af2f94b36545fdd9f85a573e59eafe710260a",9.317957166392093],[12895,"9e48fe579f5f41f4e504e30a6cdadd2aa598a384a8b8ba626e39850baedd54ab",9.917710196779964],[16680,"7a490e2d465d3cd03b2b8cb963d62114bf4726e27680a95de6411230722f0f59",9.317957166392093],[19484,"7374bee7d5561f68f72b8987e36e5f17ca98a945978a69830c172695f3d6f50e",10.052724077328646],[14448,"c56eac9a80d552498f3fe3f4b5c1178cba5d8018839be352dd85507490514f8a",9.317957166392093],[10051,"85946b798fc7fe3427130f5bb4fcdb8bdaf33368600ec1fe8b8f6e4630600abe",9.917710196779964],[16303,"419110fc535c943e18c916cf19381abb179393122afde651b2cd636aeeb30d61",9.317957166392093],[5882,"f683a72783203fda0195375c3da24f40d550ce771c79d95577438b0a9471cbd9",9.917710196779964],[14695,"45a75201dcb88572507b002c1f960cdf5d66c3b4e087662ceafdc3b69a52f184",9.317957166392093],[6410,"405d49e4ff7e1030b2ded262e599cb9904b9d8506c34ad55e282302523d643d6",9.917710196779964],[6806,"974185fd810a165a940debd7423a2d3c69be031a1370f44faef560f1faa239d3",9.917710196779964],[7650,"afe1208ef3c3a5571c95cd09f9f2dc807e32f625e966bb502818b831bd03e2cd",9.917710196779964],[13300,"75a56aae5f8089d7c18d05e0cde4298fb2c13eb1a020e0fb69c9f45e93fe89a4",9.317957166392093],[11495,"5ad6321c14c24f3faae562395a5b217054850726022ebf83fa2eb409239b8cb4",9.333333333333334],[14058,"ff96fe4ced28a3de9530ecf6d11e272e688ca6c2182358397390a783cbe98593",9.317957166392093],[7714,"3fe79e1b5bd079fe606322b4687851a46fd42a722dffa74395751a404eae72cd",9.917710196779964],[9045,"e055d84f9e91c31a331bd280dc9f3a7a884e5ff8e91119342892c9d7c47b7ec4",9.917710196779964],[18594,"ac35e93d63df5f424f9bf2d5fad6f62c08ebf6ed7d30420f948be206fefbff2e",9.317957166392093],[15952,"253f626237b0ac0eb5c3fecd77b0e87d541873d3b2fcc3da838a042ab851e969",9.317957166392093],[9486,"3d31b668f1048d0254d7e441cef77abc3e803379431e2c51ad0de33ddde6c6c1",47.79250720461095],[8594,"36c2797ce3575dd1a56e9cd3b04dba38ab10d8fd932258576984956c28e17ac7",9.917710196779964],[2868,"8a4741037a25e057e56163adbbe4e0e92712e4df783bc93c9fd6c79bf6c64bed",9.917710196779964],[108,"5f8f9e6243b93da00b704877a54084d10cb49c3f343d1dd1cc5a774215bd55ff",9.917710196779964],[6601,"dc2171600d2203ae8e65daee79fe3704347d2b65badfd0bddafbc240c888a3d4",9.917710196779964],[13389,"5d28e5752758529592a26f76ca66c7ac1ec8000eaf2aad0e1fe083619d4d9ea2",10.018281535648995],[15801,"2d1300a5f55c4ed927e1e6389a7cb0af173b3ccf01b8c26c2d48d553bd69616d",9.317957166392093],[13541,"f60878bdc667b89082cb18d98fdb278fee357c114fcb46cacb68eb137871ef9e",9.317957166392093],[3457,"407278431191b6aeb4257270ab4dfc609983ac3d032516fedf1e027ad9f355e9",9.917710196779964],[11303,"d85d6721ca7dde33786f4d438079913698c4924f9a8c3c788a0c4064d59cffb5",9.917710196779964],[12313,"ceff8ff13bf29d0fb04d5d827f0e11cc995355e4b114a4426c45cd45993827af",9.917710196779964],[16091,"46ec7cca7541c2e99bb4bdb7bcb565681f3e4fd5234997106b4c66738e7f6c66",9.317957166392093],[6299,"06c28f63108cf33b4f806530b8916d9ede876d13368b3bd3fae1881b9f5308d7",9.917710196779964],[16095,"cda2806d786c3a0bdb755576486dcb94fa6ffe955c05ea80270b926841af5766",9.317957166392093],[2560,"9a007a12593597748e4ef7e6bda0cdbef469605047b51bf880556127a69c7fef",9.317957166392093],[18421,"a4cc5a768e9c8848bd4bde0c823bc4f495cb6a9f07d14a3ec879422cead62333",9.317957166392093],[13640,"c2760bd4d4b3704e90704536704e35ef916fd476331fcb12d9c90f3a1bb9899c",9.317957166392093],[18455,"35d71d462ebb8924344150bd8e6b65187167255d5266ccd5fa5a74cef0a17d32",34.80504908835905],[1670,"ab1268b9afd41027b8a6e7e3fd094de1b71a4c2b97b7ea795d9fa6096e0820f5",9.317957166392093],[1975,"9d6cbe1aa2f293352d2e36ee764a0e71441b216e54a4a5f1f7f2a0ac5c1b29f3",28.100358422939067],[5844,"aa114ca5ecc0eb8a27deed86a0c595642a5edb268f3a9e0168d71d52ca0d08da",9.317957166392093],[752,"b17fff1b61a7206ccf7d85b96f0ab6f41342f9bc77cc5b5c726cf463dfd5dcfa",9.917710196779964],[16650,"d2d0da14a13dec4a7fea6df83a0673475e8ea47d6b72808076fefc779012c359",9.317957166392093],[19635,"acd7ebdcc4312caa3e8fb8666fe0c97ebfbec395540ea5f06b2559d9ad455508",9.647446457990116],[13822,"93cd69d6a993befe22a5d8edded6774b2370704ee73eb1fa7f4e4fd036d40399",9.317957166392093],[3482,"74caa5251b4f6af6571674fb9c999ef008c5c251ffe6ff1e6df621215ed126e9",9.917710196779964],[14301,"40d300098b49532c19c4890111b8dcfff01f870ec52a29c96af355f50d5a7f8d",9.317957166392093],[6006,"fa7ee33916448f0bc9811ee9baae17ac6360bf33a52fcc4b0d5346c216f108d9",9.317957166392093],[11106,"70f179b065b16173e1c23db94c7a65861093acbba2a0512432127566a22337b7",9.917710196779964],[19286,"149f314646c03cfa804fc75f4a2745b66c22c5a1ac477763a7923e2de1543d15",10.028818443804035],[12861,"814a95aaebac87f37b13cd6f825ce551c6fda5cba3bb73a32fbaec4c915580ab",9.917710196779964],[13040,"d48b927dd269e9e0ae3da276012397ef6a06662b21508c0e012d3811fd9d4faa",9.917710196779964],[14071,"34fa8f075b108941f429e82b58360eee28ce9586639ec08c36051d6843814593",9.317957166392093],[7653,"57ea102e15e7fb2f08196f79beb67e6f7b9c73f5618f2cfbd0abcb7ddfbcdecd",9.317957166392093],[16684,"bb561dd6b9b4e9e67238b922bab3894f8db2328bff5dc665ae56ba720b0cee58",9.317957166392093],[13961,"133a285e5852675894bdbb0d05b7a00fb9374ffbc1cde1fcd787c2d73133cc95",9.317957166392093],[9556,"798925c76ce6421c7e5a08d7eda487c16e1864a65acdbd3b7ce307a471954cc1",9.917710196779964],[11905,"400aa5902d4f158cc1c0c0d9e82a5667a52eba0bb21095cca9a7eb5d870efdb1",9.917710196779964],[19812,"2368c80cd25ac772e5d797e7aeb82b2f0683d7b464e8855d8eb9eefa7d023902",9.647446457990116],[14617,"2a7cc20646c2c996f929fc35f4d22bc63a8687d2462c47bb92e15ccf9628b186",9.317957166392093],[14053,"8bb90ce1cc6732f506285f5bed7d402b4b7a5167bba7c674d0e64ad43980a093",9.317957166392093],[5090,"08bd6e30c1bfbc8fd6cb0a31c77f7c2324c5899da66690be18fc49d462cba2de",9.917710196779964],[3584,"ab5cc010c6d466be4a17d0469cf6194d9852ab6b3a56e76ee46d46de8fca68e8",9.917710196779964],[661,"ddf918e514453dae260bbcb305e6977ed62a7f3307563e1919bdd10e41e882fb",9.317957166392093],[16256,"f312148890756a2d34de8d8ae8324eddb7d9b585190cb25ae281c594dbdf3262",9.317957166392093],[13753,"6a0d162272d560430ad4090f1730dfbb4699fc1081743774e24e2fb83711649a",9.317957166392093],[17637,"625c9975056f3ad278bcb36cdcdc3ae44ccaaf252a25eb547132953acb747e44",9.317957166392093],[395,"018e4606a165c51d53ce51e94f54c92cf0b7dcfd033d974e4255ae2ff55760fd",9.917710196779964],[2135,"8c50f522f1d21d026cd0319060a0a12d6260eb1206fab40950eb28afa1a305f2",9.917710196779964],[13087,"a9f9e890f0d4cfaa19026a97742f4ab19448657721bc7e76d22d14060effc6a9",9.317957166392093],[7202,"89fee6679ff1a474e73791298ad536800db1f8856c58aac2c5ef2aed5d16b3d0",9.917710196779964],[6743,"dbb06f1432aca27e4364fec7edd430091b0bafa0678ff1b036555cf515b5a2d3",9.917710196779964],[6245,"29570ba72e4c332be4ff894bf3e6e3747a82755e1b1f3b7290d85d4caa0d6ed7",9.917710196779964],[19164,"57b0ef5bdac37e8a427b9f8b5a9ef900fc528f1e3fcd046c00a62f3dd5eaea19",10.052724077328646],[2480,"fa5fbd2af2d6650d7451d68c36c75e01e10232acdd131ba76af867f7e6f9fbef",9.917710196779964],[14333,"4256998192f3d32b429866ec9bc52e0460a8938a89c5eef1c7970578f60a9d8c",27.902268760907504],[14831,"814c962ddbb02e2d97d551b1a12c7822f24d009da9b802f4f72bf9afb05b4582",16.169611307420496],[18586,"e8a5d3afe69a3f5943540228d5197ce7af6c450cc5b243b44f5135c062f8422f",25],[19056,"2238fff47accc8f34fd57a138199da1295067e852efa7d006648cc05b3e69d1e",19.54624781849913],[16234,"92576945a5990fa92cdc60bab3d73d846a3cd52eb6fffa51d9189923f86cf562",9.317957166392093],[10777,"b0a07f0b454e7ed5499be0438cefc1b7edd5369f344262cce07fda8274b372b9",9.917710196779964],[9253,"b7d56ec673164072ede3bb0238c71c65e005e9a03f85fb077162a9bd2b6c1fc3",9.317957166392093],[15287,"956448a2d3e31bb3ccd41ffc34fcc5c57343c4af34e42cec144ea080df95a178",15.003322259136212],[19579,"a1e940723ab44707fdf72c20342df361b00b32733dba6bc4ccafd67628b91f0b",255.10204081632654],[13021,"be54ce085f0e16741d62f559dc2136fe7ac25a2801803518e99eacd2ac9671aa",9.917710196779964],[17607,"bb39cfbf0b5d6934acb91c9cd4531c5f1c72c9b180475f230b23ffb57ed3f744",9.765625],[19851,"d859277005148dfb70c576548a476fd5514c77438d0240fa70157121a673c500",9.647446457990116],[15503,"ace13aabe698b60b80e57a8d843a2c731c172894417909b0fd015d2bf09e0874",15.858407079646017],[16325,"a5eb018e5b2b122e92d2ef3a6a4918f9934c8c8197ae34075e9f5c6ac0b09360",9.317957166392093],[7512,"7dd9219010736b9851951e00d80953906634525387d17682db9a6e0eaf91aece",9.917710196779964],[19036,"859f987419448f9f095ca1515f81268d07387d02f328a71a5cc9574bfe77621f",9.317957166392093],[19746,"ae997f775af067e68fd5e0f6f13d52cca053d2b8fe68f9c766b8029f148bef04",9.317957166392093],[5176,"99daa8eb8e9c249e7d4445d069d4a849d28ddc1446afcfb95e0f9e8003921ede",9.317957166392093],[4638,"a494f2764a7e3ba44d781a22c69d34cc1c38e19c4310fb9045cf1772162362e1",9.917710196779964],[10745,"39d3c43cf21a8ab677f8b7eb0a1607d24b1c1f9c20d68679b42f1bf566ffb8b9",9.917710196779964],[10546,"dc4e87e269116fe7eadb38dc6cbe5b0d3d58380336c445b9c8ecb5b633fcefba",9.917710196779964],[16862,"08bf9a927a5dc77b6806affbebf3984d76758402f8dcbe991e58051dea2a0455",9.317957166392093],[4838,"163c5826c04245666bc4d02b2bcdcda477ba3946a428725576feaecea33733e0",9.917710196779964],[6850,"38958513a4c435b087217c91afd631d97640a73eb80f0b6d5950ef2a08bbfad2",9.917710196779964],[9914,"a585ee855793f2bd53ea9d50c8ece3489d951fcdcfb70a68cbeaf5e238bee0be",9.844961240310077],[8688,"0b1e623677eea52b96fb60e09f6166f90df0b25729aad005934021f9a133bfc6",9.917710196779964],[11825,"a1f3d0e63b453bc54da608a5f33c17ca195faa20a5299edac2da382281658cb2",9.917710196779964],[12509,"7f107b3018cb5ff91e323bffe82efcef541ebfd7b94b5068ee7e5462bbfde9ad",9.917710196779964],[13294,"697a26e40407b3b0733a6c7d72469a2981ad5b28911212d3030c1a38313caba4",9.317957166392093],[614,"91a193726f23e69327ee7c272f9cb81758bdb3a1cb3e2205203e2dfe1e56d3fb",9.917710196779964],[9789,"dbb09d184968160900c47ea193fbedccd041ad8d369aa25b5e93d7757eb8bebf",9.917710196779964],[16666,"4f8d0d29516cc44ed1e780335adbfa7162d745813d6c03b514ef95ec10085f59",19.18831168831169],[12412,"d3c7cc9ee3437d4fafb9128754ac93862bde9f31bd1326b8dec733bced1b87ae",9.917710196779964],[7365,"058583b09968c76c1b5d5725d60c2021fcd7d28e3e1972d6bd91e89cc2cda0cf",9.917710196779964],[14219,"1ae2ac92383a8c35b93509de060e0fd541f42dc34480863938f31928abb5ac8f",9.647446457990116],[18997,"da35c4647189ad199e9e58e60ed068a695312ffb60f1d9d7b815668eb6cd9e20",10.052724077328646],[18869,"d87f4b09d00b9cdfb231189abdbc57a0b66b18f091a92c7b93fa5a40f1716b24",14.864253393665159],[7985,"f60e80db3a009cef4fd017c545ba564939c951554eb764333159449cdd7d9bcb",9.917710196779964],[4907,"0a3967c205e0eb80af765aa55fffe9169fc59f692a1e427bf6347f006568d2df",9.317957166392093],[12055,"0225209129b9ea813a55d58fda9eafdf75e60cd36e18b0929d0f5cdcf1faf2b0",9.917710196779964],[4913,"7ac89a06f96e3fbdcc8b840ac032611c1cf2935ab4f89e2db262d0488a19c9df",9.917710196779964],[17866,"0272394939c9571483301019623ba8ada5ecdd61d8b956584d0f434f6fdcd73f",9.392565729827743],[2547,"44528ad2fa026592edd67817e6bcc1a70073330441f95e7a09e8b305f6ee8cef",9.917710196779964],[17586,"0abe9469de54ca1265587c4c87d32abeaa55dce94286e27ddd9602dc0cfd7c45",15],[14111,"93f46f360eab9957aa1cff7694e48ff91afd7883d2fca07cfedbd26d998b5092",37],[16467,"b4433ce1a79f62d00158bafe3adcf39a984619034c6a0e8cece66335eedfeb5d",9.317957166392093],[4287,"ea78c2903948df8068e799ee50f24d7e4a6890dc32fe8b4ccc96540644fed7e3",9.917710196779964],[18384,"c02711e6872e551c0bafaace4d491a6df39a5612504b5db58df610552f2ddc33",9.734306569343065],[569,"862fcc3f2c99b6594d01e3bc7f1a351af0d85c8559f354811d933a80445923fc",9.917710196779964],[13533,"64189ea493c1f957a9ed990651c85592926b086ffea7a65c219ec0a36ad0249f",9.317957166392093],[6143,"ee6928d0a0627bf7d82a991352a602d0bb8338837bc5af4e01b04e66c04f2dd8",9.917710196779964],[221,"cb93c8ade0d2b7c686ef49609039240027ecba1a12537647b64f13bca7ed80fe",9.317957166392093],[5779,"0f83dffb220680c7783b4eea55ed62b39092e7a001366def16680a1dc9a990da",9.917710196779964],[17490,"f7cd7d7234d2920345959119b58d1353bf558cf27fba96f3a7d0b1134279d347",9.317957166392093],[15626,"b998ea553aeb819658bb0112fb0c3589e75295fa1b9b3cb338374d88c119c670",9.317957166392093],[12705,"5a5e9b302884b5730dc781720098ca2002e843d6043467e1931be7f5b2e191ac",9.917710196779964],[2520,"0f7bd86b35585cc271bef3d38a05bf4666a7bc4d9f7e77a4c61d0fa98317aeef",9.317957166392093],[2646,"0a7dc0d5b5bf9d47a9cc19a4cfe343e0127876ebcd461ddfd166441d231cdcee",9.917710196779964],[15975,"c744ae9c6e31f7c3f06a4a7fe3ffa47c08be80106001f91c188be62b575f3769",9.317957166392093],[3247,"630da153a51574ba11fc9dc471c4b83369b661ef87ca0c74526ccf542f53aeea",9.317957166392093],[9896,"65b515f0d219157419dbac727ed038d44c1ea316764534d11688acdcdecef2be",9.317957166392093],[2066,"013e46476493e718ebdd6285932ffa82c713eff32c803e3687747cc9616575f2",9.917710196779964],[8839,"47347caeae52568a910c5a7ed7bd7b1912024142bddb35cf526c534c614ad5c5",9.917710196779964],[2661,"2dfe9f7df32ae3eb10fec5a81125b5dc36fe7b4e57e9bf2c61b2c25d6babcbee",9.917710196779964],[8633,"e68703a5de43ac6865ce2320c4edd6ca6a0b00cf4cfafc9c4969d8bad5cd35c7",9.917710196779964],[16635,"d2f6eb272d6815608e96cb1442986e0c6a2bf2dac7cc5412f7a773a5b32c1e5a",9.317957166392093],[10161,"5aec1551cbaf9823a2913d0e7f46204bdc207445003d1e8050795a47e8235abd",9.917710196779964],[13754,"1aa43d2d72a93e28bf9309035f1cca40963976aa447edbab876fe4ed4594509a",9.317957166392093],[1770,"f3279ff60b86eeaef56be6805dd9b03f823fe13484ed263de9b41cf0d3e278f4",9.917710196779964],[7094,"74e4a39ba6a865436270c3e89765a609b768ede868fd0f4e5f4a4bf96bdc5ed1",9.917710196779964],[3176,"0ca08653b5182401b4be025144ba4ad4206246d76ec2f5277f711d25bee12beb",9.917710196779964],[5021,"1547b7510062cb66ae5389f54a4845f6c8e9f55e54bc749a30294997388e0adf",9.917710196779964],[13009,"e21093343b08dfaa8b028df6c805dd239d61387e5534b9c6ccde4ffc429b88aa",9.917710196779964],[9297,"1ab9d37011eec802183b75694ae3ffdf07a2589beb71440ec2a7d5629f06d7c2",37.936395759717314],[12406,"f38d2c0779ef95abb474f9a9f9eb1c0cfc92303c1670a690bdf355e18a1393ae",9.317957166392093],[1612,"2f06b6d7da3db548b01e900c32136971941277dc6c6c506f42224cd6f0647ff5",9.317957166392093],[10863,"1b46b222a94759f02235ae7bd59dc34d7551ad7a963526c77f1f809fb02ce0b8",9.917710196779964],[17194,"874a1c7126cd2299159de4f2fd24fa42307adaa15488c4d4ea45bd880805d84d",9.647446457990116],[16347,"47d58cf9f029372b69f034a0766d51e18703b7b6830054f22d627941d44f2460",16.056140350877193],[7229,"c0de3056f9a8288201c3b5222c974e8a508391bc2b184cc917e26a11f83c7ed0",9.917710196779964],[12102,"96122297e42a241996e60ddff5382059f6f30e1208c2fe752a14e212c903b1b0",9.917710196779964],[2258,"862142190442d3f52efe94598998da7d47e516d56b5d4024f6b87cddab0c35f1",9.917710196779964],[17123,"88d14a6a7af4768d48348060c3764bd741cd8db70c81224be7cfc438abbb794f",9.317957166392093],[19620,"2abbbd7c6aad80cb5849cd983f66b63e499342250187dede321a9a3ab2dcff08",10.030959752321982],[19230,"ec8ff091963c6c857638dd6e8b79d1fe0c9284329a3b2347f4f4ba9a3a3ab117",10.052724077328646],[6516,"e5eff9a9db8a5874d613ed42a230785d5f46639dd29f5f5afac6b0a808c94ad5",9.317957166392093],[18734,"5b5030d41eff64d5278699754457096a037d9a2af086baa2fdb39e460a113829",31.401360544217688],[7124,"45e9ba09f4f55dc0209a25370868a18e507e41bd20e9640323d745f9e7fe2bd1",9.917710196779964],[15586,"dd2c70d6f0819c3a5ac59ad51c668ddd0bf3a90f9c084fb36d5cf28b8ba89671",9.317957166392093],[16609,"3b39bbc22cb85e69bbf8e732dfcbb35e6ca946daa9880be996da926f1697a25a",9.317957166392093],[9676,"e2d81b07f3e55b3143f109c8a3502c0db03bdcda00b2f91d379321432c278cc0",18.174843231279972],[1053,"5008b495d83ec439a4c777f26a001ed46774380bf7280f62f2e11d68aee0ecf8",9.317957166392093],[12540,"7dfa62861fd93a5e7ad4d4cd354bffdeef0cdc4f1eb6f6e77971796ad53baead",9.497392881432782],[8841,"b96a3259165d48dbd940e3699c5aabc9442a850696a1e1e677661cca37dfd2c5",9.917710196779964],[14536,"120e59b84e5e4912bc842bff13999e533d26cd50e7c4ff801d38dc8088dc8488",9.647446457990116],[15603,"3eaa35541c5c18848390d7cb74f50d399a5bcb85283c2d9cfc25765615465b71",9.317957166392093],[15862,"7879178dcb1339242f67133bf346b337b7dc747fdecfb0457219389daa89ee6b",9.317957166392093],[15428,"e34585399b57196b2bf25ddbf6a66759da4c1f74250efea848891c56e33aa975",9.317957166392093],[2619,"902687ee8865e14de683c845183975f96e11d2d111f7db2f5d00dd195f830fef",9.917710196779964],[7283,"d41f9824e9a9a77ba5a92c44cd69618a3753a1f80300f085d064737bf1bc28d0",9.317957166392093],[4647,"ca9dced559d1ed1e28a956a57f6fba46bf225a4076d6c11512fc0e0de8c055e1",9.917710196779964],[1501,"224e97a9112474829b9ad2a50ab3eae5ad388ab5d11e0ed29ea43b93b2d41df6",9.917710196779964],[3509,"e4b35b4005227609540c20ec689ab95da27dc3e43ca683ac6cc9295f3715ede8",28.955436720142604],[17117,"38d967e365cb1fb6e4c562e7b829c034a7e8dc7a8b4beb6394787ca77b2aa04f",9.317957166392093],[14444,"23297bc90380398ef8db3ffb1ce8fbf806534319c9a80f8de8f91c6ebc145b8a",9.317957166392093],[11959,"608c6212e82d74cf25a34a59dc2579b88afe0db114dc8a591c938e35e69d99b1",9.917710196779964],[19171,"b4ef6716a73b8d8a40727cf171594575184691748046decddfe3212c5c92be19",20.49846782431052],[622,"3e07e65ed762bb29b92e1c551c3f0bfb591aec59b977b01afe8f673aac84c6fb",14.375545851528384],[6318,"f742da6d8422e99ee2d653914d6ddec469f5065bc8e8720d629f418f2a83e3d6",9.917710196779964],[127,"0c4cf3aeb9f202e0242b5507490f81faaa6160df670f2ac029473688e7ed2fff",9.917710196779964],[7428,"154dfa1d044582271b42a6d963dbb9fe6247d406848102d810528955596133cf",9.917710196779964],[3112,"e2757cce52ba18ccf944216b8863a0f6f84597a424a96a408312ee9a9ebe96eb",9.317957166392093],[12522,"84d0ca5228e01ca01345f34691fb97be91e7f73eae92f0d633435b8ff5c3cfad",9.917710196779964],[11858,"3e900fec0d982d9115071458e4977d9426a7e66657bf5cd8327da3dffde253b2",9.917710196779964],[12618,"19e3475bd2b978026dda627f370f0980298adf85060d1c3c09c519cebbac25ad",9.317957166392093],[16346,"58cc6a0a41fea2cbb537fa8138fa2d945e5642e88687ce094e45658171882460",9.317957166392093],[8520,"80612adfec92d9cacd598356d25b19fd98a7a3d2cbfc875e0d4d5b6f246ae8c7",9.917710196779964],[10582,"8ae37c202a33473c382d6df44ae56bd014f12850ef7087af5185a50b555ebcba",9.917710196779964],[8065,"660b02857fa9f88f4941ede6d28fa0274ad648162975092aae422e8066d200cb",9.917710196779964],[14533,"f5683cbb600835d4698712078d10b739b4df95fb0b39defc4256a87d8b388b88",9.317957166392093],[10263,"804af796e459559a6c8af7d37cff5f1de3a70ab21d05e920709fd66f48dea0bc",9.917710196779964],[18488,"b64040d0cf1f22d74b54694811feeae30504b762ebfd8469136973fd774aac31",9.317957166392093],[4244,"df219e11f8701f804aef48c7d4e335ae147b49cdd503f84b62942b50874e29e4",9.917710196779964],[15461,"c4084f4dd3c6e45ea4c36dcafbe426450e1af6544d2daef05f9934e91455fc74",9.317957166392093],[8391,"98be5813129635420979b362a6fd35d658ee881645dd6d27211f17899924a7c8",9.917710196779964],[15722,"237b3e023ee6db7095e9a9b0ecda6bdfe11ebd54f94f218d9b2a7c68cf310a6f",9.317957166392093],[16639,"36d54e83cd0f7f0734e78eab66206b7ce66a7ec4fb98557cf7b4be32a06f075a",9.317957166392093],[19204,"c0e486878864a75571bbc4f4fad9e5abc8705519f0f933fdb6cc0e0bfe147e18",9.317957166392093],[12445,"8074b888c8af96c28e54920313cdf240a5a485cedc89ebb9e4a2a78a53e44cae",9.917710196779964],[8184,"26d14abc9634025cf68ba08caf13008e04fd3132bd423f4d012ed1ded9ee17ca",9.917710196779964],[18145,"154ad2219858e1c452665abb424f94fe7371381f7687ef699ba4426e0c87a239",9.317957166392093],[13938,"54b66ecb743e16c3a38eafe1aee0dca656ffdb18eaf2a928285a76b895323796",9.317957166392093],[6587,"3586e3b40c678dda1f0e0387d29f44611d760739124bffc11aad902dc862bad4",9.917710196779964],[9052,"c52ac139f27f843bdb4bd023c33376145b509f6f01630c9606a224a2a2a672c4",9.917710196779964],[189,"6ca4bc9a24f24f61f2b4bc2db54d6881c2e37c62c3e8c5733ffc2f6c4af5c1fe",9.917710196779964],[1461,"094ba47efc3a80e3bcc19af3842cba865999c9edf3c277fac43234c0080b6ef6",9.917710196779964],[1041,"717fdd63f2906727683c0ef82abbd6a81475e24f70c523622ed6c679b35108f9",9.917710196779964],[6622,"3955bba2a18a6ad764e3f9226f217aa8b611d8f26c3d47675d003443502281d4",9.917710196779964],[783,"de7fe540b68b3dfc10eeab25eef10ef764fff647c35263ffd2796fc2d9a2a2fa",9.917710196779964],[2581,"07e5f4cbe8171563b00385220fe03af4c6023414cc5c6f692241dc3a144f4aef",9.917710196779964],[3336,"c4539ae552cd2461fd61940444bc3435885ba5410826884ad4894fece91f17ea",9.317957166392093],[10792,"dbef96569a4d65bf2bde715e23bee30c92c7bf385a03e5e3ec5b439e584258b9",9.917710196779964],[18802,"9d3740a98febb6e03f4776481319fa0268647fde1a7ee38c1e50cb432d78d726",9.317957166392093],[9908,"10e767f24f0bba7b1c8ba8395daaf3b7de08fd02fd8861ea198ef85bef1ce3be",9.917710196779964],[13548,"1a30320a51120065123f3739cacc1760e861fe06a9c07df462193260f191cc9e",9.317957166392093],[16248,"10ca3ee5987f97bfa97c53a6bda216df6ce6f527e27a80d8684a913c2ddd7d62",9.317957166392093],[9365,"0317a7393dfc714456c3d286a8c0beb5034b2d212c6237c51c7e46c2f95474c2",9.917710196779964],[15765,"b5132a644c81181a84b05208e1bc55724961919a7da15c0c8ae304381953176e",9.317957166392093],[18538,"1868c329745ba063a199a22f21c599ceae1315cd31ca07e40b68f91ea5c7bb30",9.317957166392093],[13276,"a57d36e3cecc7a2bb386bf8e9bdc163c1aac80214587a50d6521bd8de0a61fa5",9.317957166392093],[8523,"931ed2202e6415a9319da905d195cb21202baf2271e0da8d77388413403ee2c7",9.917710196779964],[13868,"c77e93edab22cac0c5aa154c10d1b8e8f83afe020b9186d7c06d3bd4a7dcef97",9.317957166392093],[7520,"7a174170ec16a058db40d59ea60eb03d57d95c679936a78bc0d90739a488a3ce",9.647446457990116],[5383,"3c25c643c0d198e9191d13095a359a8061478d627f76b79185158526ccd4eddc",9.917710196779964],[3115,"e4613f00090164880b890cfa06074c919849beed0e220cc3f97af935d1508ceb",9.917710196779964],[12046,"43f12ca98eda23a7e925ec8d0c5ee9cf3157ceb76f17fc56190ee58bfc1402b1",9.917710196779964],[4513,"0372d8fd9e18bf4043ab3b10db94b578770f7c010dcbdf8a3108fe75f5bc47e2",9.917710196779964],[4542,"fc62becc66d115633263f0c0701aaba8b3f2d02c2588d90fae3effb670d814e2",9.917710196779964],[13852,"763aac192534bf47834e4ee1dfc5f11bb920aea81ab52a0346c093e76bcb5998",9.317957166392093],[14141,"c06612ee5183e3d341ff3c4dd44a074185c916c381baa1bb5bc0f176868bae91",9.317957166392093],[18626,"61a2bd7fc9cdbe5345eb002c9a2653660ed921a5e5c309b8381444aa29e8f62d",27.36474694589878],[6453,"ed965e3d399b8d7bd9b59cd8a9c027ab0bbe1058932322b346efbd25e108e0d5",9.917710196779964],[962,"9bae0ebc4554585c37aa8d5efcf2ad4649dee19829916b188b1e5e62ee2b6df9",9.917710196779964],[13924,"965cb1225cd7ead5439fdbe9bf68ff9d9c0d3ac23cd54b38ca59b0a005e77296",9.647446457990116],[993,"958ec5afeb755f072a95c3c4884fa96d698149e082c8fe169c04554d180744f9",9.917710196779964],[10218,"8a4214674b5c9032002fafd2638018d674a963dda08bbefa3e73128916fcd9bc",9.917710196779964],[3683,"c5e177049dac6d0135e927c55919b2efb857de8fdea026fbb1ad60fa3356b7e7",9.917710196779964],[17829,"a2ce4cb9480d64b50b20f5080906a92ef27ef8448c795237067cfdd15df0b140",9.317957166392093],[7767,"316dde70c40d059c34399cb4edcb34550352e575b8d90c11bd1f469a11250acd",9.917710196779964],[9016,"d72cb92607de615028b8aec8b5ef50d543e33d5bead06906763b50aacd07a8c4",9.917710196779964],[2841,"e3bb326abe873560db2abacfd037ceb764422b36c90640faae6c9077d56066ed",9.917710196779964],[585,"f841493e23338c8d2bb718d930e2d4c8b3876336e77a6752b4ce5486cebb04fc",26.945754047145698],[18608,"2ee5175b0fb04b2a003f0fe1905b1cefd835bf0d914a9940d34b8bc219cc612e",9.317957166392093],[983,"f86ff602dbc270b9bb5a8b368440b789c055c1f44cf13f336dd6adc9e45b4ef9",9.317957166392093],[15753,"319b3dee70c8536d6523bc5cd54ea435b22479e146d3b516b1eedead53ed516e",9.317957166392093],[1301,"17de019ba62572ed8ed099796be03d90aa9dc74f5fbce6970309e119891360f7",10.052724077328646],[17929,"0ea4b0ca198407c3c482b3210e0aea5202d2268e0e8e89cb7fcb7cc89ab0b03e",9.317957166392093],[2557,"e70b33866b6651eb5e69f82b93aadeeb023230499ef6e427464fcb2f343880ef",9.317957166392093],[4556,"6d8797fcd09bed498648e3c957e438738c35f7b2031c9dc137d439df8a8fede1",9.917710196779964],[17896,"bf918837ee2194b6333e0e91b3b437bbb5c3070c3ab502a788e45ba8bf013a3f",37.16444444444444],[8422,"6c3a53462557492efc2f73c116a4da2f61b4178262cbc3adf7c06540601b7ac8",9.917710196779964],[9870,"47750f39a2ed18ea662cc725145b35d926900b48cfe70a1704a9896297711cbf",9.917710196779964],[11557,"ab1eb0d1586f685876972631036cfa3f310404ec9091447c771e847c901a32b4",9.917710196779964],[320,"e9f129844978baebe5e8680061af6c42fd519419054ac7b74e9a7b27c0e4e3fd",9.917710196779964],[18261,"b631c9d212b7e60c6171f798c600c82946f0deed501ad424d0c86067de2dca36",9.647446457990116],[12014,"db5eb01d82cf0ec3c03a5a662f528ea02119205c33600225ea61d9603da33db1",9.317957166392093],[14421,"b22fdf4653eee57b0b58d8fd332ba2902bfe103486404f9146948a8c6c3adc8a",16],[2921,"67ca07b94248ed312300f57860022368e89dd906c2de6256baeb9c60b7a6ecec",9.917710196779964],[17341,"1e47018e9cab44ceedf3db7023b9f6c5be1e38508020809b9e39c4d196ec144b",9.647446457990116],[8669,"b39ce04ed228fce2fefb8be7275e57e9f0ae17525ad97635eb2ecb35d596dcc6",9.917710196779964],[7206,"cdfa14da10c5275aab4854b58a4ed621d3830436db1fb3c82a872e4535d8a9d0",9.917710196779964],[10668,"abebf4578c174b58d5e7c55670f15a0237be55d09f1da7d69b12bc1c306d3dba",9.917710196779964],[2059,"f4b122c1d0573c40fc4ad71496344d3779b0bf62376a3c042903b7a71da483f2",9.917710196779964],[7847,"2c01d635151443fcf4992e812b63b0aafac05532b18c153d8003c07e544383cc",9.917710196779964],[18630,"7a78113bf95c10ebb7b2a4820dba940761c3a888403b095572cf5af73cb1872d",9.317957166392093],[17354,"9eefc5ba0248ce731f23f6ca269fec619264f5548aa39a9f5b45af207f25d24a",10.052724077328646],[18412,"5442e866ed1ba3f14e16b5d03916db293eef6fa2df7955afcac1b4dd8dce3933",9.317957166392093],[5923,"e668de510aacc0c312004fc23c88636dc4debf51c56405af819fd5533c7e89d9",9.917710196779964],[18002,"ea57f1103d3e40e3148b913d91b8eefc38539588d63c702714aa749263ed3b3d",9.647446457990116],[14469,"4b1d9b309d44dec95196df99283c739f53e509d7f06dea763ccf39d2f468e689",10],[14662,"21fa1d47c2577eb92323068bfcc207469c3d43bbcb3a1ca3ea9621b660d8ad85",9.647446457990116],[14272,"096f0695dcc069b4f05871d6c7d8753eed9bd673ca9a6c4199d520ea8fd17c8e",9.317957166392093],[14379,"1e621fd815b5765dd89017307e5e912ed87479ba05b341a654c99883f7e8c68b",9.317957166392093],[15983,"e4b3e5631eaaa47a3776ff714a7f79c67ff989d23551153920521649be0ee668",9.317957166392093],[12928,"e2168a77db683a2f40dd18741fdc31e3096bb59a431a689bb2163c7def6818ab",9.917710196779964],[15083,"fbbaba15ca63cb08f9a953acbb48dc62598e6c96a25e3f025df46cce65f4fc7c",10.043290043290042],[6614,"002362babdb40137fa450b013c56cd707c51f638fa28bcf2e0f35fb4d81c8dd4",9.917710196779964],[15201,"2b30ce2f384a13263bbf34dbf7685a22bec569efee638e1a5a567c9d3a84837a",9.317957166392093],[15668,"7d69c442c92d74c3a40501e01a4847e1612b5d90386a2d1244119b9781390e70",9.317957166392093],[9319,"f4f13055e7d4c1760ce7269a40dcbcab65117ec3a242c99fb964d8595fb0c1c2",9.917710196779964],[17269,"170b93cf99165466500f42bcc761f5d0f518e0cc3143d2c6ffcc35e3086ecf4c",9.317957166392093],[8642,"68ab447d5bfdb68dbf8870a0b8c8bcf8146192cc0863aed300d0221846981fc7",9.917710196779964],[18395,"e6fb66a36f1f0abf6a73c5c7c21b0452a1d6d2830db989d2ba3dafe229218533",9.317957166392093],[3389,"cdc01aa49e91cd959d0d8f3f9035a5ae928619d3c4627e4f317cd780ef24c6e9",9.317957166392093],[8514,"001ea0142756cfc07d313a5d9dccf6bb9ed6258b45a50378b54199bcdc88f7c7",9.917710196779964],[3968,"f027cb318d7a1e66f401df7e2e854aff98f9ce32edebdc76c4d9077fb0f5ebe5",9.317957166392093],[4982,"26c8bfd60825cd92b1e82e281622f3658949dfe68aebaea8fb53f6a346654edf",9.917710196779964],[17398,"10e84ff0a434d3ed60f70f2cea8ab51b7504dd7ac65dcce87cb66d87e247cb49",9.317957166392093],[16841,"13fb02b76136588259a9a2710ff647e6c543b54ce6d003c586e01a01c4597955",9.647446457990116],[2904,"df6a9a0cadf4b024b2ab85b5c5ce24328d75cc988abd148135f3b5fa3ac617ed",9.917710196779964],[6624,"92463f158c28019e7242f1619bd61ad7dfb372849c8209507330e7b15fe77cd4",9.917710196779964],[15517,"224b785c507d27141e22f5c2322887d7caced1ebabe0d21e16d79ccd72beb873",9.317957166392093],[13732,"336eb0bd71892f171f2a67042a1495cda1b4929b3cdccb207790ad1daf80cc9a",9.317957166392093],[19717,"ab1458ae6778458c1ffb344f1c1eec2f82af7d3a008d0932b25a7a1001242006",20],[5976,"82297228a2a61c554e265a3bf8f03a7184f2ef8f877704451b36f8397d363bd9",9.317957166392093],[8481,"e3ccdf18409050f3fe4a78cbf210bf2f4da691104854449e0bc4cc9a47f420c8",28.124444444444446],[10244,"2c944510c63610cf53faa32695afdc3bff0dfb83c9f137764f388c4dfb4ebabc",9.917710196779964],[14513,"83cce505d17ab5f70b29bbd93deb26b03dfd39826c9e1995c0ca75574963e288",9.647446457990116],[3032,"462b1775f7e24462135d8332a679083a2f29a3c8a0d0884b101dd633514219ec",28.43979057591623],[18350,"805aca4eb1d2c2c4fa7fa749411bb6ac404a17c3ded3b964e5b0773d6b82ce34",9.317957166392093],[7661,"a0b3dde422f429564f6a2d8b90c262ec7cf54dd625f6efb495f94b37151fd5cd",9.917710196779964],[18132,"89facbf879d6f6a19af18061a0d797bb011731fbba8c96c90d8deb97666e1c3a",9.317957166392093],[3157,"4ad9558a9442a00395f528322e866040244e2c8a1f394eda375b7217625d54eb",9.917710196779964],[18778,"b6f4bb5021980064169d0295c0e63fd436fd8082060e3b733eba4b1b6aded127",27.571428571428573],[11362,"e72dad784c455bb0135dd3c4c308e63b7e3baaa477761f2daf7fac2730819bb5",9.917710196779964],[8990,"b8f19883365b6aa21982838ad568253191a843809e0dba4affd5931f5fe9d1c4",9.917710196779964],[2422,"47bb7cfeaa90f5d7dfaca9198693967e8349f3e05e92e7cbfa2a989ed0d154f0",9.917710196779964],[8024,"0c9c35df6b8c9858bf2468c7957a32cd30c1c3051a26c7654ad28213083b67cb",9.917710196779964],[1218,"a37bae53bb75c7ba119e1ef1a895bd98045d2c923736b170b5d3cf902c0ce5f7",9.917710196779964],[10517,"f8f2d14f06f9648c60ad67731df49bad7e74a1e6cd9f1f96f5b0b69d767617bb",9.917710196779964],[14856,"c29f18c595c6498d9b64a42501deba4d0e52e05081815039fd2486c97307a681",9.317957166392093],[18960,"081a462fbfb2c260c3bf5b763b42b390991425161b2839ac4617edfbf97bbf21",9.317957166392093],[6101,"5f7041c631d101bacb9270bd6c53a95f3d475cd9683ff7254128e7b59ae069d8",9.917710196779964],[3016,"0f8dae45b1a8455f06efa29ba06db9ffd6419fcdebb452f2be3c2b7a92f929ec",9.317957166392093],[11667,"a7cc6baefb864758e497b40fdbadad54c6d0ba6fe4d0556bb666aec8ff707ab3",9.317957166392093],[8485,"4a60be4e1369a8256554ab304496317cd8bf9fc0ceb328ff7b21309a926a1bc8",9.917710196779964],[11542,"55c1a76f8c49212c280ed344dfe11342678bbe62365a206e37457d8e473445b4",9.917710196779964],[15863,"07a96de22b31a2a33621e013ebe2f72d1f522549ba9f549c69a8f62c3a9ccf6b",9.317957166392093],[3654,"e6cf356ee6b7fda3072709645a1565e012b32a792c82bb15cdc4fb693114e8e7",9.917710196779964],[4531,"055b552ba1145b4e9ecb1a1646009f5e66de2491d6c2239d2a584d5beb3f29e2",9.317957166392093],[2068,"cb6597063c3ab7761e56e802e93c7b979fbc7cd09b07b9ee0794741e7afe72f2",9.917710196779964],[9967,"2ed8e546b3190ed6da3de091e89646ff9a8786edd2a402a0e7bacfe84e8584be",9.917710196779964],[19601,"7c03fd73a2573424b948b85d937a78cd27a45402f801b67f04db0ac7bf280c0a",46.848072562358276],[17400,"81ef7840a09028c155de6f406e89d2ebc25c871b96794d0da85f5dd4b3f3c349",9.317957166392093],[4406,"fb4a01d8b6693155724937a96505447edbaa1aad3749b9399b0f6054575b09e3",9.917710196779964],[384,"57d3a8ccd0dbd57feae64f5393fc21a705fe55ae8589e5aaeeeb03a0c87875fd",9.317957166392093],[18342,"71c035ce85bc9ad334b17b8447062059878a341c82f4c01759f32dc37103f034",9.317957166392093],[1433,"95bbf7f538a1d581e3e983911c8a5c4a7e2a0d7111e6263e71d85179a0249ef6",9.917710196779964],[13694,"82bdc1cb727ec1fdaea9b047ff165a174ec1bcd6266612e74342623b9f21579b",9.317957166392093],[15886,"3edb91bb6aeb2180cf746194c5b7b97a89b8a0e0eedf0a5c64885393d23a416b",9.317957166392093],[13419,"67ea075f515547a726264fce6c20a18edc7769fd79d472dbe3b17eaa44b700a2",9.317957166392093],[10101,"764c39b696ea3ee82afd90276bbfa4b471f48fc3a7eb5c06330393600b49aebd",9.917710196779964],[14207,"310d59e32dd7a705c983b9ffc356d196a302374cf5f16969d8da427de7f51690",9.317957166392093],[6476,"8c1fdb32395d565714813564e33a1b30afcf05862315d8aa14355f3a582d9ed5",9.317957166392093],[17732,"b770bdcf129033c06a122c8085c665cd0fc7f822851ef9dc0069b9448a509f42",9.647446457990116],[19390,"a66a6d18320fbe23e567fb9dfcada6668709fa1a98d42c2486c7113b51213212",9.317957166392093],[16252,"a8902d9b0b249fee3330fd19117cb9f31f39556d5ab86e5f3342f54a390c4362",9.317957166392093],[7549,"337b52dd3d5ae874c82821f53ad609b1c8cf0a72dab3273459229522a0bd83ce",9.917710196779964],[227,"7fdd72569dff432c2a7b76355535bd03f5b01192632302b0a966c48f20e573fe",9.917710196779964],[13385,"a606b198193e2e222f891be5f0ade1bce8f037c69f16594694ef706212dcb3a2",9.317957166392093],[9651,"e99a2d18c5864071bfb53ea9c4e20079d91a2b3552bee1769da3363d513eb4c0",9.317957166392093],[9129,"5e6d1ac6fb4b58b8b77e5f2969745d0bf112f5c27e343b8f40e638ee28a2f0c3",9.917710196779964],[12781,"c0263ce030f3368da41542c8675dac461d642b6ea729c7f1c969c637ba0909ac",9.917710196779964],[6506,"0761b2b8fecaf7d2cb06343d35c59b24a736e29ab506c40099e6e5e1261f66d5",9.917710196779964],[11731,"ee0d26351ed807f326c8c828491e9cc8868c5af4f3bb5bfd59c6189c5cb717b3",10.052724077328646],[2187,"fd84ce2b46af978ae22cdfec867cc2d380f66e32e7eb8f4670b7a94a3763a5f1",9.917710196779964],[8149,"0eee383412f4233f0c09a829b6159238173d624df62f77a4ef6dc40c7feb5fca",10.052724077328646],[12270,"18db9e7fcbd8b4fd1b1492c7701fe0286808ab7b470901431328e57dde9586af",9.917710196779964],[8608,"a944fa00e80ddb31c702e140c5e6d84d82363d646b94eed922e8c46ebc5860c7",9.317957166392093],[12881,"5d2dd58563af7c490243e807d03cff36d1453550449605a7c0a36ae2a95d67ab",9.917710196779964],[13737,"70ae81c728365ed678c6d75db8c38058b0977a0235f94bdc7aebf43f5429c39a",9.317957166392093],[19218,"77a237d21685d265c38210990b6d4582fb19559cf2ce2221df255d4c78641018",9.317957166392093],[16654,"c3c9a8a67424b02085a717d14664b543cef8c6aeee2b9e7c9f01d5e563f7a859",9.317957166392093],[7633,"ea525f17e8d2db5d9412da1781701698acbea87fb63a170b5a25ca0a4769fecd",9.917710196779964],[10209,"a2b6fe39fff39125649585a2d3f0e9b64377b8451b7d9c259d4132d43bc4ecbc",9.317957166392093],[11134,"352904e3b84efa09b050c80b25b8fade796e231419623b415bc554fc0c1210b7",9.917710196779964],[2671,"7e7ae0550c6e47dfd8adab122f62e586bdb41ef598ccd2978622eb42ab60afee",9.917710196779964],[7232,"cc44514de33b750599508fe01cd7cf5aee48bad6b215d787a0be2d9d20c17cd0",9.317957166392093],[9457,"1d474c981ccb8f8d8484fe4b570d77b87c88520773897ba55d908bb57aadfbc1",9.317957166392093],[16126,"ee0f7e7060ab4fa009f78140d63016e5f836395b1b7fa1db51ad177d7f1e7165",17],[15941,"0dc7e8356b3c7063ab1c759d50a4ca7142471867366edc2c39372dabdd161e6a",9.317957166392093],[16191,"0340dab22f1195e78c62ec08f2f883ee1b822576856ba5254d80deffbed02864",9.317957166392093],[1662,"2e00edcfadcdc0f0463cd514188e440be6818b3519ff2251efd8d1a3ab872af5",9.917710196779964],[12240,"9c6c49f667ae9e68930288314910ab68dace4a976dd1b0973cd2c483735cbcaf",9.917710196779964],[5053,"672b268a424e4db6a8d0c73fdaab563db5ea252317fe2e5e257a8986635adade",9.317957166392093],[9888,"ebd0f26939319fd37f98ec05531ea9ff94843eab723227e200fc7816ff0d00bf",9.917710196779964],[6559,"53cc008addfb5e195a33f2b23c5fcf29592f08c97ef5f8c40d37316e3659f8d4",9.917710196779964],[17540,"ea9531e488abc23b391be99f39a0c6952923513a28e9af30b33982b897c0bb46",12.011288805268109],[14801,"1739b23a20406a8a2fe77d509bdb2e0df93d42a9b24bbbbe9c6eec2219c0d982",9.317957166392093],[14880,"b692ab252520ec5e4ac05e274b6607b45ce9676644c8b35723dadd905bf32b81",9.647446457990116],[5663,"f9285af1d8f7c154b3f602d05fcdf91eb6e47f26246b18e95c5cbba0bf813fdb",9.317957166392093],[16930,"2333783bf35e8a906f0d696f621b75ca5775667d2fc12a76711164ffe28a7a53",9.317957166392093],[1176,"6a5a16e21497ecb862095df2c6ea925f039afc2b87d4541b60b46528e30e24f8",9.317957166392093],[7969,"c40be68f04dac0a1138b4631195b4db3fad0ac3a4d4566c89e64bcc25975c0cb",9.917710196779964],[1087,"e2f1defc5fae4252c491d4c40de7353c6f011692681980c753fc09d5cfe7a8f8",9.917710196779964],[14398,"73f877c0a6b10c1b6d5e206f6b1496426e4755202ccc441e70c9612f0a324c8b",9.647446457990116],[10731,"a71b3e02612cf7caee5582b549b6b6e6fbd57c0cf4511338e82fe0bfdd47cab9",9.917710196779964],[12367,"022c99d45ad601e9b4a72da617b879fdabedf902e7ad0e89f32c901d94f1d0ae",9.317957166392093],[9011,"0a20b94780ce7a6d471ab4a2ab9e1a084019883e2a530660b817fc021eb2bdc4",9.917710196779964],[13629,"c4c8e9820e69b09a4f190f46dc13ef1bde43413fb3dbd62f4cc170ad6c39bf9c",9.317957166392093],[7913,"fe5540211741a11e74511efd6f180b0d6a2da831ae01e4892c092ebf25c528cc",9.917710196779964],[12494,"23b8fed2f7376a2c2c78b680fc17aba100c30378532f9794b7a71f1b726efcad",9.917710196779964],[12237,"fa22dab710789596b6dd6bfdb2a2e3fe88149810bae041bc50f05a86ccb2c0af",9.917710196779964],[8915,"6e7c0ec502523377a828a55fb7cf50f11df283bfc58b432c6dd5a938d8b45dc5",9.317957166392093],[8203,"3c13a98ee5432603c51dba5f0904cace00dfb2e04396d044d0411230cd57f6c9",9.917710196779964],[3570,"31a40ade56cb296f76cd8a2d91e6977d09516cf48f5a6b2b68cad98652ac79e8",9.917710196779964],[11302,"5d58dff0295875fd25b3513593cf381a43280f5ca1ff0ba2268aab10254803b6",18.96797153024911],[6064,"0fc4995f0262e603f569c8e8864b0fdd699d94b4837b7277e2220ea7dee4a8d8",9.917710196779964],[11077,"f90e0de9274fe089f1a56541fe49122e44259fcafd151117101866f1c24c76b7",9.917710196779964],[17999,"50b0e812063562646a26785812c5c99dabcc31d549edff63ffd930c58213433d",9.647446457990116],[3950,"9066ac07b8d5ea95aa15da56d07a8d8a440a53637c720a95fe5f0c1094b401e6",9.317957166392093],[6092,"c0754c98231f30a017ba87c09a480813db6a43bc1e98452317e4fc6d14e170d8",9.917710196779964],[11376,"1b60b57e94a7e0627069f9ee48d8752ebd7e70a208ae44ade41d0a4422048cb5",9.511868533171029],[14916,"86f9f5bd9027eb98140b526d479579ea2f7e7a005c7e5e25af8aba04d0d29680",9.317957166392093],[12287,"dd30c0ec660984a3e688fa40c705d90cb2198667893d6fec2d73545e98bf56af",9.917710196779964],[13540,"53d947ff6b7cc72b5e237a9a2d352d7c9fca3018c84225fce875d3a5848af09e",9.317957166392093],[7902,"d5fdbe0691f1638e539d3d8c271c4f15d32df60858fa65a2fb204ea9994839cc",9.917710196779964],[5825,"11606667bb5aa7c7a3862542982e687143d1eba3da871db618157000b11133da",9.917710196779964],[15396,"50fbded84f3c9b3b987aa3b8241013e71e0c2644272b70c3e51a8f2b462d6276",9.317957166392093],[1991,"8ec882cfa985c7eb1ba7afef1ffd5d42a1c387a01feef3ddde98227afad410f3",9.917710196779964],[7351,"48bef7981562211c48b25f03bd4e24b4d2cca5bba19b0598e164706e6b7bafcf",9.317957166392093],[18063,"2d4ad208be5b821de5f92193812489faebe7534488065687acefaf973573f53b",9.317957166392093],[2740,"7006da798c491c76ca61305747157bc14f23315d0cb2661360fe0729e67a2cee",9.917710196779964],[13254,"d0dff721768cedc0bbfd12ff6b53e3f1d99f18f63ee118cba45b133fd35991a5",9.317957166392093],[13858,"54511b64930ea9e5991185f261c86d550c6ae0d8e5038043588e2e4fed723b98",9.317957166392093],[17712,"6a823541a9217a2ae937eaf86ea3fcc35a339882736158edeb65316b123af642",9.317957166392093],[18415,"4bc920a5bafc42d2a2aed1e5252c07ef85477ec8d1bb098e39774d1a21803433",101.30892448512586],[4897,"fe04f51038fc8d06993cf0c0649c8bf56642f7a9262b2aed5fc5444d69dfdfdf",9.917710196779964],[3701,"86ef08c28d544a3a22228c2fa57e1b8fbc9125788ee931fa61d61f44ce9c96e7",9.917710196779964],[13663,"110321cd823060e86eaee6de76557c708322f69114d7f9ae7e677797e4aef79b",9.317957166392093],[2056,"1d67178d5350acd30d6e25195a7e2ed6d8ee7a07527be7cb4380494d523391f2",9.917710196779964],[7357,"3bbb6bf6e58c408b0cd387eef0608639eee00b38282d034b9a951407b69eaacf",9.917710196779964],[19827,"0a94e25551f195162b50367a5224a2a99c0306540960ea41451c9a8f45f0a601",9.317957166392093],[12560,"3910823c14f1a5cdf71f8454d74058d2ced2a61d373525ba6d6a523b461f95ad",9.317957166392093],[19486,"99c4d1b068aaf6bba938991c57b21ac08e7a54687ebb1017a6b160d55014dc0e",9.317957166392093],[3487,"52ffe92af17e0fa54359f42f883d942a555a2137ace1a7c50d68f0f69af41ae9",9.917710196779964],[10808,"2eadfa0c1eddeacff9cebeb815ef4ee4ac4dab036abb6f0f08c4cb969ea542b9",9.317957166392093],[14792,"542279612c48c182057299faf84392053addc6bd888553f5dbabe1ce84a81b83",10.052724077328646],[12206,"f61555ffcf3a66078a080d69b4241f670f30ca40df786de2b5e9d7b67ba509b0",9.917710196779964],[18826,"8c575ed5864286120d3b28ac91068add0a679d00b582c505bfaf60a0a9e8df25",9.647446457990116],[7995,"7ebd36a8236f361ef7a1657d887667227b9ca78e704c925f0403f6913e008bcb",9.917710196779964],[7372,"5d9bf0942e45db597eaceaef628777ef49d9fd244d999742caec459bc7d991cf",9.317957166392093],[862,"58f72a0c1ea7f8e9063d56382a17ec84e7f53d7a19268d567f310e29ed3326fa",9.317957166392093],[5086,"7a97e7be43d9e00e7a7f6ac41fcd00c97b08b56e37e4a316698a4e58c609a8de",9.917710196779964],[7499,"a950addf79e09c2367604caed1f69cac1c6be8aa4defb7dad308659f925ac3ce",9.917710196779964],[233,"f0b725787700eebc4ba822816aaa3696e5a23fc65bbbbed4b225107a286d6dfe",9.917710196779964],[12342,"c5675330ecad950608c3c62a61c02c6d65a0e17a9b5ae3e4af90503eb9cbefae",9.917710196779964],[17107,"ba2d28ca0ba3f3867b42298ab91ee5d9d83bfd32e0c9299e93851150165cd54f",9.317957166392093],[1634,"6e9ad0cbe8f255d251107a2083ed4f5bc6d7764f26be8281ffdae56481d265f5",9.917710196779964],[6489,"44748e7f65fc142e0051e5ffb9a2df659f01d4e8612ff84eeab7f8339d1e90d5",9.317957166392093],[8297,"52ca650b986220facfe180de5f5aaf9531e1c266c8b66d86c35b1b14c13c5ac9",9.917710196779964],[3310,"34ab9b9340ed158d2e095c1ea073d151062b0ffb577865bcb47f86e0290f4fea",9.917710196779964],[14623,"91017727d06c7de69cd32930c53efe595f04f8954fb43abd9e562f12f2437f86",9.317957166392093],[17664,"a600de5f846bf73aba0272f0e7a38fce82454cbd90c0e3ee508bc524d7e2d943",14],[7117,"f4b2ecfa286b2f135b959c8541cc8b86778d75b19f5d02f94741831222ad3bd1",9.917710196779964],[10136,"8cb145d523b332f91432182e465f50326b350d785b3853e34f243ee93b3976bd",9.917710196779964],[18651,"70093bb8fa9832b7aa5e8db771afe7c84371864d98605cbe8e64d436c43aa02c",9.317957166392093],[11492,"76dd3325d76fb95095c06c6217fe39b3b644dd38d0b9c81a3405ac773cd390b4",9.317957166392093],[16733,"9a6a4887f037da806711eca30801205bcbee0bbfdd0fe9b66182a582b677c657",9.317957166392093],[1476,"b3614d69ebb55e34a0f18ba7a805a3c3367b8cf477fc5640581195b68e664cf6",9.917710196779964],[7926,"a44c4ef94b2587b35d2d3102535fcd1391ba6b03e4e7edf4fb3b24b7a3c611cc",9.917710196779964],[12991,"3516c9bf2e20bf7c9d6b4fe596c6e4f80b56b522b123cc845e991209f5b4adaa",9.917710196779964],[18727,"6cfc6b0fb4ea8b0fd39e1aadb107205d7cce9330efa533ad474db77a9fbc6b29",9.317957166392093],[11634,"b04256a9282823bee7252b017b43f724386fc2cff536e2cefef9ceb1b3e9afb3",9.917710196779964],[16089,"cf7c26a80df965df1ca1715f97028e44fd6aca1d0df2d6e9c8b4b85506ed7e66",9.317957166392093],[8968,"000907b63b59fb3b581be96993f4e05f5cd5bfc4ef23a504c44a6153a89e07c5",19.19720767888307],[12657,"bd47aa2e51602ba5a0035039da1fbadd872b4506abe2bcfbf0f7b046e801e6ac",9.917710196779964],[19255,"86d1f5b2070459b41a76836ff515a11fba4ae74548e737f4133a8ebbd5df6a16",9.317957166392093],[827,"a1163d5803f4e564d7ee078a75e2d28b7bff0d70b56a21709abfbc2492545afa",9.917710196779964],[8818,"95764083a456f9fee2bea411819008581c84b9c3aacbd83a3d8ac57222a6fac5",9.917710196779964],[18282,"14c5e302fc64c640900990913e47a5d1e6f9e3171fc5226a226c199227f13b36",9.317957166392093],[746,"6f67c7ad6c15cb1b5972f49e2418820e6b17ede49d65cb2e2b1ee1901b7eebfa",9.917710196779964],[677,"bf5ecd1ab4c38237401da85d586af56900afda606571d69558b951cd5e4964fb",25.385229540918164],[13658,"5b8210d994239bf8eebff502da19bfa95dacdd577d6ba3ed05de6d2884b2149c",9.317957166392093],[2356,"15343118e3abc1a4a497314832bc2ca58b989570cc60e5d33efab5dc48c7b5f0",26.90949720670391],[11396,"73e244f65b549b4d068cd2df048d2506b708d0c4c3399dfa10aa7a6324aa62b5",9.917710196779964],[17077,"8f009005a505a688ef2b8b345c12a98a810a677f8a4fb1899783d9c427eb6050",27.9247311827957],[19403,"2047263b56566974faaf1904957f5df478e5f8d6ef62563b85dcb9a2ea676311",9.317957166392093],[14385,"4be3c7a6216a8ed94db2d305e525bca3024d3218a5247023d066d7312886998b",9.317957166392093],[8343,"4a6c0d7e7e5072ab845a74589e78e62ef6200e3ecb578b089e2c2b1c6ebe0bc9",9.917710196779964],[16560,"26ab0fb99ad69497cd76ae2373fea3308512f128bfd24fcb661f599d32c8e45b",50.26737967914438],[10602,"1224dc551d1cb86f2015e4fd7b39013081d94391182cc551949adbaa60c2a1ba",9.317957166392093],[4291,"ce4b940676b04b7549706db0a18c300734b7901387ba40d0c2a19da7e3a4d4e3",9.317957166392093],[16871,"39455d694542ec1d757e6784161708d37480f3bc9e4fd5daa54845ed095ccd54",9.317957166392093],[1413,"5486b7edc3d98df1cb024ca6d98b1166eb3e02a9bd9cdb31a161cc188110bff6",9.317957166392093],[9244,"e3a8064e345225902f71a4ede69effdec9243b5fda859ecd541efc69a10326c3",9.917710196779964],[4341,"c6eac673507ba3486d83d18b01f9b83a29649849fa302c1cbc6057f851787ae3",9.917710196779964],[4193,"c2421d334dce126b61316159d9862d52dc7bec91bc7d43cf45cdfda2651377e4",9.917710196779964],[9573,"a7056ec4092cec0441ac8dfc83b0c99ca3511b7c473096f8fd820a09d53a2cc1",9.917710196779964],[6168,"18b43abf60fe318a1fcb5c7015b3558267e9c8a77a0daecf7799429b3ca602d8",9.917710196779964],[13896,"49b6685b3b4f6cca925937ca41925340b01cd4220dadf3b2bdbfb928dc4f1897",9.317957166392093],[12610,"823d1d77620ac768b461f0fef2f4c2a621caa742752c9b590088f50824c433ad",9.917710196779964],[5661,"972e2e782d4deab8adb83e2760f2ef8cca4e7dbc54b5431e94aadbb4f27642db",9.917710196779964],[10634,"9a2cb7a72f2add6d5ff9efcbd7b705d7c59542aa620fac4745b46a6618947cba",9.917710196779964],[19240,"76a99f3df318cb7b114a2c302bc017801363b46517dc248ff32c1ad3ce513617",10.032279675985139],[1043,"9e9c18ec8ee46e50f57e82a1253d6a4aeea66daa6e9ebf9be5c3f1a1509103f9",9.917710196779964],[165,"c88950963b1b3afe93695bf3205335b1f785e4b5c7a6b86c5eda3d6762dfe4fe",9.917710196779964],[15635,"3c28a0334c367d9ea755440a3bcd325503dd3ed65c6c73cffc2706afb4c0a970",9.317957166392093],[2941,"25043dae437e2565ad480423f6c9ebc7c5dfa4a4727c4a58969bffbd6584bbec",9.917710196779964],[5069,"d5ad1ef4da07ca7f825160c8e7319a84364a09993cac44dae372b4a06a90b8de",9.917710196779964],[10761,"1f6856a3df2ec6c4f16a6ee3619b8d34c2d7707a3f64f1fe0ee4a89d949c95b9",9.317957166392093],[945,"e57931909e509d1ef06dffeed0a320570431db49185c92b11764341ba9ac84f9",48.42043795620438],[8289,"19a503da01c7720ad5c4eddfc0b06edfba1af3113d5c1999cd2c3ee9df8f61c9",9.917710196779964],[11802,"4fd404c99a7ab5eebfc9b60642f069ebf38451c2e15e17daabdf6474038db3b2",9.917710196779964],[15001,"e9ac710b3366df93cd554fc973d9dfd1e73c142c3d767e79c6ae8dfe6225787e",9.317957166392093],[2225,"2d19f7e8576267dd4c5dbb90c7468a3b3f20b3caa99d52bb82e9b52b6a475ef1",9.917710196779964],[8417,"70b5c1d5c8edc071fe5e77519af70074cc9698e369de1c3826aeb15dfe0087c8",9.917710196779964],[9478,"061b3c91401b520dcf854c44d17a5b69bf3264453cff84012811937daf9ad3c1",9.917710196779964],[4436,"ab335a6c55419079c8ca3c3119ea7776b3a6a25030bd96c7d5e3c5272d51dae2",9.917710196779964],[10976,"1696523fa706cc9c4379e8e97011105aecdac79165ea35663c19ebcfbd7c2fb8",9.917710196779964],[16815,"a5fa22e05234bc5555fc058401d3c938aa4b000440233be14272daa8dca3f055",9.317957166392093],[14983,"b73192e262a6c403e95c0ee39b7b5d11a6168d14aa98a3222b59ff0e4d25e57e",9.317957166392093],[10999,"322c549fe85505b7765e69c509512f0cec1eab84b79d47fcf9c6f74ba0eafbb7",9.917710196779964],[2722,"b4b80eac9a38ced3ee22cacc0acc550b59906fddc918271c67835ea205cb42ee",9.917710196779964],[13144,"ef24ee4a7e858131240c0555911d82dc9c19f7ed3b1c48d414392d0275b312a8",9.317957166392093],[13784,"7f5760433dd685a09481150162297ef94ae2e1a1c1f0d900b40cf227a304ae99",9.317957166392093],[5013,"fc0fa2dda65f14953b604ad21d6f51e936dd89a5061b44cf63996773d18413df",9.917710196779964],[7423,"1e1ccd33e03167b4f92e7c2fe46376fac57456698c8d6441d46df5496a153ccf",9.917710196779964],[15308,"b500da090198fb5769cc13d4a0908b45681c4a592919f00f32dd19b78e1d3978",9.317957166392093],[7631,"47e105aa0cd8c31b93ccaff614f39b949085c1e2db38fc205697180a3a8effcd",9.917710196779964],[19375,"49b7cd911d8c10b76fe254961d1601fa6a263344b4aa11a3e03c540c4012c112",9.317957166392093],[11263,"a542bfd2e0dff43b93e18285e79ee132eb3290a3ee5b7d86dd10c52003a046b6",9.317957166392093],[3704,"b8f25a317e33050358c273bbb5921f21fd92f83c677a70fbcebe1fcba71f94e7",9.917710196779964],[10874,"5c9b290921a12f4e5e9e0aa7b5cc9088599273067741ce7c20b9d421a8acccb8",9.917710196779964],[4787,"4cb71de24d370cd87fb7bdb39cc04f7473b4b064681cf65ae26be5906e467be0",9.917710196779964],[6819,"3614e0c48c63e19b0932bcb4d5ada84b56d455348e327928fca632dbc0fa2ad3",9.917710196779964],[2098,"fb8f354a49454abd0f05e16dbd3eaa978ade59003dde9c3a22b55cee281644f2",9.917710196779964],[3024,"8d93fdc6faf296bddd4f52e2c09c9abc6edb133ea382a24d353dd305ad891dec",9.917710196779964],[7487,"a85a4d79fda72f27c13c6451050f6e9deffc742148e87bd44c7d525183bdccce",9.917710196779964],[18920,"42e3ab19788b5ac916dd53bbb0e3387685fcffd193f4b7bd4ca482ac10f5cc22",9.317957166392093],[17913,"d75267ef9faef568e9a76f81e88bf991a7bc30f63ea0270941a03f3913a5073f",9.317957166392093],[1125,"18930f29fdb38e235eecb1ae87eb9295738e0e9037801e3a2ae932eb7ffb6ff8",9.917710196779964],[3949,"59af6539ec4a50ae75364ac14b7e783c1f59d0726914fe451978982077be01e6",9.917710196779964],[19856,"86ae351c3755de9ca5692a7815aea01656b8538a7bc2d8b515bba1a490a78b00",26.17848970251716],[14240,"082984f7f64f97675fa8db6f66ffde4b8c1715bd9a0ef65197e31bed2f1c2e8f",9.317957166392093],[19527,"8ce2c6cbdb8552bda6ae2147b408e373a2492f9e0ef130dd9feb8e17f864960d",35.650623885918],[12730,"ba76cda27f94d827a5febb8b3a6a2c96a8fb2bcc76fbe6478293aaab531366ac",9.917710196779964],[9610,"3045934822b3dff8483b983153fa4efba9200b72fe818d76f317e26e5fb3fac0",9.647446457990116],[1777,"72fdf6420a12c49a5172ce93eb1c3d5481a4502c4e8501dcd6b7b37c120e67f4",9.917710196779964],[12718,"23e8fee295358929e5ea22d0f4794a3b64591abed507655953976c58884f7cac",9.917710196779964],[17381,"25e488a4da2624b7aa31bc70c8a85d58fb20edb01df518880b538ed2fe0a304a",9.317957166392093],[8053,"0f65b3dffb5cd731a7c3998b37ab249f4ba4332f5562bb22bd0d9b08c0b523cb",9.917710196779964],[4419,"fa3e0bed4452eb321057a3dc869e830ca7b95a062716d260ec298f4adf74f6e2",9.917710196779964],[9982,"d05b27046758c63adf594be34dc657f88cbd63dbd38803f163345669597d6ebe",9.917710196779964],[4084,"c70470d60403fe33c365129f67d5a50252a60d377813f92551292dff3ec02ae5",27.851590106007066],[1879,"cd6687eb3578aa0911651fc88554224506d7abfc5d6a8bceaec6cfd93f99c3f3",9.917710196779964],[18722,"efcf6922c9783b766603a17954233e5ce4cfff4fa7a386b34d97e7d9bcd29e29",9.317957166392093],[434,"4e4b412bb4b22f07c00e936cbe9ff158053fa6ef8739d0dfa2295180740523fd",9.317957166392093],[14621,"27fb9925aa6b183e01c69aeb3e211964e44a16f618a0b784c97b7471da078d86",28.12785388127854],[17984,"f6a4988fb15b44ae4476e720e1a1d54105904baff5304ee72c9ecb070b3e7c3d",9.317957166392093],[2278,"37c2de8fc510cbce9e40e7dca832a36e81fc1a51c02f0bf5dd29d47b14ec1ef1",9.317957166392093],[12778,"8922ca0aa048257e3c9198858f4199d4157f953217cb77b8bf231008a2c20fac",9.917710196779964],[6365,"3d15905fd5c4fcd766a87e7d42b353a0b753f485129126b032174a5269dd8dd6",17.572115384615383],[16280,"c6dc2561d5154759afeb506f1aa9730417a8aa4212d009f9dec09554f30b9b61",9.317957166392093],[6053,"5a3afb208f99909c5395d91774b49612190bb5d45ca56678a16a1a9ac6fabed8",9.317957166392093],[10800,"494aec4b235489a0fa7ab32125111b12b76091949ad259e7690b6e137b124cb9",9.917710196779964],[18294,"ca3b9217407793a225a4f4282df8e00234c55ba52e80ca607f1929b8dff3f135",9.317957166392093],[10638,"503b079b549385d043b4db87f486632db604df5aa29babdd94a0d918ead96fba",9.317957166392093],[19463,"6e42029de068ba37a62e6124f8432a244d4957ec33b7318292626bee6b388c0f",9.317957166392093],[11734,"85874a08e89866693e58d6647db6f6068e6042d1eeae09d974c1838d9ef915b3",9.917710196779964],[5072,"59726bc281f6ca71f7493b4c72ce2f44efeeb39b47e2c3a18021d1dd5507b7de",9.338112305854242],[8535,"5a4977f448473ebbd95a91949fc83d77c86f44a9685d2127aefc44006a5ecec7",9.917710196779964],[15057,"74a811b5521e01f41c52529cd376cf64d4107adccc7fd749183e1bbae5de6d7d",9.317957166392093],[5595,"a3e5be03d21247df85eba29def9f9a93e8960e46363deb93d1296e3a7606abdb",9.917710196779964],[11996,"67207b911e8879ac4fc1d61aca1f037b3153f9efcc6309908eb2905fc0225bb1",9.317957166392093],[843,"9acbb3ef9e1ea6ba9a2ced30d2028536e6f217ae877f7bf126702e3866a847fa",9.317957166392093],[8506,"5ac283aa563a729697fbbefe58d0cac54e6f076a7abd51f3562d1b41d4c7fec7",9.317957166392093],[1079,"f4a79e4225f511aae20a0d524dac5cf436777e33ff71badd00c6452cec35b7f8",26.092307692307692],[9424,"31364fd8631a65d86abc3382f4f2c02fcf678c4ab18d84ccd7a08d1871782dc2",9.317957166392093],[245,"a48e99cae9609700750622726fa4b7198bf83d99c0725b27bb8389e6334856fe",9.917710196779964],[11940,"fa74cbb439c45f60c19003527ed8eeaa9805d658f30980f8c1905c771e43b6b1",9.317957166392093],[18389,"c68f4fd7fdb9ee00f3e3f2da6fbb5e5db20bda58c459870392b7c1a88286a233",9.317957166392093],[9578,"7e1ce7c5071e88397a76600229187c8a7bf09a405bbc2e1e80234fb826b024c1",9.917710196779964],[18792,"d494caaa30fe993c158f69309d00e2cc220c2094b23a2a8919e9daf0695b3527",9.317957166392093],[14474,"6e55e494b4160b74909f418ac60854fb5884e8dd54f2a49bb427367ff755c589",9.317957166392093],[15876,"e735e29f36e1c59dbd52b23876551110ee793688be2e2e830baeea4ec1457c6b",9.317957166392093],[7757,"84ea8cc3cd48f137c3bd6e6a223154ba1b1f7ffd3ec05713804e6be652f114cd",9.917710196779964],[6334,"ed004ffe843e01ac01ebecac40286f10affe001e1700c0889cbcd8524f99c3d6",9.917710196779964],[14865,"bce2f380972dd534e054d1a377154ef8462b0892c51c2a9ef8450479f5ff7a81",9.317957166392093],[229,"4824fdb3dfb61cb7d4a5237d7c5edb9d58f927dd3203ac227c64fadf5e3773fe",9.917710196779964],[9171,"abb82db1417f5f5e5f0638e6da6279b43291cd0b2dcb9da943412f5694acb1c3",9.917710196779964],[10199,"4f98688289dd89054888c8345b185557b2da916555b5fbde69c4717078e904bd",9.917710196779964],[19399,"2e5e396ad5c3e58cde48dc69f3794ccc0bbae5e749299249245f4170bfc2c211",9.317957166392093],[7132,"fcd85cb2548e70bafa5dabb3b41872776ce860faf11632a32145f15a214a1dd1",9.317957166392093],[15185,"af1aa2d7d50d037a7a9e684c7076c2dec37f6e1114e44675df665a505c00d17a",9.317957166392093],[15341,"f4bceeae7e900067f535d4ac27b91dbc04d86d5ab1af9a4a7e75e8fe70828677",9.317957166392093],[17303,"949699dbad809c976a50037c46ea5ad1bab6c18dc37bad045b6fa2df4a34f34b",9.317957166392093],[19243,"56b13b0a9a4a50a9dde6d37b30123b57cb62f3db5e6e7d82ea0bdd9680dc1d17",149.55606708319633],[7806,"e16b513b23621f66970a35835a3bba866342a4cfa3c170a54e7959b8ab9dbecc",9.917710196779964],[9403,"6560ec775ca060619d05f2e00bcafac2ca80493ea908018284d632f71e1144c2",9.917710196779964],[3237,"7349f8b890b539df8d75a263f8efa708c16edaf240b421b6685587886d15c1ea",9.917710196779964],[13660,"df608653a62446608d9c882474af906f28802e68f8074d73fcadd3c41d380a9c",9.317957166392093],[5306,"3b5c8233b08cd5d33ae2bea10599a854fc8470c2dcb7325dcf5598e9430358dd",9.917710196779964],[17518,"062ff09709a75251354c888f597d60cfeffb7e13b141c4f8df31858708522c47",15.951807228915662],[560,"6f3cb9c07cad747c92a037014198219f8fbf91af3fbc5b3101e8ee4d267b3cfc",9.317957166392093],[16038,"344c26d75feaff2953b7c93e341ca62fab47b34f3a4fa9d936867dd15378a667",9.317957166392093],[14750,"23fde7fd4d7746fa25a1ea57873cc6cdc6f690f59df1d5baea0185b18fa5ea83",9.317957166392093],[7878,"4a4e595363504b76090e1138822df0094fb90416f11e6fffb1590be2934568cc",9.917710196779964],[6258,"58fb2b194b44c404d047b885e8d22cee46962897d6a48dfdda62b0b45efc5ad7",9.917710196779964],[12831,"324cd51b13aeb49ef9cdb6968ac282b84c46ae1280a43daa0c0a3513d8e3baab",9.917710196779964],[2444,"5a6433a2c52a87f4107857e3b3dc996ffdd45b9d45ca3a8a55af5492881436f0",9.917710196779964],[17376,"9c7a4ef9e1677eaa13dc16ed58217aca70c2e745b0e1c93417e517b9a0e9404a",9.317957166392093],[11219,"655e358e0d2b28dfbf6e2cc4827ec4e2c142f70bf3480d299ff748123b4396b6",9.317957166392093],[8784,"bd15ae4f89fddf94f2245472b50f6f052267baf4e94f2fb4947c4e8d3cfc2ac6",9.917710196779964],[11133,"20b1d00932f985df65a53bdef46fef02f5307969fe9edc95a94e839a389210b7",9.917710196779964],[3887,"a5f0d742ce67392a9e1ee1f8413586245a5bb59eb721e1bace7a405a11c16ee6",9.317957166392093],[14434,"4488346812167f3c6c46910693f0114cabecf9f1b74635e7230046276835978a",9.317957166392093],[8900,"533bb3bf22a9df46793a4901a21a5dcac83dd43aa4a178c4ea2e40ee69ba73c5",9.917710196779964],[3013,"e04e4d98d03e5786f24e1ce836ddc79440d7cd849dd803f6ce008313879d34ec",9.917710196779964],[3042,"d7eeba404002958db5311b62e7600ccec104bc3d486394b02394aed3ee620aec",9.917710196779964],[270,"f2fecdabf1576aa0fa87b92fabe4933cd4628aaf5da9c771e7389a42f6c722fe",9.917710196779964],[13615,"8beeb42bba075e5bef8cf0b1d076debb1cd87741ece71c8f4052204117c40e9d",9.317957166392093],[4001,"023a575a3649253728bee8122805af520a7dd45794fa602eecbf8bd295edb9e5",10.052724077328646],[7607,"cf75c272dacf06b405a2bb622858a0194e97f3083385de6e69423c29b2a22ace",9.917710196779964],[12889,"f3f20ae09db3e0249006fce406bdc83fe223b6aa7d463e59372a881d30db58ab",9.917710196779964],[16334,"680632b26ecc323e0fe3a1223ea0365077737a893fd635abcbcc3ff09d735b60",27.450800915331808],[1122,"4eee8568f2ffeed10cd4353f8557ce4cb02dea676eab2101bfa04893f33f74f8",9.917710196779964],[11059,"27847be235026df3e235ce8b31d4935f44727ef4445caa133a7664c88d0f9bb7",9.917710196779964],[12532,"d2b1eced4c8590eb71822716a58303998bbbebad2531a190f3116050a4b7b6ad",9.317957166392093],[5810,"ca3726a61a38efa065095b865557a278f88fafefb12ce1e12fe8638e6ca552da",9.317957166392093],[7821,"e3bad681d273bbde3bf724762a4d107b148b1266190610efa932b6cafa05a2cc",9.917710196779964],[9071,"c288fed07e2cdc404015efd7b2ce9c8e1a74ac93a4bc77e2e76ff034eacd50c4",9.917710196779964],[664,"23bc5524a29ad5e1ce7acc8e6a5f4c34b277a3dff200cb7391a859dabb2f7efb",9.317957166392093],[10750,"b7b41a1391787e7580b72d5db32dff83fc2721cc49c2e271c5ca1da8f4c9aeb9",9.917710196779964],[9744,"a2db1cf64e6eb16bd937594841389c5320d37fdc70c4d4c6c0e07d483dfa07c0",10.068649885583524],[7543,"f3a89d03bd59803ee9f23cdd959f74a6a2e318b164850277c7eb976b45348ece",9.917710196779964],[10685,"f208c346b5aa32c3253cd3680363c8f82a66cb171bca3500eb4997fff91226ba",9.317957166392093],[9910,"bc26d76f9ca92a520b3fe8ceebae2a800f299f752387efbad1ff8c5ccecee2be",9.917710196779964],[7891,"357fc4723c37378bf71cca9ae955c0eb8abbd3b2b523433c9900a22f208e50cc",9.917710196779964],[36,"51b4799eb16fb758b6b6da52c738082ac63ee5c06aff3c5a5279db08ea27c7ff",9.917710196779964],[18326,"7eba841c3aee70fb5631b11a03b4402b55aaa92304a7ddf3e37f253b2c945a35",9.317957166392093],[11458,"1fb9fd007ffbdde7da2d8f87d29b732fa9170a801fcc4ab6f5bab3234423deb4",9.317957166392093],[7303,"bf611448a3dad0c520750309fe136d6a5cb82ede934815cd03818a012c670dd0",9.317957166392093],[12358,"5905a64b762eaa2b5bc0aaffc16660bd2925a7e52b36760b190431738d74e1ae",9.917710196779964],[10664,"af223c605901fa3dada16d8a4bc9c304ab73a314bf951f6d3f2f1942c4b743ba",12.085106382978724],[3039,"aad3c669de4ff13573ec5ce7a83e424b9943a7abb32018bcdb45a0a731280fec",9.917710196779964],[12688,"4e3933e8b132308a9aa364f5718c9287507c5532042dee4e7b5f0ec7821ba7ac",9.917710196779964],[15674,"f5153abfc71105a6d8921c9da8d17162fbaa3fcf9dbbf1a87bc57fdac594ef6f",9.317957166392093],[3141,"7eff41bfde20dc1fb56c71913daf45012736e22a6d2036ba9433b1c1f2686eeb",10.052724077328646],[6165,"2a33ebc12710ad18c1a767663090b63643ce3fde1a45ec9149fe8a617e2d0ed8",9.917710196779964],[16969,"c8dd689253d2c17163780b12ad14cd7ff6eb14554590ee76754b38ac7acfb852",9.317957166392093],[9083,"c226579489e5e4a44eff6e33eca7f5fab328e341611b6b779f4ec206a7b441c4",9.317957166392093],[6386,"4317ae6553d29aa036b577e93cf265bbcb08dc6fa70fc2748f194b51c17867d6",9.917710196779964],[3764,"c0bcf206a3585e0fdb078d10d0c70fd93e09e358c3062b4783f9f7b20f492de7",9.917710196779964],[16290,"7cca719922e015e3fb29247e9e3989298e3680f14175fb5f78ac8a6f4ea56161",10.052724077328646],[18409,"0afdaf7bfbfb3ad34b4ed223904a0716bbb1c7d92301453bdcd788f645344433",9.317957166392093],[12817,"1e886e65c3a75cd317ed132bd165976fb2c5b4847bb7af1330e3fb7231d4d7ab",9.917710196779964],[4391,"fd4efdf5861f2a4af662334fcf4bcfbdf6a8de9c6ffe06434d7373fd2ab421e3",9.917710196779964],[12910,"0ceae1356d810f0227413f6a94ba2d125c6d2072f3c40b2cdfbabfbd7eb13dab",9.917710196779964],[8747,"a6f88aaf86a7ba0d9b401d02ab36b00276aa6ba57688ffeb00d3f2ce4c9568c6",9.917710196779964],[9085,"4d5e111e1d77e11f4007e0edd4fb57fd118020b2dc25bf9860d806d2ca8040c4",9.917710196779964],[15293,"2da740b66730ad5c3d8384a3939cb5729f444e80e6420dbcccf6cf6160cd9a78",9.317957166392093],[11432,"1e24b23430813d2be795dd1ed8a162970a3bf9a5831df3ad0e4776e9add119b5",19.985410334346504],[5955,"8f97c08bbadbcedd108367ba7117770d0027d0a8441f1e8dc976c2784b1063d9",9.917710196779964],[10589,"209a925865b13f8ca698dc1deddc0aca902957a3b78bee13026dfecc7368b1ba",9.317957166392093],[5770,"dc9be6f7f03ad641e6218019b2ec21f9ad85697df3a8717b8d0b5367317ba8da",9.317957166392093],[1626,"5aa89f552ad04333f2a7b0001fb25327d0e2f9d8f30fe47e646977fdda2d6df5",9.917710196779964],[17001,"093759cbcbdc28f743e16c7548f6056bfb17a3197f6676472d725eb5d239f651",10.052724077328646],[17583,"431bef9c3cce6d6a427bfa215446ee602025956be94bc73179570e448ee7a845",9.317957166392093],[974,"d7f918d1421f6f331ce8249081135ffc7bde063cf778e2a9f95f6c82627c5bf9",9.917710196779964],[1209,"8fcddc166b847da4d840d11f57e0a145f227c1a81dec157188275a9ebf21f7f7",9.917710196779964],[2189,"58e9b6c73879400ec467f393e6d34b2e33a917dcded3dfac709386681cd09ef1",9.317957166392093],[10938,"802206ecf58400754d444a762bb9def47f9e54ade18966caa37508d5af1775b8",9.917710196779964],[9738,"e79123ccc7f322efc830eea13152ea37909162b5b3fb202952bc726540370dc0",9.317957166392093],[19053,"cba425a893833cf079bcb7d78132828fde9bb87597cce1acff8a2887cec2a61e",9.317957166392093],[7746,"6ec395a0d7701db8bfba6797ab9224d3e045b8e9718c1753f355094b27e42acd",9.317957166392093],[13552,"4770fa808fb55c8880a1148e6d59460e8b7c7ee37b0527845eb0ea049d13b49e",9.317957166392093],[13646,"65ccd97ca2dab79ea0d289b16b82e17923ed8daf6e4ec439e759e4ae20e94b9c",10.052724077328646],[12258,"b2515ef88401e8de5fc350639324ada465a4ecaddeb8108dcaabbd4e553ca5af",9.917710196779964],[12013,"1da34134a16f6945f8dc36b23fff28992442a781042b0e7ddb8c861d2ee73eb1",9.917710196779964],[2727,"24870dfeb03374dd2bfbe5a021393093dbf4e1a5825dcc089168e1b1f57a3eee",9.917710196779964],[6554,"25e7d5de6c195b99faf8c7b53bf41c690cd86ac9e32a349eab49993c3f12fdd4",9.317957166392093],[11632,"1f75ee6d5a1f00a5f49793126a4a8c510a22609cdc202f6ddc850603c1ceb5b3",9.917710196779964],[15698,"45042900179c979b15243150bc3d0ebc9a51182e4d08ec4d812c5af272708a6f",9.317957166392093],[3046,"f40d82ad6ae40cab77a6ab5df4c63afd690c4f3b86f332c82ffdff568ad603ec",9.917710196779964],[16022,"90401a9b692997f5581fbae2d3c6d817e10a02cd83838a40d88f50364fdf0168",9.317957166392093],[6821,"bd2620681a7915febf1c93b02e0e0d80d30b4527bc209ee721aa5e37935923d3",9.917710196779964],[11801,"a6abc4059b929a1273612dafaf9889fbd7a9fcabefb3a94e53f9ed4bcda5b4b2",9.317957166392093],[643,"aa6bc62c0ad191c94166745e084427833aa13eff64abe3a6c6e7a7d959fd9efb",9.317957166392093],[502,"3927cf7f9e88cc0ad49410b900c497dc95c7005e6f9555b9f467f208c9d0a9fc",9.917710196779964],[3879,"1f9bf06215a68c3667647d451238ab1c9fe0e1c5932b35b92125d6863cc881e6",9.917710196779964],[16947,"a85f0dbb8478b7d802648b362ae71fb67824806ed06616b568b1719530763053",9.317957166392093],[10604,"4df7087ff1d872fa19d9e3628a8e21033132e81abca365520ee938edc2579eba",9.917710196779964],[1096,"397fb432e27bbd704ac9f2c9ea8c1bf6c92b308c7ffb707249d816e1532f96f8",9.917710196779964],[3805,"224d154a923e461635cc91a8f556dbd3cec45d958e542c53afb10bd88624ede6",9.917710196779964],[924,"c56f00d02e7d6612fabc537c814798d16a71a4602bd650d31a71e56d4f1cabf9",9.917710196779964],[14013,"4845af7623125fb4eff0ebf6b01624f05e1d67564ad6c2116b922970f0ea8b94",10.052724077328646],[18764,"8c7606dfefde15408a6942f00742c306086d80ab26f26a8be558282e4a202028",9.317957166392093],[17813,"08304b1f9e83aa716c2379c54bc6236f1a3e389265f76ba0b1c3dc75d3af0741",9.317957166392093],[12173,"cfdbc86402fda525ad9ff64af8c81e5dbf66cb3f01f4ee07ab68a7decdb43bb0",9.917710196779964],[14121,"741cea6d8e4c70fb93c5b3c26df45cd5be71946c3ea9299ad7527be8c4d41492",10.052724077328646],[15080,"9c0420bc3324fef2cf4be139929e181b6245620bab67ca9f157aa8ddbe0b167d",9.317957166392093],[18956,"31d559e4e7859d6e0ca398fd105a4550607185f00c8862d476fa71616321e521",9.317957166392093],[4709,"da6d624d0f7e64a4543b0ea6430a5fe83f5c178dcaf6576e037904423352f6e0",9.917710196779964],[14812,"c08279d4d7d2b4c41fc24e7cc8f4e6214bab8d97c679aecaea3d31cb9bdd8e82",10.052724077328646],[8488,"38bd887af495651a2a77c7f84bb551393ee7a3d89b75740fd26ae5f18f8414c8",9.917710196779964],[13224,"8933563f605d96c90e38a69447fe7ff7eb7606419692af74f725d38d79ed6da6",9.647446457990116],[7362,"d41094ce6f50c3e9a6e1dcea4b4333f7195d56046676a8b3084e4cc11b95a6cf",15.079646017699115],[1173,"56babaee4dca40c4d01a2faa76f8f09d2dee3239a6a1ab53d2bba4064b2129f8",9.917710196779964],[9245,"2b4637ae5807ceec4f130b281546b5c162f714f906cdf5f5d494211bec3925c3",9.917710196779964],[5945,"6ee3a77848df2c5d467c406cc85675a4b361ac97b0f44df35a7338fa3c5c6dd9",19.81330685203575],[11773,"2792fb2e22c1426fd5778d9bafb1921df21b0f79395c68f80d54ff2a6f18dfb2",9.917710196779964],[7977,"0710bb33f8aa244525b66269a7e051776ecaa55042dca1ba5bd7f89e7c45aecb",9.917710196779964],[10888,"f73c0f4862818f8fe1e800f47aa002383e4f1fd6e4f506f82c82380427e0bab8",9.917710196779964],[9495,"a4c13dce57064386494c5c894c0d2330383007541f69dc8153ba50af6728b5c1",9.917710196779964],[14646,"3b0916263b0d462ad3775ef6e24df23f62defe3dea04fcfbccd23cfb1758ed85",9.317957166392093],[5700,"6915806ad5689c2dca77dd6b078b99658fc3b054475de78eafda0aa7736a0adb",9.917710196779964],[89,"190217bafd22d40ee1286959caa8b50c8faf60eaadfa3a71ac3e9f41ec1a6cff",9.317957166392093],[7495,"2504c7fe0b770ff037ce88f18e00bc78eff60c82be4607aee56665cb6735c6ce",9.917710196779964],[14625,"e790b38962938873491aa54fc13b48961b3902aeeb7682cc91c2116c24677c86",9.317957166392093],[18689,"b5885bbcad7364c05eb198fb076c73c093274a968be640a22a8be9c5a126b12a",9.647446457990116],[1644,"c7c165273fa66e2b069efb9c23afcd8c95f85e623facbf53b434b2d3f16154f5",9.917710196779964],[19679,"398af7304a26a55c4196d83049c2d13d987fb8682fe6200ea55df8cd12646307",9.317957166392093],[8377,"441766c639ca023dfe93c5a721fedd4c315d282096e2f9f2f051988b2cd7cbc8",9.317957166392093],[949,"ba8ff0ae9dd76f1ff934b1a3e6b0dcc7a676e37cae6c5dff56c11b42dea27ef9",9.917710196779964],[11816,"c8d8928facd2acf17d095e397c6811fb607e058b1c79103a0049199017c598b2",9.917710196779964],[19165,"b8ec5e89b82a6778f46aeebefb28deb7a137fded50ed5e07ba7e169a0fcbe519",9.317957166392093],[12114,"c8f4a1611a93ce7c6af0ff130ba18d353c6d708f16d382e7b93fa55b8b36a6b0",9.917710196779964],[5109,"22dfd98fd428e93f3b78e39724c5b0ee8160d750788bde7f8e9350ce5d2386de",9.917710196779964],[4076,"eeb4df2e31140ee9b96aff2b2cd9ec240e5f88f3a0ebf84310f0d4c3f18736e5",9.917710196779964],[10198,"7b556a47934c4b9e9abe86eb8c5dd0385ed0b5be2411022634f50430b0c505bd",9.917710196779964],[11184,"5e6363683161be1035681a743ae373d23fafad7261a44004901712510eeecdb6",9.917710196779964],[13714,"840820cf502222fd6219fa32a965a3a3f47614bf26119be787d9fa41ace5159b",9.317957166392093],[8878,"2b21f2d16f960b8af39f88eb945bbdca2adff3e4210e8cd4838466ab70da92c5",9.917710196779964],[18623,"a40538a729607cdee97f30b49db6695615cfb7bf54d8dcc211ac0a3ccd4f152e",9.317957166392093],[12442,"66735aa918ebd483429bae25f56c66e2a3fa3ed91c5c47945da51cd6dab151ae",9.917710196779964],[2449,"fd894853eadde57f4885ff2194ba061981f90cb080f3a19fe6aceb5ebb4a34f0",9.917710196779964],[965,"7ee4eabd30f25dc4460b141d39d40e01b0936e94dabb4325ad33134d4ca167f9",9.317957166392093],[11766,"c56f4ca2d8d50755d32216867f37e7e5ab33f791fc43912ea60b9d7a65e3e6b2",9.917710196779964],[17036,"0e588aeba3bd1093a01f489541d4987e681e79d79e55ba910c2bfff9e7ee3d51",10.030959752321982],[14725,"a8ba806ebdedd35571cac2c017f8061275a89e6a31f52e5dbee8cfd52e876f84",9.317957166392093],[6446,"e4e0f99faf82e73b06973bcfffd5806416d8fbcdbcb64a88115e7965bd18ecd5",9.317957166392093],[8640,"61ee76500d5e9a96ae66fd84ca1f3c15c88d0ea80b5b60f0d1bcf44cbdd128c7",9.917710196779964],[18868,"9310d1386c1801cf0bc54b0c10654a4f8f56b6893893062ad6001ce2f8db6d24",9.317957166392093],[2738,"2820ef3530c4762205735b81d269ba4657947e1c2b68d5b6d6e87625e8f12eee",9.917710196779964],[13342,"48fe8ddeb1f26dc24b1a7903ef2e5503ec0c96d4fb0f94fc2f2936a8f3f29ea3",9.317957166392093],[6424,"6589c3f82b380caddce65304d20d0b537e8d9cb4550006573fcc0e99bb261fd6",9.317957166392093],[7917,"a93220e65bf3727adbe1f0e6acc24b08209749ce6ee3897025b0bb2b6bd81ccc",9.917710196779964],[16548,"8f737d4ba08b4d5756fa2f9a4ce3efa17dcc107cb2a99a60a3e3b96f278b0c5c",9.317957166392093],[1298,"9737adc899cfdab62687e62a6810b445dc1c178653efc79d755b9852061863f7",9.917710196779964],[13355,"8ddb07eeee163dc7f0f246ae10397ca0bc073608a2747e0a14041e1f0a845da3",9.317957166392093],[8560,"c5f3a9704036f23aa2702030f259bdb25fe7902d7879813d5cf655505982a8c7",9.917710196779964],[10082,"9917f5159882ed30c1602094f4daf2a89714c40cfb8c81db45c2dd21b4cecfbd",9.317957166392093],[1189,"23431d65c866cdff7af99312e4f468f5156b86925d4dd1a413636f4a290816f8",9.317957166392093],[8071,"4356d9b39bcb00af748445c28bfbe2ac4630796d8ce417dc8c67a1b2b07bf4ca",9.317957166392093],[17938,"a199ec28fb461f5a36b7a56d882637e5d2d5bf0eca8b4ba4741f7040a15e753e",29.30366492146597],[12791,"fff19421d5a736e75d58fa9279315720758aca719706238d1cb885aedd5cf6ab",9.917710196779964],[2812,"65109d405078ffcb7c1acc7e6d307ef2d09533c454ec9843bf91597433c497ed",9.917710196779964],[16212,"aa514b15ef30dad21271bc0f5a296bf99dd2a1853cc109e83835751455069863",9.647446457990116],[16985,"ba0387911f6913f73b1d5f604189cb92c703908893aa68b235d02ebe26bd5e52",9.317957166392093],[926,"311f44277b7ad63ddbfebbe7070a4bbe43ec5914db2866456d277200ff1fa8f9",9.917710196779964],[9405,"9db8f4156fbcc4b11449efc89d4079676cbffffe2203e6d52deba984f5e440c2",9.917710196779964],[15788,"0f8387196d0c92e2f979dfd99ccddef7632b73c06e9096ba68135a32e0fc8e6d",9.317957166392093],[6169,"08f16b7be6ad5c9b8d0f4298cc33ad876c278a75406d11d9a27688bbd83401d8",9.317957166392093],[11201,"028cf9b8837e582a12690e950b33d10f89b52722174fe2f63c4ca8aa7c31aeb6",9.917710196779964],[1660,"81d96f08bc640fb861eb57cab4c2e525990a84d02cc84488e99be5276a3d31f5",9.917710196779964],[18428,"4e5662c0940ae69b80396175a08ff4caacca7cea102bb5cc1be8021847ff0933",9.317957166392093],[10568,"ecf322acea44e81d380b6a144b2fa733fb2fd57e6ee8046327932489fcb9c8ba",9.317957166392093],[14592,"98307a7b4faae7b539a824652738900d7ee99f5fc7ad761160ff72c6f8384287",9.317957166392093],[5516,"24f88b162b6b6ae41d52a5cb120cf49f2fbe98eb289e203b114bfc160ce224dc",9.917710196779964],[13712,"cd2b09b01714281f803c63dd641ecdf9ed355bdcba5493de587b37fab4421d9b",9.317957166392093],[12931,"4980bd7460539d88974105739aca499ef40821907f3736a150ec01617b5707ab",9.917710196779964],[13857,"cce2b8703b644d45cb3c20e585abf4ae6df2b05f623226a86e9529b46fcc4898",9.317957166392093],[321,"8870963be21dfc3af7729a7411970ec6c49195fe85ee59b32a97e1ae9451e3fd",33.08943089430894],[14527,"d7872f52ea483280bd4ada72befeb383c61426e32bb8ca46076c7c19f929a888",9.317957166392093],[16966,"6c8232694a35f1bf42f10aaf0625eefebf8de9e437d1993549ea3e46a68dbb52",9.317957166392093],[13435,"0e0a016f8fc70e351b8be879ed100724185f833bc4c61eff98549c451373ada1",9.549738219895287],[1898,"a56a7da3f7475f1ad122efe81a518a551efdf150bfb2b3a48faf1e0ad755a1f3",9.917710196779964],[2629,"99b1ea739a3671d70963531874298d55066430f9bf49cf0e02b0e810e60f00ef",9.917710196779964],[18929,"8cc4b8442c04d2ff6127009eb037eb8ae68b6a2a719ca7818c089717b5679222",9.317957166392093],[11974,"862617a374ff8416e8aaaeeb77b70fc1e2a73743491ddeea901266a8c5c37db1",9.917710196779964],[19149,"e402d84569ed176a74cf2521464e75d638ba4c8c0a3b9f303c428c3d4ec78a1a",9.647446457990116],[8548,"a126bd60897bcdadf1310737b515bcb9256b5445c90ce4747d3f5709db1dc1c7",9.917710196779964],[17670,"0c9bf76db5f3073d8cdeb79b7b6fc1b5774e7938ef7ac536ccfbbb20c85db843",9.317957166392093],[18198,"f514800314e23838b76075a5cce67d00a50a963c959a9bb50b387b2290e93638",9.647446457990116],[9023,"0cd778ac65a04363f1c2db86bd458816c78ed61c56156aceccbfa1fa0f4ca0c4",9.917710196779964],[3688,"9bd697f09623a3a69aec4e54bb3d98c4069f3f9437892c54af4f6fad14daafe7",9.917710196779964],[14937,"b6d04c848ec42969325d8f34c041839ddc3975596b3a66b08c8125aab7231780",25],[863,"9dfae82bd957de4f2c541241115574828726a68388de82a2842af5535a8c23fa",9.917710196779964],[10452,"92ead12d724aa6dc96d7ef89708fdf0b5e56bd88743c87fc34530145a8e669bb",9.917710196779964],[14348,"d8f3550f51bee28f0ab0d7d3aa3af8a89da3db8b844478b3466df5faafea628c",9.317957166392093],[6182,"9da9d0701ac8a4938216c3548f82abeea7b432502bc8aa683dde22340d0becd7",9.917710196779964],[14672,"860b6fe0936ee01366a13355f73d4be1272199197661c3bbd6ecc30ac4d56285",9.317957166392093],[1484,"0dde0c3fb92d3c7de8471cbc9b66a4c0cc88dabfa1cd2e638ea84e2506ac39f6",9.917710196779964],[1719,"cec9abcf2c84f52c4c25f382b4dc34bd83a30fbbb6918153914699d2db6fcaf4",9.917710196779964],[19312,"cc1ae250c65e5cfcb2107ffbebb4144718a222fd334046ead7ae9e27d9008e14",9.317957166392093],[12410,"3f842a49644dfd3d1ef4caa1aa0b5f4dcb60c75c84ffcd829f2bf218c1398cae",9.917710196779964],[9385,"aa1a21b6114af8337bf11b80e478ae8afbd38e89672010e360c22e0d2a445bc2",9.317957166392093],[17009,"dd092107d02e08da9e331b7d3912dd0ad32a73ccba781ec6538f2efb272de051",9.317957166392093],[3891,"bb68d9f01a28c29eb089e0998605679a4ba682d1485febefc8af88c08b9d65e6",9.917710196779964],[1272,"31b9de6a966e4379431143073c8155f0bce58621f7f4fdba415dd215f2d58af7",9.917710196779964],[11716,"78ec3f815075d75acac314609f4c39ffe846253c6616bae9f2a077e2fc0936b3",9.317957166392093],[2399,"1065bd4e7f715151e3bb1dec411390ac5ffa644e874c5e3febd12827176e80f0",9.917710196779964],[19001,"b0cd5206508253005e1042e6815ba76bfc19276ac1c84e696d9f60a5a3117f20",9.317957166392093],[1489,"83b34b69f2b0e822d37af309ec969294b13a542ff0e76fc64bcca4f0a26431f6",47.86147186147186],[5187,"74bc61abb7fb0f07189e1acd27dcd2b90191e95451547d93afd3baf91a3a0ede",9.917710196779964],[2926,"254b190686d13c49ce72a291dcd0bc39c52a0ec76c2213ea948c08037e99deec",9.917710196779964],[9172,"6217912db870a5202255c108d1dae513c382915523ef009a7998a1242ad4b0c3",9.917710196779964],[14431,"1cfba13df258e7e2703e1ae97dab3954c68545d1ee38b60fab51c20c4c2aaa8a",9.317957166392093],[17268,"be59f8d3631d13846f1e900beba6ba0aaaea6fd60daa12fad0e6cbb08ef3d04c",9.317957166392093],[3664,"5b0b570fd1451d095ed92fdaebf228c09741d61d474a3d3a1ef2218ad459d7e7",9.317957166392093],[1652,"9833d3f21f07e48c307c6e5a477ff357b0c09dd7456689eec86a95bc41d344f5",9.917710196779964],[7840,"da7fcdb68080d5a8f184fa431c002b9c9111ff9f7ace0013f604f5dceaa68ecc",9.917710196779964],[9344,"19f10cb925a67a7cd54f5edd25e06fad7beab2e92f3fde010590473f876e9cc2",9.917710196779964],[18071,"ce4a88db150f214823bae690d847ff5f5ca21e2072db6e46714f3752c865b13b",9.317957166392093],[1284,"d7efe1df824c6e924026ce5067813ebe10c407b02d8fdf930b59c2dbc03f77f7",9.917710196779964],[577,"bc4a3c4172d6787c1f63b7e994b679ae9ad501897888f33a94404c72825817fc",9.917710196779964],[13051,"69fc24d69df67f33f39afdadf32232050c7df272058ac0cb4aea3538bf8544aa",9.317957166392093],[16525,"e347fa4908f16b05657a110a0d5ebc5039d07096c8ea54237821689b30978f5c",9.317957166392093],[2817,"6beb2acbf3e017556c8f0f9cfb98d13e219f67aaa9f9979cfae270b0d47292ed",9.917710196779964],[18535,"8423a9f9302eae14305bca150904790beb3873bed3240c0720eed97cd7d1c830",9.317957166392093],[9181,"b03649ab2d929f91895100a06e58768f3e63a89f4fe09ba0694280ee48a39ac3",9.917710196779964],[18377,"b82e3f7021a423279e4cd560127f0138d0e7d88d6c26774204e553ec627a1f34",40.97682709447415],[1957,"a216c06ade9dad56ee19acb2209b77041c865673fa9e532d77b7a0473ff14df3",19.07569721115538],[5848,"1784dc223e71d03259145eb92b7c22297b2364ff6ddaa35368dbdde7984c02da",9.917710196779964],[8638,"d4b80699e7cd8239d75f869fa1c96a49019b868fcca160bed4759a2dee7d2cc7",9.917710196779964],[2199,"9ef07f09156833a9eef28a608db94ecc73019d2c1aed09001c94e301714e89f1",9.917710196779964],[18602,"33e86c991b608194f26a2fdb0978af8a2caffc8c31af77ce44b6d12f15a8a42e",28.098939929328623],[14844,"6c6f1153eb808183f15070b876febfe6390c9ba9e2058bf507218dc43bbc1182",9.317957166392093],[4879,"7267d560630ac89bb1a60c5e8283daa9cca17746a22f79f55cac8bc4ca39f7df",9.317957166392093],[3829,"a979aab1c6ffd23a041b01390a18fcd7eb7367b92e5d551946ffab535c7dd5e6",26.062350119904078],[17406,"da7e0b8fd7e9dda0ac1ae7142c0b7f66d666b2cc29efe89e79c7af3c46beaf49",9.317957166392093],[12051,"002f17d4efdbf0612fbdff8eb5d592c593528d15a9be868e71ec7f133dd4f8b0",9.317957166392093],[17349,"06f6601217611081b0cbec2584d29f4ae273c38d04c2e7323435a86e7c3bde4a",10.052724077328646],[1221,"27a7b04be8be024648500c5e7362dea63d6c4fc1617add627fb106b7e508def7",9.317957166392093],[3819,"7144e4393d12858a7712a4d2ab944c256836ad58ecbd4e13e47612e91b7adce6",9.917710196779964],[13839,"ae806ec6734159fd51bd45c07e5149b92d3bb8073c5d084cdacabf6f43cf8a98",9.317957166392093],[16189,"9eb5ebb37c01df1b6b086639ca14aef3b67e7f2de18c76fb525f75638e582b64",10.052724077328646],[909,"e294660f33504755d26abb8bdd649baa1120e2e831a6d6a59427d5bd939dc0f9",9.917710196779964],[12470,"ba28c0cdff9971fcd1166585f0328ba800e8b551bfcb1c0ee154fb5d9d072eae",9.317957166392093],[12848,"aabdf5e7c88d211f5517f19b5b0d2b92add359d870189b2c743441c7f80197ab",9.917710196779964],[18972,"c50c6981dd73fbbdcbffacaa176425ee12f838eeacd2620b9efef2f188a77d21",26.11764705882353],[16215,"431e8883dfcb5ca7f87d66b2f4ba2848b619c0dccb2248687250060902417b63",18.009022556390978],[7272,"463cbdb3c3e54b73c41975bf905d10158597c9ade6040fc1fa3e509d100831d0",9.917710196779964],[5793,"fd7f3c7c3d4605eeddd38a7c76e1a63f9154087985b535695a9fac57ee3c79da",9.917710196779964],[13778,"7ad97e87dba2700c668bba234e2c94accc9ce52389d66e4cfc6ed415cecbcd99",9.317957166392093],[1232,"886af20530d93d31d872a5a70e95bd71f2ccda8667f1d99825cf53739cbacdf7",9.917710196779964],[1008,"5c7459e950470e1a96522af0f55e731b140d3aeb9a67036a117bf956e7b226f9",9.317957166392093],[14423,"f531bbac4737e5da8d039e8dbfcca444af17013f4fc0e09f164ea5f2273acd8a",9.317957166392093],[13068,"72bf5021af55a175c7ce80078904bb9ccf186149de49d35657af159cd51231aa",9.917710196779964],[7710,"f384cda4dbc65acb9a6e2293098ee3ea6e86413e08e0ce2209df8a1705ac7bcd",9.917710196779964],[13765,"fe6083ee7fd74cfa06ea1ed13f35b2350537c1fd5d64e4196983bee5e5a6109a",9.317957166392093],[5555,"bfe490d73f5724acfd93c0fa9522c6b0e32f4929bd7aac5d7656409e4f13e6db",10.045662100456621],[3583,"5ee097b8d080164c99d8834af0327e389237f93e034d16e294f79a3c03bd69e8",9.917710196779964],[9112,"4dac2e29256756299f94e5963b8ae09dcf43d970cf9d61ad0827433fd38b10c4",22.689895470383274],[14920,"da63b9007a81da68022c772cb124b0f79ed769bd13c770fb5579554bf8a88880",9.647446457990116],[8527,"381c4b53363db643817192a53db0387d4741e3b5b46fa72f91668effcb61d7c7",9.917710196779964],[17129,"e115433342c6b232616eb1f8ffd29c1a26989c8a1c605c1e5518ee06c06a6d4f",18.895774647887325],[14597,"27f5016efb3ba1f60cb048378bab3248ab1abbe604fa55cf31ef43b142c42c87",9.317957166392093],[12460,"ddaba5daa71aac9bf814ee3008269e966076538c31dc88687ac75fad67e43cae",9.317957166392093],[6631,"f89519c7032b937b6201a16afa0e190a86406797eda2943b41e62af56c0e74d4",9.317957166392093],[16379,"1f2748595786b692e227c8de71b356d91b6acf737adccff1d864650152e67d5f",46.84901109503136],[10434,"23ee62d8239c8ffef3438d608164f37cbb800efb3bbcce5128fe322ee0cb95bb",9.317957166392093],[8115,"aa8f968fe5620304e2e2b6ba72334dd7eb1cfeb8f64a3baee99c18d10b33a9ca",9.917710196779964],[1358,"458742227010b075d63ded8ebc86dc1e0a268ac14569557ddd9a600932d7fdf6",9.317957166392093],[12407,"8c6bd672a9eba65eed96cc34f1b3b376f4c3fa1376fbb6346a901e9d9a6a90ae",9.317957166392093],[7480,"09b0a979c6f5ce18a0baedef8d4eceb1dc927085e968d72e1ba31aa07359d7ce",9.917710196779964],[9005,"e75b50bb90d0c9fd591681df4e0566dc8b19729008d00758f782e91f2210c5c4",9.917710196779964],[5628,"60028bbc6ef20f7fb88381d91641287bd3ac7a59a05690e9108f97810a4d79db",9.317957166392093],[18640,"3cb0f38f133f30493ae1d74f5bdf954f4f326f82b4c62128421ab59ff6ad3d2d",9.987841945288753],[18086,"4d677000b7e78b4f955431e7371ba464712a72a2832232784cdaddce27c75b3b",9.317957166392093],[4591,"d826c6db0784a151137704f6278764873f09441fa5bb8f6ae7944cafe236a7e1",9.917710196779964],[4387,"ede30debb1abe67a49999246f0c972e4485f746670e92de1f9be8e885c1e26e3",9.917710196779964],[18696,"ab3fed54af361189b6551197190384d04f6ea55ba234199c2e625813a39d802a",9.653116531165312],[9001,"88c06ca7eec36302a901d66a910038de2b1045ace8381befb5b54b254007c7c4",9.917710196779964],[17116,"4cd7a6cc284abb9c40a9559c1f60244f6679bd470bc6b5ae2b0f949835e5a34f",26.036553524804177],[1992,"46707b3e4d22ae59db93a8b1338eb60e21342d57377306cd26a3060a65db0ff3",9.317957166392093],[12113,"79c4c429fec8d448acad52547004743d21b22474c70d3d165d763905c04ca6b0",9.917710196779964],[5662,"adb19258064779ddfb52af64b6bc6c65e731e4ac3ac43bf9574432c8244842db",9.917710196779964],[2316,"8dbccec3792e44bc9005f094ce04a822b942d482daf18bb66a2ad55915caeef0",9.917710196779964],[10964,"202fdf2100053b08a606cc846a62f188fe542915277501abfc3894c898203fb8",9.91150442477876],[4210,"558527014bfd3a52dec1dd74f583579f938c2a9faa06a62d0bd2dba035155ee4",9.917710196779964],[6467,"b1316d2e99699e7e87df8ddbf7c9c03ed2633f6dac945ecbafba9b9329a5b1d5",9.917710196779964],[19237,"f721981260d5a08db71fc78b69170ee6ebad5ca0b196b8ddb50595f9f4125317",17.09090909090909],[4003,"5c22f0e0055f659656257c51efadacf51362579496779ca568205f410f8eb5e5",9.317957166392093],[3551,"55a0f391b0aff8ccc77f19d7fa339bbf0e8db85d678df140ecf107bb875b97e8",9.917710196779964],[14264,"228fa4b99146242a38f0e1a46ee391ef56f1fa20542f3fab9b09c268c078a48e",9.317957166392093],[14529,"d9fc02d3bf9ad3eb3669a42c8505ffb4722cb7c1866b15eef30bd9e5f556a288",9.317957166392093],[17973,"dd31ea399ac052ce4f452d8e1d53787e0d9f4df934751cc459c7fb1ed38db93d",9.317957166392093],[19438,"bb2751dceae45e15756e9886c9ae6bcbfe49fff1291ed7e882e46641e3bc3710",9.647446457990116],[9524,"5498ca693bb59212152159fd66b4211a8fcc6f5023301c521a21606fe62f8ac1",9.917710196779964],[11292,"670d242f45e70c8077ee068b493e9c08b50f4556f23790c196505bb044dc15b6",9.917710196779964],[19065,"7fc3872a79ba116b958f0468482656379a63203a806a2421fd92cbabb831191e",9.317957166392093],[10308,"acc48c2e5700e95b74eaa2e4d0102a60dee0a07dac542e1a651199600feb4ebc",9.917710196779964],[14850,"2167135f0d7604b90cc32083a9252563d5ca4cf576029a2104cb69d3ffd6ef81",26.09252669039146],[2966,"22448c2ca2930bbabd259404a050e54ab9f2aa54102d0ecf8702f0fd11b386ec",9.917710196779964],[6192,"266143a1038d151f6c8a0f1a74be14dbfa5d448f3534a667c99823af5744d4d7",9.317957166392093],[2824,"e380074ca6b61041d47365a40022a82e4b6332be674510e4cd2d6d6ddb8088ed",9.917710196779964],[4070,"bc98c4d5cb3898b5e85807049c1b388977cea0d7da50fb48981c10f179474ae5",9.917710196779964],[15659,"7f34dd8ee7d8282e12c7b0785827d2bc938b728c82018603491a13bcee682a70",9.317957166392093],[7200,"0771a69eeb95c09b405dfc9361702cb20ef859c3c96441f1d7b7459bd3d8b9d0",9.317957166392093],[190,"a5566e728f7430f3f6c01fea015f23c07bb1231760190355342b953b6998bdfe",9.917710196779964],[14567,"280d23d6f87247b766ec2472b6f230c6b2f15c3ba98cbc0990f447977a1ccd87",9.647446457990116],[18890,"4def41a3a335a2509e6ed296598b3958944579c4e64cd054c0c8e38f179ec723",35.829181494661924],[14863,"9f30c0245e8dc264ea34296f06e2c25812cd96bbb063f5fdbd4fb9d01ee58381",9.317957166392093],[10571,"c4e88f8dedb3ee98483482bcf7f47d1c5918f4666b250e9f14e459ea9c0bc7ba",9.917710196779964],[19606,"2019641a9fa3af3707521de19f505ba9526643966a6cec2672e527c599b2c909",9.317957166392093],[7809,"6d769370e0ae01f92ce3c9d1168080205933040f797d0bc50e1c90f4c122bbcc",9.917710196779964],[9322,"a39af9ed2e6a253b03f4a736a2bda26d5d026cf87d4d777170ae2d08f35fc0c2",9.317957166392093],[12435,"90f9599a331997c91e5aba2cf2ec54d2b2661e50700d3a8db8d6d10a31e35cae",9.917710196779964],[18544,"bb9d2dadb96c8c7795d088dac3ec1f0142b715abbe56a9bfc368b2e9f1ef8f30",9.317957166392093],[12340,"92a1d056fafe3cd0dbf2b451da2f99e5b7e3225aa032326402cedf2a7383f1ae",9.317957166392093],[11168,"925ee4359a3e8cdf704c7fb28439b1a7a868ed85a641d470f06c9c7d3d9ee2b6",9.917710196779964],[194,"169ea18a96278ca5a71cc72ef68752f508bfd7c1df89af14432a20e22074bafe",9.317957166392093],[11914,"3223cc5074b269394b2431dbdf921ac4e7dc8cbf278e056086e1b6299c0fe9b1",9.917710196779964],[1359,"37ab8c0cb0b555e7e0b50bedbb533b2ce3e5ebcb8974a86bb2ea055d36fcfcf6",9.317957166392093],[3215,"d296e3247778ec9746c0c304f45522f983489b14adced2bd9c43e382e496f6ea",9.917710196779964],[875,"67d185c4ecdf8e233af7cb66d31817d6e8eebfe5f90e34863db19258537610fa",9.647446457990116],[16608,"5b8e227e14e09bb3269be0724ec39b14dfd4ef824e4a362559e721e9d755a55a",9.317957166392093],[13562,"30ff5f9ade8942438ec99d4e707d5d1f7ede3fff648d8b6dd99c9d3640a3739e",10.052724077328646],[12355,"8eae3d170e424d60c62f173a213d6c96befb918a8a57168d9b4b5ad6aca9e2ae",9.917710196779964],[14906,"4a1183b7b62b8dd2bbb7507109611bc2fd3df4fa7a7ce7dac7ebdbff2f46ce80",9.317957166392093],[4697,"39c4d66985a830f2da5248068636e5a8e2bd6d2ff89744e96a39c07a964004e1",9.917710196779964],[12256,"063fb37c1b4c1c218d2ac5edf75d70c9c7683f2e4c7ecbccc39c6ba667bba5af",9.917710196779964],[12488,"9d24c9f5e94d0419e19b1c49aa705493d87bedd0ee5716a6e658b7ef501205ae",9.917710196779964],[3269,"2c3a3584af272bbfe5967fddc379ea986d3a074d76eca65d025ecb523ae091ea",26.09252669039146],[5103,"57b710541148c5c89cccea033d76cde95bc9bb7e3b8668009a583a3535178fde",9.917710196779964],[9626,"222f5e2e500ba81a3ff2ab4da29683427e919f9d59f288e8682094ab4402dfc0",9.917710196779964],[15911,"5d77aa164afa8ff231e0e6ebc6f24a7d7681f4e095545d407439e98e2b3cc66a",27.900178253119428],[12653,"c69cb55ba0a70f0448773ccd1335aa56949f5da3c24ff55b851e9db3ddb3ebac",10.052724077328646],[7833,"eb4e7398229616ac7fc2709c76b456f6ecefaa0b2603b60f3e1da41cf9bd93cc",25],[15007,"c452b2db282c5385f55e7d26fede2277218d745c0d71acf5812b375079a22a7e",10.010582010582011],[12419,"6f58a54b52a96c3c000b8f81c455a23ab27bf82b8a98852969fc053f683478ae",9.317957166392093],[2561,"eede81618fa144557379620b025b6bc2f8a074965e900a57e6dcb4b20ac27eef",9.917710196779964],[5612,"a4f3112bb996a175c90428767dbdbd6fa2ecb7d46a43eda172d6e74caf1695db",9.917710196779964],[11687,"88a0e3b41f5f219d1708dc441b3318fa39de18ea5712a0ca1ea729d1b35b62b3",9.917710196779964],[3597,"93b902f57fe80b1bb3770b37602e9bf3ab816d28d46369765f83911239ad3ee8",9.917710196779964],[18172,"a3c6b47802707d0da32b085d2cf2ff665b296b9e0f50c648bcea9290a541e438",9.317957166392093],[18366,"bc9629646d5392b6f8f41e6cbf2e8bf33f2b89dc0a1b11e3da023a5776d75334",9.317957166392093],[12899,"c4c0b10e40a063dd92094567cfb46cdd479704f2069e00485392f0dee2f14eab",9.917710196779964],[16726,"3a4663228cb5ca59534569af3fa4a841b6655247a48d6a7b76cc557b1969ed57",9.317957166392093],[8513,"863238586b86b4451c5bae271d5ba96d455d2a6851fcf7a8c0935f75a7a6f8c7",9.917710196779964],[12316,"101bb5f78720533cdc34593e3025a19ec75e5c620c0f5a872a7b5500f4621baf",9.917710196779964],[8950,"f30be850f4f552633c0b92cea0ec7b1e69d6c7ddd23bd3d5e7dac097bee11dc5",9.917710196779964],[8616,"aff0d4f78fba0766a854e59db236185d202d0cd5ee57eba355ae00bfea144ec7",9.317957166392093],[18612,"7d9b0d6b5f7fa2090ee59768d6c517569431328cbd3803b4c1e486b081f3502e",9.647446457990116],[13757,"6071071c5f561acf2d72dbdd67ab74315a903add8911a7bb8d5ae04a2f9b359a",16.014272970561997],[830,"a011a7152a5d5c7de27329b797501583423955fe692db836eeaf508ddd7e58fa",9.917710196779964],[11793,"dea67f26293168b1e8f2f06989213e5f7235caea09d43e6ec9df2e41de51c4b2",9.317957166392093],[6203,"b69889bd99a5cd2ffac9c1821c77f1dd8f7489ecd6a64502fcd9e88e18cfbcd7",9.917710196779964],[12682,"f6bc0d0701c2545567426566af8cc38920aa667d06958b221c67a035f97cb0ac",9.917710196779964],[16231,"f03f443919dc7beb4c36789444d7d45c006cfb13ac4de6cace7d00b9c79b0663",9.317957166392093],[9913,"796eb8bb68806a07c7941a7b53e7164a7b513d6ce2c73461064cc19c1c1ee1be",9.917710196779964],[4568,"11cf928edf167cd05fc97a6acdc092a7b942222403a36a554d04d7131753dee1",9.917710196779964],[13024,"024f72be2c7c3e1fdc8b791178b3910cec77f1c380e532dff9f53159fd606eaa",9.917710196779964],[10426,"c1e91766cbc74cbc32d96f635c49d35cd14d9761d5a0d4d293451ccce155a6bb",9.317957166392093],[19722,"ee25384517851da06b2dc46b080be268a7e815aca14876812c89e2c10e0ce905",9.647446457990116],[7346,"26b1c427046681e196d9f8595d6dec62315cba54024c3c4a5c422ba51fe1b9cf",9.917710196779964],[19326,"aa7724a3dc973635208c2b163573ab3d6dda78dd7ffcc6e5e0ea2efcc4764214",9.317957166392093],[3351,"c3f760e3774bf23b1d5a3507258d4658644dc8b2ce6b9b465cb91fec45a802ea",9.917710196779964],[27,"3a04dbed9df229e2b3b31df963cadf358750e8854ca3ec4ba53e1e644573deff",9.917710196779964],[8382,"7042b1394eddf9ef50c715bd335931c1c5d8161c7cf3acc0718212ccbfc0bec8",9.317957166392093],[1458,"bdac6cb86d9a31389d24f4c6841ec30600b5c90844214cfecb0014c3f56c71f6",9.917710196779964],[4447,"36e977a933b093700ee3b8f1296ab99116231ed886077d83d414b35429aac3e2",9.917710196779964],[10944,"916030d3a45aae2fd12a56e5a6d475b9a07e6e8e8ae71ef8707913a69ad46ab8",9.917710196779964],[12506,"4c97870efdbda65c26b32570ddb77461f1c0beb5ae60202a765540526256edad",9.317957166392093],[2302,"6524258adfb39aba3882fad09e86f612cfa0bf9fa8c863d1d697c2890a0b02f1",9.317957166392093],[4164,"cf89371d01ed244a59a12f393a0011dc8cb5d7abec1a636bb9062a04b931a7e4",37.936395759717314],[6746,"d50d745f8bb66f5ac4d0623a04fe757654dabe1364fdd17ef821be0e0eef99d3",9.317957166392093],[8765,"4da87fc75dc048170f707da282fa77bf411f4bd3e907faa6dac622a70c0a42c6",9.917710196779964],[10720,"a976aa5dd7b98a034c153eecf9fea55a613b6368d8f18d515b315121c22ee0b9",9.647446457990116],[7590,"b75ca9372f16082803c578283b2d18bee822f8c72aff3311298f0da6e60340ce",9.917710196779964],[16041,"6b6e24b589b3bd6ad15383e7ea6791c4d8a60bbba9e8ba923a6bcdbf87088f67",16.68022181146026],[16613,"1679e360cf62681e5b33ede105fb11f321fb923df0c81945157275f4af4d975a",9.317957166392093],[15515,"1931a0626dd03cfce090e2427eb0bb7ff402a60d8a07e4771797c6039be9c673",9.317957166392093],[19268,"83d172de0470e8c3542e98213e4dd87d88474acbbfb7cb3a643a52a4de010516",9.997888067581837],[8137,"578306a095c62d0aa7d5255ea221acf02db456f4455ccb67a0934ae1047674ca",9.917710196779964],[13456,"78030db2ea1f002e2a7b01d5a39d6615efeabf6a41656719be27ec50df79f0a0",9.317957166392093],[14968,"27035eacf4bbe868e8d92c757fe8bdc3161a9180c587d6cb7f1941d1a8fc357f",26.912246524395645],[1261,"ab6eea739c295da8996a68fd04dc0aa7ecc7e2ad633db81e28800391970e99f7",9.917710196779964],[9851,"ec8cddee161ef3c7581f81c3e28195d129c796ca74da46709a813b751fc94dbf",9.917710196779964],[15486,"6cc7c902e8c1e95e3295cc90b6ddaeb90c0804a5085b5b6535286c2f0e856574",9.647446457990116],[16367,"ae2ecce718d709a8cad1b2aac056b63852f7844425acfe65d3e5746314e1b15f",9.317957166392093],[18821,"ce8b3772d5277acc81e5eceeae69802b0d8dff164705792b56208a61937e0b26",9.317957166392093],[18430,"7f252c7b2b948f9c9d14252bf807be0c7d9feb5213a081339bb1c13936760633",9.317957166392093],[16705,"af5dc79e42652d3d4d7aeab471e6c2841cdccabfd454d3667c3e5d9a878f7258",9.317957166392093],[6176,"fa1984e2bb3801be7ff9792d5d4c9e1ada96f09dbef4a1c2c37ffb7796e5f5d7",9.917710196779964],[17905,"3feddd55706c9499a23664cc5595358186a202acf7de74852b9f8fcc68ac233f",9.647446457990116],[11631,"4faef95364872a2b8047297dd931e02c10fd5119fffb62500d4f2a168a04b6b3",9.917710196779964],[4300,"fb6160b078e3d5b78eb56f6cd45799250b3737cf6d7032335c38f6b753dcc0e3",9.917710196779964],[12830,"1eb0f473a7ae3c7b15939c2eba854f7cb2be0f85561b10e3c8ed7195ff3cc0ab",9.917710196779964],[8718,"482ca038dfa43d62402ab26d3bd7cdd290b415ec679e8300415f4f95da8f91c6",9.917710196779964],[16070,"0d4e0da2994582fc0cf06a7394b5fd17c33e6a9e970bc91c8dfc0808b61eda66",9.89399293286219],[19702,"6a431ff4a5a543e54d9613dc2205eac527251067ded44c560779a541234cc406",9.317957166392093],[3442,"9a29de13084b6db3444c4ca47740e9a1ec674f08a99bc0b12fb66b1f445c6be9",9.917710196779964],[7084,"1fd73aea18abfaddf57b9ecb13ecacc343feeabb76d6b9a33f9b19ff102f71d1",9.317957166392093],[15916,"5cbe2436ad262957eb1477907e3e457f13eda73f24a8cab81422157c8f03be6a",9.317957166392093],[3089,"4bbdad5d160526170f40facb145503ff0ac7995c482f6ef329fd7e3d9420b8eb",9.917710196779964],[11226,"b3ed5ab9e7b9b16814be4226a86fcbf656f668dcf6d92f1ee67d7ff5937a88b6",9.647446457990116],[19772,"e0cef311838da0629915a38530eb04c55695d0c054531cf5e3120bba3234a203",14.049469964664311],[12182,"4ac36d58f6c72f31771e9fb2bcb82893b8db929f4986e9529cd4fa1aa8ee31b0",9.317957166392093],[6644,"948c0a869f9d448e77a68c899c728adf1c344439778e7fbfd8690d2196d65dd4",9.317957166392093],[14391,"31258e59f2f1a4176c3cbdb64e1f11d548e2d5c5cfc6108099d36437b77a5f8b",9.647446457990116],[18224,"90f371176f66642973d23e1bdd75cf6b7843d56ba4d38910cee150a8d7988037",9.647446457990116],[16311,"324ed66015362c012318939043c5678aabf38e9dd6e78c7c0522a356fb41cb60",9.317957166392093],[13639,"9a51fb28a3d6b1bb7f845cf047f5cd626bed1f8f913d75f3c7d04df8ee378a9c",9.317957166392093],[18975,"09c1c082ea3af2c2cec7fb1df4d51d38afac318b29c50b44c4afd997c0285e21",9.317957166392093],[9195,"27e96a1e8c0f08498ba57e9442765a7c09b755eb178f854c0229d2a5af4e7ac3",9.317957166392093],[2383,"a00be4506a8bd486e1faca789d47f40a1ea035a7a2ddc7ca57aacee7307d8df0",9.917710196779964],[5315,"681468a9e976ac02e497c9ad727664155977491284e0112afc0aa7cf5e774edd",9.317957166392093],[2563,"422d4c5856420f94783b558faf93e4da07d746974c2fe2ca38b41b091f0b7eef",9.917710196779964],[4782,"3134c3dc46bb69e7f5185130770104f0ba19884d25b8afeb3239effdd79082e0",9.917710196779964],[971,"b0983fabade7ba1bac33e2b981a78ccdcdd195e3486dc90b15e3a93c50e65ef9",9.917710196779964],[16754,"cef862cffbb9f1e764bee6eca0547063b9b26f0e0f18807dd697712604db5f57",9.381044487427467],[5257,"1194e43592da5ea34d959ad0ad0457e387489d9588fdd5ac16bba4509ceea3dd",9.917710196779964],[7802,"1ef9caa7f13653941181dbac7f42cb81090b5cd745314d911de93fbc44eac7cc",9.917710196779964],[16797,"9cac6599ccb50e2c3f045a92607c027e967e218e6cd1431921b680252d7c5b56",9.317957166392093],[14050,"50f08765a58d07e43c14f506e5ba3d8338b790c40767794c56a0639b8d04b493",21.32795156407669],[13089,"31c5f8314b5e31791ea89bccb271fdd970cf9d8ea7cfac1410b3feb394a1bfa9",9.317957166392093],[12030,"de8ae53f3cc5b2f2a9e361383385227ee699e659a1b9f2db182ef0d03ed517b1",9.317957166392093],[13366,"249db9e7de68c376b79d2d28fe5a579997fc62a4a9fb0c6198f8856a620c29a3",9.317957166392093],[7140,"0a0fa39847c362535fa05db2eb97990a39c1a39ccc6e650ac173a64eb7e215d1",9.917710196779964],[11703,"794cad562e2750e3812d35eeadef02302265128d0a6b3d33b9e1049e1d2f47b3",9.917710196779964],[9719,"1d794584e842b422d65e08f2d4a5f8ed6029d140e663b9c3144e0b606b313ac0",9.917710196779964],[19841,"ae4bb428e7f268cb4876b1429cea26ac654af5478cbce501bb6f6a750d0e1301",16.2152466367713],[1648,"79ffcc29a9cc482f3b443ee95b15eb2022b0737e8c48984e80e577c2d0a947f5",9.917710196779964],[1686,"e853885c9b0085792779ff57b8c56994cc306e839c61793ded27b7e1cc2503f5",9.917710196779964],[5792,"ba280e203f35b0ddd3802d4a4c83faff9ec91a770a5503180b616e6bc9bb79da",9.917710196779964],[18102,"962d5f96eb88ad67c769c87734d458da989af23fea5a5a03829e4a076cf4e43a",9.317957166392093],[4889,"2333fe3fc441499f485d360570066e01f5c566cbdf9efbf1a079718e4d45e6df",9.917710196779964],[12865,"e11fac2b04e0617a9ae25d39ded7dde5af76f4c264e6f2140e01dd7d6d8679ab",19],[8361,"813bb0185140de274a0780b7e5bb885d616eb8bec8e20853081ce0066cd6e3c8",9.917710196779964],[11538,"f9992458f58620ea09a723f406e92e2ab08b683a5625c81e718f6a3b43434cb4",9.917710196779964],[11628,"8d5931a9a2232d62812ff0121c0ac8b061569941cc6e0e00da2e3468f8fdb9b3",9.917710196779964],[10771,"dc5d7749e93ca3f62616f454ac7fd6b74321dcf4443a4a21a64d0adf54ce7bb9",9.917710196779964],[8793,"48c5702a2d86da9a450f8ae3c3cf87c21e3229feef793a8cf555caca47f918c6",9.917710196779964],[5366,"a948ab19ab3d6f37758d5cc9a054205a93308f5f876341d4ef521b4501c40cdd",9.917710196779964],[8198,"6280deebded452beb9fcf8b54d5c7e1dcdfa623c65450a16815ebc4ea55efbc9",9.317957166392093],[17049,"087a5cbbd560c347b396f9ceb9dde18816bc51a54224f88efe50c3a774911e51",9.317957166392093],[513,"4c6841060ed2a62eea2b0cbb436c7f57fdb538d732ddbb855d257769133b99fc",9.917710196779964],[4840,"102e7c4d15561599567b0f9379a7c1dd951504e36329b1647c9eb48c7fa131e0",9.917710196779964],[9267,"0d43fa5c2e21d08a93601809d27ba4378a81c5968cd74d009e19eaea694c0cc3",9.917710196779964],[12534,"709ee07ee59a1b67d9ff220be82df075d8148af0e3e5690b38f43181529db3ad",9.917710196779964],[6445,"10f77470ed0cc7c5871c68a3048ecfd8b5ebb310ec6af2f7f3795f383f08edd5",9.917710196779964],[2567,"dcd781526047f09c38b6a5de307950d23998ccd826a51d442ae96f96204f73ef",9.647446457990116],[10996,"b7cb5441395770b40fee7ceefc05f0349c9dc31022124ded07884222b4f804b8",9.917710196779964],[8573,"d0225329cb0a70df397dda0a416a7cb93966b8008a8b7db9c729bd17bf9698c7",9.917710196779964],[14075,"cf8080bd90390e7c3b48de72619595782a93a0250247e27727244d2b146e1f93",9.317957166392093],[9973,"3d496e3ad599fcfc539198116e9425a0914de198a349bbd097d08f48e25f7bbe",9.317957166392093],[7930,"f20148fac0fa0755ba849c12001a4a7abf4ec8bbdf28cc5ff1180a99c5e707cc",9.317957166392093],[5599,"c627b6d5ffcf9eda6d0693369a9aa314369e9677a314de5bc5bf07fd5e8ba3db",20.67023172905526],[15066,"19959e57218c00e16898fc50b63bc1b97a249dbe550d62a8cb99f21eed71467d",9.317957166392093],[17885,"b1d2d32c5d5426b6f18d750419805f44492c6d88f0a2a9e20e1a8624123b893f",9.317957166392093],[8287,"32dfdd4a74ded21ade8cadb8e9bdeafea995f34d1c158ca0fb35771a7faa66c9",9.917710196779964],[14908,"71541899c8923dceee79fc43e9af4fc55d2cf72f4aa82697e56b293e1838ca80",9.317957166392093],[16757,"025265b76ffb3b2ef792fec31b5b9abaf54e74cd27e9be1e51f345edc5c44957",30.265486725663717],[7817,"cfa2154cfabaf4319067915b06d59dc69fdd062c04b190ac05e23c16af45a6cc",9.917710196779964],[6348,"f4aba4e8dffdff5cad7aeab2c4d9f400a0efc8d9978320c119baf28cb122add6",9.917710196779964],[8474,"69391531cd22c9eb190b70a435fdeb00524f5a47f613aba1a7fc0ece4c3b2dc8",9.917710196779964],[123,"f18c29391b50b03bd5c060fdc29863c113dcc11f96440eb1ea381df3a95d3dff",9.917710196779964],[6360,"353c14f0151c448647c47188fc3bd5a0b84f3fe73278d4b2f18846767e89a1d6",9.317957166392093],[8924,"55c69687389a5bb143da3c58235c37405993b38b649b720886d8cc35e84a56c5",9.917710196779964],[9633,"1f8a1f1a2b24ab139bd21d31b65b2264058227682e070050153ccc64a47ed7c0",9.917710196779964],[16106,"6e1ab4032e926aa0f0f09e7f142fe27f1d26ede2a3a8ebe344279991ffd9fc65",9.317957166392093],[1962,"78f1dd293bbc416126a3dd035ae61cea65ee43545e4923ded7cdbdf326d646f3",9.917710196779964],[11060,"fff42c6224e710223ee64eda56e5689a3f0d2cbaca6deee7f1d723ec714a9ab7",9.917710196779964],[19009,"9785e0bc69d511582a8638638e18d23d0e0efb2b64ee94bbf07faa0076bf4020",9.647446457990116],[937,"c5d755f25b61e1d40b56535301282bd9fbfea53c58e24146d5d54588e19e95f9",9.917710196779964],[3328,"8082b60156995b1b744b07b02294bee2af7a8e1e965ceb10c7616910ae5032ea",9.317957166392093],[6494,"65a9d6a0176eb5f8a511b97b08bf828e081398279079303cbcc09e7be5bd88d5",9.317957166392093],[10246,"695f276e7ace2b78784eb96f60e8cd9b9626e12b9e2f058c7b99818a294fb8bc",9.917710196779964],[12949,"9c4b06735aebf5e3ebaa116fb2be3b0589048a621d7e8dec47843504b569ebaa",9.917710196779964],[13109,"15bdf0abe532b11792a928ad254d53462d19e423f9a34b7895246735b5acd3a8",9.317957166392093],[4304,"4b23ea6b15d03fbc326727065c74bab8794bd824a98da192a3f713884918b7e3",26.091872791519435],[10088,"2d81ff6ef1519a06e5ec9afd245dc4a98a86d2a458e0357e8f7faac9aa9ccbbd",9.917710196779964],[10208,"e98dcdaada4b8533f6290a07845036cf7bc738a1ae90d90fbbfbd43ee548edbc",9.317957166392093],[2759,"260c12419a9afd2e11da7b7f3d8c8a41962b78b9a88cdaef2098b53ae0930cee",9.917710196779964],[8836,"96b3b7e85c0f469471b43ec506b8310515eee49d2641d38d53b0a7bd5261ddc5",9.317957166392093],[6560,"eaba6f9b067d4ca43a87b05e71097d5c3d6a1fcc2245d5e9bad32130af03f7d4",9.917710196779964],[1414,"a8346d8d72d9e1afae6050497235df1825e7fbee241ac43b182860330ea2bcf6",9.917710196779964],[18199,"e9def09b47424cf3393b1d393d0b763cd3880589b4aea5da3aa96a6f12e22338",9.647446457990116],[17483,"311ab401d085d6f047ae10c59fd27e7bb53ad6ac6fed9c3f98fbdc267d7f0a48",9.317957166392093],[15878,"37fd3408532a32d161edf9ff6d9fa989c369546049510e0e32b39d093630726b",102.6938775510204],[7755,"bb8f8db7d9c7217e66e43e3bff794993289dec697672e076567811a9c2701bcd",9.917710196779964],[19699,"d07b14a9216df22bf416c63b12901c8f3941c33dfd056d882c39e82be40bcf06",9.647446457990116],[17078,"109b10435b22cc50a56f2b5daee6a1261d76b09d087cc08fb78fc74835545d50",9.647446457990116],[8772,"6d82efecf1763c0bd397d52d609a4a37038ed074be0ad0d9c762d08d06173bc6",9.917710196779964],[3649,"1fd5e8e0718a84ba7c6900a0f35615ea20c093002187b6da739834b90adef6e7",9.917710196779964],[19576,"afd38e7916466839a1098d1ed0a6649d5bd29c197e86b1fba4da7faf59a34b0b",9.317957166392093],[5936,"e96d5cd286ef903a57519082a972a2d3712703808c5010a8c8f324a8a53e76d9",9.917710196779964],[17113,"94cd6a46bb9bda8722c3bd7b3e12824f2a5f03455f21111bfb2c0458b579b54f",9.317957166392093],[4909,"ae4b73b8774bfcccd7f1f302d0fb627cf9f1cbe5909ab6403f003dfba868ccdf",9.917710196779964],[14954,"3afc0b4322f8a2b943582700a72e65c36818046541b82dd11234cb5c0ce49f7f",9.317957166392093],[4971,"266c14703642843781a7022a61688106ce6189f5e2b5f2f7d2bd7192f5755edf",9.917710196779964],[15493,"2ae3a346c2868c27dc8ae7b503c59d46f0b4c263a434a0fcd7dbc4a5296c3874",9.317957166392093],[4170,"f3792a23df1f34abd08c2733b04c156f6ccf607ef17808f25660dd5f330ca2e4",9.917710196779964],[9856,"a2d8dbc0a4715c33372667b95cceb137f78b2efbef4f3d24af31db446f023ebf",9.317957166392093],[6346,"f05a61e31afffc2af79795ca83f6f964b7603b679fab52becfc11657c49bafd6",9.917710196779964],[3057,"7b1443d49888a0efd14aaf403ca0a3a9b1735eebdac33eac3d5f74e6b789f0eb",9.917710196779964],[19723,"489177b522fd50b4d2d3bb4a5bce2a03c556e7b11c768ea14941977c8bcce505",9.611594202898551],[803,"05cca215b252c6abc93171461f9e4b811d0ae2729ef8ff1d156b471f07e786fa",9.917710196779964],[5199,"c69806c284d0dd4d090b47961987c2d1d91434925af7e817389b45f6e301fedd",9.917710196779964],[3302,"5aebfaad1e28e174ad6b13484da32f4ca5afc23ee956e2803e1bf244781965ea",9.917710196779964],[7022,"52003e1826d999179ca7485a28afe6aa4a71e8425fb9f192bf2f02aab1f8dcd1",9.917710196779964],[17264,"018c23c0f1cbb720a061f84fb7d3dd98b6311559366f168c22d3472811f1dc4c",9.317957166392093],[19753,"67ee24a1c4f1a01a53d4df679af5c16cad75e34480fcca538a3198601a6a9304",9.317957166392093],[17075,"16827e1bff2a7d599982a9104630161809c84270c5cddce700cabe2ccf286950",9.317957166392093],[15690,"f696b1d2cd60d7e57dddd3ccd1367beedff7463e94adf9c08570a6204ca7a86f",9.317957166392093],[4075,"8a83f2f79785b35860ee523cc81427515f5518f3cc076828fafbb1653df83fe5",9.317957166392093],[18354,"557fa1d99e4a20ac300e81583abfcb7e35bf57fe08a9166802237925b248ab34",9.317957166392093],[4133,"e714eef38c0227ef215489f248588adc1390de90a3385f973934b10a3e8ed9e4",9.917710196779964],[3866,"48a4437101abeb94711fdd82ba22144f1727e0ca991d0b7adace62fa589d93e6",9.917710196779964],[5815,"1f6a1df80421a36982e577da269331644eb2e2e3c2a596ff5c24ca808f6a4eda",9.317957166392093],[1529,"a2a967744909b9a5afa9b20eba90e9739d4b92e2a8e615d1118de1967a55f1f5",9.917710196779964],[16830,"8aa49f1cce31d55b6fbb7cd573d592ae2d1feb1720bcbc34a864a68690f1ae55",9.317957166392093],[474,"f68cf8da6bf23ece6428df18ed74cfbc464b3b9089688b5df7042141c314d4fc",9.917710196779964],[379,"8eb8d498a79259b49c63fe7337ae7d4927f03738c6891bf136c766ac70b47dfd",9.917710196779964],[7547,"91b7b682cab7d6c6a8ab5199b3c9b3a8a79818a36a3052f3a694f1b647988bce",9.917710196779964],[4625,"01d63fd4d3fb2e780caa064cbb49772d66b82fe079cdbd44c2af223b2b9675e1",9.917710196779964],[9835,"a6dca323519876c6b9b22ca0146f1da2cdb093c468d814d42ccfb992900864bf",9.917710196779964],[12812,"3d9fd6429753f6df5e86d73c1c1774ff7b238f726c7ff58a3d3affcf4c14deab",9.917710196779964],[4187,"ebb80260e03c812cb35b869a04821602ce0df6543f025de0b6727b26ec3b7fe4",9.917710196779964],[9846,"f1427328dbf4cc20b39607f95dc7c9674d00b27d8d6043a06c695dabc9b14ebf",9.917710196779964],[15825,"29ede369aec5bb4f9a76eeeb0e208b9a26ecdfe483d0e68851880b183de4e46c",9.317957166392093],[8692,"0569286c9b17758b4ca2e52cb7ea4a4a40ccb4ade4b812e5d156b4720303bcc6",9.917710196779964],[1419,"7f6baab92a18b45cbc6904b5c5284e91b38b2f3440fbd829734a11894f76b6f6",9.917710196779964],[12189,"6f9272dad05c8f6cc9e14af6c411e372006d0dc9893ea6e8c69d7b2660c822b0",9.317957166392093],[15472,"b0940a7ebb2b253a5d7e64733b31f1a249587d6c3a7f07d31a99faba10d8a574",26.091872791519435],[6158,"cbebcd29bc961b189daeb2cf89db657fa69f53ccad476e5c2c5ac1fa3e6419d8",9.917710196779964],[9058,"6e8c9abf39a42b84ab589ddabbf9ed9e48675a96ff7ca0010f0810f87e8568c4",9.917710196779964],[8208,"3388f37f0df0106cbb5071bbc7096822fbb73e40d6794602eae50038276decc9",9.917710196779964],[311,"a63060b55e8d6fa69bd39a3ac418a3a4cfa0d2e740f32c261eb1367a4a17ecfd",9.917710196779964],[7792,"433df64ae574191616d1e119ddf2c4dee2ba793e69663c6a6b6f69029ef9dccc",9.917710196779964],[13856,"341d6310e57b92422fda47dc1b066968ceb705cc88cc445f5d0e09161a094998",9.317957166392093],[12648,"ee661c9ba4dd09df8719a5677f6975f1791ead6147c5787cec4513570ce4efac",10.052724077328646],[17494,"5a9274888ac9bc8754a5ef78ebca589e8e1f91fd624ff13a2388c38367b2b447",9.317957166392093],[15123,"9092b3c555ba43665cb3c7858787f2513ec50e26c9a8e087d1b13a0b7bc7327c",9.317957166392093],[7842,"481f3dfbbd7959fae2371ac4d7f31d9ca5c5aa774ba357e0c93f905ba95e8ccc",9.917710196779964],[6162,"a78153fbf6061e53777b73efb9ad5a77ee33df5274147494d1bc4a6eeedd10d8",9.917710196779964],[17901,"fc751747dacb841cb051844fc9e145e9cef1b63c48225dd3989ca26900902b3f",9.647446457990116],[14791,"22ec1281c3aa871b436dc4da6965830b31a73b11f37a3779b0b264c650de1d83",9.317957166392093],[11732,"d84669b11d58482668c1cbb293e7ccb83e38eaa9b008cf0f468b2096db9d17b3",9.917710196779964],[7996,"d438152648912e473c48fcd0bfb8d5f34cb169131aa47e9b1898eb7a6a1189cb",9.917710196779964],[10165,"0fd943fd2a5f32fe3bcfbeeeaad4bd45a202c4d5b25ecb4872f78f4323a24fbd",9.917710196779964],[5502,"fcc17123e0d380d1cf12ff4e78acee3830413048aeae5f0569bde4aca9f537dc",9.917710196779964],[13036,"4db6122b70896caa7bc84face1af93fb442b98f253b5a4c8b8b1f5d1d8155daa",9.917710196779964],[9121,"f227aa488488254d2af9b66dce9f7b286b2b0ab5111840a55c21df5adbd202c4",9.317957166392093],[14806,"cc525a01bc5a8714c495e792410c6e842692a11332ba44bdb38da1edbd3cad82",9.317957166392093],[18000,"a52a52ca9ca69359f56252748a73392b1a647aca4ef996d98040a42a9e66413d",15.961538461538462],[11724,"3b0007dd399435368da30a797dd3978a2d1bff0bac826934c32b7f8431e923b3",9.317957166392093],[3620,"711099778a683f9caa45db8f076751b62993a97db4c6d2b8b99d478369c01ae8",9.917710196779964],[5523,"2d1fbf8fbeba764ec66cb80287236bd050e183db3cc7887e231807bd1e5017dc",9.917710196779964],[5775,"0524dcf70b5fefc9d23e6b163a8a05fa3fdc090425074ad7b33784de2da997da",9.647446457990116],[13901,"220a0768d746532504e552536e5409c42d9978dc66cd45b015ddb02a17e30897",9.317957166392093],[4385,"2d401b9f86fd52e2242335c0c720ed14eb2dbcfd0b8066e8e9e8646ddd972ae3",9.917710196779964],[903,"f5a731cea468c54c6d16de66a7b3f9dccb73eccace1342efb2ab90f0038fd2f9",9.917710196779964],[5349,"f7aa1629494696fdd8b71bd1db764ae4b69a611249b80d006d2aff4e9ba126dd",33],[8609,"046c4c1363b3eb29b9ede0f553868fb5e49aa979c56cd143539ee63e7eea5fc7",9.917710196779964],[19089,"ff70c2e80d44c8f3bc6e0c221d8de8b0e59b93b4a6828cc0f7c4d34260280f1d",26.89439374185137],[18977,"2a4d735f7318debb2d60fc022a491b9037fae9727ccc24516dd0d9082ff14e21",9.647446457990116],[17460,"8b6c31d154548591cbd49fb0d34ace34773255c4277451c67462bdfd4aa69948",9.317957166392093],[13414,"7a69d0b9869fefb5c70e92f81052ce5323b70ed683cec9aacbc7617f26cb0da2",9.317957166392093],[14168,"e77d35984f7791f26fce929f9a9e8f71b859ed3b4f7bb7a3174a45ac63311a91",9.317957166392093],[4319,"5915041212004da2f59b1cc669ccaddc658a64178b709f947f9f5f709ba1a0e3",9.917710196779964],[17957,"efc19d9b1ec033e32d2360468120a1bca47ab0fade024009f7cfe533682d013e",9.317957166392093],[933,"63bef487c1cef428babe49257582f3f34398fd83af942ade88bc14825c579df9",9.917710196779964],[3354,"2368192479f0aa6aa38fb3a4ee7e085cfb824d0ca5a00dac48499a299e8800ea",9.917710196779964],[14722,"2717d2426e551aabd142b0282b3c1dc045c5986bace2cb73605b01a1c8e97f84",9.317957166392093],[174,"2d1f394ae3ae18fdb4bad2025bd6c6c2de94aa841ce1504b1fd93ba7cc02d6fe",9.917710196779964],[19116,"b717d5b884ebb538b86c6370336cf73aba274b0a53ecca89eb393c86d860ca1b",9.317957166392093],[3806,"97952744f42d3605246f67a5cdb684d8bb51f99b642eb34385f2a16a614dece6",9.917710196779964],[15164,"bcf79c553ff1770a3c6dd31b3628ca993b028cba5a4e60e7b1acc09c68da347b",17.056105610561055],[5288,"40c504429ee03e8bef20d44a6f2dc7bc8db793cdee66fa4c1993ca576ff079dd",9.917710196779964],[12820,"35551f64ae6f8c46775d06c1766cb7d9b6ecad84cceeff58e98575696cedd4ab",9.917710196779964],[3466,"f7faee51e0d2ddeb732c1c5b04ccfb832dce395e4d400c7f5fcc2ba2531944e9",9.917710196779964],[2997,"50e3e763f03d55f66c960704ddd0012b8ffd1956fc5730b1ef385f66fc1849ec",9.917710196779964],[4582,"9608bbdb2fa946c33dea203beb7de29c457bcf249805fca3f8298f98df18b8e1",9.917710196779964],[17759,"c740d7643692d12d7c512876710354667b2406e1158635ecc8bf85ea10890342",9.647446457990116],[17541,"7c70a506e0fdb19b9eedf0abaad698eca6bfc0d76bc961af2e5c832142afb546",9.317957166392093],[4017,"d1eb262fbcdd3135c459090e02daf4efa7fabd18499a9b4b1eb6c65e7b5aa4e5",9.917710196779964],[11639,"ee846fdcfa401c61d54b1404a2c18169e219c08bb1a96168d279dd39a0a8aab3",9.317957166392093],[1040,"777cda087f6dc893a47e7a754567a57f2b441b28ff1995daefaa8639436509f9",9.647446457990116],[12252,"9930c577e0a705a51ad708960a584993cf22af67e7e270fa540ec3f7220bafaf",9.917710196779964],[18238,"b77da24af50c9ecfc9b285bde8535cd21355b2a2673397fac7ff96e790ad3f37",9.317957166392093],[8736,"45e3f289c045c3cab8f158cc802a48dc05398bc382e51ff714d1c262a97c7ac6",9.917710196779964],[16691,"c508644c27288bca6a53151a6721e224489ee20bda8c6015ce375d47549db858",9.317957166392093],[14138,"24312878486cf278479355a45ec4a2ba7bdaf7ed47bc9a3b9e880a7a5aecc091",9.317957166392093],[18737,"34ba567721a9c57d5448d1fa38417ffdc5ead4a83a24b3fe47b95e11c91c2a29",10.052724077328646],[14913,"97b4b2e72154d551a9964b3d2baf23766acf5144c3710111e5914b3147a2bd80",9.317957166392093],[6693,"10e4fe6825bef91ed753ffcd1db19168b446fb2af2ac875968d0dc052cb401d4",9.917710196779964],[11167,"81dddf6656e1b5ffc2df6b4fbbeef816b7ea632d4de3f8223a756eecd938e4b6",9.917710196779964],[13551,"18c9393153665ad1e673ad16fd5aa46c766ebca77076ec43d791ec6650fbb89e",9.317957166392093],[19227,"e8406e952f25dda6a934f155b3a5ec96e17e61d20955a17b9e4577ec2049bd17",15.080213903743315],[7052,"f6cb43fc2905d7e4a58332679442ce32d5478a5f23e3261a7f6381d68878a7d1",9.917710196779964],[19580,"468bf14a4d0c598f20dfb36ce6734eb662267fa2d8846c3ebd38f48db5e7100b",9.317957166392093],[10371,"6a21942dc8b6e15c888361ba88caab11931a1a6158d63054c66777080c32f3bb",9.917710196779964],[13815,"7b5138d43a27fc24a7cc342a2d0c1b8e5b5eb8edbdf568454c899fb183bc2599",9.317957166392093],[4072,"aa0091ddbd910b9c04b76599522e213f1d9ee81dd27f2e4db9086e82e3c843e5",9.647446457990116],[8795,"32b624032bae1e33c8db7e5a9912348e3ea76c4bbc4e16c49688e4ad437b18c6",9.917710196779964],[15154,"34960c1c9acd454edb5f2c01094b33442b65430214eaf9bba11e7b53df81687b",9.317957166392093],[11886,"47705f5be590f9fb25f29643c15a489e30d6799a1c70aa9dc01e14c23f561ab2",9.317957166392093],[7036,"f01220915f8d4b64b05656b634bb40534a6c7f9393c168e7566420fcb844c4d1",9.317957166392093],[5889,"6234aa8c187cf314194bf59d5eaf732241b9fd0d996701985b7217f1089ec0d9",9.917710196779964],[16494,"206bb2ec402a37a000c98f774c4234bd7ff2a72a1d4f20bdb401c8fd6e2c5e5d",9.317957166392093],[6848,"48781b9f16f7ef5b5d2b988ecca297dacaef38aecfa2fd307fbb6ebeb2e6fcd2",26.115555555555556],[9653,"5395cca5754b33424c1b839646542e04d57ed1d5084a9ee39956a2930544b0c0",9.917710196779964],[7267,"a08bafa30e1b8e5d29e7c6299e16b75ec5b6dc513cc3511bcf139511139a39d0",9.917710196779964],[16293,"cdafb3c8ee4a8be53e583ea5636e1c34dbfeb0a946719954b163925d79285161",10.052724077328646],[7579,"2fc1fb18c10289af218d7ef3ef712f8a97c84adc24b29dd15c7e068a86d44ece",9.917710196779964],[19572,"84a6d1158f0a8c14e5dd54d5cb0a3784e18090ee91a394bba4e4fd61d0efa10b",21.094170403587444],[9654,"a7833f985c555fb8a5bae036d311a591997a6246721c78d4354d73e1d4a0aec0",9.917710196779964],[15229,"4b6acf7ceba85b904c5ab64572d6f2b62dff6f19a1f9d9f416c84abbb740e979",9.317957166392093],[4345,"732911a8d24d4a366bc0f2ede72b670f4844b8c50d4e7b06aed8df7f35de6fe3",9.917710196779964],[9592,"c5bec0e2c3a6065c1de99c63e2a2b7201ae4b84276f39d1c9c2e0c6106a50bc1",9.917710196779964],[5774,"6ab5f212b3c67d4ae2a8cb7bc90156149eface808069f47f6389278a4cf298da",9.917710196779964],[15367,"b80b6aeb609f732236e8043daf6aafa3cbb94eaab8baf1f3f16c829f14c90377",9.317957166392093],[7595,"294f7e9627784901e1586feb6ed6d42b658b67091237539c56626ac65e7f36ce",9.917710196779964],[9308,"71d6b61508d75c7616f66a11b0822d92651efc02d4ab5079be0386fffd32cdc2",9.917710196779964],[6768,"1d53b732631a51d9af6f527ab1678a7fa27df3787825a8718258ec1626df7dd3",9.917710196779964],[13115,"88b480279c5a14ee525835c2e087f81ce1ac9c8fd67ad57de2c198436856c2a8",9.354294827979038],[14057,"cb479aaa15689c3f8e5b2d222ba09c9cdc18f419ed40067ccc1253e0a7c58993",9.317957166392093],[299,"03a27deed734eb526577285c8e592a60284aa61ec427a11844eaa1f5fb91f9fd",9.917710196779964],[18660,"e3ef2b68f66fa8d34a551996b3e3eca97dbf7dc02cd930abe0b8674d72b6462c",9.65748031496063],[3348,"3219866b941d007df1de3d415a99cd58d67606ee62fd54320993e71ba0f904ea",9.917710196779964],[8265,"b505e6b1d9c5894e26544064a81afb8a22bacba5b8c15b5fbb39be410af889c9",9.917710196779964],[15301,"39767478259033cf7ca4c1225b654be611dfe7b4a59497527efc3694d7ad6478",25],[18913,"56010d2a91456bc6aa6ec35a274bd6bc884e6f8e091d6a2d269fc99c9056fc22",9.317957166392093],[9206,"148682013464829bf711725b799d299c134b9693932ca75b5ca16764b7b465c3",9.917710196779964],[7994,"9f71fc701ed7a9962d0d8dea2b9435816ccf0ec609e3ab583cbdc580f7af91cb",9.917710196779964],[3837,"8757ac637de3279f3def17567d5e672fd269f0b41a397f14867a23dbff42cde6",9.317957166392093],[2654,"6c55cd16b1cbf664422d81ec6d98547d19b52052e6f8d8b13fddab01e6acd4ee",9.917710196779964],[770,"5b27c904458bc466148de464d43572f949219e9a4d8f6c2214a554f5c114befa",9.917710196779964],[5262,"f429a0d9bd69cc2ed28e3abc55bc6608db1ed9d76dd3188e2a91ac05eba699dd",9.917710196779964],[15264,"24aef0c9445ecceccef08800ea88f338bbf707bc332050903b58730ad4a83479",9.317957166392093],[9376,"ef2dc0c0ea2462752939ac2197c8f7c112ccf96484eecbe1596ea9c3c16c64c2",9.317957166392093],[19437,"4fd1f46e8d7358e435f7b284014ec19ae1ef943165ea8b66895c608d31fc3a10",34.77580071174377],[9043,"e38eeccee930a2d71eb7e608c07d71400c9f0d50c375939a94313f8c476081c4",9.317957166392093],[19594,"c1e6137f2ed05c492fb0b2b82db74479b9e908ab4cc76a5e6ee9fa3297d75f0a",40.712041884816756],[9090,"23d2bcd6268f5396dae5de97384ddeae7cf2fe77ab62cfd0daaa73160ccf38c4",9.317957166392093],[4332,"95fc20882ff7c47c5b59a046157bc9f3e96e819187e0641580cfc621cb678de3",9.917710196779964],[16107,"6298a02971fa09b60c0577643348eed07cb093a5dd89faf56b0db3752b74d665",9.317957166392093],[18278,"8ab1227dee18c2d538ea024bd32b6d4e2fa9ae729194cf8640df6eb8597f4b36",25.33567662565905],[18008,"82da9c94638211f3e799fe7ed1ced9f5f779c606c34a4700089e7235a70c0b3d",9.317957166392093],[4323,"c0d09560ddaff19368fa7154c673eacccd4fbc54f217ad10c76f179de8609de3",9.917710196779964],[1102,"c5d59cc04d2077cefa4491fa568455b208aca98d28aa318092cf8b18fb6a91f8",9.917710196779964],[6960,"cae17d6b1ce0b90be455a87180412f57be49c12bad5a757873f10773533835d2",9.917710196779964],[12401,"a1c872c9f86b33c31536d55051fd7bfa809695cfef52e7bb896c916182ac98ae",9.917710196779964],[15059,"8ee5b9f0b3f14af78b0c81abea5aa875c741ca1faed262012cfa88410749607d",9.317957166392093],[16338,"19a8d144a2f24a6d80154453195e12c52456ee51c8b7c96c2b6cd8e05bf93e60",9.317957166392093],[16046,"28d909cb780303cc85b26671e418a8c504ac060bb08334b447efc026330e8167",9.317957166392093],[19543,"d57423f4a683ed36cd09ab7be553941c9e9f9eeff33598f73c195aa49cbcfa0c",9.317957166392093],[6908,"34f76e52c8810e7c6c2c4c5b894744bae875b95e8ff8b00b57a1556a1ce48cd2",9.917710196779964],[11841,"c66533f01f48b8526866a4008f90f603873aa796914e99ddc8cf21a93d7c76b2",9.917710196779964],[10259,"7389f7915b852809cca213a8b99747edd65c04e101ac56413bb786c76633a5bc",9.917710196779964],[15212,"d0d135fab27f3104c62412c1eeb5055271f5a1f56539fd5e2cb30ceb9a823f7a",10.052724077328646],[12020,"d54ef609bf2558bc8152c8591cc391825ec0686cdabc9e7c30e5c1d9167b37b1",27.786008230452676],[8531,"aaac2af913e786aed3ad1c44ac47c83a0167f4cd3169b0d13dc917f75681d2c7",9.917710196779964],[12549,"7ab9c1e7c8952a3a3290a604cbf264b1001d231d630ca4c1e222c3f09138a3ad",9.917710196779964],[988,"a6591af7f67f9633833aacb6c48bd4267a0f4b0caea8b93509d7f05309ca47f9",9.317957166392093],[4504,"4dc4e389bf91cf85eefdd74519876a69af076dce01dd7631e1edc8d39c2a57e2",9.317957166392093],[5919,"e6a6db6e82d2d851e3fb8c2c64d001729573c66a67de108527d5936f7b5595d9",9.917710196779964],[7211,"bd266dae54792d868e7cd6a406e3fd0086d0098c79f7a48ad735ade7b16ba1d0",9.917710196779964],[2384,"4b31e978ae8d9e0a56efd4beb493eb3515f1ea5b824937c3a2ca3b0d22728df0",9.344947735191637],[1002,"26d8ab2c6ff2a4f2d722d07ff3111d7a1da3c0a78a085772df4b212773c537f9",9.917710196779964],[9648,"a027e9cec0dc51bfdc2182d389e9ece08ac7442c00be6829fc0162e2411ebac0",9.917710196779964],[1225,"04e0b0a6f16643a58b60e930ecc74f0006136b08198b90198db55711dea0daf7",9.917710196779964],[1523,"508827019c07a6b6da102b83955603d78976bad3d7b28a98801373c2cfbdf7f5",9.917710196779964],[10982,"76b6be4ce31606a23b37d0f6dc7d79f4040ef020ae76837f8719b6a9850826b8",9.917710196779964],[10211,"497510cc9169ef31335f1eb37e6896ef0ef13fd67a02cb5e93cd6e293dc3e6bc",9.317957166392093],[17760,"fa0a78ef69cf7e7817d00c948f22f73db6bf6aec0b8f28674e82d49260b8ff41",27.121052631578948],[19636,"3e7ec56816169f0b20767c2c67bac94872f908f3c212b40fe014600575c55008",35.80309101316543],[13275,"0b8c555f3a943511f1d5789294b69b5970473403cedbdb69232b043de28124a5",9.317957166392093],[17925,"2989564e5d388c04ca4de77b35422a53f254165067e6daba47215a76685abf3e",9.317957166392093],[2112,"7408e66c457aaaa34615721f8f562233123f4657efc0df9fe8032319533525f2",9.917710196779964],[2268,"7248e09794edd8ca9d49243fe236ee94301e6db8a9718cee8c05bcbf5e8b27f1",9.917710196779964],[13156,"435fcdb194f2b966b1c22eadca2a699875c28b659ffd8a7ad93a91d536c8daa7",9.317957166392093],[19162,"a4c2b9b20a1f9ed803c8d21a17f042428dc32d8f31fd953c7f051661d51a091a",9.647446457990116],[16799,"a1015eae074504271bcfc10aab7f46d89d47b8e59a56eba061d5eb8525a04856",9.317957166392093],[3164,"7e6d75940ebf2ef637cd9f1ba4cccd4603c26946cf9cfb69514a7889e8d749eb",9.917710196779964],[8729,"83e5a2e42efdd91ca04297299d90d19dafaa016478fa59190565d094c6c885c6",9.317957166392093],[11570,"1d7a1c6028297d31d1e06630faf9d452e67d41ea83ba6f2b5e614217fe5e20b4",18.209302325581394],[4445,"eafc913fcdebc8092e1394be1ba47ad1ba29ebadc9139ae8367a0d7ff8e6c6e2",9.917710196779964],[8848,"5bb1c7713dcd20cc2d2df1465541febc0308b2ac443ec4bda2beff801ee9cec5",9.917710196779964],[14874,"96bfe2b9f4777f958c72641ce2c435359275df50a17b5c5887a5ea6127684e81",9.317957166392093],[18305,"b72b83ee041e28fa6c8f4ae6be9fd7a4e518b7721bb42f37f1480757d039c235",9.317957166392093],[3591,"59e8844f0f72944f2a9144f413da779b7225c154b606be0e5afe5d07334c5de8",9.917710196779964],[4218,"00d4e2317724c71b86663600a52718d8ea8b4fd9ad99373b20162693f21c57e4",9.917710196779964],[1229,"ff772d5a980e57988d51a2201714b8c6d346519348dc399296c4f5c78c84d4f7",9.317957166392093],[2781,"84d722e26da4261a49073e9126b9d895a317f4d61e605470477fe362dcd0e1ed",9.917710196779964],[3868,"38b7f7c7cbf00233e3cc34bc075d67f1f3b7600961a3b5472a548f96251190e6",9.917710196779964],[3265,"6b63c43ec50906aaf36c00e37580b1857a1bf296f5f8c6505d5729af0d3595ea",9.917710196779964],[10548,"6a33779a1e17cadb53deb5655ed97d09a8ad18f671e9ca3a8078dfc805a2eeba",9.317957166392093],[15042,"2e16a2810df3883e652b73502695effec71b01bb14b8e584168ad0224799b27d",9.338112305854242],[12271,"4c6ff42789b9e4998f773ff16b047a95348276119a89745a1ce3e3e517c784af",9.647446457990116],[15905,"85ac057cd85c8ea898124c1ee48b917311b8823cd3c9bc0868ed99853091f26a",9.317957166392093],[10955,"09f4a6e9d0c188e86cc943f7986ef2fab289595fdff714003466ed5fa6ec4eb8",9.317957166392093],[4930,"fbd9d540b5c00544025ed81ceb87375b27d31b14d20eb8f366eada392cdda7df",9.917710196779964],[720,"829b97d2bca367dec8a0027650015478d108970c4e296086c8900366d4f913fb",9.917710196779964],[10950,"24c84cfdd2749f44676614506fcd316dfafe7a8d0050b740eb96017e2f9357b8",9.317957166392093],[11671,"38e6e330ba650923acfaefb0269f305772329afcb3503add3a2357ef8c7b77b3",9.917710196779964],[7406,"0bb55a6c47de7804cc9ebaebace1a4bdd516dbe701cc67e6cede7ca19dbc65cf",9.917710196779964],[7945,"1c60b20a539b1c744334bb187298a19f513cbed1194d353d4c75983a2f50eccb",9.317957166392093],[1143,"d9cd2ba17f38b79e384227f803288ce199bafcc6c74d705b08bba165d15058f8",9.917710196779964],[11799,"c794be0c5490f4502e5ddbfcbe0f747e958799e0937222f63b58924b7c74b6b2",9.317957166392093],[14435,"24d666a1159241449eb532a56ee5dfcb5ac4b5bdeb0ddd38305866ccadbf918a",9.317957166392093],[19468,"b9f55681b437e4329ea9c54d9b38ba70b7122e2178462a43ae36ab02df7c7a0f",46.69135802469136],[18910,"43b119aedafcb5122ae408796035dbf27b6ed70482c26dc0c77a1bb2a41f0c23",9.647446457990116],[12450,"6dc401ae5a38f1d38d90750747043b65b700ae6971a24ecc05851c96178448ae",9.317957166392093],[5873,"512f1b2bfb5999f07eda42700a59b54f14fe4550b8ee36e9c46fc9d3cbbed6d9",9.917710196779964],[13234,"fe92394b3437660e4537dd7650a72c661c78e3e8e3bb20ac872c869c2c9834a6",9.317957166392093],[4685,"a743294ddee858ea46fe7478d75134799486722fb9ceea1b4fd0db347ddd17e1",9.917710196779964],[6976,"02c581af30d4a6e6b362847ac11e5881b787d9958010e1d03a8c9530d91921d2",25],[92,"b9581ee14f5ff576fdcbb65ba1f3162932a210a964d80c331227264a6f456bff",9.917710196779964],[13122,"b891df80e3ab7f807a152c60a36a25c4a8dce978377b38c5726ae89d124187a8",15.191956124314443],[3600,"0ea208eca010ceffbc08606dcd8bec88b700a917fb4b5647bf2dd07adb0936e8",9.917710196779964],[8398,"ab745d5a24cb827d0fe73542853d32617ea77830ff24e2fb8599de2c190f9bc8",9.917710196779964],[16787,"7dd48b3e947a6aa02a56d3bbeac0fdb7531b61415890ca86f452b4a681daa056",10.0355871886121],[11710,"fb0dfb9336d0ebc043c82b72a81928f8b7a9ee6608cc4a74031c6d842f273fb3",10.052724077328646],[8628,"5326a09960ca0dfe5d728190fce24c05a8b9b2100c6dc10730af3008cf3d41c7",9.917710196779964],[14929,"dd2f7cb5f6bb9a3f28a6aafb2b011a44c68c6ba0e776864d6924594b78165380",9.317957166392093],[2212,"2e57c2ce23050e2453d372668203c5e1bc0566cb2f3113f4171a6dd740b371f1",9.917710196779964],[1459,"6707c69dd12194bbb49606773459bcff783b0e685c8c4bb51f513fe9f22d71f6",9.917710196779964],[11626,"770bd607f2644c495a2ae3940b6f89387e8ff5ef47bb47587055f7e12dc9bbb3",9.917710196779964],[8796,"f02d4fd5931e626f7d6052a422c95510adbc3f62bf58e732fd9a9bc8b98c16c6",9.917710196779964],[19299,"73b3f4e201905aae1be0dea851dc118fac737092a460f1523a0c53c4bef2f514",9.317957166392093],[17110,"f342d88ba1fce84594821b3c8358bc2266b18df0652b3e1a57b82d532eb9c34f",30.585365853658537],[12859,"be071381ec6ccaede984d85906c1d67764855d91045b369dfb72f6f0735c84ab",9.917710196779964],[12121,"bb375e56a216af92ee2c83f509629c24acbb0168b21fcc855f099759b60396b0",9.917710196779964],[11952,"8584ec5f6b0a6c585e3d1cd23c4be1a3d2b72b08a7dce01ea8979efdf2d1a3b1",9.917710196779964],[11935,"a427f7d9d267a1e1c0a3891dd0a6c54fc8d7f96d26357c009942e6d7253bc6b1",9.917710196779964],[10538,"fcccdafd5170161538051a4f1a98c141d9880674a85bff06f07a9377d867f6ba",9.917710196779964],[8914,"4862e87b736ed4373f924064926d5c11d8caf22b77fa96c1daf760d55c7a5fc5",9.647446457990116],[5839,"6b7357b8f23e3674f68e873f957f037b947c0d2962892fec21c7dbef238113da",9.917710196779964],[1401,"919608a8422f95a306220bffa3a917827ce53bd61ddddfdb2707dc04890dcef6",9.917710196779964],[8949,"1f69a917aa1d1cffd1bff10ce13666758953e4886fe993df6897edc8201e1ec5",12.034904013961606],[310,"6db15b4e22388c35145aa2f120bed6321d9ec2d53e6441db0450d03e0929ecfd",9.317957166392093],[491,"2bad2e8390897cfcf56083d99e37e24b990e4d7eb16485a97166f0e49d12b8fc",9.917710196779964],[6904,"a7c5e55ec4c810a1bf4c16711bcedd6bf047b0efabd42763b10591b19aed93d2",9.917710196779964],[779,"a2a710fbb69f7b69d20b583232ca51a4af846e42c802bba78c17a18864bba8fa",9.917710196779964],[18974,"60855eca908ab97f9185cee28cb62e19f8a86dc9f3ef8da69f4dcaa221dc6a21",9.317957166392093],[18584,"2fe4132fc02d0ef9ff14e02b2f3bdf632de3d22d835f950e2fd98789dd844e2f",9.317957166392093],[4992,"277327208c0b13ed9a2e12b76e89948c4ba22055386e0faeef52617c2f9b3edf",9.917710196779964],[16725,"fbed2c18ae5a832d93c09608afd30309ef137061da5460208d5e59bb41aaf157",17.09090909090909],[2971,"753e4efd302eb2276fdf60b457a92b8a0336d0db296a250145521cd3a71d7fec",9.917710196779964],[16137,"1b0193965528e766342fcf5c58b5c56efc86acbe4c1aa856f8da811ca6ae4665",35.89380530973451],[6340,"f4f615e6bc48f442b353a5b05e29aeaf5c2de3b3c11f8b04f081283f811dbcd6",9.917710196779964],[5074,"8b90aa6b05f67769db0e25f28c5de5e62606b03992db00aa4a5496fd5a80b6de",9.917710196779964],[4884,"1da00ef3bc42bedac7d6ec5b25c8db407c4f2e8f2ba06ba8f9a65027ffb6ecdf",9.647446457990116],[6394,"a7363df4e391f375f91396a20db6d2132a431acac05e5e3c45b89c84e79160d6",9.317957166392093],[6104,"e5e0b8b48d50dfb7716db0a5d6f8109a2195df4ba053bc8f853f3d91f5a566d8",9.917710196779964],[7850,"7d2bfe7c5bc688fa668593b087725fcbbbacdfe39c03445fd7c39b569d7581cc",9.917710196779964],[447,"71bf49ee97aa7a8aa3d5ee79135ecc2a9aa79be718f98b8883a868e969b315fd",10],[19840,"881a04c81711312c9512f4f91294a7ce06c23c4b847e9d9cbf3dcac9aa561a01",22.08450704225352],[2981,"698a10f3b7f42623da6b41d4d64134bba79954f3371022422e6b10a8df9364ec",9.917710196779964],[11709,"3541211d0a6d30203c82c27507393854da15c2bc5eb8e3bedcaa2f123e0140b3",9.917710196779964],[4277,"4bcc6cf5e4088c7a1055252835db76c8e0768801bc351f13c5a6b238a729eae3",9.647446457990116],[15329,"20512045c8d4fd48e50a4302dc54932d1e8f9f10689c3c25ee0f1e7ced19c977",9.317957166392093],[15772,"9e0ee61863244097da5cb55e92e049c4fd54bb9d036e9c9c23d5f686fad5e86d",9.562130177514794],[4942,"5648cf0f430fb894f22a464e6478c82151a630ffb19dc5a853515d20ba2691df",9.317957166392093],[15394,"212a058e0b55bdf8a50c152ac5af5da8589b254b89b0d8f8c80c74a6768d6b76",9.317957166392093],[14280,"986113673654295b21a2771b9960984b1951ea665c3b75c71a939437e2bb138e",10.052724077328646],[13978,"ad5c1a18244187355016c7b90216f5246f83927aa51335772ba72be1b99f7095",10.052724077328646],[2210,"204b6ab2f90b1ef0d01a236f0fa0222ead55c88002f0f3d8fddc937e0c6d75f1",9.317957166392093],[17903,"4e039265b17ed28ccb70b97b0e49ef2fb19940a37f93f6bba616a129ccfb243f",9.317957166392093],[18717,"39b4e8e2584c6a3825bf011a0bfd3bf1c10b914dcf136f8d4ca389279fd7b729",9.317957166392093],[436,"2ef02f100602c0f06269340aebe5b07d7898ede5ae55546946395032e71d21fd",9.917710196779964],[17394,"12152c758d4d2868af0e614338ab3e5087e0f7405be01e1154f30c05cb40e749",9.317957166392093],[17327,"a4c644b70cc51d0c3e91cd5f011ecdf40031ffe71c8620368da3050a14044f4b",9.317957166392093],[10118,"90220714ce550d2fde4a294b920ae9d90f4f9071e15e915303d3c2f84c1096bd",9.917710196779964],[17751,"cbd71654969c7de66ec45047b7743609b6c73c536dae1472ac42ec0f1ef02f42",9.397642257991386],[14243,"0a00fcd9205d71d18d27a2d410d07e6e95ea55ddede4b2dc8ca7b57a7411238f",10.052724077328646],[6801,"4c2a1301f210752984e2f776cdee0629d59b1ac2341c1209f7e879ee1b6446d3",9.917710196779964],[6066,"a2e5a1172287aff5f10453923cea4fab2183a9d0527117a67b9ed95fcf2ca6d8",9.917710196779964],[9239,"fea7a0280a6452ae894918ceb58bb747e175b4f00faff70b3fd25d5dcf5630c3",9.317957166392093],[2087,"b6637f7607cd2fcb531eedbf9884e58cf6177bb33c8d9e16234b0e5066dc4ef2",9.917710196779964],[17542,"7de1c87118b021e4fa815ff9f8819b632e0ab34c94d7e3dd23eb1c5fdceea846",9.647446457990116],[15636,"864d088c9025e9da4627cbbc1af519f15cf5128b28d83d0b75e7d81afb88a970",9.317957166392093],[9907,"c97adef2dc98bc48c6b3a2287ab18dca28b0ef469cbba931e01741eadbd0e6be",9.917710196779964],[9145,"9b1a1cd1f3248925ea20f78f842372eb75a1e246eee77b4744e62e1bbabdd7c3",9.917710196779964],[125,"6043c6b4dfbf0e411134ece1e39e32272e7ae6d5bc5a4f04f5c64f63e0d731ff",9.917710196779964],[5415,"03ec4a87db6ba12cef1648a7da82b07e3c69935c3a10ec0bd2583bd0e85fb9dc",9.917710196779964],[2039,"b2cb082242662d41de83e69cbf5c6a2c01f2efbda82bd0b1c80176723ad0b5f2",9.917710196779964],[6038,"d1af9ab532612bdef0119d1487657de16e51fa74374d1cd8e036f33c88f7d1d8",9.917710196779964],[11533,"c53cbd77f1fb65845abff02d11c99a4218f3885ca4ce3f33ff05625111a253b4",9.317957166392093],[7404,"9bb21fca02860fdf17249a522abb3bdb2aaca11f7ffac5d65721e54eaf3066cf",9.917710196779964],[6353,"3e2cd37d2c4f87a3e995c3995e03b1b47c28c5611df7101eb84e2381b9baa8d6",9.917710196779964],[9735,"b50813ae3a1f3488931e4b412452d3bdd564c1f58e3f59c5608d163eb71f13c0",9.917710196779964],[18747,"20ebdcfdd8d9fb47631818be64ac927c295ea3b6d6067d84328ab41c7ae1c328",9.317957166392093],[16971,"1b652c52926663b362c54fa41292ed71219ef8e4b17ffe6ad97d61ac6c3aa952",9.317957166392093],[13166,"026a1808ac0e3294439d613d920472396e27bde9c3c856304a8bd82a2316b2a7",9.317957166392093],[18774,"6ce69f085c51c3292520e9ee9cc2454d265c07e2de7311975dc5d85aae21db27",9.317957166392093],[6367,"6916be821d882dfe5d59298328c3d32716a220f44fe7f0833aab1153eb018bd6",9.317957166392093],[9773,"2925c12efd08310739e442e259431b44e63b94969318e513b3d03fba0441d5bf",9.917710196779964],[10375,"83b921fc95748eb6e2a8bea5c7732c451b4925ceb25fc729f540d99e95a8f1bb",9.917710196779964],[19342,"02de6f22c0d0c13153d3defb250b085f65951623c734276d01bbc00273e6c813",19.222816399286987],[7745,"48ea28e2fd060b3b67aa0f051e67f56697704b470f68455e300d997e18462dcd",9.917710196779964],[2900,"52ea52c30d007495dd72d157a783094b1cb2456da2036d1752ede225d9e222ed",9.917710196779964],[2665,"5b5a7ad847149a3decbdf8a145115d3e0e9704f2902e114f5440d228c0c8c6ee",9.917710196779964],[12756,"c6058ce01295bf283d1885e9b8cfec1e108124a66fd927a53382486c68ed34ac",9.917710196779964],[9358,"2491fbfb9581612ae5a819486ae064e376d0ad84aed2362229c79df10f968ac2",9.917710196779964],[8252,"947fc155ec39af04afad9ca610ed5d58e9fc7adcd3b418478c92c6122be6a5c9",9.917710196779964],[9545,"ffa878131882c4c4de6311971d771d98d6f5325a1ce06ca2260ed4e09b086cc1",10.052724077328646],[12394,"939e28b812114c84d52caaeda73cfed94b80823fd2369702a82be9c89228a8ae",9.917710196779964],[6236,"7000ed0c05788993533a538883034e7429d5680554868c2f1c4a7ad4e0ce7ed7",9.917710196779964],[8018,"075b42ff94364d6c5b165f328ee07bc806bc13180ea516522f813b6631d46fcb",9.317957166392093],[5376,"a2535557ab656da17d5802e8450da2d318485175bc334d4cf592d9c70079fbdc",18.03202328966521],[7723,"ef6aa71efc8de532307203a93470c6711f14d571265c5aac16332577faf557cd",9.917710196779964],[11198,"473b318243e24a41a62a9bb116768573201d46aad7ed3ea80c41ffc37bf8afb6",9.917710196779964],[1947,"effcc81353af7116a17a5fefa32d0faa38ef7a8db4b6200bd490082eb0065af3",9.647446457990116],[16943,"5b4db11d048521147b833eef17b881a6cb5b6a437aff72a5e029cce167494653",9.317957166392093],[10748,"d03cd0fd23212099689a0b07869c46c81e2ac3d06a7f07fda16fd98fc28cb2b9",9.917710196779964],[5804,"cefc9a1608e734615664e941a1725a48cdf6ee87b5fdddd50682b9d1ee5b60da",9.917710196779964],[710,"c0de47d6631763185fc6323b75c2c3ce41112186632c0df718111a97496b28fb",9.917710196779964],[11098,"8c006cd36fb968be55c2c4d9401cd842149d6c95fcf795db67f119bbdbe942b7",9.917710196779964],[12112,"fea27a34f1905862f9659561b7e8877a3fc411d3223e2c484002db83e613a9b0",9.917710196779964],[19210,"f78007424dd75baf611d7afba5bd15ec4413dd57c3eb9b206310ffb1e73a6f18",27.86570743405276],[17098,"5d290063ded01c2c59ce16247ac5080659bd3096415d78fa25914a3b174f0250",15.18324607329843],[13479,"d4fcbed517a09e9dec45891e6dc6359f9eeccbecb0a68d9b8aa2c2d2a3f94fa0",9.317957166392093],[307,"c875800acab546cf3ffb0374fd2fa1c5c85c87d42dfd1ceac18d2c9cead5eefd",9.917710196779964],[19192,"1743a42935a5db32ad50b533785c240dece62cda07265f75e5669420b1cbd618",9.317957166392093],[18951,"1f29a306b65dec80398e66b9ef656833dd274998f4f1fd4b99f30bac4edb0d22",24.596858638743456],[7333,"cab5cc27dcbf81a99c0756a3bd61a2cc6c8ed37992f5fa6583ccecde20b3d6cf",9.917710196779964],[4098,"5ffcae574b82067025a36d69b4e99ec5c2e7f98250e9d6318589f66f0e3013e5",9.917710196779964],[9116,"59c5b53f2d6366c8c3fccea4f2689882ca325cabfc9dbaddaa98abdc4a8e0cc4",9.917710196779964],[17839,"8826e30850a7fdb75ceff4796d482b8db8775ef7394af6cb0e903352e9a87d40",9.317957166392093],[7485,"1243692a0921a61b2da14fc590f7b68f6c859cfce2a802030c7bec74069ecdce",9.917710196779964],[16162,"a4f7f68768116de1567b5a1597fd71466d6d9aefed59c7511d5f144931f1c664",9.317957166392093],[14699,"7e88a02fd73ed226acfb826870bd03426f6accfc9539762dd2529405a6fad984",9.317957166392093],[7208,"e1c71be09797d05b761b812587eb63b2ab5d848bddb0a4ee01eec2984aeaa7d0",9.917710196779964],[16881,"5be4c9fcc8de89d9a7eb26c31b6a7125b46f388a154d4ad2e470394c837a9254",9.317957166392093],[16612,"d33c8d3238456c92586c0644308e96c450f75b3c4c8189b2a5aeb5f5c6c29a5a",9.317957166392093],[10217,"5c7f452df61261fbd2c24bd7e5ff1ebae8d661bf37d99f62169330b5dcb3dabc",9.917710196779964],[19189,"91ebf5ce028995819f3f4f94143451792492681d36049d6365838beb7d2cf818",9.317957166392093],[16847,"978fb7e1aa69c7e2750ef7771ebc8f7061cbd09a8b326dcce2c51297c7a35555",19.13214990138067],[16307,"10d0e1bbdebac61f1bafd356caa7444aab66932842a8ea303036e89a8549fd60",9.986586521514212],[6641,"bba74b4ae38fa66df9f73c999ea4b57b121868208aaf01411e64f58f8f1762d4",9.917710196779964],[18040,"15ee34c14b9d3beea1ddbe1ab7bd7356765a1f3f5e8c280bff2554833e93743c",9.317957166392093],[13865,"da934957fd039d464902beb2c9fe5ef64412b517e28a8155677675b54c6a0098",9.647446457990116],[7393,"c3ff8c0470c8f707ead233df72613aee9f26e05c9b224ef5f75b1dd94e0077cf",9.917710196779964],[8419,"118806461e568091b5d9d0e36b733b69a422b9c07431db27b35f8cf8f66c80c8",9.917710196779964],[9897,"016309fea61a4823773a6e98a3615d139dae74ab54f7e5135d23afe8630df0be",9.317957166392093],[6712,"1f48841d51c2ee69ab10b79dbaef5bb4b6ca32b4511ad2381a65029eb3e9ded3",9.917710196779964],[19198,"1fc5baa41e2caf1542f418dbfb476ceff282601db101f535db404f89ac60bc18",9.317957166392093],[9436,"c5cca3bac37532a98064567466fc0dcbda5a82105a4644f7fff1ae480a9d1ac2",9.317957166392093],[9937,"47f33a8d2028501b43883b4053f2bac09452a44b48d5d94b2ac1580b538dbbbe",9.917710196779964],[17073,"bd185a3b90a1b549627d8a2649d090a1e963a1694406c392451d746fe8727e50",9.317957166392093],[4471,"842a9dada9c47b04464271aa54635cef34751ee8d4306bb550f84ac9b9b898e2",9.317957166392093],[9053,"c737e9edf4708b0e9c4532695f506559569572aff478eb807d8cd0270c3871c4",9.317957166392093],[1622,"380a99b8ff80194da5ad3ab7bf3aa84351f0b09c4b2c360732582f7835c670f5",9.917710196779964],[11205,"696bff858ce4d4677b5fee9c6a34fb9fb95f5ec48d1158bbf0457104546ba5b6",9.647446457990116],[13112,"4f3550f8740ab3743e21b63707b92ddbec83403a08f59f9e92c300b9ae90c5a8",9.317957166392093],[4616,"e4a7e6bc176ed9458fd1b7307de7277618985a8153605d0c047f7512cf9d7fe1",9.917710196779964],[14363,"cdfed43c89810c10429313325864a756a4947eb8e5d1d51d790beb63432f2a8c",9.317957166392093],[2309,"0bf25b64df981bcef4c6f82124a08b5cd102a61059874b188085b6f9abc8f9f0",9.917710196779964],[15371,"f73772f04cfc4acd0a06930012183278779f812bbec16dcdf555a8b5bee3e876",19],[14305,"c1c91102f8546e6a90e86e2f15732e3c5d9e1bac55dec28bff907ce1fbed728d",9.317957166392093],[12644,"00dad53e233a810b18c28adbc77ec964c1cf5126e0304449d7cbbb48287afbac",9.917710196779964],[1373,"75b842d79ad337c7db568283fe7d423cdc7b1302c7389a40c6354df26c8fe9f6",9.917710196779964],[8744,"bb7ccaf8aa8fd6aae614479b0ab2fdb7bdf46ca63feb0e3a6f0ac4cfa79e6ec6",9.317957166392093],[14271,"0e16357514fa8c969e81c73ef7a852426c00def29dc31b850858d8174d847e8e",9.317957166392093],[17321,"2f694b77fea727f4ecbc37b77d627383aa79242481a97d1243aae370fc39794b",9.317957166392093],[15582,"5957620f4e8dd32fd6c79ac34d5f9a7273d4b1f85a4f35d66d57039112e9ca71",9.317957166392093],[10453,"c3041c9b4b989a22f8a8a908d860d149833bd909d1c684df372e484b494d66bb",9.917710196779964],[13265,"153ee18814aa2aa3ef35d526fe9671d719b34a2720803121af9ede10727d5ba5",9.317957166392093],[13178,"d4e20db460720e9bbc8f418dcf9d4466e788db33cd2fcb1b3f5f2285b18469a7",10.052724077328646],[17772,"0d2858d0df470bab653e6ad537baac225df45f2d597902584dd7597d5b15dc41",9.317957166392093],[3369,"83abbbc9246cc1b80fe2081a728ad0c346162e1a728f98025ee54b33493deae9",9.917710196779964],[19389,"9a7c21c6385de89ee22aa4111cb451a961a1f5429ff97042ab2958487fff3912",9.647446457990116],[10167,"17d39fb7b6f99d642ad074756e813baa0f525fa16d87ede9acf7b69cfa024ebd",9.917710196779964],[19616,"015cf5e2a6d03eb65a137177dc15210c42256e9b111d2b2825c08e0e5bc24109",9.317957166392093],[10635,"97e8e189cd08a71338a9932a6e0fc443f6e8230584a479a173c9a2e32c0f74ba",9.917710196779964],[13783,"dc7921dde289a5ec1ce0885f21b9ec685ef9340810a20cc49e6115258009b299",9.317957166392093],[12796,"3e9d68a05fb49b503d56b585af5de6d3345851bd0899eb4213cc98ec17adf0ab",9.917710196779964],[867,"bca08b4bce3445b1c9677c44532779574501ab3b8ff23b29e04565323ead1efa",9.917710196779964],[19344,"6b8a68f53a4491c2f80ed17446862b62ba73f30170e61fcc7e80f10e4981bc13",9.317957166392093],[14909,"36ce7d3eb469d8e554de76e9b96912ec875749f46dc0216c9ddf6a1e181dca80",9.317957166392093],[5456,"510a1ff85d08323946484eb31a7d252c751d0d1720893be8736dff86352174dc",9.917710196779964],[6132,"b9d3b991708d7a8ad49be4cd88145bae3cd7f956f129463e08f2e617096440d8",9.917710196779964],[14206,"494686fbe3ea2fc861710dc6fadb9476c37baf719dc607370599437c530a1a90",10.052724077328646],[19314,"3093c31a98e0e92faeca5e3410674c73e35d84242d506d2f14eb3c0cf1b87c14",9.317957166392093],[1100,"8b65f24d904f6c9bd04044e8bfcf356b19e9851f8ba78b31859fef47052d94f8",9.317957166392093],[13683,"2af93e6c74fbb19708e5859b2ee1226e02303645ad05f1a47f918b465307989b",10.052724077328646],[16915,"7703caa15b5badb6b1dcf188815d561de31a8db7f640f411f4cd7131f86fcb53",9.317957166392093],[9302,"15612bfaf846cf6b3d64b5c846903a2b3a6a838caffc579e4dc4688b5422d1c2",9.317957166392093],[2138,"47423f0d937d6261d1723c61dc513d4eaa6b573def3ddc3f1967efa82f2e03f2",9.917710196779964],[17443,"17bef9b8786e104b969590c5a7317dbb607d94fde09dee2c67c86250bc25cf48",9.647446457990116],[3576,"595aeeed1c9296d0a29009dbe0b94d0a78f0cb3fd4564bb78b30f767694c76e8",9.917710196779964],[3188,"8ea2ef07585d202b2d8c194b093a067e97951ee86e9815d1425d57c61c1c19eb",9.917710196779964],[3614,"1245333af09c60ec6987fef1d5fcab0cb78f66d13e771915e8b97105f1d624e8",9.917710196779964],[10386,"1e40a864b5317a882fcdb5a56e8b8b018030ff00216055d2e8bbb3fc3d44e3bb",9.917710196779964],[10107,"fb6c57b8422fa6090446ce0639041cbd74e66f6724713c729cb21dc9769ca7bd",9.917710196779964],[7799,"8f21f51d38567c29b958bd58a43d1305fddf2871245cf2c7a239aedeb43acdcc",9.917710196779964],[9416,"3932c2da8905de739e9fbad20eee745db1a656e742b5936a975c2f8ed5c532c2",9.917710196779964],[17634,"62853d2494daf1543152ef0beba80330fb91ff9dd0e67504009ad75128619144",17],[15610,"784a5954058d2dfc91643e35805ad254273daeaa6aee29ee2a9d51a454883f71",9.317957166392093],[19776,"9e11237929196cfa0be71c30b172e95490c61466c1ce8af4fa86d40dc3d79a03",9.317957166392093],[15688,"9c8a2a80c1102faf2e9f71aa73dee1b43da8036e75e958361c5318db7e3aaf6f",9.317957166392093],[2144,"d6e226a26df9382f4876b159b9f984b70d38f8f3dbc095d4afd03a06abd0f6f1",9.917710196779964],[3445,"c47c2b3dc4316399b80fc2df907205a1bd0e740f0315858a4f0b2c07402b68e9",9.317957166392093],[14131,"7c26417bc7e2bd352a5b9920c893cdb53babacd11f4df66346fc851dede6e091",9.317957166392093],[19235,"1b6c7850ef63d0ce36837b88d2f4ec470ac41a9b1beefeff3f137ddb52e66717",9.317957166392093],[6285,"0df5e64167a7bd57bb126aca11f2b21b34fc1704469c02e8605978624b652ad7",9.317957166392093],[1534,"cfb70e1f18f3dc079a0d1d1a2e5b641a6d6693612b568b6b341342133a06e9f5",9.317957166392093],[18244,"136bc983b66d07d0a0aeb5c4f25e3455d794cc3e5c242f4d50d9e40fd9b41b37",9.317957166392093],[6447,"a4c1a7147405a4505dab725886e597c30a730903ded94a4e80a5e0988975ebd5",9.917710196779964],[10843,"189d35d0508c3e794d2e5c275cf51bb97761d7c318362ead87bac531180809b9",9.317957166392093],[613,"bf285ed391d223e3bf5bd1d1f8cf1d851b5b81d17cac2f234b33c1e6d160d4fb",9.917710196779964],[14352,"616ba1441e80e74cbed9f771a41d4a33d3057b12d381d59c2f9c62593172518c",9.317957166392093],[2723,"b9adaec286f618ba557ade58e46954828f376ded4dbe3e78f63468e71ac142ee",9.917710196779964],[14548,"feba5d11b6b6afd993216f28e3f6d54139140a1735f50294a21039dd99cd2b88",9.317957166392093],[13553,"74942182d42ba74d3004b092363d3c4b70dcbf2a6932e39abb844b572d69af9e",9.317957166392093],[1294,"be302016ce678c475e3ca5624d3226487ed35648e56d8e3b9a801eb4c97f67f7",9.917710196779964],[12654,"8b683d3a5fff739190b2cd06f6bab6928559b89dd1b4406e87470f011661eaac",19.066666666666666],[6336,"e06593530e666caa20ffc6c4a51314f5dfe3c398f3b8457bd14956b76cdcc1d6",9.917710196779964],[1926,"e567216935ab45b3697b98c41d565f57a1426e7a3d6e39f9ea4df2e329a683f3",9.917710196779964],[4934,"e6e2d45ee9b900b0e77b140364785b4cc4d378d13c30e74a4d8410f063b59cdf",9.917710196779964],[7235,"ca38efe825a149cfdd0ea5d6d69adc26ced9b7dbe98192b1fbfab9b5281d7ad0",9.317957166392093],[5056,"a4d7c038b57abf4c89e3c8cc545fa519d89427a89c9a86fb016e50ed7e70cdde",9.917710196779964],[14310,"fd8cf0b8ab6c760925892d83147a8da5da00df00ea13a1b030f985235cc5638d",9.325398714591763],[4005,"e1f894390cbe9e517be35af819bf6eb49c3af1146445734940e2bbec9dfbb0e5",9.917710196779964],[1900,"61167b725c8dedc8d9a5bae1ccd1a17986af15562f91fc9f3975c42b9feb9ff3",9.917710196779964],[3372,"e8c95e310c5faa54dfa85b8e0d4fce9dd5095bce8e8352f136b745e6821ce2e9",10.052724077328646],[13484,"1a63fa3c56f0c5c24c575a3e4e556c6782ed595ddad7b54f5908650eee4f38a0",15.003322259136212],[2215,"de47d0fa8d96dfa3385853b4c7013477a19b0e288393cc45a771f405bf9168f1",9.917710196779964],[12353,"3fd44faddfd82b32986f98f5c77b821fad5915f4313ed982a1240950c00ee5ae",9.917710196779964],[17308,"073c0bf0cdbf973417a0e3c25cd208c3f462e5b3d49dfe367c7ccb8272cace4b",26.03713527851459],[7703,"6bee8182522dfc4317ddf213d29af78117a9c2b7510c011eba5590cd0cc487cd",9.317957166392093],[13329,"be60e51765a7d098365cecbd430cd8b6596580f36ecd39a2c7fa91258c1910a4",9.317957166392093],[18569,"50e08db85264f9be0826b4d2558a58456c25e361da59d05bd58821f0fa5ff02f",9.317957166392093],[8877,"8697e4b9a221ffe71cc961649feeeaf8f69f28f334351a1a391cc4c449f093c5",9.317957166392093],[9444,"c05390420192db313e35a0ed69288446872eff211eb055417ab25c61ef680dc2",9.917710196779964],[12680,"6207e6940f50020006093fa7a15fc205d72fe5bc08d1bfcd9e398caf658ab8ac",9.917710196779964],[153,"ed13caa6fd9c98401b92a99140d0878fb33970b5c018dbc09bde666503fff4fe",9.917710196779964],[18323,"0a39bd934ff393d9bdb02affb3ea4815feba73e117db238d039180afa7976b35",9.317957166392093],[16251,"46f5fa2cf60597c9a21b5b4811b290ffaef91a6f40ffc3ffdf9de0751e544d62",9.317957166392093],[5608,"ce81f088dc916390785c293c26ecb0439303e9ef25b7d2ec0271484ed7ef9cdb",9.317957166392093],[14784,"7cfcf28b952a26f71e798bb7e3db231d179afcad57e9247638fd53b705dc2e83",9.317957166392093],[17630,"cc968020681a25834e8790b456781cdf82640d09dc2472b60d2a31f72719a244",9.647446457990116],[1739,"5448745b7ed7a082d33d68e8af77df455fcf0b0d8d324b577d05d1fe3caaa8f4",9.917710196779964],[2972,"baf3207332f97481f6e591c63d83d330402aa53f7b844bcab95ac4476ede7eec",9.917710196779964],[15716,"fbc579cea6a811613b8ee57cd57404b4469cbc184192efaa3a57128402f6246f",10.052724077328646],[14926,"953d468cab28ddee59796ac6d16bac9f54c92f50315c1bcfdb488fc0a8e66d80",9.317957166392093],[10411,"8c124a39f1224ea00c833e98908aba964920d210d2be2b91a9a9be80c6c4b7bb",9.317957166392093],[3901,"08a4811d8907ea507ef041a0f1aafd8159516cc9828db3682e8882ef97935ae6",9.917710196779964],[9997,"7fbf205b2a914968e5a3a4b6898f102f20263e54413cbb82261b831d08165abe",9.917710196779964],[6124,"8688d316e1eb6d77d78998285f419720c9906935198e43109b5c5294d5fa49d8",9.317957166392093],[3873,"a0e2a22e299fc9521aa6b2f38467645b3389b9686d1adaaad1ddaa7de0f48ce6",9.917710196779964],[13052,"025577d2c803b6fb84750d408b6c1f5f495da597f0b646fd148543875ad843aa",9.917710196779964],[9916,"2e6b607e4d018ff0985dde5bcc996489007d740fe2e727b75be97a365db4dfbe",9.917710196779964],[13960,"3d15650ad21414ff6d3f3aa185a7a94c394f545c8b76ca5d9403f73c4daad295",10.040927694406548],[7558,"fd69b59243d9d3cd242aa1f46a873de21b02331ef38cb936c5f5450e195375ce",9.317957166392093],[2564,"5be13afcf66fffec559a2ca83b96acd4f5be1f5af961474f0966f1b693097eef",9.917710196779964],[2978,"7c3a5c2ce2a0231417c07540acda16624ed53338bd3cef01f524a42e99b469ec",9.917710196779964],[9868,"e0dc8d6bdcb9cb8f954b0441b48ccc2cf7949e00f9e0d1c14133581231e51ebf",9.917710196779964],[16398,"aabab91fec84f0fd25e87362a5022255787630fe4e29806915b356f40b51265f",30.284005979073243],[4071,"2f092d8145488652fb7906d66c774df3722f9c61b54f16024759558094fe46e5",9.317957166392093],[8126,"b2d12da099f3d94f6f7933341d17b6e0e257fc17325344b8fa4df7ac6ad795ca",9.917710196779964],[15874,"00d4e809a4826688db71a856e06c5185fec8c5adf89b8683ac650a92ec81836b",9.317957166392093],[2865,"1b8b3775d1a06190586fd6f5e7d1b3daf0a7e35c60472961100f7660eb7050ed",9.917710196779964],[11272,"04df2b05fafcecf375906b809fb4f08a3d6fa3eec1bf23bb97dc3dd6b6d337b6",9.917710196779964],[18274,"21e472b114c1a3e7d922331f7d47de73addb6db1da199569aeadbb19da395b36",37.93594306049822],[17726,"cecf0a7818b05992db45e98091b97c1fa3ab9aafdf9dec04d84a4c7086e2af42",9.317957166392093],[16319,"508c505f94f632f14cd741c3bf38f4b39f7aafa6992e57f58bede3fc0473a260",9.317957166392093],[4374,"b79ad28cf81c5e157d670e485337a904af1f2bf756a181b0f7c8b1109ea43fe3",9.917710196779964],[10096,"ce53c870d566d7384064b5a4f70ea7dce5c63a69917a4b81fe9ebd39f4bdbdbd",9.917710196779964],[9559,"7b19ac74e771bc98770b78da6bed4eb218bb7ae99df9ab35698963eb69b245c1",9.917710196779964],[10868,"8b59bfc0ba9aa6a0cee7896ee2af28e8db0c13d19ce204277049e0ad8598d1b8",9.764397905759163],[13535,"ad050b89a56085e24e313fbba7b855fc24398bbd86dc1a92d9d2895122f5129f",9.317957166392093],[14534,"9f268d10f54d8cfef2d0ab5576ea82809d08422c13648a91f7c94f8b74178b88",9.317957166392093],[14238,"de00b7fec75663f275478b3f155fba1f949ef1c76c30edd76a314ad1b8e8468f",9.317957166392093],[4326,"bd2fc9fd9fa421bce8e637cea1766fb4d9465dcf8857fbc20f3b559c84bc97e3",9.917710196779964],[15899,"41da289ca5f450fdf1c6a6dcc791fa6d8f62b1eb1ea229fcb0e83ab318de0e6b",9.317957166392093],[14337,"e742691f03fa47d2b2b200dd513d7c2d0db9c2da9c483c3e5392bff15492908c",9.317957166392093],[4312,"564394ae296530a2207cfa4e1d64f9081cea00631b8eb603f0238d216b3ab2e3",9.917710196779964],[14732,"334241f5ee10ccf76992030957639fd9bcfe30fcf2b6c788fe8abae4171d3884",9.317957166392093],[18698,"7d2a9335674372220b147d9aeb767c819ecd3a18212898795ed2405e71785e2a",10.052724077328646],[258,"84dc31513f287df66f295d7121917aaaf35550752b7d39e521170da397573bfe",9.917710196779964],[18957,"de3d5672e4514438be9eed50dd3160b1e3abef10054e68d7d845eb5b4bb4df21",9.317957166392093],[3287,"89f48ed79793a6a39af6898049d76c1d3394d5f4d8d1b25f614a7eeda0567eea",9.317957166392093],[12742,"a05b0e19c7a4f372301f597044a7e4494884d3b43a9f82dc49caa86f912b49ac",9.917710196779964],[10846,"8e404701949de0ddd9de95de95b4bc8a57e61f667cdcb295415cda517f9306b9",9.917710196779964],[3294,"f325daf2e4c1c3c8d2dc3d367749c9c86732c5072615339a58bbba29f3af6eea",9.917710196779964],[17657,"89f96f1ae9ef422752d30bbbcad2c2bf489f18c8eec7d1123de4f97c5cad0344",9.317957166392093],[19250,"9b15dfe513ff465430687752206a25446a34cc9092f64b9aa954abbb3873b316",9.317957166392093],[111,"6403f66143ffc6b108475f392d3180b7eafaef20aa51b93fa1be63f93ee053ff",9.317957166392093],[16582,"98499ac143d150749781897186b39b3032ac2183e1f0134700fd71206fd76c5b",9.317957166392093],[19313,"3f12dca810a21a298e069d757564a442a0691cdf1045bb07fe2d25f29ec37c14",9.317957166392093],[1194,"face8e747295689bab894dcb6676097e00619f70a7439d27bf05eda87cba09f8",9.917710196779964],[11063,"bb99f119d632e95437431540beecf2601bf56fe1770056faf292c729c32393b7",9.917710196779964],[3564,"44e5c6f6cca64fe3d550c740a9e01513a92dbf182a450d11609c964bce167ee8",9.917710196779964],[1494,"eaef4a4232d4c96f75ad21948ef6f3d999a0b6ff995a1c25721be09f888829f6",9.647446457990116],[10895,"61d7f0e4ad1bbb6b402e70fca2b0f43f8769b65e54e7ccfc4593057617a5b4b8",9.917710196779964],[5965,"ef4398db03b53dd96ab6caf459950a69613d287cb7a3dc1c2d4f3cb3730b52d9",9.917710196779964],[12497,"374f6a5cb850a3f0583c688a147cc731bcfb3440bd903f769354cf1005f1f8ad",9.317957166392093],[5472,"1fc369e251575fac15bd012ca19e1a5161078328b5f31c982f11301fe74961dc",9.317957166392093],[16962,"ba31cdb091bfbf67c981a06b00673678de1532dc4336725978a9d8e4eb8ce552",10.052724077328646],[12774,"2970329387b5327495d6ad0823f209a5f6f7cae94a4f6ffe682d610f89a817ac",9.917710196779964],[19111,"9f9bc971d1ba6da21e3d665df3935329e5f78959fd657d4d5ca3faea29e8dd1b",9.317957166392093],[13692,"4d4fb8e7ffad49f67f1b3b324e822089961ae32bb8168b9093a96ab54edd5c9b",9.317957166392093],[11347,"d350c023622d779943d877c80d03080cf0a9018ccb4e00e8ee79481a461fb0b5",9.917710196779964],[2650,"e5f5ddf0148c796db91e4f3cd845ac4948355efad8ab8309107b78162a1ad9ee",9.917710196779964],[15068,"2f21e2aed8de259296759783865894e62bf3ce48a29124d27d571ab928523b7d",9.317957166392093],[130,"27657be2c3360cf4a1793186518c17e1dffcedf5eedd8e604985db2e60ec1fff",9.917710196779964],[5709,"9f94be085dd2eb7b8f5c259f1786a75bf678104e53e54f17fa82127735e001db",9.917710196779964],[7884,"6d000d9681155f3080814e6cc3f9c909cef95aa2423726a9c96f5e799c2c62cc",9.917710196779964],[8644,"fc92c1c6dab196565752e963da197a6d7157ad07511eb3ceb33f757f5a4e1cc7",9.917710196779964],[18983,"f3caf7673221adaf4033f93b84f7e9116fce8742e69fdb6cf92d878f5ac41621",16.97872340425532],[5171,"0dc93dd586db95e973d2e4086d78687b28ff0e7c0ec46cbf03edf2015f9625de",9.317957166392093],[10050,"56c731754f4fd34682a7fad492052c976819f6a686b6a1236edf6e779b630abe",14.188948306595366],[9796,"eb5dd7d9af300ddf3163d830ac7ae1b36df360132bac0b8666bb4e3c3d5eadbf",9.917710196779964],[13814,"0940a0deb5b58713062371f6524620a71d2fbc094e94165e1ad15162e16f2799",9.317957166392093],[14578,"bfdf7a1798e991c0c0b05c98a9d6d83987a04b270a3f165155bdd5dfb5e88587",34.963585434173666],[17592,"f50bad1ea44f8aab2d81083229fc420b9a1f7ca52a8b3ee2429fabcdcca45145",9.317957166392093],[19792,"fad10f7eb2931ee475fe2b42ec03f2da3d0b05b5e37d490b71e5febbb52fd502",10.033508207818581],[16703,"13b3cf86eb779a5ba10e9f17d0303f57f593f7f4bfcd279e883f524a1ef67358",9.647446457990116],[7241,"d5d7595b47d6d75449798f734ce999b0f75547b8850ff53899e7ab14bff870d0",9.917710196779964],[18114,"a41f08110eb994c5cc5cc0612f8cd682a0cdfe05948ed4d69a64f1ea0541923a",9.647446457990116],[11653,"695a08bf533d5b2c4f38e89ee94c997ad30c557cfe061482891c4e58d5bd93b3",18.116630669546435],[1323,"b9604992394993fc83f11c4ea045cf2b3f08fb26c74ef767fa76e9d5f11f44f7",9.917710196779964],[11937,"31cf5a63e25c365962ce6af01c0b97bba292da5de4908e72d56f8c783f00bfb1",27.902268760907504],[11643,"32ab642801fcfcc83ee24d15d6403a635ab51a5cebec98f39fbb7e2ca49ba4b3",30.604982206405694],[5226,"f50bf5ed7df879d78305ed5a3f7f10e08efdd417c82f8fca03392de14e9fd0dd",10.052724077328646],[2207,"873a2a6277027e4d3e0816b950fb16414377171978a7f334b1173efc742c7af1",9.917710196779964],[722,"aab1e1d3bba69491e6aff11a95cdb9325ecb958ce9c0ae1b6b05100163c110fb",9.917710196779964],[18796,"f15ee00353b87118da5a59754a4a4be401f1ef4254cd4a4a5f1700fee9880127",9.317957166392093],[1402,"bf9cdcfe153ad15b4c5dc164dcfc39fc6df6f5ed8ddd8adbbe7e0f83eaeeccf6",9.317957166392093],[5416,"56b6577ec023a8c29576c5b649cf6b534a1cc8338b3dba69b60eaf058626b7dc",9.317957166392093],[5922,"f0f37e082981a59b97edad4cde02bc7ade6483403d2cf2b031c2a1f927498bd9",9.317957166392093],[17921,"e0d1353ad9b37eeae33de09139e9be6db68a3eacd58c2eea4c59d0ef35e9d63e",10.052724077328646],[7360,"7e436a3c1895e6cbcc64e4c03ce42eed930ee7184c04d9ba7d281cb36cd9a8cf",9.917710196779964],[5077,"66ec9bebdc65395d898faff2ec90df6b333e96dc042e0240f59ff2c79bfdb1de",9.917710196779964],[13962,"8133aeeb237286bcee4711fed1d34a4fb1d49a165174772b1c6acac022d5ca95",9.317957166392093],[11789,"cde0f4041fd73d1a6f9c2162e3722964fcb8d1d8b9654c27b0c7ccbede00cab2",9.917710196779964],[2534,"8b719875a3b3930485a8f3f1a566c9713347a8684334192e3dfdc145809298ef",9.917710196779964],[6812,"96458235b914b417747f251111dfb9f801ac6279d81d3c10aa999a46f6a133d3",9.917710196779964],[2235,"b7d347762b18642e8244532209893a6e376d5666b2311ce99d34530117d050f1",9.317957166392093],[69,"d73c2fbc08edfe09ac85a2b709bd0d60d97e2a4859fda816e133ac14dc8189ff",9.917710196779964],[6687,"43b397f08cd33da741ccc19409d2ee929e021131b5613b27c9b83789b69d0cd4",9.917710196779964],[19705,"dbbffc4253f3e4cf14f501918a0f0ebdb014148e9859f2186e47fb614f75a906",9.317957166392093],[3224,"6c5ccc15ae2527b46fbd3a089411e9096e92092c8e1942d627dabd34f410e7ea",9.917710196779964],[9167,"534f26f3200e2c8dec167bf30c78bad539a9087ba3a0866dad5578ae6c50bac3",9.917710196779964],[15277,"27f4b9b75c0e673c699e905c67101f27ff4ace9634dba794b0f236e5cb6fcf78",9.317957166392093],[13402,"a95482d5833bd0d482b67dc91eb96c5f56a399b8d2b7ee57a5e48559c9ee31a2",37.19371727748691],[5767,"29abc4ddb7ab820ffc7a7694ce483b0b1cfe160437aa0357eec3a708f38bacda",9.917710196779964],[8866,"7d3cd0990948655c977e484664ab4ae526499f326a0396cc8bc9c78f1e86a5c5",9.917710196779964],[14288,"73ea3e5d6f23838ab0256646648de1b9d8fb66b8188c6a846028b9bc2f54ed8d",9.647446457990116],[13485,"f0f088d130734d65fc66adf7613793373256d8f518122a8c4eef5b62569736a0",9.317957166392093],[4175,"a2240c9ac35cbb037fc15e6fd0facd2f4539693eeee6f09cc96115c040b49de4",9.917710196779964],[16960,"41b642b3deb5170a1b1861575368fda2fc23a01b43c3c05252d935659e1ff352",9.317957166392093],[17343,"c7cb9058a8c81523bb7de9854c050e2562fe9e7dbfa35e81d0d68d3e211b004b",9.647446457990116],[13670,"00496060fab4b1540af357ddb7ee97c73e53fdae3c95abddbd3d398f52dedd9b",9.317957166392093],[5999,"3c3a7d19ed6457a4a123253112e913b40921dada32cd9b1bce417d2847eb10d9",9.917710196779964],[2332,"8623479fe16e7643bb970be2a5764bdf4e02cb3cd5e3e109810a849ed2f7d5f0",9.317957166392093],[13790,"72cced8e4b562ea92ba78b86ca751cef2c44689a004102bcdc4183b869288f99",9.647446457990116],[17384,"82d9ef49db22fc7c79c525ddb96cd69865744d6764556ef1c99a7a0393e7214a",44.40499306518724],[18443,"3c02d8c267db430256ea69d1a15b8eab45a2bbae831e717099d35f703447d332",9.317957166392093],[15851,"08fd91471d36287a3a6308cedbdbac4ddf4cf85ac59892e35c3d85dcf554246c",9.317957166392093],[1910,"b3e1d0643665866650f03fff261f32399d2bc8d6bfcfe0795f8f98ca65b493f3",9.917710196779964],[1681,"e4983f5d4ad0b1d90a36005f5d1fc59c034a60cb45d67febdd7df8eeeb7909f5",9.917710196779964],[6984,"a8e4c7b26d94bc69a603deb7832cf9168ef053092df9624aa61659b3a05d17d2",9.497326203208557],[16855,"a29ec7f5f9334fcbb1681bb914ff5ebfa75f74b11ff8cacde2e12b7b83083355",10.052724077328646],[12600,"cf632160d6ca4913ea7e5babde8df20467d66ac595e3cf2703025e9be05e43ad",9.917710196779964],[11041,"1037d8cdf6fe838c80597878bdcc040ed61b0e9ce67c225c262389f5ccc1c9b7",9.317957166392093],[8604,"01f9626a8d41298dbfd4df47e31d386357d551721ec4e5d2e0c5fee9d9c16bc7",19.228318584070795],[3561,"65c7a63df12bce0306916db12543a97071078925d7e3de0175c4dbe693dc87e8",9.917710196779964],[1653,"1c0ffcc5b293ad5e626f401e7cf523beb24014b012256518e2f9030fe7bc3bf5",9.917710196779964],[18684,"e2905e4816c4b0119fe2c1e3c366ee4dd06953f61f5b57e1bad4e93678b50c2b",9.317957166392093],[19510,"3f00ac3b326f7f141720f677f98145fc41d3faa896f00967c44bbd983011ff0d",10.052724077328646],[15516,"2f8dad519f1097d2cc88ce1940e71039b402ba2a2b1e3859792dee668585bb73",9.317957166392093],[15117,"f12e885425c5bb57c5f3fccd93946760d1afca7b45f4dbe66a0d22d01215537c",9.647446457990116],[7198,"7009c99abec60258d243f6002e6bdb3bd5abd949b990c6c7df9615f1a4d6bad0",9.917710196779964],[13475,"a52635b432bdeec941e0c86e924ce1d0512d0d17396b1df499fbfcd03cd873a0",9.317957166392093],[6326,"fdfc42e045876ca32600b5dc40eea2ca2e07b08df2d217e9eeba6816c8f8cdd6",9.917710196779964],[14979,"12d9c268daae0b668a217c008c0c4e6f70e0cdb5c695fedcc75d470cdd5c037f",9.317957166392093],[452,"cf6933be01e9132fca8a818a12a85dffd2a8d4dbf883178d6d91bd8972f707fd",9.917710196779964],[8657,"0ee329bd91898a93d02815fe0ddeafb4ed5c417f359593b324754be3cd3dfbc6",9.917710196779964],[718,"afdcb2cbf648b595c5abab7b22b95c564326b044998e459a0d87e596b69715fb",9.917710196779964],[12583,"f965ffd2dd4545ab0f9752ef84988858fc75754d029a608abd376f413f6462ad",9.917710196779964],[10977,"1cabdc1c0fb0dbd7af4ebe37d91aaadb0ca980be6f97a5ebafe1ee63e76c2fb8",9.917710196779964],[1,"ef203e58e600c0ec9d0a3212e6ae761f719c8193f8afd3bf809f89d4d8e6ffff",9.917710196779964],[5019,"77f283930cf4a9d63f2cf3b96138ee1c0a940af3c948e2c0beb5b1aa7a830cdf",9.917710196779964],[406,"1dc202b919553668f34994c02032e091679ddbd6b6d4c798101b2a4668b84dfd",9.917710196779964],[7877,"ee0c532de6b9e65fb3ff724160cb20f1f1780dfe1262523f305a48ae85c66acc",9.917710196779964],[10164,"fe29661305ba97c0eb9959bc4ca3df23e55c88c7c897039541a0fce4d81d50bd",9.917710196779964],[15944,"c29ba44471739775d1976f90954e87223265e34b152f7a4948bddbad3151116a",10.012515644555695],[8243,"c1cebca4ece81eb316a2449d36b3d6eed9a2f25bec4e0402a5a895846703aec9",9.917710196779964],[3205,"220e6f5537fdf822924a50d3f13c9c02766ff5ce89bfb4c7d074d33c22e500eb",9.317957166392093],[858,"550f37296c685835087c3b3403df6981fc7ca6c0ed8302450c80fdbf1dfe2bfa",19.796387520525453],[10774,"37e6108d89c17a0dbd66cc7af63514165050becdfe03b6602b4a9968c25977b9",9.917710196779964],[17439,"94c0ac10536d41cc24acce969136a2dffda7207e1fd685af1caf8b361eeee648",9.317957166392093],[706,"1e29f338c76640003245161b94e70569beadc9d58e2d6fbcf8aed527795b2efb",9.917710196779964],[2472,"735b1692103f5dee458295d30dba3bcf272bc96738956b20ba5b26c4581b0cf0",9.917710196779964],[9710,"16dc652b868cc31e8d670400da31044aeb1aa5be6329a10c14cdc7c4fcbe4cc0",9.917710196779964],[9520,"0bb68ffb737a7190e3db8dfa70120e6a2f81418459de7cd445f06202340f90c1",9.317957166392093],[8930,"4b8e8af97bc813a9cc08be248ec73ae06da68970f32da1d81101d15260604ec5",9.917710196779964],[18820,"4f3e4b050c84c647a9bd23a0c34a6a20aef18b259e07a39f4b824dc096bc0f26",9.317957166392093],[4364,"e3b313e29654f171a754d63c9d9f20fe3f0bfdf94ea6a0de8d7f6a9cfd5d52e3",9.917710196779964],[386,"b8245a1441f29fe997305f01645ba93543e5f6974b9da9c7e2b8dbd779a672fd",9.317957166392093],[14939,"8c94dc695b4ce6b0ebe8ee59662dfaff30a2f4f9a5331a72cee68fcece7a0f80",9.317957166392093],[16652,"dbd07fb3a362be1e9e4c9dcd133ee7021a0baf3664b40a1eb65aaf98a0f9bf59",9.317957166392093],[4335,"10a64f8e11085bb7d3eb902a6e527127bcb83fc4e50e5f30c0f3c4a543658ae3",22.736318407960198],[17411,"e716232afe301b49afcc1cef18de7afe339af2acb74b72ff92e40239876b9c49",9.317957166392093],[2047,"3414ebd04362525b9e2c9abb52987fd7244042b058ad7e1e06245806bef8a5f2",9.917710196779964],[12312,"fa966e87db961498e1723565142651b28a3842576fb8db2a69b652b5104f29af",9.917710196779964],[18657,"fb2a428c3f0b47cae990fa40cd35b4f1ab78eea7f797d255059978279e16652c",15.003322259136212],[12451,"38ed7af1911a9297c21d032a1060416cba4e4c8cf2e53b2159fe6354b45a48ae",9.917710196779964],[17420,"b043f66fdd5280ef20e16840f216f0e18a7b9a269eec8ce878231c3d55db6149",9.317957166392093],[12985,"c9ac466e9124e15255d5d9119e31591d508b48ae964273b544e8d4fd735cb2aa",9.917710196779964],[18884,"ae26e46a1ce5921449630998af5398e4677c62a1370991a75137b7fbee9ae023",10.052724077328646],[9879,"b691514d4da3f1d31b11a17bb4543da7dd0205f56d67843b33dbabbb64fd15bf",9.917710196779964],[2873,"8f5a53a21cd49b1f23033952afa7a00be0cf5f9a9c9150f20ff01a29b22046ed",9.917710196779964],[3558,"7d9e1858229c915251ea5dd8bc40b792e5cad9bc42039fd8da8cdfd43f9488e8",9.917710196779964],[6974,"44df9b93a8d9f7f85e6eeec933923cbcf4ac98880f73be4c7c1d6cf8a2b922d2",9.917710196779964],[6859,"57f6fc3bd5ddaa222e25f80fc5f875c3c5132990051191a7afeb481944aeeed2",9.917710196779964],[2607,"6605253a46aa46b7d8e9c4357afc58bae585faa13e4d25b9d927959f72ce1cef",9.917710196779964],[6088,"d4df0fa4b5fff04a5f4ec43265e52b1f8e29d2519454b9a33f7b78e56edf73d8",9.317957166392093],[293,"2cfb19cb65f2d5314b874011c2774fbfef8c57149eb53ab573dc241e361d01fe",9.917710196779964],[9180,"4226accfad9645e22edd01eeca49f36c1354c28bf4d7ca6cc7ac1f37180d9dc3",9.917710196779964],[17463,"ecb2077727b7f43ddaff94af6a3f466b1509c690438818f3838b0b1339968b48",9.317957166392093],[12082,"81062d9456d229c961966d7938bf7557199adee29000f455fd54caf91676d2b0",9.917710196779964],[8732,"2341e78dd8c4fcf913a8e592eff19cad568454a5c3405c75d9d4d023397383c6",9.917710196779964],[15086,"dca20fadf07964db05e2b62d39de10e189f7a679bedcde4819e923d2c137ed7c",9.88558352402746],[4870,"ca6e6e9b330dd3e59132065bbde164937a934eae3058523962aa6547176104e0",9.917710196779964],[1234,"b737e6e82a115a1434e89c93a755e0ede54881625bfae45b3f0c2c4dc903ccf7",9.917710196779964],[573,"a6a2d8c8fafac2eac6037f8c6a226e65de24303864712a941a71080109bd1afc",9.917710196779964],[499,"86a95dccd0e779b7a0dd5173d304c4ad4c8d0e910c37a5387a834de6cef2aefc",9.317957166392093],[1384,"3ad33a6da69f3276c52c3ca60c9d0f748d49e3f46a9cdc2e74a63113bd1bdaf6",27.148342059336823],[1054,"7a70e76d2b199e28d3560899a17ac4adcdaf7c69c41cd71d7982afd13925ecf8",9.917710196779964],[4535,"166a277ca54108551ac82cf46fd4cfac249fa7a89fb2901699faed1fb10423e2",9.317957166392093],[11048,"708c0588c7261860e8d37acae4d5cd37ab6ba397e3d1b47e897d8e0f03c0b7b7",9.917710196779964],[3543,"6ac8be59ebee20edd3db19cfb929f675d006b31e1409d172ad4f811138e7a5e8",9.917710196779964],[4916,"5d90cb8083700e5c32f2bf15c45867ee7156ce91309f5e1863c6f4057615c8df",9.917710196779964],[9147,"5861e855bfae91c0e5f614a538c880c44f359264c675bd89fdabf7c64f07d5c3",9.917710196779964],[10772,"046c60d5cf9ed571bbb4f2009b40eae87a23c1328338ed006a179197964a7ab9",9.317957166392093],[8575,"41d28ced8d0a3b3587c69982c1da3e179cda51e2a98b2160689e5964b27597c7",9.917710196779964],[4344,"a784a523140c9479d5049cc24fa8b6e5ac75f66eb608c6cd759ae03d10be73e3",9.917710196779964],[12519,"10c00a753f756ce45862ed57f97e35c4ca3f7d69761f55df40c2bab7adf8d6ad",9.917710196779964],[3559,"d98788650150d1de4771124cd5e6e59f507d05d37af059ff9b6736d3831f88e8",9.917710196779964],[4619,"4b8cb740bd448cb29df582c635599b13ec14cda8f48e1b1a62930b050c297de1",19],[19659,"fcd457ce2003ad617050965355e7cefe5b12f31c1c1e1a25d15931f66727ce07",9.647446457990116],[4703,"9f1e43d18b0f286841b693acfcce188b7724605414fd2999bbd1f2016914fce0",9.917710196779964],[4263,"ec9bcdd0ce883b3d5db4b827703dc52606e55d7e991750455e8c3252c5a504e4",9.917710196779964],[17293,"9f1c1c6dfc2bb870fc91046d42915b5b8081b258018f4373cf2007042735594c",9.317957166392093],[19769,"7831fb664d675e053ebd2f0c601c9aeb341d1eba50e71082784ef7887db6b403",9.317957166392093],[10852,"39230977ec84d632d0c3ba2de56a30773868acb798b2b55791c0eeb678d2feb8",9.917710196779964],[12266,"e7e6da5bf7f4a7c4b30c8672ff8286b184f1af933ebd783ecabbd6a57e7193af",9.917710196779964],[15575,"6e732fa61b3a1bf992cbfa8a927333da44de36f542c2650ecd1b88be9b901372",9.647446457990116],[19219,"5be23bd031a19446449c9a0329d981e5e105333408e9efe93650f3e6ee000318",27.90465380249716],[9131,"abab830448ab9874c08b5356b3e2d656250321e70bc91884a3baf211334feec3",9.317957166392093],[19837,"629d724e8360cbbc9a7d03a1e965eadab6672826bc1cb550e673a105e18d4801",9.754437869822485],[12984,"436d0abaead3d77a25231d885def7f2f84ca09c47e70b14d63256bdcf256b4aa",9.917710196779964],[6820,"86d9b68bbc71f18dadf2d1fbe9ba870777f2416650f52f2ca569c13fd0b32ad3",9.917710196779964],[5274,"f135f577c32ee0d0d619a2a52fb8689fd42df8cd9583f13588ed40c21bb58ddd",9.917710196779964],[3198,"b4c38740a974a7782b1099dc7acb9f8727c735191ca397b8541f47d320610feb",9.317957166392093],[7055,"0f5c557b0bbf10b6c0618713ebf1221ea6af7e9934722bf1e9cfeb900e2ca0d1",9.917710196779964],[17295,"1da0fba09686cef818a2d04c4728b1de2d343ab707d9b886b29b8136e02b454c",9.317957166392093],[1668,"95d937bf6f279a5ba125ee4713f55ba1d5ed0ebdb8fad293f0c4f67fe3df21f5",9.917710196779964],[15070,"16a0066c57dbd991028a67c2b1a87a7bb6198df3b2d95cc9545d44ebd0b7337d",9.317957166392093],[11864,"d9fd1796150ae4f0686c3b9b890953c9fd8b6429a5f3b436e090be0f56ed49b2",26.108183079056865],[5946,"9555544d72bf60f70cf2e5c5d6ee662a9d34634440fec35822d6d251d2006dd9",9.647446457990116],[17339,"6cc705a2da987bc8a9dfa01a70859c75b8f798b7c3d88a6ba561450b7955264b",19.100884955752214],[8868,"cab7c4aa3f5598490a8f6123d67e18916714a8e08f60c980e348ad9101fca0c5",9.917710196779964],[17618,"877b2aa8dee92879ea02762d9936dbc63f0dc5d6e6ae440ee9b3fd185a03db44",28.743362831858406],[3668,"bfbd454f0ed7b8a7b449d6881ae64eaaf0eb6c275019dbedfa69266e6858d3e7",9.917710196779964],[18404,"4503e26fd0b32b40941b578679081ba08eec99bda48317625f11f6683c7c5333",9.619607843137254],[11603,"5649a2172bf14c50e6921beb675c6b4646192c8b368e31df66b62e6c3a42e5b3",9.917710196779964],[10346,"53b40d38ed89a0f23f6aa5ee4e8b0b800dfb966aab41178052229cb9f46d0dbc",9.917710196779964],[8510,"0a08801e76ef990e21d74b59058a3f2517faac7992a4c6e1f6fef9ae7b3dfcc7",9.917710196779964],[12269,"ce61c7ef0923ca157b9c2eea73bfb2339d62d8befe6dae9c15c3c570ffc786af",9.917710196779964],[12060,"6f0c2113a7c9157b38616e3c65bb95667312bb62236f2686e919c9edf3e0efb0",9.317957166392093],[3506,"e7f75fd991934951e7d80182e5bd8df2aa3f3de0b0bf3c0cf658f67b04d9f2e8",9.917710196779964],[1488,"3cb7f7508a531c1aaf041a5e234043f102f95cd469392ab86b1a2650094435f6",9.917710196779964],[5992,"6402bc3ccaf19439c5f97c869b4f07cfe9d6724e0ccd0efd2000fd9ba90d20d9",9.917710196779964],[16243,"08938b2abd26615731693b6e813bf3b992c428346a05ee969ee4c1f1cd0da462",38],[8671,"dc74dfcad7ec7f1d49e6447ecf0a8572673362346be7ccf7db5fd8ccb913dbc6",9.917710196779964],[14239,"a4ae4314deb07b1ba97d9eda988c8dc231f1709e36689f90afb776257e1a408f",9.317957166392093],[8817,"2299bb7bf344daef179e3aeca0ac82873863f5d5a120d89bbb6ec13cfa0dffc5",9.317957166392093],[9768,"5113ee001d7a964789a4aa9934df46ed80a7c4b873f63d6bd875fbfbfdd4dcbf",9.317957166392093],[576,"a2959ad715ec3c1d26be97a0735c308c8a9b8f780dde53c18b46f89ede0818fc",9.917710196779964],[16777,"1cfd429f0c5bee47ef57d1da2b1c6804dc3c97e25ac3b9c3ea1fea94e082e456",9.317957166392093],[4151,"bef9385486480e3e22ca14c4315f458af20e20102574e85938972f30e045b9e4",9.917710196779964],[14229,"57ff8113161f90cc0485546818ecc29bc5666a883f0d91b2c4de5444df2a788f",9.317957166392093],[12925,"9f278e945196406db9de50fee81a1ef74033e67c09100cbfd624f84d86f21fab",9.917710196779964],[8200,"d286989cca63cbf560e241ed985dd9e87d63c6b8123b3eb868a2e6824660f9c9",9.317957166392093],[7535,"9d994f47acb4582f7dc1a792c6435cebb8a3b437f976ed187a6a40d1843296ce",9.917710196779964],[1244,"ac0f9e469cf903221f4ea2772e349287b663e5907d705c30265d25a4d0bcbaf7",9.917710196779964],[6037,"042474c461e81eac4f4d38e2dbd006011f7f86e5823439512e239f824243d2d8",9.917710196779964],[5575,"16f2bbeac1daa05c03922c8a78260f207a48e1981314b4549323a853a1dbc5db",9.917710196779964],[15540,"0d754810c6a8c8c9e6b8278a44deb7593b6625ef6402236ca940ffadbb0b2a73",9.317957166392093],[13847,"fa0ebf4dd0a44162f7e7e364d90c6e4e393b1b2074cecb028333c0f5ee797098",9.317957166392093],[3907,"05d551426282f908e1822df3d62432de69a3f1a90c6bf0281d48575bf1d450e6",9.917710196779964],[14818,"262f75a243d8d4cea86c99bc092dada7061de1570d2ff7b4472849fa18986d82",9.317957166392093],[15379,"9f28952007de49edd74b98d2148f1f7fee8d9c44c0b5f2c0a6e0fce796e8ca76",16.036613272311214],[6913,"7c8eb294bc72c7fe164be15b18480c85ad9248ac936ef34ee385e00512907dd2",9.317957166392093],[9968,"e31cfce018f88f6a84f49d1c2a87e85cbfc7e32e5d4013f645b37e51438383be",9.917710196779964],[539,"a8184124eeb781dfa6cf9efbcbe3a049532355a2ccc6f64cba93e05220195bfc",9.917710196779964],[7380,"da74c42abaa25ec98a3d77704fba9ae60262e018cfab0a7b4df0bfca29708dcf",9.917710196779964],[11259,"873b65cdfa714939de0829f679a1ea5ffaa78ea4f12327cbbc7b11658b1b4cb6",28.863961813842483],[17039,"d3dc12742f903e9796b9c36055fd072b5a349fb9dd202243580f2bb561bd3251",9.317957166392093],[19169,"576d98e182b2bcbcf4d73a146183b3702213cf7b5868c2a25627a018f1f3c819",9.317957166392093],[5684,"20c38f61a08ecde9b3423484016a6a5e70f11e0a3f7c0d6070e3210a3f5125db",9.917710196779964],[7935,"abeb5e73e363728fcae00c2113ec5e3aa02b9ae0d39760f76a49ffb94c26f6cb",9.917710196779964],[15811,"ba5e856d14945bcae07a32208351ea3ff4e206587d2e1051c662040583bb2e6d",9.647446457990116],[15196,"7ecb845c80edc512895016e965bf16ef9bab0e6ba56dd2593079fb609ec5947a",9.317957166392093],[16482,"77ba32ec15f5d85fabfc501ed61e012fe28d87b856ed1a9f068738830ba29b5d",9.51504424778761],[3856,"df6b71d71de9c7018568bb4b9acdbe8317d9ba4c176a6ea30d770d3911e69fe6",9.917710196779964],[10692,"ef65e53e7c1d26a04b6de63c70be9c242d283ed419e2b2617bbd76a8dfcc0bba",9.317957166392093],[9257,"73fc71d686012cbc586e4cb876e457e8d215a3d57515e23cb7197ebdb8d517c3",9.917710196779964],[15824,"36ace94dedc734f1f9b633c781c93457da97dfe341fc7e04d8a7d4a87ac0e96c",9.317957166392093],[4693,"e79164f4f65530c72759b577c0fadd736b3920c2fa4ed1a7b46b8196bd040ce1",9.317957166392093],[15008,"ee0ad441fc1ea807d8407c586bb9203e80b5fa4054cde04c527eca59e76b267e",9.317957166392093],[122,"479a5eaa5b5b7a1a7024c8ad792860dd963310de2c839d92d4542e231e883dff",9.917710196779964],[16598,"69e9259b556a57aa1912102c9fab9ebb299d77b53359095c526f01e42382ef5a",9.345291479820627],[10075,"058d5ddd0546007bfc8c6d27fdb8c027a1ad84746daa3a8c41ed6799e9cddcbd",9.917710196779964],[17910,"b85da6806f5a635efed5ddcdced99231c4ad802fd0a879fd1ca22894d2e6123f",9.317957166392093],[5714,"a49df2e01acd720bf67573cc161309dbcde5b3387bfe2f78bc6893ce0b06ffda",9.917710196779964],[14284,"f35995f5cd7ceb45f1f59af1c95dd2e3645d93fe0b67df1f168b5e50ea1c088e",39.13879003558719],[14313,"3e5bad73cf86d53f155506b80d68fce18850c4c286bd9662e84069da239c498d",10.052724077328646],[14132,"10bc200bde80b0efa8682bd4869698824d0bb9da126d2551ca329f3f70e2dc91",9.317957166392093],[12737,"109af6d7b9dfe9922586fbb809db24040a2b4db6bd8d73e669dbde4d0af257ac",9.917710196779964],[5616,"f528db39e7dd268a79378702509bc44c8d478f988d9ee33413abd1644eb091db",9.917710196779964],[15106,"4cb534963aec3ce98ca013e13beb33526c92b3010717978305afe435e970747c",9.317957166392093],[6671,"f3b0848c96a56c44208e771cf7b412234f5dc19f7efdc3ffb91d74f408b32bd4",9.917710196779964],[14064,"f0d5e54c4083b926e2f5e7b5362f13f89fc9acc4539d38b90b884998cb035493",9.317957166392093],[15518,"4c2459568593d615543e214207f301d6f425ebf7124fedae000274164026ad73",9.317957166392093],[18813,"fe036d261f3d48e98c85fd0495af05c49793a4736835ad75b1fc71d8366d3d26",9.317957166392093],[16638,"6ebf152f3aca7bd88af3382ec2c614a9e178b6db96373a3ff9c36c32d097155a",9.317957166392093],[18521,"14630fad9d641c9f60bb139668c6b103d868f66db094fd46af00cb0587350531",28.89883616830797],[8138,"a5fa711d465a033d218587b5e54017bcf8016c1ab66f8c1d9457cd1dc5f673ca",9.317957166392093],[11283,"2abb5e22bdeaef94d4f40c7288ea7f4c94a8c74b418780d651092594d4cd26b6",9.917710196779964],[6408,"cf2a7e2583f2cd59f1f71b854e9b7577b815df29712e63a471618bc7b44848d6",9.917710196779964],[15594,"239510e899f37b573025c14ee94099f61b3c7586cce6168ea0744e845a1b7771",9.317957166392093],[14420,"79ad87a779adf8ab5bec543e284783f80642032b3101d681ec42698fd48fec8a",18.09625668449198],[145,"e702d427c21ef3e7dc252e7adadcddbce1f9dbb3d15255f2e3c6d4dd0dc901ff",9.917710196779964],[1885,"7bd01f45122cb1e7258b298c00d7b8f094c8e66a619ea0010f1f2b8f1174b3f3",9.317957166392093],[17606,"d76984e871acc532451ab7989fdc3bd2672cb626ac3f9cab0323c613ae03fa44",9.317957166392093],[2700,"75afa61f63fea96dbd3986156c8691f457b6b5504afc65aa81034c61c3fe77ee",9.317957166392093],[8998,"ba766373cc13692b0a7e51890edeebc26aee78c6a59b920811a83eaf91d4ccc4",9.917710196779964],[12622,"371b76de8921148584755dc35b0fc35bbedf1449e119ab203b3f07bbeb3a21ad",9.917710196779964],[7702,"caca9b03af3d82668c5bc52ef5d6a1365684f075b38c7a8ce0da71c2477588cd",9.917710196779964],[19367,"398c1f5c4b250ca1429c019d98824790952e49d74507dabe80fbfae204662b13",19.032702237521516],[9105,"5ac3fbe241232449825899c06a073a2889004f0cd290c85ddd47d59a4fd723c4",9.917710196779964],[16349,"dcc1a8996088296345f0fe572b8fa62647a3ffcfced1e9c0c2f1fc2850f21e60",9.317957166392093],[7998,"b36cdf0fb7299e914c8cebf626709378d8764d1fc067698e3007699f334d86cb",9.917710196779964],[12609,"565e7e37e76ac0bb2d1c34e6a3fc8b08a92cf78cfb60c73e866276a670b335ad",9.917710196779964],[13157,"8d8aa548b7cb9feeddabffff207d45c601fa042d2495260769a0693e5bffd5a7",9.317957166392093],[6497,"b8c05143c50427e5c623e2cc74e7b7dd7b9e791e9b9148c201f5a156779e7fd5",9.917710196779964],[2768,"aa2b825ae38c403d5dad8ca1da066cc192b9dab44e370084031c661884d9f9ed",9.917710196779964],[5647,"c01fd7e53f255628bf530797287cbe521d7fda6bcf136d1a3083f2d6d5dd58db",9.917710196779964],[10238,"c294ef4dc97a86f6e2ffc6c5427400ea60ec2f767dfe8bf1d5dd9fa04394c3bc",9.917710196779964],[14952,"4b12e756b7a937ad0ece7f3c1fc84287f1637a070489dd1b5237daa1f289b37f",18.51923076923077],[5357,"e19f2c0a5d2f32bb4d6d79cbdb5ca558cff7e56fb452b34f26c9ee00928019dd",9.917710196779964],[10946,"492067b1a5dc380fe03f3c2b0c2d494d75ad450e54fca961ced0e0df769b69b8",9.317957166392093],[789,"a72475e7e4a5a08cb1beaa708391e6c3491cb93b6177eaa644a52d2adeac96fa",9.917710196779964],[9144,"b8af66f1eaba163e3769cdeecb9263caf2c4066a51d5f71573359d2a2864d8c3",9.917710196779964],[4073,"f08e763baea1fa3de973b0c82a069c88336f5e003edcf999cb334f06c92c41e5",9.917710196779964],[8837,"83227540a5cc95ba50390f40e34250d3453e5d04adab6813fd82b9122575d8c5",9.917710196779964],[16478,"8423d97482218cbfe7ca6e228d6ab91f02f0dd1bdfcf3a870698e2d6c754b35d",9.317957166392093],[14380,"b03579d7d1548fca81575121ed466f0987019a0c57564f5555998248a7e7c18b",9.647446457990116],[1718,"e681f8ae2737761783c81c509ee7c7417cc0625335cbfa1f978ffd44639eccf4",9.917710196779964],[8824,"a0b264584f9de975718687bfbd5c2841d1714e8652e2db4c6f4cb64c55b0f1c5",9.917710196779964],[5627,"053851c102ba7f2ee57ba059850cd694c7f065520628ee025549abdb2eb87edb",9.317957166392093],[10586,"25b6ba41d538b8a46970e6353a0442e211f075b6b71851d68a2840718a65b5ba",9.917710196779964],[8749,"9d55c3b450d01b026122aa138e061a60754358311cf08fb62b611581841262c6",9.917710196779964],[8204,"2409658f608cdbfcbae944abd8e9c3889628c236367ae90c01adffebe6abf3c9",9.917710196779964],[9618,"2ac0d9738b0f62b363a7356c518299afc24f41cf1d0052585b749b622614ebc0",9.917710196779964],[1503,"52ccbb34fc84b7d64e4bffc775a5abc3e9a3ed38be3281bc7d5bc40c4b9319f6",9.917710196779964],[10966,"cd0ef357f8ea39285c8656608b2002f3b5776f1aa575c0b39609cf24e62f3cb8",9.317957166392093],[13316,"1c8c86fcd811460bfe29a81028c18f8b9b04bd9ab1681575e3c596f545124ea4",59.05759162303665],[14539,"befb7c094758ee1fe341129b3ba6c97c246979f3ad238b474f06b1ba3fbf7988",10.052724077328646],[17328,"9a539391a26c71477515f1f0f7b06a5eece910e28da6584bd04d4eb8a4044a4b",9.317957166392093],[18025,"54707c8b507af1100ad4265b71af2d30229aebbe4ee7a82e804ee096db41c63c",24],[6224,"a183b56bf52a8bf14d4aaa5c5a4ec500f68f560b2fe32ee83d7f8022b14896d7",9.917710196779964],[5431,"22906fc28fa1b79df09fd7ba4cee726ca3de36072978c78501b4736b661999dc",9.917710196779964],[6785,"573bd85efb6141bce850a0ecb5cfc3b26ad64e7c1f4bbafd84952cb3426862d3",9.917710196779964],[13586,"f1cfe2d992992f0a3854ff4cfca9582e9e55f7e35f9f2785d1bd3e97ffb4c79d",9.317957166392093],[7910,"61fb65e6da673fbcc0f095c547f8bd27933a43fdbb229159a8c1921a65332bcc",9.917710196779964],[440,"96a24c68c5cdc742a4fe11547d1f58cdfbfa563804c8668edbeb32c2b64c1afd",9.917710196779964],[16854,"6599ad5f8fedd65643d589596b39c6638f1818c72eef21986c8ce281758e3355",9.317957166392093],[13943,"e828d313e3a94eef22891b86da7d2c4bf3f22f090925cf83102acf75a06d2996",25.53823088455772],[5912,"5411d8b944fb7c2f1c9a02f1bccc8e47f5645261ea8b1a0b1da8eb4731189ad9",9.917710196779964],[18573,"314cff803ed3225464b31cb88234c90b28038ba42f8110dad1ea4229dd6b9b2f",9.317957166392093],[11633,"f7978f4e6a5f9da35f1136cc80f51ddaab4bdb586ba0f22b5caad135aa68b2b3",9.917710196779964],[9461,"a11cd61a6021b3ad4221ba0116511297ccc063de5920d0ab6796717c1954f6c1",10.052724077328646],[16904,"4509b21646f08605a930f3ed36ec09f87cf3781e67c8a8e657925e909a261154",28.19221967963387],[7649,"b0a325101e6a1b0346d470ec22d4ab5bff28691fa7f1700f84d2affe5b85e8cd",9.917710196779964],[5733,"836d939b1bb94deefc960f6778cfa1325c708ac1999c23e4fd1315273bffdbda",9.917710196779964],[12933,"04c763457a146bc2f9042c07737cd5c9aad92a6a038c33e86aabbc80bf4605ab",9.917710196779964],[16840,"7699a299ff1b19a8c7252f0fcc664009f86131d3955685598dcb739e9f4d7e55",43.533568904593636],[4565,"5e4c164472927b93995cadbeb65f48eb8d44e58af09866471e932d2f98bae3e1",9.647446457990116],[5153,"38fae800188c3296a23a4f847bdfa9e7bba42b2ac899f0d7a92089c246bd47de",9.917710196779964],[16469,"e7c778dbc059097cd25f632d0e7248f8a9f1d1d74ed355da132ae5e927ffe75d",9.317957166392093],[16821,"a95e5652f2df8ef3d5fe3ac8073edd7c0fa43aa968480bee8b082020957cd955",9.317957166392093],[11861,"7c21d999fe643ef2102c574866ae3e511a0fc36ec6592a5f37ef14d098504ab2",9.917710196779964],[15762,"faf15230b0108a543828bab6f8e2e3226aaf9808db5bb8f2142be2395b23266e",9.317957166392093],[5589,"d3ddc5f76fb5f8e845121e281702cb33844eee5cf51d97a5c3d1b56e882bafdb",9.917710196779964],[10614,"98e8dcd8813615fb36e9564ab2ef4e91d305875c63c75435443df39b565f95ba",9.917710196779964],[19408,"d32d2e0f2cf33b0fa7ab9af4da0f9e6b6c45781003acee9404492ad369a73811",9.317957166392093],[13058,"dc36b898ca14d1754ce21b08866e3b606f8012dd951c76d1778ce08d2baa3caa",9.917710196779964],[16599,"83dfc5d47acd6ac2a753213ff4068cbb5c617a296c164ebef88ee727c58fdd5a",9.317957166392093],[8682,"d05458962c2a5f506ffeff62fcc496b0ec36ac6504e7dc3dbce810f8c760cac6",9.917710196779964],[5129,"99ee8c0d6edd07ae556859f57174b7fc3881eebc096a8f77889143e8d3b86dde",9.317957166392093],[8168,"b80686a6b82c26b015fb05e62a8528cff0a61ef7fb98d297926120fc73d22dca",9.317957166392093],[17692,"75b79ec55fa4864545533047d971fa965457d1dfcbf5dcfd6c3cc40d1f906243",9.317957166392093],[2486,"fac8721cea27595a505ec4b689cad6f8db12e28453faf308b6e1cd168114f2ef",9.917710196779964],[4394,"334aeaf2a3bcfad0d4cb8bdeb39c2005604fed6152d8e49b6b93ccd4d3301ee3",18.11332312404288],[13628,"3c5fcae30bff087128cdd404c6aa916b380c735925a986f29edfbc315961ca9c",9.317957166392093],[5705,"b1664abaacab7ed584c65a5dd9dad01580c08f9cf6b04b9b461429e4cbbf04db",19.614973262032084],[9387,"0f5888d57901d93cb230721653b7a74fd4aed1d7cddf57f92d5ac7a993095ac2",9.917710196779964],[16230,"64429f097681a1fabac0a437af64b46447ba5498dde0544327db16da0d541063",9.317957166392093],[567,"85489d25e1724d10401126c3d5d63eec6ce99e900b1db3774299076baa2228fc",9.917710196779964],[2939,"0b2164f2973a4699da0356c24d4e23cb26f2a54cef17d74cab296fa1ffb0bfec",9.917710196779964],[18226,"51c6a54e711d4d0e47d24cb5754d9266592d7077603cb9532b233df3dc547437",9.317957166392093],[10141,"5c7c6c36b7e46bc5ef731aafdc4b98b721634cdc6d1ca74c1dbac13ccd3670bd",9.917710196779964],[7205,"57d86470c44a19c8dafccd2f1b6141f80b4a94f26df0616d170f678383a5acd0",9.917710196779964],[7875,"5ffdb978c0f1a11e6123b531c36cd719ebff42cfa9bcfb2090715bf7b1a06ccc",9.917710196779964],[13606,"1142d71ec50b1e55e7dd5e0876d4570b1e7bc1c14825a8cd422901170d374f9d",26.091872791519435],[14797,"9317cf94fb351f78b5559b6254e0d90927aaa411f0b1cafdd606d829caafff82",9.317957166392093],[15436,"81f4a3557b4e525d8db16da5a01930d8b4005289a68c884b76e1162488f76d75",9.317957166392093],[7133,"8c1dc91535589148454f6a6f9c49917bd789a749cc04becbd9aa424d9aa01cd1",9.317957166392093],[17902,"6f028c5b706d76809465a7a922e9b9c5a6771f66234f4b71efe181124be0263f",41.102473498233216],[5584,"d91d9b1c740b2a3286f6b4727567dfb683808dac0bd622d4280cc4d9ecccb6db",9.917710196779964],[4546,"ed24ee2d8d5401d443bc2968967a44be497a66da0ee18c7ef90cf53718c10be2",9.917710196779964],[1516,"dea9c8a7ca351970e52f1d55caae797463566da4c447c5eec116b40d53adfff5",9.917710196779964],[14616,"50399cc4b2cc078edd8907ace9549f1d97a5316a7ce30a0c5384d44b47b2bf86",9.317957166392093],[1166,"a731f6b9f6d9785d48b16a1ce3818474d3dc237423f68b228e2f872870052df8",9.917710196779964],[15571,"d69af85d13edbc4530dda66535eb89b6b08e4daac7866fc4a73018faefd33e72",9.317957166392093],[16454,"f32ef64c538bdc2776dff02ef814807f25c025f0838e5d1a046de781e339235e",9.344947735191637],[17981,"b717912afa70cee4b34fc0d6f4e620dd6713d564ddd002f1cc5fff43009a863d",9.317957166392093],[6357,"2b08b0096b5229d5e4d98232ce0dda7ecd827ff76e1dd7d2ddd141e2a38aa5d6",9.917710196779964],[13338,"823ded5a075062ba014e47b7f01f9bd13f5f84e2513076fa7139fa39fc75eca3",9.317957166392093],[2856,"bcd1ec8f51d059d27f0164417e437e3331090a645fc11744be8d6b8ecc1b58ed",9.917710196779964],[7596,"b0a01aaa56165a844eb3f60432dda3e8d458b0a6950d5d829c90b542f3e431ce",9.917710196779964],[5585,"801c84f205199382f8ffe930b58686b3beae5601ed12427332f81357a49db6db",9.917710196779964],[2724,"23de6a0de155231153c1d8c956e9e185adac5b0424a3c14c4fd425bbd5fe3fee",9.917710196779964],[967,"16bf61cb0aa182ce1228ea2ee522e33fdfec59be6692796ce084c8662cec65f9",9.917710196779964],[10665,"b200ee9854c2b3e3e160a0b05011e1e589cd81d1b50fb1ce63983987820941ba",9.917710196779964],[19655,"3fca22ca3dd572b8dbbefc5ae63fffb7ce0f589c4c47f52667454840f92fea07",9.317957166392093],[11743,"f4e7afddcdd3ff59f896f924d96941fd565df9fb2e1e20f6a1f236495f910bb3",9.917710196779964],[10053,"355ae80be2bc68ce4ff7f5abe253d70d61091ad9232a4f67e8b631d46d9e09be",9.317957166392093],[6280,"114d5605a6221103ebc3436d11d873c6c1e19231dd5a60a087398365d28435d7",9.917710196779964],[12969,"506067557ac5e0d5fb5fe692065faaf11dd10bf59d8e03d42682b358d211c5aa",9.917710196779964],[5266,"aac597a7c5d58a91e4b1183f9e0b104a5843e5aa37081a9d9885f913c3aa95dd",9.317957166392093],[6775,"332ffa28878e5330fb87236cc11357074ec314b3ef3a05d8fcf25f6a0afa72d3",9.317957166392093],[12956,"a766ecf3614e61dda03a4c671465084e0ada905ee81a78c10a3d84bfd5f1dbaa",9.917710196779964],[4247,"47d22b3f10a88fcefc5a95c3dec45c01d174862375a3db1314d3c0b8a4fd23e4",9.917710196779964],[5444,"aefd878fc7f6664d2980431e745385c984ba7d4e7d4a560b28fbb73a4e4f82dc",9.917710196779964],[11055,"d1ac5c9393d0b96b59e10f00d776649ebde75477b77d68d21ee71d05b83ca1b7",19.215686274509803],[17801,"43682406114d723c38293457f0f8e824592640bf9a3f4ee91e644fdf60894641",9.317957166392093],[7770,"9a60573f2b1a3b6eddee3feb03b6f34a6d90bb37dfb2059b2e7f4deeccca02cd",9.647446457990116],[4045,"0cde55c54989b8e83ff77f9e77e5799b4c938029152e2c68dfbdb9ae62c075e5",9.917710196779964],[5335,"8b628bcd3722f5b4937c414327270544fe0259fa3437dffede75efe1d34334dd",9.917710196779964],[6752,"8a09c51577f2c00f58ed8d4f9d9beaf29aa23b087d1bfa4f3f061a4bda5392d3",9.917710196779964],[5059,"0a676022e87bc397876d1db06a94e13be44656ab0aea214ffe1b6a497fc0c9de",9.917710196779964],[18804,"22ea467dd40d8d7ddc60c88cbb5f021d606329ff4fabe623a0ba147d5f10d526",9.317957166392093],[14571,"8b93e0149d9dee8e23d4fa416748683faad71d369575eb503931ce1dd7b3b187",9.53899480069324],[5439,"897f4860cb8f6c0943b6d7f8c7088f537ed6a718f615819080e3ffef35c689dc",9.917710196779964],[7388,"702d87596cddf26bea116d71353ec0a368b7e206fd0bdb7700fec848a5857fcf",9.917710196779964],[17203,"2d03e64596dad1515b41620bc9319a75e3f745f59245e0ca4f60e188720abb4d",9.317957166392093],[7689,"8489cc74b6a6680424e56a9cb847db2bed1e9d53c878e2f141d99c010ec89dcd",9.917710196779964],[16008,"a6f826c59ff89834bf8f5c5e332eed22a61ba1a0df80517b9d6eca83eec04668",9.317957166392093],[19530,"e3a49df038719310c0399afce85e8dbddd1dc4a741e97079989d8607dee46f0d",9.317957166392093],[9872,"e485c5b6f54f4cce904490e6614c9d21562c0d62f6b26a10f97c31c9acab1bbf",9.917710196779964],[5894,"7c7a7275c0815f99832444db780eb9b3bec9c897cef60f0ee2e0c9ecabffbad9",9.917710196779964],[12433,"c1c6247689e5dbae44046846c46ec653edd219c8a59c49fe8f3d0ccd6d925eae",9.917710196779964],[9421,"729d8f6c3af6edd987ebac2c98e9599075175ec6e2533d7f34c938cdc2be2ec2",9.917710196779964],[15427,"10455804cd3635f4abe1c102d8dc333a17231a80713d40815288a12dc912b575",9.317957166392093],[19858,"e01d323c9d181502cd33a9e1163c5c600267bdbd83cb3de466e7d699c55f8900",9.647446457990116],[16718,"63346b255880782a0a9cb72a0b4d14a29c36974134d5e6012423290ce4082858",9.317957166392093],[9739,"fa38c9bf9bd513522613c06bef10ed691f0526627638a5be35028a9bde0b0cc0",9.917710196779964],[12097,"990c48c2cd13d66520759e519c214eb94f4d5cec97363b800230a45cac2fbab0",9.917710196779964],[4632,"09cf2436b134acaa06be149820a1d1b60f52a3daa13b173faf5aa40bce276de1",9.917710196779964],[4480,"474e6c0932257e660bb22d82c47bad36238cc16151d250b74d5685ac0b0a88e2",9.917710196779964],[14599,"9951841f8594cd90e300b20ab5dffd571102ce0a122e0b93bfca96cae49f2287",9.317957166392093],[4525,"bf4a1564be09512d80bad301302b12ea90e4bc3c3a4a9afed8f38201ab4830e2",9.917710196779964],[18990,"93dc5e78c8a3b48888c5b045653f2751742926143a142e795c5d1d15d011f520",23.90625],[639,"a1c7c447f05ba693de98db053b761064558d2b310591e381b798948d0328a3fb",9.917710196779964],[2821,"8b1e31d84bd139c8a82e4f01cea24f4e481c74617eda2fc2cbdfb997dd698aed",9.917710196779964],[11265,"5b9569f466b3235ad13ecbe03d32a1f3adcd6f624ef08b32070dd51e27cc40b6",9.917710196779964],[18629,"47e69dc03a00d62d1fefc331082b03dd9830622ac22d1d2d51b6b4ea8558a02d",9.317957166392093],[6579,"7887c57c7b96ab9ba84cf34e1ad5be2742a049112f5a601f857d7cbbaef3cbd4",9.917710196779964],[2503,"a9797a1646a11bc8e87f27ea96faa459565db98b5ff53cadce5642a916fed5ef",9.917710196779964],[11707,"f1081a778fde628d2da4870366603082f3746ca86a82aeefea167dbe974543b3",9.917710196779964],[3025,"5d885bb9b219d1e0fbfcd0bded68766d4efa4d0562d5087820e792d75c501dec",9.917710196779964],[1315,"080266afdb55c2dfd483d48e647f553de96fd13c0ad92b74dfe28e57d93b52f7",9.917710196779964],[17838,"a2086355f2a6ec92dff5b5cd6eb0432053190761ac2eab4d9e71d74c0b537f40",9.317957166392093],[8202,"2285fc919c14e10c91ec9d6b152adc196bc91042ddbd94c32bf91c8c17a6f6c9",9.917710196779964],[2105,"7af5cca2407b49b17866995cd284a57d090ea992d9a743a80c438353162833f2",9.917710196779964],[13911,"79b750681eb0040687d670b923587bdc8bb63826068ca9b2ce6f06cbe7d4d196",9.317957166392093],[11727,"53fc5fff432392300c0a3e9cfa6f9c1c33e2bc11baaa0c1a6893180a07341db3",9.917710196779964],[1695,"56d3c343ef31e925d0f5bb89f1f3deb244d023376ffc5727d8e80cfab83af6f4",9.917710196779964],[16809,"4801137db7cc9617b0236291a6663c2282642a680f76de91526903d3d60a0d56",10.052724077328646],[12093,"9b1efb2d6a06ce5481b81c2f2457df3bba5fffb9654759139cf8c3442e86bdb0",9.917710196779964],[8873,"ed800e3c0be57a1e424aadea8fc9b78dbc5c86c9de499d0a3490443168879bc5",9.917710196779964],[4369,"c45bd75f387e600fbc983b7583272ed7a866f000830caec639befe73f5bf4ae3",9.917710196779964],[18505,"e483a4e16058889d19aae5c3dfcb365a1afc258c2db9035625345c5428165031",9.647446457990116],[9731,"86f9a4ccdca93f03c2c9dad6cfb504585b08b67ac1a826dfaa4d1e8daa7517c0",19.22994652406417],[9337,"dd18289243f04fe969890b570196d01e99b6bb11d4175dbd0eeed3943d3da7c2",9.917710196779964],[13871,"7c61704818df171d3d50cee0046188c932df0e4ce9d258aa4d1a836a4f99d697",9.317957166392093],[4891,"80432742d80cdb293d6b607c6fe5e14b9ddaf607358d32701e2f7f830ffce2df",9.917710196779964],[13627,"a893390d87622636d24b37ee588eb62462eff26df630d3bd7537ddf62257d39c",9.317957166392093],[9364,"272c6051de154e2dbb354309c3413481ee5fca3c8ee9f388fcdc67d4bc8979c2",9.917710196779964],[9586,"73b2bea5b42e7e50431bd33448f2bdbc680645e38a3aa57bc0dc5ab437ec14c1",9.917710196779964],[15917,"e8bab7d1ae599f66c45b148324d44472f767d9d3b433eab33188667638d4bc6a",16.056140350877193],[14223,"98e1295ecead447d81c2a714d71a53219f6f6b5073372ab5dee8ac811dae978f",9.326968973747016],[3242,"b8190c86fc7d7f52ecc78963fa9fcbe32a2f2e3d4cbeff5add7cb9c94ee3b4ea",9.317957166392093],[103,"31752bf6199cb6d27ebea711d044424014535d366590259b3a7c28feb3965bff",9.917710196779964],[777,"97f707f8337616c05dce33289017c29a2e5b81c4e8859b46951eb7748c66b2fa",9.917710196779964],[15890,"fe5f6296b8298c7d4c685d5af0b51ca822207254963fc388185b70e87ebb386b",9.317957166392093],[4996,"60df50082268e971a9a8072c5967d342b2d825a7f2ffe5072e4f71e2e6d837df",9.917710196779964],[4336,"93b46fcaf2d8693b766ecc0c16f19d4e76e82c96c1248d9dddbb1ca5d40689e3",9.917710196779964],[10992,"eb86bc50a73965f765af9fa3650c2b79864f6056533ffdd77c34349ee72b08b8",9.917710196779964],[623,"ba915f31ea8ab04c0980322c82d79edfa9dd951bb01e5de72aa62e75a1c2c5fb",9.317957166392093],[13966,"2ec409f2a8c7b725172d2d3b46f48f3013ad3dd65742ed6d363ae9114e25a595",9.317957166392093],[3738,"2ad4c9f9d967dbf938f3d4d2899031a9f85ad1a43344190ebeceb8db6df456e7",9.317957166392093],[14744,"f8c3c4b020e27228f26b546a1f75b9aee17b064ee7dfb1e2a637e6f027bafa83",9.317957166392093],[13631,"a5c4599196d9b004bea6d1ded3b71da043c4ff3fc41b480e80d85f50c847ae9c",9.317957166392093],[12739,"e9aedb857862af3eed42e2798c49894f3283d83d5bc3b2e3563d55f3ef1751ac",21.711229946524064],[19470,"91406df85caadbada49538c1366afb380ad29465a1b24fb3773d7e72635b6f0f",9.317957166392093],[6542,"94ae235981aee6aa122f2d1368e16e5c31846af2bab2c7b4484d6008eb5011d5",9.317957166392093],[4944,"23146fc0c2a780d9a7afeb741c4781bcabb6f3f83ffdab66383898f8f3178fdf",9.917710196779964],[8976,"1e448ee9469c715a8fd3771568899390d8de8f671d3ca7b134c0479ada73f9c4",9.917710196779964],[473,"fac6d0556b0fa1a2627330add5a45c745833b31538e56fb0de10740e3d42d4fc",9.317957166392093],[2115,"9d97d5e90803a277d6579ca790b89671242372c2d2e1ce66152798a0cc9422f2",9.917710196779964],[5179,"96470aaeefc62d8ef22c1ef7f709c7cf0df73937104c906af5c5ad99413216de",9.647446457990116],[18459,"32cfcdfbc353194c27cf96e21e7f1bebcfac5f48202acd4f83571c7a69ba6832",9.317957166392093],[18563,"d45dd5124899057c97cff90b9e813c37076b9eec31f728fa732e67cf49e52830",9.317957166392093],[7390,"e9e220da26535d5a7a01608ad4279ae938ab4c41038537d2d752b5284a947ccf",9.917710196779964],[9164,"adee059d57c10501df17394916a2928053702d02e6c87bf646d72e0ff387bec3",50.77031802120141],[8553,"a1f9cbc2fee1436ec138a7e74c34fbc3801986ae041480e3b2f112d84dc5b3c7",9.917710196779964],[12418,"a581dafe572465abc67ca67bce531ae6f3ba7daff7c99e02c808dd407a2879ae",9.317957166392093],[3100,"691e63acd7d248383a9b212a5e69893c8bc6a456b6197abb6d6939543cb5a3eb",9.917710196779964],[2811,"66dcad20c63ada5ff087021e4f2444bd32db9dab2bbded1b6db522b9aee997ed",9.317957166392093],[7626,"60dc51627d155bde752361621fae4998ffa8f1f5e66fd88e0f7ec60af2770ece",15.003322259136212],[694,"d9eb973505e2d5fda322a5cad22c570e57ee046835622850016540accea346fb",9.317957166392093],[19709,"cb715a141f70bbf9af01401a259ab0e0193f3e043542d3f089f913fcdec97f06",9.317957166392093],[12571,"f8369e97bf07f367797f8015803f52e7b02d9b2e6a4602fc4f07969b802671ad",9.917710196779964],[3977,"2292dcce54ac55d609cd6604cf37dd33d4b1a5cbbf230a96de44e1345dd2e5e5",9.917710196779964],[5579,"ab4d1051fd66f1bd0063417a3ed129c0aacc7f94619c779d8a317ec2e65fbcdb",9.917710196779964],[13672,"9ed49a34e030c9d50731caa4fa866a453050149911023464b006f92b314bd39b",9.317957166392093],[14690,"6e4267393f14b26c94b742b73e37fc5744049ec33a1b64e6bdc30df245490a85",9.317957166392093],[19460,"c3eda8747a1bc9b365c4cac98a970af99ab41c0eed5d6e3f6b65e8110379a20f",9.317957166392093],[18143,"deeb753caa43210009b74459d2b5a016d03643561b45098b650e92abb750db39",9.317957166392093],[19216,"047250754cf7dbeb4a8e8573180fc75c84fc48867f45ec181b28b9bbd34e1d18",9.497326203208557],[3505,"8aac41235409974203f48d0c69bbe961fcc130caa69c7a28377c8b1a42c4f5e8",9.917710196779964],[17140,"4b40edcd3822072f3295032359ada9db18f594138b7f86d4d977c107ba8c4f4f",9.317957166392093],[6210,"85242060ea0da290fe4e6f242640dbae9932fbb5373899a4f06c777ab9e8afd7",9.917710196779964],[13853,"809a08d9fe5db3b9446b147d394231c4f4f97d076a283c34b1ec4baa3c285498",9.317957166392093],[17680,"6e4decd3e59028c132d507fcde52795182c46269257494aadb7a85a9b10d8d43",9.317957166392093],[17337,"b1b58a781ee56bbbe9b01ef46aa5ecf0629f23fa2d78d32750ae990e3ef2294b",9.317957166392093],[10077,"35b7c4c8eaa7a9794955897be296671f9b2f712cb7e037fa21aba91fc9c6d6bd",26.574610244988865],[387,"a8796cfe8c4979f6cc44e775357137b74bb53c7063fa4ba37c945111c16972fd",9.917710196779964],[11129,"f8d8f3a4af85ea81d7928c9f6b0f56de7ec0d451f9c63649999db82b4c1c1cb7",9.917710196779964],[979,"c8f7f8abfb8b7df012718c5bc035b36208f9f2912f2445148adc2aefb02d53f9",9.317957166392093],[16185,"e915e237c41d23416185349d83f2bc16bfcaf0d8e57326bda1644872e44d4264",9.317957166392093],[6923,"8c5599caaaf6ca56835b7b14c0725b374915b3b7b10b6e5b2abe9dbd231f75d2",9.917710196779964],[16208,"64bb4b9087bc4c3d000d9eda384db90de957258a74a9cbc39add554d8053a763",9.317957166392093],[17183,"756263fa1a4e0fdd6d3977d348177e7603690d0c109830ff99b2dd34b3822a4e",9.647446457990116],[13147,"5db464b19138c95b1a963e9d1c0f3391e1bfeacf7699f5fc701c2aa4a95009a8",10.052724077328646],[16259,"270ea650b24a833d8f787702fb6916429637e1d156410dfbbebbf5079d1d2862",9.317957166392093],[19373,"1a455e87593f13fe35dccc224fd3477c66e3f1e818ca45350d7cb335d6c3df12",25.312036508841985],[2341,"46c67039492f8d223ca99ca42d8728e9cf260e0246951c709714101e5fdac8f0",9.917710196779964],[3884,"ee63b8dd264e759b793b3d40afe3053a6510609d72cfea9872713f46e53278e6",9.317957166392093],[3774,"1e10d1664410faa532500013c0d0fe0e88d491f7980bbeca3a2779ca839b22e7",9.917710196779964],[16030,"88a3db1de65007b56dfacdb23bb0929d1dce13177fc84bc5abc58b29b7e9e567",9.647446457990116],[4881,"097ab6ec01890815a9db6b7ea7e1173cbced761db83b3d3fade173e43b46f1df",9.917710196779964],[10968,"49519798395a4f2debc712ec02d3e65687b1f8a10f43d60ea4fa413c3ca03ab8",9.917710196779964],[11995,"10fe1bf2252c85a85317b3beb08ccd5837f7ddfd59b4bec81f1bc03a5b9f5db1",9.317957166392093],[158,"d69b7682ddd3f96449b4be5729e997fd247264ac7eca7bf3ae784b6ff6faeffe",9.917710196779964],[4594,"cac95f9d39fedce10da9685401c58429722e8910b6c8b780548b47d81d78a4e1",26.09252669039146],[11615,"fbf21833fe95d3ad92e0dfa7a0782aa38d1f72a5392e733f3835527f9040d0b3",10.052724077328646],[10883,"d8a4d527887e7e172faa7e2a0eaca28144183649bcb06b02efc7a0e9676fc1b8",9.317957166392093],[7530,"9961af7a99100c13ae4484605139ff6652518dc5a007f8c78fda4ee153d997ce",9.317957166392093],[13806,"aef1d41da56b922a6adfbdf5925ffae8495f42adccd596398af2c9f5eaea4199",9.317957166392093],[14390,"955ab34b7d1a5cd474e2a8c5f88c4e8360ea96743ce5ab5030366a549fcc638b",9.317957166392093],[10873,"4b212c8ed03147f6153213d7ac87cf7d7f3dddf743b91d3a2594accf1e03cdb8",9.317957166392093],[14468,"6dce684a15d4626ec4efd296291fd9f550bfd8fc49e1757bdf6c8433096bee89",10.028818443804035],[18361,"9de866a85f8b70892a84b696a033dee57b05c7d6531be63fe80b047ba9537d34",38.02017291066282],[3166,"3113e4fccc1aabb4b38106ae3c56edc152619a1782e402063fcfd75a922e47eb",9.317957166392093],[10872,"58058d75e04ab537fe05a9b0bb2c802046b080669c82865bd1920573a993cdb8",10.052724077328646],[7270,"e1823cb9b15ee6f12d421f3e337c7da864dfd6012b6750e03790517f55ed34d0",9.317957166392093],[17351,"8eef571f2bb3c159c41747d0a8e44a2a44f796668a410f930070fc06a0add84a",10.052724077328646],[19789,"324773a85f912d5099485b996392b9796609ea646f3a6b2e13995c94f1b50203",26.00780234070221],[7014,"7abd851fad80c3e2fd35cf2f2f3a06b20ce83f38fea10fd4b7d4299a1d7ce9d1",9.917710196779964],[12710,"dc2382edbf8756f874f2c29a2108f4e0c44433798d25d968c014cfd63dbc85ac",9.917710196779964],[18456,"f91780a93cd923d5bb654c646b8393a13e38efedad58e2f5208f18247bc46f32",9.317957166392093],[8806,"e6f1025f885de76555dc4c9d9c9596d425fd45cdb32c64c0fad0347abad809c6",9.917710196779964],[14375,"0a53a3e63c09b764ebea1771f1f240b6ef50a36f8a4bf54e6c494e711d8ad98b",9.317957166392093],[4601,"469073c2657c4ae247b7246589d951538e0e8c78b5bec475473341e8e8789de1",9.917710196779964],[15708,"2b6a8d9511af0f8925b023a2fbde17a78e4924ff84cf243fde7275653e0b566f",9.317957166392093],[10040,"e5223e5a844d306927560366d7cd2b34049750c555dfa3190031479784b317be",9.317957166392093],[15566,"52d0451822c5950be973cc045326bbf63716a48beeac58f542e41c2cbbf65c72",28.702222222222222],[2008,"b80038a47e2cccd6ec2ef089566fcfe5a9a714e860ab7d416c579649da29f9f2",9.917710196779964],[973,"3a73a9d4ddf7badd6981e30e74fac1a882054ddafdfba2800153b8a813d85bf9",9.917710196779964],[9832,"e5475f642d3e05aa02dec0e0f86a7d2bec60b3af084089b8c730d518762b66bf",9.647446457990116],[4564,"3654c8dde74038dfb57a8460cb9f1ca1ad2bfe99172da23d710c7f84af4ae5e1",9.917710196779964],[4687,"157957744ad24be875841ec4c8bb0f56eaf01fb79dbbfeb0239ce8bb305f14e1",9.317957166392093],[17284,"fcf3e454ad453fc08bfc838045aa757cf50e92b61ffd2402ce1b9d884fe7804c",9.317957166392093],[210,"063d741cb07ee2b293a11ae05a1409cfc33235bb46fbfdfa88e5e9109aed8efe",9.917710196779964],[10922,"7479dda6216b923af76be0e578d53b53a8a2734bdb6659d91eee54f2fb768bb8",9.917710196779964],[15793,"0173324747769ad0dc6eeaea770ced5043ed5e3b04ab940ba56c84d0c2f17b6d",9.317957166392093],[10242,"730526477e1ead85d50a3022b5a3a96cb07890a90d7eeadea4a0cf8de9f3bfbc",9.317957166392093],[12976,"53ec5c6b78c686032ce58caad6d21a21fc230dccdeee073e54f40840ec00beaa",9.917710196779964],[7204,"778676584da30533ada169079d97cbd46a75bd0a7c6a6b294cd1a64c639faed0",9.917710196779964],[9551,"e7255e5b2d7b38e2c75c000c44b9fee0cf717d0013d7becf89672455404863c1",9.917710196779964],[1290,"f5a101db62e324d6fee5584dac832a5533d81e3cbd85fec292ff4679a5396ff7",9.917710196779964],[9390,"4f8b33ffa93affef3782839b0823be69ccebe7a55d32d8f6df30ee5d4d2f53c2",9.917710196779964],[9491,"e1a2fe19db6f313469336550bc6903d4ddf653ceeeb93a4a068cd79eeb09b9c1",9.917710196779964],[9558,"7cb4b139d648ec34209bc113c16633c938aed9e52aa28da7f3b09c31b7f845c1",9.917710196779964],[8509,"ab3ebec7365a0adba4dca0b01f9d3d4cb0a3272929ed9ddca4f17c0cd353fcc7",9.917710196779964],[12349,"edee0c81a25bcb0286cc132c1ac210a4f12b1d039b0bb950fd922708fd0ce7ae",9.317957166392093],[7114,"5c926269ab0901e3808409bf3334538d50ffd0ae73911a1d5522df9cb5da43d1",9.917710196779964],[13106,"5ca142e9de8d9e30c981ecbc1f2e5b3dc4f153f34c2aa6941e404c6fc8d7efa8",9.317957166392093],[4375,"e909cdd4c0b0de170a9b732bb1d6df076314f830bee6971239d0d74dfff43ee3",9.917710196779964],[8253,"e22be637329dbb6bc59026aab5ae3913fc72ff8025a788b013fb6b02e2bfa4c9",9.917710196779964],[12330,"60bc828ab71aa7867618036adb47b67577367089ade789eaa6688b3bbed506af",9.917710196779964],[18422,"8538f94bfd73b021bb70519793f9115c8875d25b733c69339599d4cd04072333",10],[11434,"1270aa7ae64754c0995aafe3ecf733b0064bb0f5bd10ded6de3a11ef32c910b5",9.917710196779964],[8246,"8aa60cd9742fbe1d06d5d23869f7cbae4f9ba9c9f121d53e409b27b89e29abc9",9.317957166392093],[7538,"ff22a9d447d6ca6948476410e718c845ce48be1cd4bd700856c71bd0e54895ce",9.917710196779964],[2637,"37a384747325d14a51f2895bafe47f7acd54ff2c481a949c36f73a22cb11efee",9.647446457990116],[3464,"3f37618f5b05dcd0a4671111dadab5817ae3c96ebfaf60df02c15cdb876d47e9",9.917710196779964],[430,"06131b28a645d7d9e969c05db6c4e16ced33ff061eef72b03623d207b99828fd",9.917710196779964],[7063,"84aa2f8145d90fa22ceb708e0b90c175ae0920874a7028d1b9ba139c89d296d1",9.317957166392093],[10182,"d0773bfa8afbe80d613ff47f1347363726e3b36aefd878dfa249a3d1ea8122bd",9.917710196779964],[14106,"43c72443c45c5afeeae652e6519383d0e7e5e5a349cc418c6dc59914f9816992",9.317957166392093],[13859,"76f9a2955dadffb7d905823a710a3862fa4dd4e81448f7b0653f13bdc0223b98",9.317957166392093],[4545,"66856724acaeacc8710b5a7261c8f1e78140f0af04f17e021e5d3b0c996e11e2",9.917710196779964],[12491,"d0a298b04791662f2fc58244c3906143d0cf8e3356de719ccbdf51728fa102ae",9.917710196779964],[6620,"e13627484e7acab0d0d1b2f6db4e597baec2108116c57db844ca251d0c3f82d4",9.917710196779964],[8264,"4ea136620e5d471bfc69f20a071c23eb9259447c0857a95178a5f476cf3595c9",9.917710196779964],[13333,"3fb04be9b4cf412f67ab6f0c54fe3965fce6ef30d333ea95166c735275edfaa3",9.317957166392093],[4740,"19be43cea45b6188cf2dcd3a1ce1aa6c6b30706f867598f9a8a6f5456881b3e0",9.317957166392093],[3625,"1320e28b7818e5428e607fd9b46a94f520361bb2625d2d8e9e97fb580ace13e8",9.317957166392093],[8655,"2bf808a70cb6b8bb7c6daacc5a358b6e9188678aa7ef99f512e07ad79b1801c7",9.317957166392093],[8849,"b2186331c181356a79a70677b74dc1f1b8dc8c125179e536796fd7a75e6ac9c5",10.0355871886121],[15768,"983e971a50cda44010c8e083b27a3760016f7d940fe603d3c05f3f20b662fc6d",9.317957166392093],[5916,"0b39a2c8720e06d0f0ca851dd89f9ff587179f2e041c40901aa38911980998d9",9.317957166392093],[287,"adb81e9b69a540802b9251ce096a0907e8ca4f75d465fef16c8515145faf07fe",9.317957166392093],[16557,"45e56456aab34fce519ba4af789c610a289a690d0dd738a56075fe46ef08f15b",28.089456869009584],[1045,"5267f12bbb3604ec33286b9cf36e642cdf274bb169862c4f4d2f2c4ab50101f9",9.917710196779964],[16159,"c91f6dfc7d6856067321aacf66a4b0796629a05ba163fe63a465e9a41c82cd64",9.317957166392093],[540,"744c7d7cef1e5793919418b5225f325c32549fddd6957a02069aca12f66658fc",9.917710196779964],[7370,"9ec0571c90f1fb035f5b469c3b18e3adbec46b04a602ed5414930e2153bb92cf",9.917710196779964],[1163,"790deb082b2070b79f325e367c400f7984bc5163919a86cc20520ce84fc92ef8",9.917710196779964],[143,"24101a8af6e6962d68fb1e59dca64c5985eef2575c78e5666ef7ffd3d5eb07ff",9.917710196779964],[11316,"9dcd7d29d887b8fc1e1193ba6f778da78db4541d1f5c7b3c4a1c15495fa5e1b5",9.317957166392093],[7259,"f558596bad4cb7d433134aec3a3c0aaabcd4997f6deb1e87764e96ecea8747d0",9.917710196779964],[15774,"f9373ad657facbe1e96e58d4c31cae7cd7893e3bcf7388d9db05ab323770d76d",9.317957166392093],[12155,"b52d07bbd0cd4e70eb60aacc1ff92aadeb0ec6a222cdeeb4e945f79b8c1451b0",9.917710196779964],[1178,"0c711ac16267e0d108b5f4814fa67475fd121510d724bcf56133bc35253e23f8",9.917710196779964],[13989,"d8a3d3bde469724f057a62157c2acb4fcf4744c7494cbc9d73dfdc7b55f53095",18.032374100719423],[4390,"7b1b38e9680c3a1ca0b3a849437348cdf8b2deba59a5cf0edaf00ca7002123e3",9.917710196779964],[4114,"8d003fc5460bd44a1bb06a045ae6d6a0101b1e909d67525a9df724f72131f4e4",9.917710196779964],[17697,"836881afa8ad514613b7263c653bd7fdbfaa9866aa1f7a40e2ca30a06b814843",9.317957166392093],[19575,"0a223d0891f222f3c023daecb00daaebd19d0a08b5ea424c014f28699e4b5e0b",9.751351351351351],[4380,"ebabc74744366d303edc96ddbb01eebe6095e09440e5117827bf71a9b9ea34e3",9.647446457990116],[14032,"914be8a44e982542add374559fbc6eb98cb431c1d4819a2ea70f33f668c90294",9.317957166392093],[12637,"401ff376c4e8ad921db3ec4173bf384982fff1f4d604a75aa5d8d2b596d706ad",9.917710196779964],[13443,"8da82e8c146b2213da5de5bf9bf6bd324f8170945fd00f781d0519e320063da1",9.317957166392093],[5581,"f0c9c9f4ac639996ac305b53e9f52719ead7ea01793c27b7fa87657f8a0bb9db",9.917710196779964],[15720,"dddd9b0f8d08cda0cbc6b042ad8754b09b2f458f80c1ba51daf29894c6600d6f",10.052724077328646],[1773,"c2d6c2266aeb410d88a13a8d6a0186de7494639bda97cf154056c8fe99076df4",9.317957166392093],[7497,"4e27313cb721e3a4df5910fe959cea6e6cdc55330d3c14e7956758dd1d68c4ce",9.917710196779964],[16000,"ea120f45d79e3f16732b86058b05f9fa882d0ed0cbb32764db5f926fd62c7b68",9.317957166392093],[1061,"a093a775f916b3fadb25a7bfe988c4e09d554539d8dd1bdba1b3871fb36ddaf8",9.317957166392093],[10011,"3800ad77c183bd27e826b3ee739f6f879683becfdb4a7e6adbfa0b2b77ef41be",14.188948306595366],[9869,"0f8d915185b24b39ea6bda316fb20140fc985eae415f475048e1445f8c8b1dbf",9.917710196779964],[12448,"d221894076cf8739b71a0b36be939da2d4b2e16415997d002244600ba4394bae",9.917710196779964],[6295,"fa487140e3ffa2e23274be67d2c64a49eac1a3ef6fda635aa81cba33778b13d7",9.317957166392093],[1964,"2c983444b9c58b32dfb2ba57f52f361c153576804caa04defd91d68ce95d42f3",10.052724077328646],[6865,"3c6d41b148bde3c13022b318a093d63be1b3d64d2d48299e5ea7a8901a6dd9d2",9.917710196779964],[7412,"ccc63422c7e3c118165e30b150819466c53940ba0299b27b84a8ce4953924ecf",9.917710196779964],[4101,"9bee0ff02493a53a6c62b57e038e1de0a476f2cc0153ae192bd92288b47d10e5",9.317957166392093],[11062,"33e929d9f8bf3e5385b219ba124ff296e28343a1fd99c988f3bfa92308e695b7",9.917710196779964],[17479,"ed3204b4471da20bdaa498cbe04840f64db92140a11bac5ea7a169399f041f48",9.317957166392093],[3603,"4d6875c795093174b50f902590f534d11e60716d5180d929d5fb364be4e032e8",9.917710196779964],[9353,"ccd35c767c383475591b56df87575bb9ccaa0e6368e896cdf948cc64aef391c2",9.917710196779964],[11474,"d537ae03a8da16bd892b06f75aedc0598ca0e34092d4b130417a3d31c193b0b4",9.317957166392093],[2626,"e1c3b5a1d91bd7cea7eb04eb1302e697e633f0616a8c64fc2715540ce04d08ef",9.917710196779964],[5750,"f3441d85a15eba12c0303aacb25e48cfd2d8ea5005d47c202537b2f0a3f0c7da",9.917710196779964],[13451,"c0476acd964ee5de4ced7b07aab4d7ba2955f16c0f26dfeb0efe7cc8901503a1",26.091872791519435],[12947,"194d191b47d177e105735facc8f7e3f11eb2665543a5ea3c839811a7d775f0aa",9.917710196779964],[389,"557a47a7fdb88f1d7fd6e1ab7152a9ae6c3ab12ae3b682dd79a8ba795d046ffd",27.268022181146026],[6993,"5e357a2ea7f3b79b044a060c0209647d041d47e015dd481ce1276575e9680bd2",9.917710196779964],[12768,"7f268c9ee6712d040adf4f05fb1ed9e4af140406537eb8e7c6f406c451d11eac",10.052724077328646],[11284,"efa815f76c2552cfeb5d5a496a1b375e62ae637f79bb3a2b00e9644f7c6c25b6",9.917710196779964],[12721,"cd1887f9b4ba41274522a202425cd51826e65a239933b30936af3ae6a17f76ac",9.317957166392093],[16393,"923e330f3d567fe103a3cb380b1350a2e5f9bab11875f072d40415d01c7a2d5f",9.317957166392093],[18750,"35b4071a41a33bc7b8cf11d23601a328fe61dda2c604aac36f646658a4619828",9.317957166392093],[7654,"0798bc03602b5adfd6864c20de6a486427b2e86e240b008ea82ea1dcaa5adecd",9.917710196779964],[6332,"3d4b60383c8cb8ef66f5d4c063973aa0eda1629b2b0ec7244fd2cafb348dc7d6",22.278026905829595],[1710,"4a96e3400a88cd48d09bf957437a42b285acf002b9ba76b6c7550418d92bdbf4",9.317957166392093],[17473,"762f1af32a28b353eb1ed7da9ef69c01369fb1497d0f6f649ea2f44c5d8a3248",17.073593073593074],[8555,"cdc824140943ac498fe5dbf71c8d7c7f915b92510dbfe0b31ceac8a11009b1c7",9.917710196779964],[416,"9cd35e0b6d557e968db41eaa3e7b7f75751f4986c478b629a2a551f3c0a845fd",9.917710196779964],[5995,"65329368216565cd3b88b4b49dec4c75600d9f7a5d38fa25819e4ddef7b818d9",9.317957166392093],[12339,"c94c02a0f7e919501113ddc0ddb93791c7e301a5fb229bbd7cae3399bc91f1ae",9.917710196779964],[7442,"6c1f7b7b4cf75cb6fad3f3310f2bf1a3eca44bed4d95e31a4c2998f448211fcf",9.917710196779964],[13457,"6c107f9828dccfd67c9bb9e86e56f41be81bca6b415d87589730cea3b172eda0",31.52797558494405],[19031,"0d1315bcd872922373341f547613c30057878912bf10fd497ed8fc925d7b931f",9.317957166392093],[14852,"d258f8fd8bc76c81e601a173138a2bae46ec91a10395049a23ec0a12129eca81",9.317957166392093],[5447,"f95e9986f0526fd0ee3fc8302027b0d391a6c4b42c8f3163bebd2aa5cd507edc",9.317957166392093],[8163,"d1e31f6fc3c8084a2a5c7086ab027167b43ce9bd06dd6e3f4a2071a80dd53fca",9.317957166392093],[1985,"cde2ce5a95697340de53f769f43c8301461d249f15d4cb24ab7a835a88a818f3",9.917710196779964],[8250,"605be24a464f6da431a7f004a8f1435a2d50284b7a1dc80f547a00b9726aa7c9",9.317957166392093],[13626,"75c3c8fb0a731a0abcb988ceb7814cdc457dda19410a739e8a8970a3ba92d39c",9.317957166392093],[1732,"2c3cca3013eca3b6164a8f45701ed634bf217a5da8f92c69d2afe7976531b7f4",9.917710196779964],[7244,"6ecbd57075b87bd8f594a5b93b4b9821db3132128f95e6e1554e0939d8b96bd0",9.917710196779964],[5319,"72b108402160a4ce8e5ed75af07e6aa8018701701b0a948b94994e44a8284bdd",9.917710196779964],[14673,"08890e7e3b06101f690b41e0a152e59334ec1ab262b8ee93a864921c9e056085",32.90619469026549],[6382,"9c1657ba5b928caef4b94ebc3b59a17b32c51a461700dbac448df6599efe70d6",9.647446457990116],[14581,"244271a3ce3d8fa596e9e871eaf2268f99d8ef7c9e9ea346618a5db2e3c57887",9.317957166392093],[7887,"9edadfc5cc50819f3f707ad30e713c5b7e8565d6d8fbf9d3cd4bdd67200c5acc",9.917710196779964],[8549,"b4d868e41416b098db8895e397dfbc1a99100060af1b5cd4bd7445daa689bec7",9.317957166392093],[13941,"bdcf325f9907be9b5f55d1da4b3b81a84ee742d9305f39cec7f8acacfc1d2e96",9.317957166392093],[12596,"f7eed697b3e19154977754563eb1ac6657934ca70ae614ef9957c125ab764aad",9.917710196779964],[8991,"46736b7ddf736fd7ec45dc171eef106cafd91787b08712dafd73ed680ad8d1c4",9.917710196779964],[15191,"1cdc614ed168724296fc236709d415dc9228bb20120b7f89cf6fcfe269ccb47a",9.497326203208557],[3075,"fac9c5511263b0c7917b4cb195d00065d1c175981acfe1211337f7abfc00d0eb",9.647446457990116],[13939,"eb4bff3b5a85b79a7a6a7633ae8f2774e56f7810a7727bb3be82d5a5e8c43596",9.317957166392093],[10673,"10f052642d65e605b3ef7d48b3b861365be21e15426e94667029d82091c437ba",9.317957166392093],[575,"dd280f786230cc9bca42a95f7041cefd37d9ff7a8b81d2f42492474c064a19fc",9.317957166392093],[7296,"92371b6bd9a9228c09d87afaa1bdd42f238cd96990581d58fc91e108673819d0",9.917710196779964],[14692,"88896a7f7afff118b8a6866de053622515bc55a62509913a8afb4a69c6d30885",9.317957166392093],[14145,"2dc4756ff9a9d4b9e4877d74ae1384058d834a7001ffbb368e1ee1c5365ca691",9.317957166392093],[18396,"2c7cc1c30efa2283c0ef51eb302a8576aa047b9516ac64e501a5cf9eda987d33",9.647446457990116],[961,"943f5a6af2d67e9a747fd7f57470c040b177376b7dc5f68b5c23f0bc41706df9",9.917710196779964],[9969,"5e884dd1914ec12ec94a072d182048a62e9730fe0f353cf4e888574ce45881be",9.917710196779964],[18113,"bd03c1617881d5f2d36baefbd78b604528eb90eddc7ca42b73122260b1509c3a",9.317957166392093],[1346,"673c6fd4467bc9e4599138cbb64c17fb80d8bf85abc98c736c4947d266f017f7",9.917710196779964],[2673,"f0c46b06f223c966d19213d90fa460d0ece654efb229376e5e9c78ebc77badee",9.917710196779964],[9920,"7b324152270a0bfa33cf1cba92670fd7fdc887790c4ca3abfc850414c092d6be",9.917710196779964],[7553,"fc44cb15a9aba3c6008e203c7a3abf54988d93a1448213dae7278e30388779ce",9.917710196779964],[3295,"836a2e505a95bf298dee0847c1f1e7a8922bf72c7a7776e462829824d98a6eea",9.917710196779964],[14251,"31169852b1eadf66923b45aa28098db329277400397efb7f23dfa918da53f48e",9.317957166392093],[6339,"2e8a44105b3e32ff600df3831fa454d1d4f9b8e3978f1e0fd1c7478907a8bcd6",9.917710196779964],[16834,"4832e68a2258e6b1e0a1335b6ed4390eb8d515f13c4617688539cef64666a355",9.317957166392093],[9944,"87c41ffef37388ad96e09923114cad22910e99eff86845f89d8fa7233136a9be",9.917710196779964],[3663,"1f7dac1fb83aa6cda5c71884b2505a35f64ce71f840bb4607f8e4f1bb659d8e7",9.917710196779964],[12321,"9c30dd59411536700aa5a7875e71913c5a1584bef74a8bb57538f5bb486a14af",9.317957166392093],[13049,"8f197a953fcc257272eea4b8ac5e1dcfe744b1486ce0ea952e854a1e254a45aa",9.917710196779964],[13582,"981f0c685cf12b6a0ef89ed1379629855a702a4b5d3c24f6863523fe5968da9d",9.317957166392093],[12001,"c2d90aa9ac42f5cafef342ac4952f2d7ebaa9d0e9c413e674640f6be87684db1",9.917710196779964],[4500,"e52a19ce55e337affd11b9a0714e9662bc8d9cd685d2b62173c6bdd4fa0668e2",9.497326203208557],[8432,"be4421f9f23ad3fc92a6d63c5b09d62c227b28e478a4e4d3e5d2e8fa932271c8",9.917710196779964],[5741,"740cb9e871ad6e0023132abdf98372d5b31c9e6c4678d19c7f5675685df6d1da",9.917710196779964],[645,"9cc3e5f40426f643d24a9f859833bf5a40456bc8ca3012f84df71d3cae109efb",9.917710196779964],[16364,"96204ff29e8afb92af71fd11c70bf5efa0f12a10dd5854cbc2836544e69ccd5f",19],[4969,"8cf10e82eb92fa3bf26be69be0c820d352329bca40a142374d946249c40366df",9.917710196779964],[18872,"937085446a933913cc055bb7268f2fdcfdd9e44e3aeb7d446b5ae2f1cfc25124",14.074866310160427],[15570,"3305220589eb96e009e2f8610ee58aa7d61d206bc12eb86820933e047be43e72",12.01410105757932],[6800,"a53f6c3a30651b09e76796c9f75666c8f13450feb48ca11cc61776b717f746d3",9.917710196779964],[19304,"a502a0236137178a83e383dfa9f58143ca04187d320e3d93ce05c22d2837d414",9.317957166392093],[12747,"f1ab8ec956d9d5413d7698e9e661b67e8b92918b0397270f92f0d15353d643ac",9.317957166392093],[9476,"cb53cf90e37f6be7f0026d87acb8c6ee1589fe09060819446a8cd8380ab2d7c1",9.917710196779964],[13048,"dde4dab45508e7ec8992783e7dcb5d66a0abb3c7a7ea09bd5e2c291c83b447aa",19.09375],[18841,"213fd267c985296019bcccaf8be48d17e01686c4a342d0b06a911d5b2cb16825",16.40421052631579],[17613,"f00af316188be9e25e2dafa6e41c60bf3650a27aae4071b4117081353c34ee44",9.647446457990116],[16183,"25b0535bdce40cf2f5764ae9c9ea9ebc8ab5a5997c94aedc6c30f8e393104e64",10.052724077328646],[8973,"f4a19f9d0240280d37fa0c501de0c60cecd8a3ef4a65c7d874ffbdbcf983fcc4",9.917710196779964],[19810,"a32f214354e996a3ba60d4ed91019d5c79266dad12f2b98c25975deed6b14702",9.647446457990116],[10963,"24cb5db8a282b7d12f82d8a61981bd333a14537577608d53615894c5f4ee3fb8",9.317957166392093],[2861,"4e1399cc7374c05c0202da7ce9cb62ae1a5bcc8acd1b850ecddf45809bcb56ed",31.043630017452006],[6095,"b0e4a68461a0e7349d4cbbd621ee2e7dff02376300a1940b0352424d35986dd8",9.917710196779964],[17986,"3ee8913a59532d7facfadad89ca1fda152cc4858363a5803be03eca99928733d",19],[5473,"43aceec8a9d665a8a541da12b21ed9bd5d1d357f2ef452537df9084bec2061dc",42.36397748592871],[10952,"d6083a3768070d813efaaf2c1a021042f4b55d83e256382f25fac0a1e4f053b8",9.917710196779964],[14549,"0a3941cc4369b91a066ebe1738dce7abf9e41b3b373b47c2dc9d337564692688",9.31958762886598],[751,"343cf6df442fb9648a809a54b935844248fc1e9f56642fa55ae962f7da3de0fa",9.917710196779964],[2413,"d3fcac674bfee51fcbc669020b63c357ecddef4d5263f5035c10ff64abea5ff0",9.917710196779964],[13015,"06f1ddf4ab3bdc903c45cac75ed861550856cf356b11af20e9d89140dc137caa",9.917710196779964],[4719,"de967c57995a0c2f5b1e0aa6d6351c8a9ae826d1bf8e85ac18f6c7e3736cebe0",9.917710196779964],[9303,"7be70abaf461e3a96da3976e94b5f560f78d882e68e27cd978bd0f23b26fd0c2",9.917710196779964],[62,"a1890bba99258b40d1d0962b0cf791b3df35aef628fac777bcea22c6c4bd91ff",9.917710196779964],[12010,"98d928ffa7616dbd97f8f3f1a7b4e8cc6e80734bb08743667d5d83fa67a642b1",9.917710196779964],[2682,"d88ee7ef088e84b8d41d7a3e695650285822b8370ce7e253d398ad92b8f29aee",9.917710196779964],[5151,"2242bd72443c13f20dab74e90e62a93eeeb060f1b15ac329bc247fc369be48de",9.917710196779964],[1886,"f8f34e89a923c40bc43b320f8677c424d2fc04a5bb53fd6df94abdad9fb3b0f3",9.317957166392093],[16931,"cc5e09ba45fb4ee5c8a0421402443b57a7d2be23b365036b89990b7f2da47653",9.317957166392093],[2903,"4aa4de3aeb7ef1511ca29415ca01f832a8a2b1dcb8f689794aae963838311aed",9.917710196779964],[10811,"849e5894324d14ae146e39bbbbd97a113e7c41c901025d2a5b8ccb5aacd335b9",9.917710196779964],[3740,"89f48c01ad47eb05ac046c16f6f840ba8949f7e8a0e30da8022e94035d444de7",9.317957166392093],[4974,"842ea1a4d7b5f73467e3dabcccbafff45e22b192619f2e0e6992296034e95adf",9.917710196779964],[19007,"0cbf632e8e87825fff3048a25e9952fce55dde016e877d8d838b6054baf34b20",34.026415094339626],[915,"47c29d8b10c1209392f77f834c90a789efa197c08833c975e8fc0df79887b9f9",9.917710196779964],[2943,"71461a13e78a1ec070bc76fac1a82f822b76444717e9979951b0d488797eb9ec",9.917710196779964],[19264,"3d64743d07077312355817fbc5ba039c68f799c6132698453f40897ab3b32016",28.19047619047619],[18674,"3e9d295cee6f2c59cae667607bb8efc5ec2a444bdfe62cf53df3e572d8bf922b",16.04359673024523],[2421,"a5b5333bd9be3ac942899ba9ffde855cffc14ab9ec6a2eec134ebec5f21456f0",9.917710196779964],[4541,"7d52987dadd8fa1cbad205dc63372d0c866b3936d8103251f44cf791c5ee17e2",9.917710196779964],[16535,"fce22b2249da8543e6a8eb21d9ad87b6245f9c4da896722f3e808b127f33655c",10.052724077328646],[16523,"d0c8686a365578d829b57ee6b535a30c9521afa0a1e8cf38163a0716f656995c",9.317957166392093],[15142,"03f3c5232127a12bed2e2a59b08a754f5c5aa2ef6725c93a1bac187f171cb57b",9.317957166392093],[4050,"ee0d2ab507e99ec404bb959f0175f72f00ee03384bc493f32b84b23aedc571e5",9.317957166392093],[680,"5c43eeec5d627c5615dd7f702232688bd2444789a4191c44f7133c95edb862fb",9.917710196779964],[16466,"ff6f66acb288a6ab89631023f0a2d1546ed1cf837cc7dcd59076663c7fb6f25d",9.317957166392093],[16027,"028188e0e2cd74f06b508478091fc7bc75f849bcc28f99afa3be84ce1b6cf267",11.10477235326385],[7471,"de91fd206cc759e6727cb9f8720d22d5d4a0fdb374e5d073e9e9c14bc431e1ce",9.917710196779964],[2530,"4197fe0ec6383171456a868cbcaac86fc118208934d2c6ec0d4381c86eb49eef",38.98932384341637],[9759,"fbf0109cb990435b9315997e0727dec725506491d620323834bd7c2e8995f5bf",9.917710196779964],[19272,"4c067593fc2445b5fde4acceea2afc8bab9a922adbd5403ad51bb69251a7e115",9.565217391304348],[14381,"fc1595fa80414e7d47ba1e9b1944aebc70ff256a9244a513e9febac143f6bc8b",25.97245179063361],[17226,"cc9df64957bcd9c69aa861bd674d38f3d914e098ce5452864e4c6ecbffc2604d",9.317957166392093],[565,"570aa307b5f0d2d1b7366f8c8c96050aaf4873fe4ac462517239847097372dfc",9.386666666666667],[15829,"53177f5715c4b1ea1e20ac5631e6518c2ff088ffc953ca45fc6c0ba9e992ca6c",9.317957166392093],[10908,"284dd2303164ce564b5521bdef0b186be6e414852d3bb442e8a08e16a06f9db8",9.917710196779964],[3427,"fc0e8ec203835176494d1e27eac9050d104ea7e1709af2b562aca51ec2637ee9",9.917710196779964],[15530,"10a5899e80818d582d664ba4ccd572fd3624dcba3d0a464f3899dfbd4bf65b73",9.317957166392093],[9354,"2e8245858f5a2fd9660c0b67bdd631a0e424fd2f9bc456b0580a7d9229b491c2",9.317957166392093],[5786,"66ce638ac01f8eac4c38defba52e4f3cfb0e7142bbb6fb2394859efa3b5b7fda",10],[19838,"973d1b10e5b4e1d607d0de6b59057f42dab1174e68a72867fcd5738ff4023201",9.647446457990116],[16374,"4b3db96a75c377674dda754c194ea2d1d8f322520ad46af4a376a1663f36995f",9.317957166392093],[3677,"f4f3351c13177f3f8e1d4b0629e1c39ef2121b346cb848baa10c3706ec0ac1e7",9.917710196779964],[8891,"b0302163f29f3d49958163bf0d741e6a68684d446e0930d5edff1478c39879c5",9.917710196779964],[14971,"16b4930e787f93bd6df62a807ee77dd7bdee93d3e89ac200a0268781d989337f",10.052724077328646],[17939,"dfa90167bb2ef367604a9d67ba655e0282e36279ff52f6c6dc8e9352035d753e",9.647446457990116],[17573,"7d1824e3c21b8189e04eab0264b876108db53156a67c73f211d2af10f17ed145",9.317957166392093],[3027,"5e21a4d20a51bbd382454e8abab083f6588a86164333922b5708d0b4f9531cec",9.647446457990116],[19685,"22d1ecbd46a0dd00f792f55277e890784f569680a7c8856e038f764e72642a07",17.048710601719197],[5708,"8f2891460e5e0c49c17489834437e06038eb722b0423ae374732562c3f6d02db",9.647446457990116],[16116,"53b201dfe625fc699e0c799271a4d8bc520d46d9ccd645b1a0d63cebf355a765",10],[15441,"ebb1eacd00cc2c046e51a30b8da59ecc6ce3a244310f0fa9c84e1f53ac3b5875",9.647446457990116],[13357,"000b57b42217d2bbaf7c6b90ae48a817daac0aae0221a9aa58e4d697652d59a3",9.317957166392093],[150,"1bd75f009ac485ac170fa918d3a1d86defa4f6be979807075dab76753397f8fe",9.917710196779964],[6672,"499cb38a209e5530f06dacbfa08cee2017c041752ca03e3c2c1f3b308d652bd4",9.317957166392093],[11150,"54477730dddefe08ddcd386a34c9af80c1ff80bd8a08cf4c2b6828403aa1f6b6",9.917710196779964],[3718,"68e1eecfd8cfb28d0bcf41a659a359e30e98c088aa7c1273cad94a77e6517de7",9.317957166392093],[7085,"e620fcf764945d89a4bd2bb3c043e9537ed306e5d77d233408f2e5e0d3e26fd1",9.917710196779964],[6878,"49d504a23be76830ea20f0b9f7d027870514ff248b7b875ac9c2bda16e84c1d2",9.917710196779964],[12090,"d885c165fa54492eeb0a8c3332e6e5487fa944226cf770f0e772fba7b257c3b0",9.317957166392093],[17576,"b9e2d5ccfe4fa2049e96d3ea46a07c5d26879277f70c9d0dcfea327bad93c645",9.317957166392093],[1509,"afeadd3ca0490079dd0e3c5d1f61464734be84afd7392f18bc3fdec88a5210f6",9.917710196779964],[16693,"9416ef580be575127cdef6a030d096b03b72cbb53527f298217c91e640d5ac58",9.317957166392093],[780,"47cdf1e2de52c6c3f723b6c2dfbd95aa3267d9443b34a10244458e8fa9b5a4fa",9.917710196779964],[1760,"de55666431ff8ba56f90b8fe8e8b2869a7643ff55cb9c803a76efe607c1e8af4",9.917710196779964],[18781,"860a9ce4d1fa0d3998e901c5b7873c9fa4fdeea9103483b51efb2e3064b4a627",10.052724077328646],[6951,"2fd59f710a2f07de4b5157ed16bb4efb2b884037a49605ad7d2c473bd1e540d2",9.917710196779964],[4067,"81c1f28dd359417d81b8118b5b7d3635d05e685c996a57f0299e2acd27d84fe5",9.917710196779964],[7927,"36d940594bd8d01dbbdb8f262fe387f25658281933ea31869b1caa6a6bf90ecc",9.917710196779964],[1345,"637da8029d894ec8c0469936d5e565dcc17908da75f78772919a3875955f1cf7",9.917710196779964],[7449,"fe54515853f19aa29edc15ff2a12e9db7f337bc9c04c79f05e7daff1cc8916cf",9.917710196779964],[11817,"b528e94d7459f38f9cff07bf61e59fc3076650b3b4fb3261e783ec17c1c098b2",9.917710196779964],[14373,"91a39c57b727040fab60a2fea6e5e3b15484fcb0921c1196e3071b1aede4e38b",9.317957166392093],[1548,"c3def995791fdf634ca16a5838450a90636a556a224321efc4e18c204a8bd9f5",9.917710196779964],[12007,"9cb7ff39cfd68e93169e7d0f94a885e7072e24d0164491ed92f34355641646b1",9.917710196779964],[12308,"7f5b2d4a1c9772fc4f04ae5f2915d96576f8f6f72cf50337195f68ac61fb2eaf",9.917710196779964],[15167,"a03aac252086ca49d25b195fb37c8b7662ac005004f89ccf92701477eb67227b",9.317957166392093],[11155,"dab461dc5e0c98f24acef633665236a08c82836c4c465e1a9bc17f97e975efb6",9.917710196779964],[5551,"9432db7539c43b95578d5d37c81ae21e019d4b067d8b3d2e744ddc0e639bf1db",9.917710196779964],[7925,"e698f0fa5f950e89ff86694b6194c961ed517fe1f4f64059c3ce4b8220f411cc",9.917710196779964],[1852,"edf2ce228902536059f23f70c76107cda1fb0fa00aa5e987fab25987d4eaecf3",9.917710196779964],[10724,"55d564b5b7d37c90ac12b0f6169ad6ad02ce4011837c48b217f9f320028ed5b9",9.317957166392093],[12883,"ba523184e7c7a7a6f3a7dc53be7851212eb063e98a78d5168bc25a6046b160ab",9.917710196779964],[11717,"7e527b501df7f6d56b2872db634cf25299ecfd203e6a9004d1425799ace834b3",9.917710196779964],[18519,"69634fd4d38e126f8836f0ac463733c32eb0942d91528e902a49db17451f1131",9.317957166392093],[7794,"3b98c4b199e87ac920851718ed1295e5425af0f21390ed49eaead5ec0df8d8cc",9.917710196779964],[10197,"7df5e359d4cfd78a8eb51df97bff2210ad946413c89f27cb9d644ad0260206bd",9.917710196779964],[617,"a7bb06112c80550bd285cb45f3c20453f9b2ef2b851da307c62b89313f31d0fb",9.917710196779964],[8217,"6dff841a773a2ef1ebab98f256c488da7851cf753bf907c27d25c71060d0dac9",9.917710196779964],[13762,"07a7582c1b60e5a47a19bbcfe34241a71174def9c42d38c5aa42cf897799189a",9.317957166392093],[1591,"6573db0cbde15e84317807404e23c9e1c8ee351a325c117312b9e5be44f398f5",9.917710196779964],[3864,"dbcb0b19cc1abbac05c1907123592cbaa7d0fb67520d55a6c29a999f779395e6",9.917710196779964],[18194,"daca17b752728b47f5fba3a3f5556dd06691d381575a24ba1351413d2adf5438",9.317957166392093],[15110,"84fa738a6e8bfe1e390967f5639340cc7435dbfac1b2fcbd2c02ad02a081617c",17.013545816733068],[6262,"041097940836909ca6a2e011990d77a21ed2a9305e760f85236478cca0ba53d7",9.917710196779964],[5878,"80cdc60a4e93fc874a8fb1e9dba1465c340f94b5b19a6c350a2c7796004fced9",9.317957166392093],[19848,"cdb4d8e0f0624799d80b34b5e26e5c543a26b04f4c561e37cfe265631b4ee800",9.665960176250767],[19032,"2744191165caf99eb82eafe9f68e5a2e471fcf5c724ba5f05108ed5fef36871f",9.317957166392093],[6021,"dd99966940d533969e966b0d5deb487d3761c5cd7d5726a83157da9b017ef0d8",9.917710196779964],[1226,"699f68bbad688bfdd3745439d8f38e008165c309bc067f008c7c3e8409d1d9f7",9.917710196779964],[4852,"30137f63fa58a5244ae5a8cf97b82a6bcd404a23d94ba5b8285363e1ac7a23e0",9.917710196779964],[17160,"34e0832aba198210c53b22b1a6f7aa720c0cb5a55c25b7b2eb8a3c1cc100d24e",9.317957166392093],[3207,"dda65ae988b4d064b4e2ce62eefef01f008ec34b9e1345c0bfe042f56855feea",9.917710196779964],[350,"75aca8f67c39a477889dcbdcdeb828a73a0a6141460bbff0a645168b3011b9fd",9.317957166392093],[13285,"443f0072d6a408a20a6fb99ca02105e21d678859c6c5a03c8b63c8c3b9f7d7a4",9.317957166392093],[1436,"5529cafefa2d38cbf1d87a5f3b14cc56da16a353838e99a302505f1d431499f6",9.917710196779964],[16832,"50845ec3e32381e70f380f24eb2c8e10ceae7b6f3b94eba1c89cd35a499ea655",9.317957166392093],[8032,"c799f18f2e08771fb945778dea38f85b202f331d3416ea425540349c66d75bcb",9.917710196779964],[17060,"b6bf4f5979febf31fa7f2e462f1cae59a1dfd6f503ab60407039de2c49ebd650",9.317957166392093],[10542,"d8c21aaa708e4449fc2279d898a406bdc43cc9a855dd71f30b86acbe4015f3ba",9.317957166392093],[7234,"e341b5a2fb6013a7c9ee1a774a6483524b5278bc17322b842da2124960997ad0",9.917710196779964],[18948,"d434e39ae4e9ff4f101488c8dba830d24591c89b7d731c9f246aaaf606033222",9.317957166392093],[10038,"88ef9efac2235ba2af6f5af9e4bf532722631142b7fda0fe6767ef5d353f18be",9.917710196779964],[10154,"c68b4625569acaf4f81e4aa6efd84d547dacae9598bcc3480b8411ac70925ebd",9.917710196779964],[4333,"ac9f8745dfea88d147f493eb850a2f5d4a0c70ac0e26793afc35db3d09278ce3",9.917710196779964],[15402,"e96301455ad0f1da46be9b439d2a4e9c225d2ffba3b669a38d1fd4739bc24476",9.317957166392093],[3766,"ea54d37929ee19aec452c30f0838db7c66ca01e2e43d14b679364f23a96b2ce7",9.917710196779964],[10160,"8c5dc4471292193f58d574bb3ff17f3801bd0ac7e9b0c2dbec86b3ea682e5abd",9.917710196779964],[1819,"c8a85a3fec1f420d5f5b3a6188faa7aea5dd045b5dcf554fc438cc0a37c720f4",9.317957166392093],[2558,"de03e60d1b68461a555b95ae34073cc6cc8023e46cf8b36db3b73acadbd57fef",9.317957166392093],[17747,"f5ae46ec0279d10e61ac57d0f5f01f7bdea24f993baba07eb6b119721e983742",9.317957166392093],[1800,"8432c7b1dd71dd660aa5941def7f9ec7aa2219deb57d361c93611b5bd4ed40f4",9.917710196779964],[4194,"2155d00c25fa99f07d74518f876fee5d1e489bef3df50ee71e899fabe06a76e4",9.917710196779964],[11079,"27c2248fe0777c15f881948f5b7dfd6f1a0187e9c88e7ac3936a19ade92468b7",9.917710196779964],[8475,"9394fb36be59315853f9ce96a1d6283ff0bc3a2b97fda39781fcb0b5979d2cc8",9.317957166392093],[6531,"7d1f6f4df2c2355420899a06fe07cb511dce91e504ed0b585ec0282e3e7e36d5",9.917710196779964],[10283,"44780920f4b5924cc8ecc68337e679fc207085c547b8948750f6bc5dfd6b81bc",9.917710196779964],[16979,"ddcd1ae02f0ecc523216591025f3e1acdb6302a2f2e438edf56c144f3a5f8252",9.317957166392093],[4097,"a5a4b03a7eda144d5eb8070e677901c8dfaae73dcdc880be1c3e8bdb70b113e5",9.917710196779964],[15819,"ecaa0ff092f8441ab05694bb409ccb9f713fa13c55bd0f0aac76a67f2f64ff6c",9.317957166392093],[12652,"17a51fa5e62d83147b33133d9aef2b66b17aa6e53be3ad7b546f350060b5ebac",9.317957166392093],[10189,"e833165c99667ff806cf226825fcd3cbfbec88489b0d27f3a6b3e3edfe2314bd",9.917710196779964],[4961,"79b40600a117bf34a1b2d335dee957aafad0f55e5824a33f357480ea26067cdf",9.647446457990116],[8006,"ea13907f18bb22f9440ae7b7a097d5d82dcde67f9381657c11fa8e05713f7ecb",9.317957166392093],[10981,"91b5319a844f1e8da3615fe83fa2239538105a253743393efc0c15c575b929b8",9.917710196779964],[18702,"65511f338d74dcee088420996b75dfa84cdbc0927c758d46f36212a6decf3c2a",9.317957166392093],[17050,"ed4f2801b016a981893570740a42ab73a49cfeaeb42a6c9edf1cec5dd6091851",9.317957166392093],[7955,"8bfd1f9bc193a09ff7260acff36a906403248dbc42e379f93d29baf7ce8bdccb",9.917710196779964],[9261,"59c0f342d33e8ec96b544d3b454cd40ca28ee7287eac4fb45bf7f236a33213c3",9.917710196779964],[3761,"355270a6dc46ec1cfb678b786e9f82ae4689cb359190a2514e7bb53d3b3b2ee7",35.893048128342244],[15633,"ecd8dc1c8b21b23140ea03df0ef16055c2ab1d2e10522d2a7d83b605547bac70",9.317957166392093],[477,"06b87e414af9fcdb14c29d37b46c140b7664f5cb80bd24e54b69a5972f96cefc",9.917710196779964],[4452,"9539f6cf16b655802881564729c1f50e2604b00d3265800988f651e0f130b9e2",9.917710196779964],[2952,"85fdd764042cf635aca6cec550cc52ce32a1a5bf07203b166c5f005d6c5da2ec",9.917710196779964],[2818,"3817b8e175fcd3401bfc6c94c46ed2e3c1fecaae7ae80c18aa9735bb32cd8ded",9.917710196779964],[18765,"37752abbd253c2745f3a6403249f6d47cfd456bbc36a2fa2a7cf8c64a33c1e28",9.317957166392093],[12772,"c8e941427a77328b667ed206562e71e86a10764d748d3b425b0d0d71e4f31bac",9.317957166392093],[6238,"a49aa9dc22eefe4a507f9110266eec945d2470b90f5ef51fe6003c222d087bd7",9.917710196779964],[2451,"d6923d295b9f73aab9ca5eb9ae40face5fc3a32cbfa6643f057418a837ca30f0",9.917710196779964],[15771,"1bc94d1cb7fecd65b4d44b48f92dca5464b17425d33d6bc2964abe48f5bbeb6d",9.647446457990116],[4520,"b7f00e8e13c5b5cd91efa2cb3443c2567a47b2e131e21e762562a81ca3e839e2",9.917710196779964],[11749,"9f421aaa0d49d96f2a7182049adc1b142b150a252dfd3840fc505eb0b47e02b3",36.99270072992701],[18527,"de54987d79b3edd02457baef9b2f467d118daabf455480d431a30feb6eade630",9.317957166392093],[12811,"9465a752d187e5d6577057e8989f2a7f99b62674451ba8b3d1af38011e27deab",9.917710196779964],[1581,"c52040d29f4e5dd4c5f87f5ff6b1d2f671961fe653e0b950b65c1932624ca6f5",9.917710196779964],[12168,"0ccac5fdc3a495e59ddfae4376db2cee2e49340abf94a5a129a9e82645d73fb0",9.317957166392093],[12924,"7bc0fc59a6a307621fe7b05b516ba044643274c141f1a277e25bb65884ea20ab",9.917710196779964],[7577,"1cd98458100f836a2837d25292b380f88952bc03cac0e9e6070840f9e5e353ce",9.917710196779964],[19621,"1afa69c43669df5bf74db77038d47018a26560f50f8b1093f1093db554cef608",9.317957166392093],[18012,"e45da29463bf5b5b5e37c0992eb784eddf0a348e336c8eac2b4bd4eb4f76fb3c",9.317957166392093],[4093,"b0b3fdd6a48111c2c6d853d800e292698d1c1a7e262333d0b9e4bb798e9b1ce5",9.317957166392093],[19076,"38487d20b0696804c889def268444c6e83476f0eca15a83c1ea9bc191597c11d",9.317957166392093],[11552,"708625c80464882f372472f15a8ee74d29510e61e8bd7bd8b839fd38b96d3db4",9.317957166392093],[11772,"6ddc28735731ffa4064678e0143e2044e89a2ee06da04354d340d3cc6465dfb2",9.917710196779964],[17190,"7e08560c9eb419c55aae464b2156b719ea60a6d401ed2e89c16600f019adf94d",9.317957166392093],[18107,"8005343f80f66e06d758ec0e5b6abc38b278ba260ba472785d2573ef3b3cbe3a",9.317957166392093],[10309,"08e4e891e1d0055d995245c8a3941a34f698a124a26a007c702b216286d54cbc",9.317957166392093],[9673,"69b822d621a0387757ccc343f0f64572ddc99675e883951bbeaa919e9bd991c0",9.917710196779964],[11282,"9eb0b908b73ef27b5d6d4da00c52fc299285f74f4bef5b8b2a8fc09e0af127b6",9.317957166392093],[4527,"691dab22e15ed5604c862ee17be96ad5ce0c3dee8ab0a71785b4462df2632fe2",9.917710196779964],[7505,"0b79c4fcaa1f97d8f2eb8de17ec2adcbeb8cfe1bc16718b86c7b55c0184db9ce",9.917710196779964],[18931,"b3bf2b5c6cc0ac30be6111e4fbe29ff8f722d5dd5e2cc8124729c94a2b867e22",9.405895691609977],[6846,"5fb0c5b9eef69bab0d1e1e9615abcdacd7a5638bcf4210ae6955bdf0c477fed2",9.317957166392093],[13842,"05ebd68bfaf41856a1aa19dacd5d09ea1508c333444d9f907547243ba12c8398",9.317957166392093],[18907,"ec76d52a8d2763dcc99821850c95b9abe07318c8758718bf4164935185791f23",20.292792792792792],[19146,"59006bf732a4e87c1dbb41118076d023a208a457ceffbc58741cd87a8d629a1a",9.317957166392093],[16823,"8a9787f147297b64f73c057731fc307537a7e1f4ba103650871bf950d176cf55",9.317957166392093],[18470,"98cea56c631e1f87ec979eb4014bdfbb358780d73d6b9e088a2671ba53e63632",19],[14176,"dafbb6a8add1a4c2a3489901aedc4250e0d8b6fd18fb2331870f553864cbe590",9.317957166392093],[19847,"e9e951f669eacc7ca9f80f1fae2ca2fb9137cfb018eccafb0e5f5f681998ee00",10.034187455573232],[13771,"09a7ab0c7a3a10b86883a39fc169dae6ef71762675f928e6a1c4abc31742ed99",9.317957166392093],[18842,"48b767cfe6a20a4eeb2c4095cac882ed9b13e5ea3428519183221d288cb55e25",9.317957166392093],[15707,"91888fd09752c691d506de8764398b8cbce1b02a3f1b089138ea9fc909d95b6f",9.647446457990116],[15053,"31afc2953efb9b760e90007e259ee754ef728f806c04d7da2ef94f21c718787d",9.317957166392093],[3517,"7fcd75784a76b0cf691027a4705272b67c74c8c115f22993aa5b406a6030dfe8",9.317957166392093],[9774,"574f822816c97e499720850e1d20616fa819f51d1796bd2421d1cb83095dd4bf",9.917710196779964],[12156,"460ea88a42fbe29394d19dcc9d5a0319f1b574902c17cc509827e32336b34eb0",9.917710196779964],[1415,"8e584cf290e018d823caecaf959dde6f15c68bda61482e3548fdf9f5756bb9f6",9.917710196779964],[12982,"1f3707b69dbeb8f8199eae040bd6464ca2730d1163c42714c6ddb3d94251b6aa",9.317957166392093],[17522,"0d8449c04e357010d3ca6736464fae486aa04d3613985fc848c4fb9a0ff51947",32.15384615384615],[19382,"b08d7acd4bc33f19b628c9981851280a9daf85a43a28a4a406dbcec8d5478f12",9.317957166392093],[17827,"5cee47c42775869d13ab9eba2ced6ed22c1c30e838bdb25c7308ef7c9c6ebf40",9.317957166392093],[7679,"7755cf9b1b968ccce1d934fbac181f08d06c9eb096bf44f5717edc4b71bfb5cd",9.317957166392093],[9639,"90a3bf2b4c8516613d1f4d0ba921ac38d2cce85c45c58ccaa5ab14952709c8c0",9.917710196779964],[15860,"debb97fae01d62bd81a63f1d6b4821e24d43944e146174f417939060e7a1fa6b",9.317957166392093],[9314,"3861864089826ed72c4158a7d4d9142e69e6e86431490fbae20a034609bcc5c2",9.917710196779964],[1227,"0c3d9b3873feb370d666317d4708cd743ac9a299a2d34a842306f83bf757d8f7",9.917710196779964],[1895,"0c10de7126bceeadce8d430fdd2d4e20d5655d8eda4930758d90159c375ca3f3",9.917710196779964],[5574,"c3034981e26812cbdd04d7b2b07c1c128157abaff46f732bf25b1ea01113c6db",9.917710196779964],[2606,"06215bf4bd48ec7efaf88203eb993e65f3cd43b8c837ff585cca9dc956a91fef",9.917710196779964],[8777,"093e07e7c80f19366f0118c0167ce8636287962e7a0c7731985130141b4332c6",9.917710196779964],[9379,"235a917f882b1e2376e66507675657855e15235ef40ee5cf55835985d47061c2",9.647446457990116],[655,"7cbf9f1840ca2fad2691d54379bbb595cf60e533aa0e8d2ec8bc4f3641d18bfb",9.317957166392093],[6874,"4983e6aea52fea33183e3929e98108d85f3011af94743b9f9fd42650f413c8d2",9.917710196779964],[3685,"e86d4a3e83f054f224143b482412a000bfe0ab99cec3c4532041c9fa3134b4e7",9.647446457990116],[13035,"99875b0570bfe80d7eef35d8fe6a42a832ebe6b953ca1d322aa58444be8361aa",18.100558659217878],[19385,"55f3a7148d32ba3ea661cdcb690bb10aae12b20ce29110fe4096f02393b58512",9.317957166392093],[9263,"68d2df4fb18940e127d73b423c44d5bd4d6f95eb850061df135d07512b3f10c3",9.917710196779964],[16541,"6f3c035691bd85ebf449d18ab90eb78d4bcb1248c196c564de5bef85c419515c",9.317957166392093],[16372,"5b41150059eccfd9bff1d70e0cc3700aa76ce24ff08728562f6bbd596cf79d5f",9.317957166392093],[10823,"8aff3457bf020621c341edd3f626bc6432bd5466f84164119f7856fbf72526b9",9.917710196779964],[5816,"266c6d3273ddc0ed31549b6833c6e1cff704666ddf012cdd5ba0888664794bda",9.917710196779964],[15327,"e7259e5ccebc58f9b8d24ee5ee1febcb50e97f4b8ef7f39bc360874d897fd277",9.317957166392093],[19726,"7081cfc35d8b668f5ef98df39d306a161c12d864b279cd1fbeac15e833cfd405",9.317957166392093],[5329,"e8e28086390849bcb73af79b66623d598e87ba892364e238be2f5fa7fb4442dd",9.317957166392093],[18985,"fe24087ca958afaa2a97c6f0259df98ec74a41d6853336233bcbf309a4aa0821",9.317957166392093],[7138,"726c604868d966534e5760793893733ce35a775d4f4c3a63cdb8fe584f751ad1",9.917710196779964],[9125,"14cce54ab7ccc64a92d6e195a12c6b9c9157d2e59e92939988789afb5511fec3",9.917710196779964],[2340,"2ebbb82b9bba0916e5b01a77e4e206a3d18acbdb143c698b89b239506460caf0",9.647446457990116],[11787,"97a3a06b230a0fc52ae2cbcb98cd702437ca7e33f3f03507a604a697c84acbb2",9.917710196779964],[8876,"9d4e6f0ade00e4d55358d0f19338d080aba6e26950f7d3f0ea29b9a075cd95c5",9.317957166392093],[18506,"8a8ef09609532fbf71e04b866fd63c7a34c4b839f01ba331f28a3f3d28d54b31",25.831050228310502],[19771,"e024cddc3735fe7d0ea9841d70f9cf451c5bf76275b5e8e77d51c87119faa303",9.354679802955665],[12858,"f14b4f328acf19efc31c9827242ed9dd937a5be5fe380808eb591b78879d84ab",9.917710196779964],[5124,"6e390062a3f522550ff763fb2f3cc210806676e2fa5dc705f1079fc0f19e75de",9.917710196779964],[11433,"96afca7b8538d0a34a88c4fd67ee506ba30d78f1765613839909b8b10ccc12b5",9.917710196779964],[15115,"088989373100b5d84df81c6d09f3df0c689956077bfeba4cabef890a8290587c",9.317957166392093],[10755,"e380f6d4e761c8860fa6af79ca41efe55c83c5101e457720e34cc97d00b4a3b9",9.917710196779964],[19490,"9944b37da11f30c03a0febf9d819bd9fbd435a66aa7e5dfd7e45fdc5b3fab60e",9.317957166392093],[13063,"be86df7c5fae4ff5a81bd40560bc0769231cd3166c616ac79905fbc73a2b36aa",9.647446457990116],[4023,"5f274527abe957f7b8870e56c0a8ef351dbee1f4aa6e6d8185b61ea19e909ce5",9.917710196779964],[3398,"51ff519b6e6349558d583e1eb91ba0da14dfb6de38c9bce3e13016b4638bb0e9",9.917710196779964],[9419,"af4a32cf2d9952a498f2fc40c70d3c5e9e636c40623875cf5e2101d1dc3b2fc2",9.917710196779964],[7109,"b47501011f6352aa8131901cc8b32ed324cb3e0aae3822871ef78d9e2b904ad1",9.917710196779964],[16028,"eff5c53f30baf10ff470664a7c45e59b0ea8626df557fe9de4a3a5abc70cf167",9.317957166392093],[3225,"72b388ea588ab4ad365e0dbc603848f696e3bf18ec4efa5ca870e3b3d6dde6ea",9.917710196779964],[5166,"c0497507c945f74caf5bd6a28334e71578c73fc851bc5d7d1dd0354f49e82cde",9.317957166392093],[8570,"81b61cf0154805e14ba727604024073ef5b6b834f0178fdb78499ff30a989cc7",9.317957166392093],[17729,"464684a9c8aef7ef93f223a4e5af97de4aae37443bc5765e532249a27338a242",25.947932618683],[8737,"66ed3361462c3931486b7f387609a0cb20bd295be5e76a5eda953125d9467ac6",9.917710196779964],[7674,"f0b065abf74031db70dc70add48ea4c83e870fe9d496fce2d275da7c4f54c1cd",9.317957166392093],[18473,"9d4ff8fe740310e78c46825d554d3ef7b60de710d2836242329a37ea04c30e32",252.01380897583428],[9534,"2ddc16a9a51dceb6927719014efa651221dc62b1546ee47cbeb297ef381579c1",9.917710196779964],[4873,"e5abf83f28cbc902f7860761b9323398dfcb88ddcb60ea7e853227bf5eaf01e0",9.472566371681417],[5561,"5757090adc8ceffd30661881fea17912db1ed4b4c80529940caa403d3017d9db",9.317957166392093],[13841,"0caef7c6ca36ba512e5d5e5d29a97df0478aff9388aa04ae2470c25367428798",9.317957166392093],[6513,"3c5adbc4ada8cd81737396d86b518a97bc777023eb3e726da1afa9c0e65e52d5",9.647446457990116],[8935,"50d1ffec8481a95bf34feb5150791a844429a83e69a947a159708e823da247c5",23.582766439909296],[12784,"6e99c1ce78647b0664c2e17ff0f8e4c55b3e8af030b405595cfc16cf24bf03ac",9.917710196779964],[13044,"73ed91af0733ac129d7eb5b613ec6035c9fca8656ac8c2e037e7d6cee4d74baa",9.917710196779964],[17313,"2de86a1fb0b07f0e1b164d7257ddc77bec7f3c68563fcd35397ce21918a2a74b",18.08],[17609,"a3623667309b08565422d59f80f2e9e25240f2c6a02d9a2d5ec01bbed6eef444",9.317957166392093],[12845,"75a8c23f37b40f83cc1bdca7300af9edaa4025cb5ecb90e31e1b6e49d13ea2ab",9.317957166392093],[16721,"b6f8cae602c0c303ba97f8fbd1423abe873225a8484bff28dbe291468b060e58",10.052724077328646],[2051,"f601e9711beeca5e0c605a7172021c9fe314d2143c52e345e6297aaefc559ef2",9.317957166392093],[18211,"fadeeaed1dfb649bb4afacafce5ea0d9b740978b631182e59b5a53f3fe16d137",9.317957166392093],[7639,"0bdfcaeddd60e0e05d34830eeecf456ca1e4081159fc1429dca78ec63791f3cd",9.917710196779964],[4432,"d9463c2ce789a9b55ec8df952c46032cc1df8e3b31ea62a13ad55005fd46dde2",9.317957166392093],[18865,"f639752211f6e273a310007d852a4412403411afa1ddb8412e9ea3418ff18324",9.317957166392093],[6172,"67f822f76bbc1f5c5f486395f82c4c8f64d7f0b906f005d6ddb48f4915e5f6d7",9.917710196779964],[1519,"d537dc608c0518af82dcff27889775b3b35690824d6939ffdc9068fc344bfdf5",9.917710196779964],[11929,"cbfdc6538d9f457afe2e7708ef3390be91891397999d8935c41cb06f299cd3b1",9.917710196779964],[8256,"770deaa03bc26b5f7cabb75d8ce43faa7563931ba7500f7b210fd241ee479dc9",9.917710196779964],[12961,"fb32660218666ece4496e47cf275c9a909af585fa3f9ff777454a7cb8775d2aa",9.917710196779964],[14339,"59738a2ba1c5473ff852e8e5377bf78df3acc1eab3ce7cadca0ea790d26e8c8c",14],[6539,"0f6f4ca421c4f241d50f8e7cce592221656a530149c90c86a391a90b53971bd5",9.523809523809524],[7839,"5c92d179a5132eb1e1e2263e3c16c993f7e5767398d39e60e48abe503bb58ecc",9.917710196779964],[7646,"22fc8d32850011416f7bf03ecb5ea910d3d2d8175f2b34c8df6f677254e6e9cd",9.647446457990116],[4018,"e28999d148f8565711e46bf37d87ab5a05c064ffb29cc0c7c3e39934a411a4e5",9.917710196779964],[9918,"df43e5a98e7d90b7a935c37b9deee2c9337910f91aae11841ef63ef904f0dabe",9.917710196779964],[1117,"040adc2977a17a41b1133be730e61029ae55d92f41dcd808c93de99409a97af8",9.917710196779964],[12171,"d416bd8002872df00d3f6f35eba15af7ed4e4c2fa4b8bb6510d7c17492df3db0",9.317957166392093],[1594,"3018dc0782922f7477bd2d08fa6726268274d842f0ddf0d9061d15d4606a95f5",9.917710196779964],[15072,"671589337a417070cccc4a4c099adccdd84a418e657b3a5dc64b5255b27d297d",9.647446457990116],[5586,"614805b46dcdadeabc6cefb388b1174d1ebe51df9b5ca91dba4e6ed5a36cb5db",9.917710196779964],[3925,"315104309bc1de2949971b0bdaff9c606789e2b3a9d40a88c145a577e75a2fe6",9.917710196779964],[13282,"d71e408cf7aac112792edc16709fd8e5b2a6fd62aac213a87e536565cc3fffa4",46.35240274599543],[3694,"7883b38225106228b90718a07a8120ae9fb680522b6d32d67a7caafa67229fe7",9.917710196779964],[2434,"5ba1d8ad9eecd0ef31fa60f1caf50dc980b13e53622179f3396405e545343ff0",9.917710196779964],[4926,"47deeba65d510c1c6eaaea217a42cd2ca41424f259327b4d9fa7857ca67daedf",9.917710196779964],[6137,"d88fca35a5f1362a65ef3d635214f5a47383ba1fd4cdf441e099418c44a83bd8",9.917710196779964],[10666,"514aa0385f30ad556a67c8c4843f15b1a86783bb1d66b9bcc428cae1d3763fba",28.12556053811659],[15577,"75d544055f555925fec1ea01606ecb62abf3970a453ad698c9db3e9b38920f72",9.317957166392093],[6823,"edbec539e9dff2b4a2d3be9c07b3bc3ef8cdf8728e88c4fc9f69bde4a2561cd3",9.917710196779964],[13187,"e262f260a2c169a6f84d0190de7bf28129979748c266277d0e82aaf140023aa7",9.317957166392093],[18835,"2efcc7314bf1399f38d12230ea65975bacb652f1ca071a0db5f55db29fb58425",34.7773851590106],[12593,"271f9b06adef67968b457ea3e32b9b3abd8bec84124434f2ad520fcc7af94ead",9.917710196779964],[15907,"9c9ef03eceed3589cb1606edeacf947ee4cc7f5632408ebe992328a1a75ee86a",9.317957166392093],[13827,"2064f6094aa2cd8a8716232ff72ed9b8dd3b06fa4c2d4600278f599a8b4dde98",9.317957166392093],[9663,"260d31fc3d49449669af6424b768d5c20b98a24118cf74a0e5c48df5a37a9dc0",9.317957166392093],[19498,"f9f6a9e987fe3d10fa22bb3f0cfc2c154bfa93095350c0fe5088d9e80889610e",9.647446457990116],[11331,"98316d7822d70a2cb2dacd59d71aa3c77ff1aa5b2f36dc30548ea30554abc6b5",9.917710196779964],[11181,"65182f7519cd3703893462472be536653dc9fedc3646b3001b3b94a40fb5cfb6",9.917710196779964],[16914,"aab0f6ca4b90aa7a27f67de5f3113c4a527cc2adb96d1896ed8bad085aefcf53",9.317957166392093],[8157,"f6a4ddc39c7b2951ac0244af565e08d081eed8d203edb954bc427320836a51ca",9.917710196779964],[3230,"5d9b1e39aaa556b85be2f1f5ef57c32ec579ca99510412b091822b507b1fd6ea",9.917710196779964],[12257,"e4d26fd11dd67ab03d37e4508515169ad77e330a1ec5ed9214ec2fff9bafa5af",9.917710196779964],[8196,"7d58ffe8b4f3999698cd0a1867871fa56ed7cc64529b827e305099d7df0502ca",9.317957166392093],[18471,"9df26167da11c82659c058b3f36a8b4d2c3b3fb34a44a7f7eb49b07d0a7a3632",9.647446457990116],[9707,"cbcb694fff8af6b67f0230fc9dc21fd1312109320fe2ad567ece9029d0c74fc0",9.917710196779964],[14320,"883f0f7dad8553667790971f1b10c16eaaad1b6e5bc6b270ecad81c2724a2b8d",9.317957166392093],[841,"a403fab893fec9ba9db21a8eadfb89f9c7397ea6db45f4abf7e0b05365f648fa",9.917710196779964],[19566,"c6734dfab739ad391f2b1f0b1f05b8557b1a75c57112ecfded428d0714bef50b",9.317957166392093],[1111,"ac3affe876bf385f8e7c8b9f21ea15eee49bf141667b2ffa68cd1401b2b683f8",9.917710196779964],[11202,"7d972da349fef5a70b12183cdae26e272c620980f80300447fdb2043d07eacb6",9.917710196779964],[55,"512b889c62be0dda13c3d06ac909425330c69c78f7f57d08edab12d9ec539bff",9.917710196779964],[5499,"817a53d9f2ce7803825812cc14b266783fb783353f7b6dd4eab94f62bb1d3adc",9.917710196779964],[19004,"4eb51154ca6bb8f44a274896c3b058a54f6c552d11ac824816d6b4dd244c7020",20.620644312952006],[17539,"b977dad9823da28ba0b1a0fa8a20be4e849ccd14b88c9a54b07a587ae4f0c146",9.647446457990116],[7803,"ea2a92c3a72ed284e6988b0826f5c48e48bdea6023b6f2a4896dc573c853c2cc",9.917710196779964],[3894,"616bf5407cc415789b8e564fafcb65a8bf500fce6011db3aef6ef3bfba8863e6",21.842931937172775],[3507,"a6c30fb20881d2d6ad33d15787a41b5810be4549d6556bf2a6259d1f3d95f1e8",9.917710196779964],[10200,"86c3c112b59323e0de4304ea60a146ead4e9aa2c79f5bc2f999ed510794504bd",9.917710196779964],[10043,"d7e6549f2f11ff56abc870b4c0545b27d85b9e46da7ea22327a2d96de36f14be",9.917710196779964],[527,"2c02c111ff3ec3dd3dbf191d2541b8f377477603a096f97d080879d075a57dfc",9.317957166392093],[579,"cbdf887fc0d0c9423cfc7e34c1183438bc24f77a3b59f93f246662dbbc4714fc",9.917710196779964],[7118,"9b1002f0d721e786eb1103a286c0b0e5fc8d7e5a8ee223d60e67dfc1a04c38d1",9.917710196779964],[3786,"feb01b20d235bc6fcd31f2918831aea318ed6d388756193270034c5bee5d08e7",9.917710196779964],[15662,"7bae2552f40af7b2addc54f0b9f8a9f81c8774144b3ece39ed85232faded2370",9.317957166392093],[19441,"22f13c71cf2fdedd95b12b7a6ec72ffda2ca294e27e04555f8b2fa5c2d280f10",19.80295566502463],[10744,"45030087f0b645acc4b0ea7d4e92c9cf475e5fee54a6c098ffce4bcf4ac6b9b9",9.917710196779964],[1499,"1d7b64d053e20351ecb352b2035cde5e4eec74e6860ed75b1b123782a76a21f6",9.917710196779964],[4679,"5ef10d0206cb53c1af20c8c7ba6d323694f0929f4254dd59d4177c81c2251de1",9.917710196779964],[10706,"4a618febffa513fa01df2f067cf3646d3c6d65b104301972a29d9b363187f9b9",9.917710196779964],[13845,"baeffc980d3443151d05edbf98dd911f24b7bb4768b7749619001b8beacf7398",9.647446457990116],[6160,"06a0ad336eb245815a23b141380e15c00a501313cba9e61a9b886f4d58b116d8",9.317957166392093],[3577,"155314f609c74a00565b6abb63d5a6d6bfe5466eb804bb2df12afd382ae873e8",9.917710196779964],[15658,"13446d8397dd4fad6c43211a1e9d8d069bf1b45a175bb83e18e65b25bc692e70",9.317957166392093],[3808,"c007b408d75c6cac67cf92636d5bff11e497f211d977cec0100e033684cee7e6",9.917710196779964],[3995,"1d0d853799e1349a208e760433a8ddfbb43c5415ac73d023ada19305776cc3e5",9.917710196779964],[15065,"c65572d10a128c8ef8959661702acdb0a0e013fd8e94e02f1963dfacae244d7d",37.58222222222222],[19285,"68f45b6aeabc90652c65025f369f7232960b93dc333874946505695f87ce4415",10.052724077328646],[5110,"ca70e92d2f519137668fddcfeb2163ffd89474395340fe1f63085134ab0684de",9.917710196779964],[14248,"01f4b791d3875ad2cebffe06f8d2d1706d873d76edd7f3f755e0162b9954fc8e",25.40463458110517],[11927,"34fe3bf65bf5eb4117a0463c0ae908d6fe59d825c598f439eb96c61551ced8b1",9.917710196779964],[15265,"4344eaae8fdd3cbbf7097a0ec0a87e92b670d5c4aa672227ec842a1e3b181379",9.647446457990116],[11904,"1eeebb2c3f86def3a5f2ad449d66dc9ae7df2dfabd29aea77bd81ffd34b600b2",9.917710196779964],[1606,"10aad421af72bb603b1cefb00d6f74822668fee849222f9e02ec61445e6587f5",9.917710196779964],[18139,"d1371617fe92099e090fb7212a23dee274a978bc634c8fc7516561eb01e0ee39",28.376681614349774],[8387,"a35e4d5314a58f9386718fd51448abcda2cd8a7523297b7f28a5ad01ac76b5c8",9.917710196779964],[9153,"ac0559e57b5fe0447a5d6e871ecb60fc7b6210b396af41042ebb6b3885abccc3",9.917710196779964],[17180,"0860e58f56928ef32c6bd788938c063de8b3d1598812d109750de11d67893d4e",9.317957166392093],[6260,"a715aecee71250a25258306426db6fc1993dbea4518cdd79375fb61174a55ad7",9.917710196779964],[14140,"b31c1ef20e3ea95cd9b36018581c53dde9f9836c82b2aff30155f1ce7ef6af91",9.317957166392093],[6250,"2561a1944a5a2cb450970d5b31c4eefe443bd727d2491343c629e6880ba064d7",10.068649885583524],[16542,"c5257714cdcbf962daabe272215a947d0009917e0d634b3733ae44feae193e5c",9.317957166392093],[8048,"5950725f45cdbc4a80ee472a66e59feac0d3c77a247ad6615d1d95a1248d35cb",9.317957166392093],[2441,"736b0dc33593374d28ad338cbf4c49a53b9eb8ffaf2d92cf8c4cb80cb9c438f0",9.917710196779964],[4306,"8feb6e5b475f6b176398c4452111667c4e1242f6ee81c2127715091be992b5e3",9.917710196779964],[17017,"99ad9e13662fc027c7757ecca6afba240c1f23cc6f64b114f5e54781b395af51",35.883805374001454],[14590,"1148a1a1ab9d4b9d50ab66a3a811732c5d05866f198fdeb90a451f4020104f87",10.052724077328646],[10036,"bc1702eb4802ecdead44fbb6d70989923ab40fdb38d195e2bcb43f91649e19be",9.917710196779964],[6892,"d1f33a5ce3bad8eedc17103fd9649106c6e64650ce6b557bcc2721303ffba9d2",9.317957166392093],[8183,"7bcf13a4bf3336d4171c7d75ef02db2cbd148a885616f8cca33c28c65d9018ca",9.917710196779964],[8566,"af9355bfb9fa5fe58da926bc01dfc29e51fb0da411479c6607160587a44ca2c7",9.917710196779964],[2784,"8acc0a85a16dbd9e427328a87bfee9edbfd71cc05cd1bcf794a060ff22cbdbed",9.317957166392093],[6946,"89914bb63fca9284c4dc67fbb712e710918a75f0020a8caefa1c7d9bcd004cd2",9.317957166392093],[2988,"415c035cf10ce73b3e05b6e157e4d3d27e99ec3cf67c14f2730e8c868dcf5bec",9.917710196779964],[15892,"63964abf5ad5efb2c441cb570b3c875d1d5b49afc766038715ec20ec2df52d6b",9.317957166392093],[19303,"df0aea0d587631c9920a4127c52229ccbe3e0877e34e8ae7ce9ee9f3f300da14",9.317957166392093],[885,"87152489a44aa7a7fb117d38ffe3f9887c1444b5ba53b14f04204e7cafe7fff9",9.917710196779964],[16236,"77bb7cf1220e06429a421aab990e4ce9a22b6d344009a89ec658698d67c9ed62",9.317957166392093],[6194,"21e4a187c743c9406ff81fe47e7b8be36373b2eeedfda2d00a74ff0d316cd1d7",9.917710196779964],[14629,"31171449983e1ba654089bfcde8600e96caaf01a17f520d0e7b94795f2cb6f86",19.228318584070795],[18642,"28f60702ebc66df82d419281a5a660269dc0c55113526a462d53e77e52831e2d",15.003322259136212],[12744,"95f05361d0ec1d53c9c5659f2f253f42ac9b3a16b41833c95292ee5200bd45ac",37.99791449426486],[9236,"dc745f3e0af26c9ccc1480e094a9f7565a22fd2072c9c18b9e963c6c897633c3",9.917710196779964],[13303,"cfa2c65e1adccff985854da99456de4792654edf3bf92560a59c2d31b1e77ca4",9.317957166392093],[14090,"dc2c8f6586934efc239b60bd1d559c8d33269a583d94331895b2cfd6762cd392",9.317957166392093],[941,"d1632e59f92f43d7e603046194fc9a317767af2b79b5d6313831200ed3d68af9",9.917710196779964],[2443,"34f1b74acc38f528e028f16a70404f4aa548b52a80582602394ef934798636f0",9.917710196779964],[13070,"8964b4545fe5e141a6bd9342a0e506192c8e4d869e4bd5011ffaecd61a7a2daa",9.917710196779964],[1956,"d2dbb18aaf042be8e96d3b0c81e1319ee3b676d1b0f7d99683aaeba70c9d53f3",9.917710196779964],[15260,"332f76ee799893cef35193617c3f946b15fa19e081a7f1b71980384dc9553d79",9.317957166392093],[14006,"3bb575a5fa2539bfc6f5dd110d365941aa20966c9427d9dfa23d9918145ca394",9.317957166392093],[19249,"8d6452403406dc0dee7aa1f645c2299c003ab5ca387a68bcd062e0405abae516",9.317957166392093],[11116,"d7d96688f7e158c1a68070e22334627447433791d8c3cc661f7c67b2f96d26b7",25.967914438502675],[18708,"60a388cb6c48b2c6369add5c2c6129a704365ac73d3bd900ca28091c9e3afb29",9.317957166392093],[1012,"e73fa686a262a9580493ee0ebd4a8f7eb488f429974c1523dc888a4b869120f9",9.917710196779964],[16142,"cc372df07be4ea68033f67c427d2c41dab8cbe3fe2888916fa344f25b1203165",17.80415430267062],[8547,"b17fe3f71f7a1ff9642e0c71fa9b681e847f34afc47276a96b6a0941df64c1c7",9.917710196779964],[6338,"1dbd80dde4c7ea5108bf574d8b7b002300c7d05eed61b86d8c3d8770fcbcbdd6",9.317957166392093],[5465,"188abcfeb9ad387abbd9008f196e2924b84dec945a3d10faa1ae6b1a59346adc",9.917710196779964],[7704,"25405b9169754df3abb3320b9e06b1ad1da06bb21d6d17208efd4bb67d9082cd",9.917710196779964],[231,"c84cb82dc459ff3ac97e6201a40252605bf9cad0abea1a54415289ec55c972fe",9.917710196779964],[15976,"463b10501ff4f56601f5da29212ba365f32a1365e044adff02868d8511442769",9.317957166392093],[11312,"b5af24d4cf2a52e22ee81dc91791f6e722ca4d57a5671fbcf45709505228eab5",9.917710196779964],[9658,"f3125c5a05adc7327a0f316e4722694e0b1613cb3df1c0b8a89b05c13fafa6c0",9.917710196779964],[12227,"865cc8af64c876b84dbdea350cefc3212c344aecbd83e6ab23c26f469ac4e0af",9.917710196779964],[14142,"72be8562ae05b07d600bf5666a9258e642ecf209c1486439b7c63d7e6e7cae91",26.138053097345132],[9307,"8a67bb0af1b38641add26797d4802862af1a644cf75d60971b7fbe1424e2cdc2",9.917710196779964],[1701,"1aa9b843e92c2a6bc580dcb0b76206caddc880f47258d68da8b7617b0d02ecf4",9.317957166392093],[14202,"546d6ac5ecb3a0540d14a2e9b4ab923f99ba042ba378e6ed640909e917fe2890",36.948306595365416],[3060,"d798ca5243154baa428388f0286208e48bcbf8de0fc07af84a85147a4e9de7eb",9.317957166392093],[11169,"75f07377108790f41a1d5997c7af555e4e6e3215bb52f51de05c9acfd805e2b6",9.317957166392093],[9600,"be9341a328e8c9e6568b0099393bcf0459bb57861a4111552ccd0f55817b06c1",9.317957166392093],[11414,"9fee42ca6c31a6e192ea0f51bb10c6ba7f8b3ff08043bbb8ab8082e6a1ae41b5",9.917710196779964],[6580,"54446ffc4fb1ff3fdea3b327786ac7110c9f22043dcdbaabcbd5efff41bccbd4",9.317957166392093],[13077,"fb568252a0aa9e44e88d7a9758d0ad8d3a6433ed15537ef6d9b49c28170b03aa",9.317957166392093],[10857,"2fb3505fe663ed4056b9fe78e891be503d0567b90a7f7ead426ca113d19ce9b8",9.917710196779964],[18414,"ce736478ebcc06776abd4425caf1fad3ee076a33e040f96d3d292cd9f0b13533",9.317957166392093],[11160,"da1f5dca68a8bbb3a13a7faac1221e1c61fcf9182f87d5f4d645f92564dbebb6",9.917710196779964],[14312,"ad8cf97426e518cf744d6799c91f00632d4273a9101826b3885d69a94e7f528d",9.317957166392093],[8581,"8802588dae70850e47ec575cb9e349a1de5f560cfbc9e0e8470a4da4d9358ec7",9.917710196779964],[6439,"5a87d8a5b576b643c5a2de74162eaf37227280a40262caf24f0f7daa5e7ff9d5",9.317957166392093],[3542,"f88c428a0c03b1679082de99b2ee2be83e5313ddd9b161f5155bcea6f402aae8",9.317957166392093],[8124,"a750b235e5d4a4fde5e81fa0dce27db206b0927ce4b14ae841a799c1bf039aca",9.917710196779964],[6381,"b01c72c040d0f558ed77f7e2285397651013ba5029245b03b060d072bf0a71d6",9.917710196779964],[16042,"8bbf1747065813d8a514e90fdfc2f546e6b2728539ef8c9197cf0edab9d08867",9.317957166392093],[15715,"9f35e4a30ac2b7a71bf2797e78a150641727470610c9f0efac4fb3f80aca256f",9.317957166392093],[5803,"214de3c928e41770bf082a0422cbb7eecd9806f9f8c2dc6bc9e629b29de460da",9.917710196779964],[4103,"5a35f6f3a2ff8233aea06cb7731257603c1abfb8ae4e48da868e38226b4d0ee5",9.917710196779964],[144,"8123a3b4e778e954b77d2c4115fd36be9e538202c255e0711cc40906124f03ff",9.917710196779964],[6186,"f2f4947f0beac0458151fc2c75f658c6f4421ad5e120f754c07cb5f8d022e0d7",9.917710196779964],[2719,"faf770bf95734da416bbf48eb83efbd6db8e8aa2e391a073988b48aea4584dee",9.917710196779964],[4659,"2af443c3a7468a30076c0c611136f5262732848306713eb9bdd11e2397863be1",9.317957166392093],[4011,"b49e48654cf4c054ab474bfe61f83b2b537c62fe953690ec40d518e32f22ace5",9.917710196779964],[6321,"d575c5f441fa5666f7e156eb4906a7a3f46d64e6996c005ccd76df1ffa74dbd6",9.917710196779964],[17668,"46dcdc91e27b093fab4090f95a3606050f51acd9e560b3a7de40a8b038f8c243",9.317957166392093],[16508,"9b5f97594405175ef988c25adf63dcb65f6b52ee727cf72b710b86a36a51105d",9.317957166392093],[6496,"fde0558cf08e32732dee6a51d99e39c97c83af42945d540d123e04d2571684d5",9.917710196779964],[2944,"983e686418dfe7a9eb8fb6260d0102954c009c3e22b044bd5532ea81800db8ec",9.647446457990116],[11321,"bff77f65490f7902a55024e2080ba52ad22f392609014a1ac086384a7e5cdab5",9.917710196779964],[7170,"29e896cabadab099ea3aed23df7500908f369453630c3c1b3e875bada4a3e3d0",9.917710196779964],[10221,"ac2d76dc8e293ed09152dc3ff33dc6950864ac70482858059a4fe645181bd3bc",9.917710196779964],[17785,"6d254c09f66c7751b6bab5d0ea7acbe07637e5b8eb495b821679e58b77f29a41",9.317957166392093],[13637,"6724878232289fac2766047588787409d26436fabe853cdab04294a7eec28d9c",9.317957166392093],[15595,"aa36b646df8d67ba7b76a2c5cc75aa1c2ebfb44e8ae3f37ffbf6d225da227371",9.317957166392093],[4168,"2cfbc46ea98666dc623e0095669b7329a8b41c084135a59578ff90261217a5e4",9.917710196779964],[4828,"9c36abc8bb61ca217b0e6a16ff8a91d9d997f75e5c182f072654f7fcea593ee0",9.917710196779964],[17028,"360087d460ac0fd3e7feb354ac669ecf1426ab54622a000a48bb7aad611c6951",9.317957166392093],[18330,"6c363dbd16690fd2b5676655c229b5b362f2bb3a9cfc0d250b1b267b10214835",19.155807365439095],[10303,"6bf093ebe6e34ee5d789331371954ffe245c0739680eea5deabdb71bac7c57bc",9.917710196779964],[11004,"144e3864598ffe7ac6c21f9945c0ebcff21f99a268d22bd90242e2ef2a25f4b7",9.917710196779964],[2955,"22ccef10f5c846c1ffa6f1d865fe8987ed0b5555ffc7fe090555d360f8eb9aec",9.917710196779964],[3733,"3430364e74867090c1c87cfc0db0ee29e75987febf09a50d77d6a9f660f75ee7",9.917710196779964],[2226,"123f769c3baa58fba93ef6088512307b94901be0e77351bb3397ce463dc75df1",9.917710196779964],[10951,"77353a260f1b3b9275e4e25d8a5a203db89de42a46c6ea1d0c746bab9d7454b8",9.917710196779964],[4829,"8ef0f6cf91cf9215c4260e9b4121915253ed985216302b2664d7ee82aca13de0",9.917710196779964],[13031,"35e55f08e9a5d53b6036aec477424bb9968a2f98affd50a8e1af82c1e83a65aa",9.917710196779964],[8713,"17fe9833ebcbba7cd867f2f57f53ad011adb5d79343319aeb48ae9154db599c6",9.917710196779964],[14108,"0b94c2e2f3fba1e24d8965c828ddfba8e1cb4932d825f3cd8ea33d7538526492",9.317957166392093],[6982,"211f9ba2bf510731d4f847eb3f51148806ea02c67b250770b680ea920c0819d2",9.917710196779964],[16019,"8485724f54dd445f68af647938c6e0f121ba99b888ed0592f341732b80b90f68",14.199081163859113],[5697,"86db77ba6bca579c752b1d83495a0d17223b7d086adba522d8f741d1794411db",9.917710196779964],[5386,"7219c17c27ec39c9d25b33020e675ebf8e2a8aabc4b6f7e9140659a03e99e9dc",9.497326203208557],[12388,"2c9ce320da102780b429badac8ecd736dd1edceaa6a3ea7e9b253b42916bb6ae",9.917710196779964],[19824,"ab8a41aa644258ce9d7cef1f6ce19a17c9c9d938c8f197bfd6ff9244e2c2bf01",9.317957166392093],[10790,"752747e09d50f6f6c3e948dbe63b289c7a1abd902910085c2bbe0149f8e15ab9",9.317957166392093],[10412,"0241d140bce94bf629d0aed186fc43f2833e4f58bc9984f36a5a61033b49b7bb",9.917710196779964],[6384,"900e754a60dd6f52fbb6d8f34ec28947a34fb5b7acf0c2f5f7194fb0a2ae6bd6",9.917710196779964],[11612,"91bc7be9926b2546cdf16997324ca4aa5bf23385fc7a1a6d911363b0429dd2b3",9.917710196779964],[14782,"3c7437666d7dea540f46ba4b28699da653c950decf4114d31baf3c9c406e3583",9.317957166392093],[13027,"e40e10cc5cc4e231b71b9d1c2cfe1ec9044bfeda824195ca79f38be383f168aa",9.917710196779964],[4274,"230792610cbda5eb6ebd2f51f7bc3cee20bccfe52c6b674af187843dfe9eeee3",9.917710196779964],[4771,"57e5e99536e460625e5fd918569e335d4aa4fba799ad3d6235a89ee104268be0",9.917710196779964],[18582,"f4ebcae7019ce4c8f19bafe32a2bb4ebe902f0c047d4d38391d1c134a913562f",10.052724077328646],[2049,"3d948b3dc7eb3d97f087c7573c2b97764b611b14ed25fb7382c8fdd4f9cba0f2",9.917710196779964],[15457,"ac9e214c3c7dc910a6ac89dfa6642a90cc05c2c89817304a6e40a16a89b50975",9.317957166392093],[5745,"5adf4e56efcaeb36afea45059e98669349edb44cf888951abd183c7a24aecdda",9.917710196779964],[8193,"49d100d55f45d1c49658741766a88ef6d6b181302c8f0be313f4d9f08a2408ca",9.317957166392093],[6764,"0b73be2bf827627b58411ebbcc44bdcc6fbd9d20e169d6116d4402d11c5382d3",9.917710196779964],[17782,"e42600b521b42d0ddb5e7ac4209465ff312f7801163d83b2ae46f495e430b441",9.317957166392093],[3986,"e62021bcc9df5f19ea4ead0b3f58f662143141bf5f93edc609b049c4c4efcae5",9.917710196779964],[6832,"afede8553d186f69fb3666f193c7a06dc73480e0e4b3f460aaebae250eba0bd3",9.317957166392093],[7737,"d5d06f4f8d4d58f92e9a85d6155be5d6a4003ebd2da8165022ccdc472ded42cd",9.917710196779964],[8110,"7245c28f091f50466f3deb8b7b34263a659c913ddecb57ef3892ff59de6cb1ca",9.917710196779964],[11860,"9a37fc5b26bf564e319e6fb041d4b9430ad0541dc6ff6da7e4e6cc9c88a64eb2",10.052724077328646],[14858,"9cbdc73d50569ee2607da68c4a42d28cba893ccaafd61e9c84287da958c59e81",9.317957166392093],[4608,"532ed2976414383ce7dc86a41c3c6dbe4ef98b2ce5399c421f247808434f96e1",9.917710196779964],[15803,"ece5f265ebff4907910d435f6b7a4ce9cfb7b53f4dd975bda3b9375921154b6d",9.317957166392093],[14077,"7b81a0ad636639385625f988567b04719a8ef6656dd91a09eb02263db9e91593",28.09964412811388],[13377,"65d076980b093ad731ae5c98589f5c6fc04527e36d0d402a71f65f7a8f1fd6a2",9.317957166392093],[1888,"b983ca7fe09c6ce27a37188a5ee6f420017b5e6f00bab4367efbf483a827acf3",9.317957166392093],[14715,"a136ca52722cb9b27befe8d632f598f83bf8dd2107f8dea41e1a61301a999684",9.317957166392093],[1915,"c3ad87e6f14a682f555ad1e2208eac0892ac3903542cab5a1450cc5affed92f3",9.917710196779964],[6954,"bb0cea154e1d027067c77eaf314e83e8ce9dddacba098fb1008ab5049c3f3ed2",9.917710196779964],[18483,"c19b714a369c77498498abd2481ba0793abde4fe18e5769e82ad7efd6b33ca31",35.830388692579504],[6472,"4d9111759f9b058fc18fa8b56a3b7542a917214381459d0f113f3054e6eea7d5",9.917710196779964],[7681,"5e1752e2b6efbc8cca63dca8b7c4c613336a4ab632891ce64d52b25da160b2cd",9.917710196779964],[6174,"a8edf836d748a2a0cedc4f9c9ee77f3f2acfd48765ee3d398217ed9a6ea0f6d7",9.917710196779964],[17421,"8d237d116365547b539c94fdcd61fb8b327138f88b4a2fd8100997b254db6049",9.317957166392093],[9557,"192808f0d3ebd2bf687796dc9a7fef41e7671e7b66b1bc1afdd374cfe1c748c1",9.917710196779964],[11120,"7b212f9c932e1bcbd8910175e720d987493262a1aa0f1dd7cf0aa88a466323b7",9.317957166392093],[402,"88ac3b4baec33b9f1455ae4125203648e4ec93006de58ad7b9c44ae5903b53fd",9.917710196779964],[19864,"d531e9f0bc9293e30b5021f169c3e4fa0899611f8c3cd0e996359056f3c65e00",26.929503916449086],[14277,"172ad52b98bb38926147b27660b2c007e0c3a9eb39cca74dca68f8a6fe794b8e",9.317957166392093],[6007,"b8d89d6ef5e9b3c160f8e1f55a4f5a4983d1e4efc38cd9e3cda82b56197f08d9",9.647446457990116],[11092,"d29c8424fb072588986f681189a561a80919b56fa2c48d249838716574ae4bb7",9.917710196779964],[917,"55727b75c6fd8f54d3ab222e3835883fc69638de328fdad49b4f6d2069d0b5f9",9.917710196779964],[2850,"9a8cc72e00015aeeaade84ab05d8da2adccd076c89e52753f49acd04aa555eed",9.317957166392093],[12633,"9f0f71ed0d879d449e729bac72b5509867b9bc5bc863efb8c5a682a46fef0bad",9.917710196779964],[11368,"1e562fdbdbeadb0a79d20f32a71fb0231a2eb594d9ee5ff338681d86c3e093b5",9.917710196779964],[5941,"536669f42a36eebb0a9d4646af4f1709c643a7b5a623c5b66819df72b9f66ed9",9.917710196779964],[17334,"d7c39f215b899174f8dcee9718abc1ad9fbec777037f1ea5716b6f700bd7394b",9.317957166392093],[10310,"699c51b96fccf19fa7f732f11bbf4c4dd78d24ea8ecc56a7a88a5dde13974cbc",9.317957166392093],[4725,"8dbdc656d1804bbdc29278e46dc7d63b67593a71e3f7803d4661a9156200dee0",9.917710196779964],[16255,"baf9f67b426695f4f3bb3b64d17531b14cfbb246d6175d4a03f2a510153f3b62",9.317957166392093],[3168,"35f39b2dbd5cda614f803b6b6e749821832421cf30e7e90019ad06268c943eeb",9.317957166392093],[18270,"f9c1fac4be49d66764e0fce9b6db143b63be97cd1bbbfcda6f8eb7360ee07336",9.317957166392093],[19006,"cdc40e78c5cb4622a14f05a809967b35169577abdc7abebdf8301d196a6e5c20",15.073529411764707],[3000,"dbeb3c7b74dada09f442f13e2fba7b6f6707b037a832ce58f1f77568da1b47ec",9.917710196779964],[865,"8c7e816e2de84e04f6861575002d21de34001acce05885fb082e2d7545c91ffa",9.917710196779964],[11733,"db674e51f26adbdde25e58b3475879d2d469ebde09a6b2a0d029d48a175a16b3",9.917710196779964],[16235,"548e87ea9eb725aa9e58a3b661bafaed6732a4b3c1fac800c08ccfd139f1ed62",9.317957166392093],[16603,"92ccd0a6a3eacc97ccd3366ec4aed15948238ba0508ccb16cc992e11d7f8c85a",16.17081850533808],[9496,"feacf2481ac05cc7e2ab29c07cfefeff079f9ab8c173431870ce029a0225b5c1",9.917710196779964],[5689,"4f60c29a956924a92cfb9324f80dd902bc08b90d0860b9986cf8e31db0371adb",9.317957166392093],[6793,"9e92d879bf8397627ecd9996316c46646b9ba708118e3a30c719650d7cb456d3",9.917710196779964],[4708,"23083c54cb97d3553720309042b795abc53d7272d157365a6baf51ebaab8f6e0",9.917710196779964],[15225,"39941de6e2e66583bc83cb74e1dd0ddbb1b71191a2ba2adf98fff844ad1bfc79",9.317957166392093],[7136,"c1937282aa9de49ad966d97223a9773a0d9599908eb3532929751fe403201bd1",9.317957166392093],[6153,"a21cd6ca6d0e337f7700565c967b429bc668ab8f15e0a8ffbe5f63d1e62922d8",9.917710196779964],[17243,"93891e333ecdf08fb6f4ee6d1077613ba17d6975d854e344b05c5ab3844f104d",9.317957166392093],[5529,"b87ac79393a29c9d5b4e88a6249e8852a10d4fd0e9d504006e602197c1950bdc",9.317957166392093],[2736,"6b32f10c70d883cbb68c4dd28031f1688cdc2332362b6b15ad8a8db1565530ee",9.317957166392093],[12081,"de15d81bb3fc5a16e9d0000a64ebd15bf9fe8c85734ee08a7579ddd24eb8d3b0",35.830388692579504],[3659,"0468e3046aa8745e3157f4b2fd953239ff2da9a7905bd2171c0d3c2ced72e0e7",9.317957166392093],[4423,"c26124ff0773aa93615ea176339176cbb2eca7ceafdec403e35f603658e4f0e2",9.317957166392093],[5081,"fde679dd1a4369f1c079ae8b1ef76b81ec1b07ee02fe2a80990d9a792a91adde",9.917710196779964],[8892,"d107d272cf051e81634a913dad3432092a236b0fc76a6f1a721649eb0cd078c5",9.917710196779964],[8453,"788385af53e48f07cf93b6a6aaabf7c0cbf13c67e05dd0a7026e5dbc17dd4ec8",9.917710196779964],[15519,"d99a793a14013c40f214453bec0f8f479447f00fa8136425fdc2238470e79873",9.317957166392093],[18738,"55d3b8c33dddcb3e84b1b7fa6d90a92ba33486b4fbb9234bf8a2231863cb1e29",9.317957166392093],[15015,"7543888485b15af7527be610a1f82f8e27172cc821ea0d3d9b795a15a2d70d7e",10.052724077328646],[2109,"272644ae26b92e5b1acfc969cd3f39cfb99311ac3f8e18c9e7f4f5c32ba82af2",9.917710196779964],[8284,"eea97dd893843a216441c369e75b4e6b6ac8ffd67447cd0634af5851672c6ec9",9.917710196779964],[11893,"4273c064805cfe0be0380b8e9ee42d16817ee98efef2ef69d514b24b645e11b2",25],[18961,"fca19c07a4f6f501cb2065ffa47819371d6df7b142d81010427891c190b4bd21",25],[480,"26868bceeed7890714b40147cabd62d2ab8eda30c596c581470db8ebd556c6fc",9.917710196779964],[4145,"75da11045d53c3b00920bcdebe891a1fa72a763d8a7c545333a320f46becc2e4",9.917710196779964],[10212,"2ca158583890ad9b729d2a14f085de11b37c94407201392443d5731b05e4e5bc",9.917710196779964],[2634,"b5b94b8c24e94c8f28f0f9396f24aba5da729850af6203e74650c7dd857ff3ee",9.317957166392093],[16370,"01e37c39d09f5a0530e9531dae8d2455488e56945746a8e6acd2a3d92202a35f",10.029773988361077],[9829,"3ca975b00ae6145db4672a1061d0b877249dad0f92ee93b51b8262f207796dbf",9.917710196779964],[13041,"da349d30f2ab5ca9210c29250ab04f2cf65a6fdf8a2aaf21050a59f3e3cc4daa",9.917710196779964],[1127,"818b6c97b23e7cc4ca94e03b6338c9c8dd1e29b52ac167c30d885f20bd986bf8",9.917710196779964],[14788,"d61a3ec8e874879fd130a8cea884e15a5c58bf74c70ff22ae40d45ad00112783",9.317957166392093],[4328,"e99b2214de0bbfbc0b654e22fa641fb368024e93e0d555dc0f582be6ccae96e3",9.317957166392093],[2691,"07a21b269d8a37226dc1a99d11e6353690c34e3014a3d8e328144cc0025487ee",9.917710196779964],[14702,"5e5bc633a5bf663e36bcab65e1ba4a092f74759b5027df70004cfe2b5a92d284",9.38219895287958],[1038,"c3e404a1bbad270cd4cdf23f09a449510e93ec707eff5e267145e2c72bed0bf9",9.917710196779964],[18094,"6268ca1e0f7a3485ef3da074daebdafd907be746a0cc687d4b04215b7df7113b",26.138053097345132],[7958,"8f74ca1200596dd25620bb92b6d65fe328c92c3a1dc5e220feaae9897409dacb",9.917710196779964],[2888,"8984bc8d88d8a9d6da457d390849f5db446c44f0324d8fbba33fabe2718433ed",9.317957166392093],[3634,"5a0822459cb525fd24b81050132a8e11fe0fd81b6f552bce246d8777cf7307e8",9.917710196779964],[12957,"37878493bf50f5b04b4bb6a1b1b11e2cd14dd868f5d55bd4ad89a6d27160d9aa",9.317957166392093],[17419,"0c85b0a153f9b052ba54088966fd49612851c2a5c45b83c1fdc660e82c386849",10.052724077328646],[1684,"a9e964c1a68589629527fc32ff1cbd1582f628f640273696650276c2fe4005f5",9.917710196779964],[1182,"36260c874bb99bff33257ca0d0fe20d8b9c3375112b1b4c9e0fb74ff54ff1ff8",9.317957166392093],[6033,"b8bae11e61f15bbcf77820212bf657e3814a11f2a7529f48d9c27005c361dad8",9.917710196779964],[3438,"bb019f57b8580a7933ddd7bdac334403cf6c928d9eb9675bd9e92fb6aab370e9",9.917710196779964],[7116,"13b51b461c38611e43568e8c5e2d878ad3accf59675d576e2dd37327790141d1",9.917710196779964],[15067,"0974e535df12cbb1f58f2cf54a6ba461995e1014692821fe7b9f353b2d06427d",9.317957166392093],[15240,"ab2e4cab0d695cccc082f4ed9399700f5105b6590990889548ce0985b93aa379",9.317957166392093],[18140,"2e28057d1841c40a3cd45e5d936f3751ab796863056e60bf768e6a8d7650e739",9.317957166392093],[4847,"fcca149f4255bef36f8ac009d65cf58ac4accf8f4d639cbb7da2594bb47629e0",9.917710196779964],[11933,"649794b45790f55334384e585181f6693eaf9affd0e1c47409b5ea01e8e7cab1",9.917710196779964],[15572,"9fe23167038c9b659b8b1fc3ee837b357d7767afa47f3e06fd807a4206463772",9.317957166392093],[4514,"9a117afc102764377c203212e69f8d59dc3f30ec83ab49d15f11aa6e2da845e2",9.917710196779964],[10468,"6b2b9c556da8da450ec20d110804e3cd308d5e029fe64079bcdcf762205c52bb",9.917710196779964],[8828,"133ca6e4e6ec59ed7b69e9ba74877090ecead1bf9684cff59f30e41b6893ecc5",9.917710196779964],[8306,"2e3cd1b812571077930e53443730347cafab0046e5312d9c54962729cbf948c9",9.317957166392093],[6733,"9baafe0eb16b7e2daf596ecdd5f7acd5d4a01a6beaa8be8572a4edc75793b7d3",9.917710196779964],[1257,"66a269f616ce45ea820923e39e4f1d84bae97882d04c7eae9d25466cfcf49bf7",9.917710196779964],[4179,"f7389973fa7ba5e1f656031627b4a01e7d002f759f5225e77ecfae649ddb91e4",9.917710196779964],[13100,"449922755d01697dc8a982e2522b8c25fb891aa92e3ea6b0ec9ed83261cb43a9",9.317957166392093],[8808,"12eb152d2a5c81d5486e8d63c13c715ce706a83579ffb121cfce6fdf584608c6",9.917710196779964],[12877,"8b184c3eee3520c3208e5c2c5a995070e433048720d8bf424fd16101810c6aab",9.917710196779964],[7106,"48ebeee86312e935c72e5317195b3eb9d9301a60a0bbf7d1ef2fa7e13eb94bd1",9.917710196779964],[561,"231bb5519d5d6bc0c3d3d090a3ebcd01da6396d071f33a80a461a256b84732fc",9.917710196779964],[15127,"f3d71463af4f76c0ddb14c9710e7f31e0385e16e77bfcf0a8500bcba45c9277c",9.317957166392093],[13823,"2586a90634cfba28d48acbf5dbb67b49a2f84eb9af236fc6a90f92f04ceaef98",34.83420593368238],[960,"b266cb9670e7848b05bc523197fe8db13dc4e30ada4585385f976573911371f9",9.917710196779964],[9437,"a82ee7b7d25fec39ec2a8c0d109d8ce0803256e1eb10c7a40f99a051a24719c2",9.317957166392093],[13880,"ee75ba171ae8c4ea5a1628927f00093b97046d8e8c06a4eb27bbe9f1a22d9c97",9.317957166392093],[44,"bb644f821705fdff3fcd782a590cf5543b0a67755ec16832693e60d6700bbbff",9.917710196779964],[11457,"7abcfef5482641e4d258be9c5fa64f36aa1b78cb4202150d4edb1094a24edfb4",9.917710196779964],[762,"ccb21606015f4863b5faa6756666dde0b0256a425a3e82b268a10cd066accdfa",9.917710196779964],[11281,"a744595b12a1caf04b0aef909f69457cc2fbe1b3c5319e502227a23f96452bb6",39.824858757062145],[15190,"971054dbb071b18fd078af7ef808d82321f4ba6fdb19c8f84f09a5c38310b87a",9.317957166392093],[6556,"6851cc9c4ad402160139e4675cd652766d5bda05bd9181b174790b3ce59ffbd4",9.917710196779964],[12464,"78d192241c8731eee7a3e5f2fa59fce8e7a05c8a8c05a9511f9bb719ae5236ae",9.917710196779964],[9690,"92d9319e29dfcb08468b0c271b4575e607bab8f9ca070914b2f25fc2373476c0",9.317957166392093],[16577,"f6c8c0eea0ab1d688a0f3e85372913fcd18c0833754d5c8217ad288a7c5a925b",9.317957166392093],[16909,"6152c5e9b1bf6f957a6c21dcf3ebe634e05265e73aad7d302d622bf54d16e753",9.317957166392093],[4963,"2e516bb673c338de130f1ce0585682199263f7b0a548619f2031e302e0ec77df",9.917710196779964],[9450,"1f4ac250433f85dfdb52663d99ff1e581400216119cf9ce7d901478b699203c2",9.917710196779964],[11348,"165443920cb310e0c12763201f5bc97bde1a4bfbd789cb9fdfab0876db94aeb5",9.317957166392093],[5462,"893a852e273defc9143975bd223d59177877093402b40977266a31b7c0af6bdc",9.317957166392093],[11677,"968f453b8c8922a6ea9b9618907a7bba1de5e9b1d5b18e431e9a530c645572b3",9.317957166392093],[9065,"02af0e2f236350007f06e8e48080640e35728a64566b8a50062e078bb9135ec4",9.317957166392093],[1158,"012d8d918de6c57af0188fd9d91f132dbdcf6b22d852a182e9f91e65278342f8",9.917710196779964],[5887,"cd20d1aace5242b669ed7af8dc6ce52b1eca83c4ca4f0a62dd51458f2bf5c0d9",18.730713245997087],[4935,"e5a70e0e0d50065bb3d25f42cfce1a38f8a3d9fcf799a8a06f8f30fe0c569cdf",9.917710196779964],[3924,"826c86cec0c60ef5cb2315be4776f88f51c0de731647fa7299832ace002a30e6",9.917710196779964],[15741,"39c263c5316779cbdec6d0aadf5d7df9b9c7ac2bd08013764a2d6a024672936e",9.317957166392093],[11460,"10297d1d9fb3bc0fac36d44f110c9bc4b8b9e2c5a0e13accd0ecd4e8b8d1dbb4",9.917710196779964],[11193,"5fc8f9302204eb1d12da89d87103d2d65cc3df6f87c36095aa184d5e7d66b5b6",9.917710196779964],[3658,"c7207485323005bd961a264d05f17b6ea57dba4bfa51466d46f8f38ec96fe1e7",9.317957166392093],[5881,"603d325b62c195999f9e91ae7d4c089b578ab71bda564c4281803e73ad37ccd9",9.917710196779964],[2132,"086d7566c91811f005aef46d060cef641926f4a258f2d8c50c3fb1b61a5308f2",9.917710196779964],[5504,"5179c8a9d1b9eb87236c19d490e34a34a625b13f03335d2a75e957edd5e230dc",9.917710196779964],[5813,"e8c4869aaf2123d399318390cd18425132e4c0487da0f148e9ba6efd89794fda",9.317957166392093],[19209,"d95dc15224cbfc88a0ec80715bb0003ad31e8815ad8bf8f7336fa8b04fbb7418",9.317957166392093],[15967,"e36bbead198689f89dff5ab4c34b8894c8faa5cede9171a04541484ba9ac7169",9.647446457990116],[7024,"74b5160ab5ac78ae27f4a01d454f7cb2ea9dfcf69176bbe6555474780147dcd1",9.917710196779964],[19512,"b8be3892923b7ff180e59679c0e9a2655c9993f05185d712477528d554c0ef0d",9.317957166392093],[11156,"01db347b0905f5c26747653e598fabbe5fc104b59942e7a21e15d81f54b7eeb6",9.917710196779964],[32,"1c01e451a3d3b549b03b09b41353ee2cb6dc6c768f8869cbaf60bb2f5f0fd5ff",9.917710196779964],[7508,"a952b123ecd491fca5b7c0fe4c8a1e073e6c9480ddc69242dfe60bf08ea9b5ce",9.647446457990116],[19182,"d83d58b8f58d35fd0853b889285731ba7af6467d9ba73af90a4d4010cbd03b19",9.317957166392093],[7402,"f43b660d46018497b444c4b8cd0b3e1bd93f37682dbe514d79ddfad486396acf",9.917710196779964],[9631,"a10cc4c286c64d747a0c131b522c23690b36e7adbc81c45f8413af030eebd8c0",9.917710196779964],[14838,"bf47e3385b33c35b44222640c469d99317c9fe55a545b41fc4c80591977b2f82",10.052724077328646],[18928,"3d5875ac9910eb8e58acf07a02a6319602c9d567a9a44bd6f87b2ab382539b22",9.317957166392093],[11206,"e0f67ff415940b4402912f96d400b165004ac9beff8a0a9d2502ee93438ca4b6",9.917710196779964],[19094,"222914edb48938e10338f69e92aa6e386a0801e502dd141634db482f821eef1c",25.13368983957219],[6283,"cdbff04f6fbc934338aa02efeee7a0c134040821a299f0bdeb70fb93386f2ed7",9.317957166392093],[8396,"1707b994b5bf2627eb275b95ecbf5b4888353f62e47b4e24d7b06af2c5b49cc8",9.317957166392093],[17683,"1364f22578c77e5b777152b673f2d826068a8550de79476bdaeb19efc1747d43",27.86761229314421],[17944,"7d95c08bb5e554cf7755c323076397ae554c82b4f33e6267e48480609b3d553e",9.317957166392093],[19627,"5134f70bc3c03d762479d14d610867546cda15faaaeb5e43e6009001b97d8508",9.317957166392093],[6142,"d2bf3ce9ec8564110ff93b7e8ec1a5d5e4185c71a65e41fc86b678cf5e5835d8",9.317957166392093],[248,"f2597aa44c801f6755acbaf0acbb190f9a73082e04ce335215229ef77b0850fe",9.917710196779964],[12040,"496589830002ac4e346eaeaad2308c38aefe70ca6b692ca8d93034fdce2a0db1",9.317957166392093],[211,"5f5450fb7f44e2e04681d6000a25eec0f32e2dbbf2af25b357cc27e32ab68efe",9.317957166392093],[17259,"877bb4850602421191f1545bdfe4c61e46878b31a59fb1a89d9cbcca5e60eb4c",9.317957166392093],[6792,"7e436d98ac1f0863a37bcb2222fa3ca1fe2386e906e005144d05796a0e7d58d3",9.917710196779964],[3816,"9092f4c4052d9d5f1b9aec4aa3027e5c66371a445091458e5876e17440a3dee6",29.189448441247002],[7695,"e3ae895dc3a367531485c7ec29db68ff3a3e5b51826da61f36b33ace9bc294cd",9.317957166392093],[15478,"32be5f054c66fbf0a23632b312720d06c843593f640d427c1502acc4ad558674",9.317957166392093],[3606,"8f4c0cd85f6eb7c9d45493e4f07dc27b4f0658ef44c4d1a9a71c9e82953d2ee8",9.917710196779964],[4462,"3ecf660a477cd1976a86000f1c27aadadcbf7427d06d6c86f6f415413d4fa6e2",9.917710196779964],[9368,"b01b38b21fa695dc58aa457e20e478c00e1b2c2cbb7ef5837109f77456b36ac2",9.647446457990116],[13854,"10003166365ef7e321c9ae6816f76c087f8dd0ad69078d60c0657c7ff0cb4d98",9.317957166392093],[1989,"d54243c8afc81f66b804c5bbf55184908caf2116971a4c2d6de4c218416d11f3",9.917710196779964],[11327,"f0fb5e562c42c501f9b4a6db4ac0bcc73c9b4618aa3b6c6e0d3fa4251ac3d2b5",9.917710196779964],[3440,"70297d93638137741b49ecfde297248157d9624d3946996fb1f2f812aa196ee9",9.917710196779964],[1727,"fadc75ad5d6fa79ba802b735953d4c6b977c38bf64ed717e30aca80552b5bff4",9.917710196779964],[12234,"6ecca189a47c4e73127c2c89582e740e530b81a14328143a8451f1675f94caaf",9.917710196779964],[11668,"f3ca42189fa805827c2ac6dbd9d61a75beed974ad352fdbc025fba2e85de78b3",9.917710196779964],[1958,"beff3f0358a6305b13a59c8b2370b6004f7eadbe2bf8a6c9bb26b19396104df3",9.317957166392093],[7214,"1995bf82b173706771be22490fe59ad3d3ceeea1a1a1f98e402a88f905bc99d0",9.917710196779964],[4165,"f31dee5be9c244884076e7cedeced4498eb21537e834cd71fc84248dac31a7e4",9.917710196779964],[13825,"a3bd8aa38d864b1bee2b0332307a0d69fdc67c65329a615174f0b57a47c5ea98",9.317957166392093],[2910,"1374e1a885605713f3ba1cc7fd937068af4aae56ca7a3413bf89e2379f170aed",9.917710196779964],[9184,"8ff47f4f1b3c0030e493c0bc7eef8d903f8c9ee39e53166d9e876d2e9e2a98c3",25],[18547,"c16f1ea9e3a811259602d1314aabff768cd4d5a9c9b9ff2e4656a6ae96a28830",9.317957166392093],[7385,"842c34b81f609bf3acbf2b0c1dc563d94d6bec1bc124a885e6411b44e85782cf",9.917710196779964],[4929,"4f92a9bd03c4e65c90294a7ad7c44f68070582271d150518db785c1623c0a9df",9.917710196779964],[5001,"2e3535180a185214c9c0eeb7a632b6096332de92084800c06174a065fb0f2cdf",9.647446457990116],[16371,"845df5a612507b921203bd917bd0b24966f03b4f3d430a9b3824083e9b76a05f",15.079646017699115],[13928,"b89b7cd6faba1ad83313e953146b98241996e7774247c3452ae8879341ec5c96",10.052724077328646],[11900,"7cd58ddba6ce6a9b2271f65bb95663cd07f9643c38531ee1078716b1b2100ab2",9.317957166392093],[2154,"228f78d37531a19ce31ab9cfeda8334d7572dd68f663cc2e8b235e88b340e0f1",9.317957166392093],[14286,"44e5edf2bce151989b11e13f62f1decdf656e408762e795f312d998eb93efa8d",9.317957166392093],[1203,"e20ca2a797ef3900393551a9d9e958f59eca72d80bb381d52817749796fd00f8",9.917710196779964],[17136,"7dcdf91051a9ac3cc15603c92292a45cea9ff52ea58a80897d9250d3b0f9574f",9.317957166392093],[10455,"7fbfd56755f44734243fd4bd9fe7dc1afe6c47f8ec38601d712f545051b664bb",9.917710196779964],[14756,"b4bc1e8a96bad158e1eeecfc2853bea08ca3c545d97666ae5b377d959eeec883",25.1811697574893],[16283,"1f0c542c4763592a9eb7438f5322b8d1483f97427ab91f8c0ef09a71fdd69261",32.726003490401396],[5212,"8ebcf27a370bced6606a7e54149828eaa46ffbf79c11ab08aa3463589b25eadd",9.647446457990116],[672,"2adeb461433e01d6d0f0f0ed33b1489efa16fb73421ccc7f0adcba9e4b236cfb",9.917710196779964],[14338,"c503da2f4a9b27d4386bf7dc812de5edf08d5fc3ff24619317ace6a60e748e8c",9.317957166392093],[11936,"9be56fd7cb068ec62772173de0ae9e9f43ea13058eae0e240e3ac7b5acc8c1b1",9.917710196779964],[16630,"9f330ac539e52ac57b2b492052dd9b47b317a395bcaa191254b9374626682a5a",9.317957166392093],[11360,"0cadfb8d047fe8ce5b3043060a661a8e7e77460b0e796b0bff3de1ba37f49bb5",9.917710196779964],[6276,"aec703289ca50bf03cbb6bbfb81f256832413eb8b9974aa376c5cbcfbed03dd7",9.317957166392093],[18100,"b13835bfda33445e258a82a9f5cdef3f9dae5b0b0c5d48e963e29ad3b9c4e83a",9.317957166392093],[7441,"4206b085e87df6bb33799d9e8a228add92f0f8c9f2584568fb3eb9d0b5c121cf",9.317957166392093],[15285,"03909f3132736b3b4def39aef223adbe36da539f5cbd1e4f8cc1ea827790a778",19.20142602495544],[6448,"323de14fa9ae412af986baa181071b0daff91acc46de96f3c642c4baa845e9d5",9.317957166392093],[8049,"018e51e66ebea58ffc6e3d8eb7a1fc5b52414455ea3e3133ed43b97d2f702ecb",25.614035087719298],[2825,"1df525ac14f96195ad2e680c5606a8fdc52aa782de518a56b24178fea70187ed",9.917710196779964],[15150,"e23fe256f4fe3b70c720e1a440cc4f0d86916a418100381de5f054dd0b77897b",14],[17184,"e753411c669d474a27da7b8c8e9e4c97392b70e2b80728d41fd1166e8014294e",9.317957166392093],[1549,"582712df480dbb3b0e15768a7400a2221f0ad33267593aa774ca659f3776d6f5",9.317957166392093],[7548,"d825f2a149100ca3c390eb4ba22ec004f4a69aea4d6ee54ef0cd30a56c138ace",9.917710196779964],[3895,"4e4d814b6cd73d23f1193fcd5244cc1fa90aae6895815cebe0a8e7b4c17363e6",9.917710196779964],[5434,"91b16ae61fa2d9defcd0817bcf9a16e959b8be69b8b998b581acd7d05a9892dc",9.917710196779964],[12902,"b1d242d1605e42a9eeefcc7ff172b340c00f01364b492653d95797004c2b4dab",9.917710196779964],[17451,"50b437a6ff1cfc05576526716e7d72617abf97d8fd99d9f0212c843ed498aa48",10.033508207818581],[7853,"fbabc6dde1c4cadb712bc304712244454c499df50c1f3dea1a8e84687f8f7ecc",9.917710196779964],[13919,"ff53b34b8843b30e906f32631480816fecbc634fe527964c3fbc90b27cd68996",9.317957166392093],[17686,"1c3d3d90febeb444d00529e6d43e8cb8f33cc7adade1d3af9b5aee8b2bca7243",9.317957166392093],[2279,"ca35eac4fc76b69c4cce3dfed9458c51ba9d6a4e724998fe600b361d52c61bf1",9.917710196779964],[11187,"ea01a7cc7706329208d22468711d5712c9d682f656ae5d139971f7a4564bc4b6",9.917710196779964],[8996,"2f439b2b9e62909e3a4c63e7ef6a10e924d151437ec7fe159589c88d1b2ecfc4",9.917710196779964],[3835,"1d178a3e8ea993f21ff3ba04371f6deecfa7c2cbec3275f446bddbcfb5c7cde6",9.917710196779964],[15357,"2ed7dae8511f8d282f1bdbd5b1528d45c6bacb6d456d1bfb2647621d19a94077",9.317957166392093],[14650,"ae821ef178e0d364a570d4efd9f3154e4d720139bdf9c470c1dbde005740e385",9.317957166392093],[3421,"84e3f9fb77c0512011df78a4f0932cdd74d49ffb68a595454b3c55027c9285e9",9.317957166392093],[8753,"99ae4fe3a99e9e11625a6988f52fdba61eb1df8683a97adc083c11acf64f58c6",9.917710196779964],[7931,"09640524a5f4137fa28a40430e08a9711daccc3d0780ac156dfb2ce9ae8d06cc",9.917710196779964],[1066,"10b0ef8c3a7ba46373486ad66abc09fc82df1b41a554afbc2ce3c4646cb6d2f8",9.917710196779964],[13605,"43a94fea2f01c16fdfe8aebc3bc51d30bf4370fe9ca134b24ff7e9bb6d10559d",20.102564102564102],[13882,"d1e4e1da90eadd2c8359bca756f82d20fccab427a1baacdad9a03b7ba3a17e97",9.647446457990116],[12207,"2c2b1b7cb59ca29b91ee749a48c07da0ccc6b129e122db60ec74b13cdd9109b0",9.317957166392093],[10894,"43aa328a0fb1d81c6bc97c980092fcdc65b8679214e859f0e7a3bd197e56b5b8",9.917710196779964],[19293,"d808cdf803ca05b99c8e3260784878ae529182e1a5117ef6f0adf22e83b80715",9.317957166392093],[7602,"bdba70a88c484fa355ee5a8c0ebe7e68d1759f15e2c8137d268078e4b1632cce",9.917710196779964],[14876,"4f5f490d1d8bd285c5e0f06f22c311cc8be21b638479fb0d71fed944ef7d4581",9.317957166392093],[15203,"824f4da1b868d9f411a5d4bc545e14d810b3c169983e842603519d9e80f4747a",9.317957166392093],[2869,"3882d9fd9770ce9eddc839f3378ca6d0b0e940e7f4fc117e3b71cbe819c64bed",9.317957166392093],[17699,"3f67d01bc538ebb249f81cc57e4f75cabb5d6b3c07ab7921a7e7a8ab700f3343",9.317957166392093],[18372,"c5fe5723967d3a30411ae7a8491d553d25d54603a98eb28887e4ea170b534234",16.06476592749032],[1673,"4804e6ac600172b3c37d15dff172cbe43849df4cd29cdeccc61a89c8e04c1af5",9.917710196779964],[15200,"76fddc5c086ad84d4cbe387af3daaa2c84df1c42f337afd5e15a122498cc847a",9.368983957219251],[11124,"56f69a2d3067da75e3624130264e363a9870ad5f7534855ae61226c53b1320b7",9.917710196779964],[6164,"ba3635b53b0884c56f5db47a11da229a1164fe3c748148d26eccd366d1e70fd8",9.917710196779964],[17836,"092bdbdcd2af6c80d983565a09f0e5c584ddcac95644f6840cd678ca4c7b8b40",16.07111111111111],[8919,"1c7d29b9684fe67313e1cced0a64150a1e673ba480ea90f9730846663c355ac5",9.917710196779964],[673,"c2102b540a5b9cc6ea6ba865c6bd1b0dccf5f753234e2825017f71909afb66fb",9.917710196779964],[19473,"f62e678c2ded74b187885c8d5490984c98c7b07c9cda4f1d99cfdaba0d25590f",33.7674177097821],[2001,"7c96dbc344bb307acfef0b765ecd281b049b47635643de369064c3681dfd05f3",9.317957166392093],[5392,"e5dcfea833465649d460825284c7643a921b7308005805789a451a53fe53e1dc",9.317957166392093],[17879,"74222d63f21c86acef776eaf19e88ce50611b3b7f5bf81536e0909af3ae0b23f",10.052724077328646],[4990,"7a9ff6a578ba32f928302efca0a5df41600c70f4a890863ff9d67d2536ed3edf",9.317957166392093],[13043,"0e25d55502d9b4f43d16c9374ed4d61000176cf4bfd8a6ea03d0399816024caa",9.317957166392093],[3299,"68a104c33871acae2c9809807fc372c846864fa66100ce2fdf762983e11367ea",9.917710196779964],[7363,"27c4ef4d2c1fb977b20d4f29d960986d9fbc3f38883c41800f91fc65788da4cf",9.917710196779964],[8340,"6a35c8ac69e8cbe5f7acd2252095d48adf3c35f93362f04b4de23ccd2ef511c9",9.917710196779964],[12828,"258f4501268f1e1a93ec0fe0db9ffb981a40c14b1921b1716e39b2f39473c3ab",9.917710196779964],[3478,"529d1b26b50d9440d491eb7afe954ad00956c5d2895a7397576f6b552b6a30e9",9.317957166392093],[5536,"facd1ba877fb337fe7e67c72c56ee525241ab430c334006490ad9d5bf048ffdb",15.0873440285205],[4397,"15e04a67074e7f271389a489efcbc0c21bae43ee81905cd49e79567b9cdf19e3",9.917710196779964],[12841,"dc28c85185dfc4beb9a79b585e7292909c491f23fbfbe8b08e2526defdecaaab",9.917710196779964],[11080,"0a4f9ac8d8a9c39ec01f09a048ed2e13efbdc9aa105813e1f21dcd8b1bb365b7",9.917710196779964],[15667,"d2f41f3087591ef4e45be4323e35e25eac79f0c1ca4f3c39419f9a8d92181270",9.317957166392093],[12043,"41b3b78ba9c7423b5a2ab282675e166aacd2e2844171b665c97999e4ae2c08b1",9.917710196779964],[17553,"271dffab7f37c710bccfc9187f0161aa76384240063b2afb2fe77b6d0b7d6446",9.317957166392093],[11909,"5b6f6542293934d80d1cb364de42d7a4ea578117c57f3731f515698ed565f5b1",9.917710196779964],[14359,"78693ab41ba3dbc880a9156f15b79230946d50c80250650854a09cf3bee03d8c",9.317957166392093],[5827,"138eb99fd875baf9f5c51f18a6d45623b6896dc5bf51ffc9052ea77812832cda",9.917710196779964],[14487,"576bc76237c9e88a3327340cc5635c80cc015832240c5d434fbb257599a07c89",9.647446457990116],[1846,"0e58acadde88e27202e79c975b1e5e733284457108f82e0dd00259328d1ff1f3",9.317957166392093],[3828,"287754278cddba8d47d89a299af36360b8dbfe58c1c5a5d8cbc6e3d807e4d6e6",9.917710196779964],[1699,"c1717ac8784f870b4e1a896748bf3bfabd705beb3fcedd651d7bc3d3d645eef4",9.917710196779964],[16225,"de465d7abb898142244c29c52851f429c0cd5d3e7e3ea57210e22ca16f733363",9.317957166392093],[7184,"3338d6a940028cb32d09a4e2d119005fb1754f60121bb4579b6c62766d8eccd0",9.317957166392093],[17847,"a5310ddedc24662045bd61ef2292dcf212734aefb77fdde0b27d4c0bfe354240",10.052724077328646],[12180,"77df412c2ce45a2ff01f98a5577a061f4fb5aa79a6d2474b094dc6dc1cdc33b0",9.917710196779964],[13635,"7c67d3d24bc756d754ebdd8dd4c6d918254f06f695aae291045ea2b90644979c",9.317957166392093],[8319,"8f8fbfd292f59619463d66ba62ac29c597901a88d21c20e5b8b33332ae9f37c9",9.917710196779964],[3422,"8985c46d438ebd8b25400b1ac3782be1bca3bed09822427a046e6df2253b84e9",9.917710196779964],[1883,"31835be091a5d6de6597018cc5a02502c062cdbc8269507c3198bece22c0baf3",9.917710196779964],[4478,"685d53dc7ad945093629fa2a8cc3f7a40a8523000ce02a3496a60ff132308be2",9.917710196779964],[13510,"7fa4ff8192fc9e19e61cec56991bdf814e9771f0bccabcbb6c9f14898d72979f",9.317957166392093],[10443,"3e745b17c4ac25fe1d72dd63e713e67dd568e7dca1389003893aab9bb3ba78bb",9.917710196779964],[3138,"abbeb5f4ac657443f6411694cafac7a66e6f5da5f48a62373f8fd21bc25570eb",9.317957166392093],[11165,"02af62456aea8e63e82ad9fbfe01d4d91db1100de886a91d13146775cfe7e5b6",9.917710196779964],[7176,"bc0bf599006c67f99812506dfe96c2d18204af148db1d17d94e3b8a4d75adad0",9.917710196779964],[7506,"11bf463cf29275257255cd3675fe8a1dc4db97901219f120a8a1b7bb824fb6ce",9.917710196779964],[124,"5299fa3ee36242dd9d8cc8656bc566d20042ed3c1864052eeede82d91bd138ff",9.917710196779964],[11204,"23194cb704ce0ab0eac34e1b00b7d5f814107d7595c9ab35b81321db2c2da8b6",9.317957166392093],[3967,"aa3a27b2ab1f79d7247a0ddcbcaa81b9d5b630a9feb345581d9e3e1548c7eee5",27.90088495575221],[11614,"ecb8446baaa57f9c5f1f07539cec1f46dd53a423e53f916d64784354d3fbd0b3",9.917710196779964],[4738,"d09d4632f6ec3f649a22714d6e445653984ee4489d2e19cb2dec1561442bb7e0",9.917710196779964],[8073,"da79b86d4bbd0fa0437c0be09f9ae9215487f7ab602beaa5d1b2fb25f35af2ca",9.917710196779964],[9351,"a2701580f65ec969836d70e62990270793796694e461e0bc3f23caae9de293c2",9.317957166392093],[6279,"199e0b67a1ddbdbc95fe882abb460b24771a88f31ab2454736d5bfbd4a0c3ad7",9.917710196779964],[9336,"32c5c16cf22dfc962ea8d6fb280cfb72c54b4859406f4bda0881ed2f122ea9c2",9.917710196779964],[18120,"7fe1400e3771dab43fd84c5fbb53d53d09d0a699f0a3f5a1a46ba4f004d36e3a",9.647446457990116],[14749,"b68aefbe1fb0250d8ee582c9bbbc10e3a8793c0d70eeb2079eeba96025dfee83",38.72],[1872,"84aa6e41d02a55fadab9264c4b1d12d1a48c2a5335c756f3d7125d12563accf3",9.917710196779964],[12293,"ed33a5b34ed4330d8da359ea0d83564344fd880904b96463bf6984b8f47a4baf",9.917710196779964],[167,"a8c0375e635d95ec00c62478950240930389aad310f54957276b86cc545fdcfe",9.917710196779964],[9598,"870920a0471ca6f447af326f14a94c3686d2b69970754584f4c39d9a062a08c1",9.317957166392093],[4056,"5598d0fc23cc05859257835054ec0e0cbbf838b9f69391aa28200c0aebd763e5",9.917710196779964],[10015,"33605afde3a8271703106a1b7e3a904725adae34e73377596adde96fe1ef3bbe",9.917710196779964],[1619,"b3019fd60f897f72a046ca410329664813b2f339d48edd87bcf28e9ae6b973f5",20.31205673758865],[16918,"4ff239864f85e6c65583c2dec05b77ad673d59202be746aa6cd772c05ad8c553",78.27788649706459],[18182,"7f09276cb6dea5b6b073337d4a27e489fbc975e5e82f0d6a6fdf87ec98719e38",9.317957166392093],[15556,"828967ce9c20897af0e3175bcf2bbbc0d383ba1b8124a15ed04ac4c8a292b072",10.052724077328646],[14510,"017fa653822752c3d7cb817ccb6d4c7422c7c1e6c4adbbb3c8cb39ed95acef88",9.317957166392093],[13268,"9503182d7592c9c0a95a08e20104ce1d6d70067c3c75f45ccd27e73cc29f4fa5",9.317957166392093],[686,"425b28dca9c7a11f0bab3e2ecb889bf2733454e1c68c65b15437a42d15b955fb",9.317957166392093],[2355,"122fc36778af248188fdcbd49f5e6bc27fa35c5462ad297273e08f689983b7f0",9.917710196779964],[8532,"c12cc21a4a040ec7958f526ab0fa25b80a2475015fdafb240bd2be4c0ea8d0c7",9.917710196779964],[11803,"e015072ea6bac3fcce8994c79320fa1e18084d92564a52dbb7e98e59ef2bb0b2",9.917710196779964],[7909,"9ad705886a5e46aa4306a08e3b6cc6db5dec8d3488c0bdc9c8d42eb910702ecc",9.317957166392093],[19024,"340bff02df68d4aabc1998e61d0a6b05e7dc33bf2dede13f0739ad6a35c8c71f",9.647446457990116],[10482,"1bfaa6c4d1eadda7aef50ab81f9183f8d6eb4929b1a69406e3dda2f26f7a43bb",9.917710196779964],[21,"7e2b30570f87a90cd949ff072185913c0084858e93e64ae67fd141c9b010e4ff",9.917710196779964],[18817,"7d3d7d8fb98c4024227e0dc92f5ccadaa456a2ec1aeeebb6fa0ec25b68452c26",10.095238095238095],[11968,"b7e9387c43b656efa858608ebd9d8bb5d55b99b990915a7d1eba59edbab785b1",9.917710196779964],[6221,"e2c2177dc2c2db4760c4e763ddc6c48dc74e9fd5da80773c2fa61dd1ae8d9ad7",9.472566371681417],[17861,"8f7c982f35380ba04d0104d83cb2dcde5da364c6d6209462f48867ffc1baf63f",24.727777777777778],[13745,"ffc389d4a0fb8a9750fbade85e6600d95578453d631e36cfbbe183b9f7a98c9a",9.317957166392093],[4869,"169c0fab4b55c5c855d3f628df5fcef474f94cac4ef766f8c91f569a5f9204e0",9.917710196779964],[13965,"1500fa935de1680a0e3ffeec96d86fc01bad76b05f6720bf6f7f354ad72caa95",9.317957166392093],[12724,"f79fdcd62bce1fd37811b0dcdf48b7516ec1f42e1a6bd7838b34164534b16cac",9.317957166392093],[10552,"a62a8f0979f59bf8df0e6c9dc91e8178cc1399340bbf3ac6ee9282a88d8febba",9.317957166392093],[19047,"785938429ccbc4e6821a3e847a0907167a5117046daf4953a7c137ed8a65dc1e",9.317957166392093],[6546,"075b59a0f148a498a859b601f6a8b63b987ff6f9e5b41c61d500cfd0ecb90bd5",133.89121338912133],[1571,"54930d122042cf1810952cc5bd64ca57f8da964d3cc574fe5a2be6a7c579b0f5",9.917710196779964],[9526,"4c3d34b1d52162d3a6fa7ed7b767cadc6a24fd60604c3d238534e1c73c6787c1",9.917710196779964],[1367,"9996588c17938c761f419c6b7866883e149a9497a5617d926f3a08d98114f6f6",9.917710196779964],[12559,"17ef376cc7ee462d7006458f9dafff841fb01296063336ce1a31e7077aa597ad",9.317957166392093],[17079,"be794e902d41b7fc165d240b94bbc9789d2ba6f2a7a526d2bfb761e014d25850",9.317957166392093],[17688,"81605b4d0c687bb65a2367ff96fb9231d610ec368b04e5bf97c1b60538156e43",9.317957166392093],[11325,"075f4b1263c37e95e9a071768abd146a4a49bca840608f55a36acde76db9d5b5",9.317957166392093],[18687,"f6a3b7ddd7889068ca5178388a2c81540791ba5d0eac8330dab4da9e0ccecc2a",14.993318485523385],[18493,"2731b88928390ee4a10d88f0404503e4e7e844ab6461dd0086779cb1eeb08631",30.26710712600283],[11293,"22b765bf9bc20a33b44aeb2b9a90949569ff5a28f62f4590d2c54cc807df13b6",41.30769230769231],[11788,"325b7a67155894da68ad5b6c6b04d1cedae0627809328faea3b44c3850fecab2",9.917710196779964],[1399,"e3eefeb5eab4f9bc95757c71c5dee464002dd2379b33ff68f28267620298cff6",9.917710196779964],[2848,"50b4b9f764a841f498f821e5d6b219afdfccbcdd55efa504a2c63ff9bcb560ed",9.917710196779964],[1880,"59b873ca1521112a35716f603bfad1d4cbe6850e78e7dcdd513cfffabd5bc3f3",9.917710196779964],[12880,"425153e6ef7a47aad0e6597b2a2d733cf3cd035cfa0daeb59caacb5236ef67ab",10.052724077328646],[9115,"d1958de0dd5c6c16d628d8a735a469a8be43a5c01cdda463e799bc0099f70cc4",9.917710196779964],[6086,"be674e6082501b09880d517bcd7f4de9d7ab9603ee16e572090f121e2ded79d8",9.917710196779964],[17821,"9e22d32e282b22ac041d88522b935144b29060f29c8b7d338de56581cc3ade40",9.317957166392093],[14162,"fc60a496cb74c99c6b1825632ecc6a4bf77dc4f58cb9f66436bad8f30be13191",10.052724077328646],[17409,"977a6b971b1204ead878ec84b1c7719f1028cbbc2a7a36af476c663b8260a049",9.647446457990116],[10592,"103258f40d343d3c5a8c057876b56721966ed61e994b06eda4e8239ca408aeba",9.917710196779964],[6905,"42bcf5cb6dac6a1d58ebd20fe62a0bc5b0ba187893c927f4a5ea6876a37f8fd2",9.917710196779964],[14268,"06f579afaf58e2fe5fafc44d81578680f10e4952e5086dc71e18f810fa22918e",9.647446457990116],[10168,"46e0f87507f5b7671e50d8592c53f7c9a4085ba39beee5728bd5a37eced14cbd",9.317957166392093],[2890,"ccd91a6d84a1e4761377d03ce3d2f1aab2a6a06d924bcf4f5fb3d962a26531ed",9.917710196779964],[13725,"6aa3ca917a20ff35e771bc4c6acf7cacbc0582ca0e89f685b57c0bf4ce25e59a",9.317957166392093],[2200,"7b488645689db4ec85918b6af831a133f91bb055c615241d8b07e532ef3689f1",9.317957166392093],[9979,"48865d396e6c8cb141edc2c2e21ff4f657d1134803fd725a1e278efb935374be",9.917710196779964],[7088,"96538fe7861dc7dd3eb3bb558329b77ea24ec2f3ed2bbf90893de3561cf96dd1",9.917710196779964],[3627,"0de998ef7fccb0880ec7a63779dee5aae6f97e26a23457127c3f2070fe0313e8",9.917710196779964],[19716,"737585aa5fd6dc4b0959a0a4c9957375817bcb5200c17ac4670d93db8b283806",9.317957166392093],[14453,"776554bc0f8761aea7502e1a345aedd9c245456b4782156bd51a918ef4382a8a",9.317957166392093],[13286,"6f74e29c2842149232cff74d2d28d0c0b880c31632f39317c47e0db1d77bd3a4",9.317957166392093],[17693,"d0e56917dc21e53e022829732d14f241644ea37e0477e9d92f87bf7d2b0e5143",9.317957166392093],[4167,"21217c0eb9deb5fb6675b916dcadb985b8eaa44bae40900705327e03ac37a6e4",9.917710196779964],[11783,"df091a7d1a31be221edb13b497291fe8003e2cfb32c83bf874f2727659e4d0b2",9.917710196779964],[17615,"981bf56cf872ae152e33e708acee53aa9d97e349065b77d83c919358f27fe844",9.317957166392093],[4892,"e05eae3f224b08dd746738890b4204fef8e293ce5643f4bde7e0f99c81e5e1df",26.138053097345132],[15845,"978d680bff9b8e092f955503766354ffc73e7a619b733c1bd960bc7225bf676c",36.80861244019139],[10877,"a2e3a20519ba461f3c6c71bfcc483c4627e3599d41d2f4c31817177e10c4c9b8",9.917710196779964],[9815,"2fdbc415928df5453e0b9c19c3631a9f403baea1e197949caabbb208da468abf",9.917710196779964],[5235,"a47a501f96ab48793f189aadf88c6df3c1ad43849c21707e217ddb67d776c7dd",9.917710196779964],[6585,"e93f352c568f8246d9c3e67fabb6c0fac9988cea70d409f43b42f3309107bed4",9.917710196779964],[18135,"4792e0975f4569f0fb1b474436d615680815495d73f34e740d4a9f5f85c1043a",9.317957166392093],[3496,"27e835d6a1984fbb02796f4728de40b3f306dda19c84507beaa987d4caec02e9",9.917710196779964],[3134,"496dce41a155d94e90c237b47121bbb293899d315a2d0f1e5080148a97ad74eb",9.917710196779964],[3862,"e0d66f070c29ce6859944241cc9a55b5e6944e968f7063e3d49c593a639e98e6",9.917710196779964],[13569,"601d7bcec6161d256c4aa10d4f735b75469a1ff9fb60a84d143e11992ee53a9e",10.052724077328646],[16448,"9991e893f75e14667ff4059c4fd15d057aba08e28c0ca394496885a42fe1435e",9.317957166392093],[6511,"06a1fc115cfbab0a46ea51d5a0b1c307cf640da4a4842e685b5bd7a16f8255d5",9.917710196779964],[835,"faabb82e8481e03313bdc3d45757b33422616f746513aacec390f06f197f50fa",9.917710196779964],[16831,"0f1898c3087293160c9fe04b167ee2397c1726337f122586bb689296037aaa55",10.052724077328646],[11375,"808ee11d893b6df068215587db885b31bc6816bc8670e62a011490dcc9308eb5",9.917710196779964],[3,"9f38df37b99d42a3976a142caa6e3f2297d025c3bdebf1c75780a47c1d8bfcff",9.317957166392093],[6077,"0a476fb0d83564397ee4e1300d4c7ca22cd1d7e571a149f153388e8025d48bd8",9.917710196779964],[14972,"328b5b5c383488d05c2ee1e89a947d11a31430d209b88f078677d95ea821327f",9.647446457990116],[12728,"ab1f54626aa98c4b00a9f0c1c286fb9384ebefcc6777fcf661ff6b44907868ac",9.917710196779964],[16712,"5ae0ab33b3275624b3ae816787c07ebbc5cca7f3b68d908e6d75949946d24958",16.056140350877193],[3201,"be2aa1c305899be11aed3d227c9a38cc8ce66280acbb7cfcc9e4bcd27fcd0deb",9.917710196779964],[9309,"0cb87f8ba1c37623b05d0b39e8935baac81347373d42645fd65a86bc9cfdccc2",9.917710196779964],[2458,"a3c3d9a62f3a846f60cfa87d7b6479197dd4bfcae75b36c69edcb90309c423f0",9.317957166392093],[4479,"8e313db2779c90790952ef7bfb2de2f29a16c8fe5024055573d5f3dfb71c8be2",9.317957166392093],[682,"11f4f3accfa28d9e1228d00fa2173c24972263c8d9b3d9e83c2c250f264e5dfb",9.917710196779964],[12827,"d03b0c9941bc1fcaa60844414220d2ec5a8cdaa529b922f140fb5f59c01ac9ab",9.917710196779964],[4351,"6961c28fb58354e389a781c00df02f66ae8ae8b4aecf0a09c81c78510c2069e3",9.917710196779964],[2339,"6a83b792b180c8c4f2bd9b43aa3c8bb191393db80f7c05c8fac71dc9a595cbf0",9.917710196779964],[4688,"0771bd1d5310e4c08bb377d2acc562fc513e3ece01b6dd2f93878d535e5111e1",9.317957166392093],[11399,"a656550c5f6422c1167ef195ce592f42e4d1e03bdc6b18fd8f899dcd9ce657b5",9.756272401433693],[17820,"c4912eb5fe51dc5dbf8b5456fd05c3823ae942e74d2961d9ac34eb2eabfae140",10.052724077328646],[3443,"04af9962bc19247382f6ea82ee1f58517b045858627be818f8ce423fc9496be9",17.09090909090909],[7381,"c38bd90a7ba85dceabb5f609b64f287728efd2575a310a9b12bdea2325298ccf",9.317957166392093],[16886,"86476860e838707ad66610e5933bd3db0a2ff13aab023b01d00c5381ecef8654",9.647446457990116],[14543,"9376889507c73d7c2e0ad937fd62768e1649ee221ecf6bc1e826b95442a34988",9.317957166392093],[11742,"b3241e204606574b7d231cff74b13e5c83504a8b478410bfad2ef7b198340db3",9.917710196779964],[17673,"f5c7333a633563ddf6fb156bcacb7b7d03d930964b4e561a7873da82ba80b043",9.317957166392093],[12350,"bdae862cc140a25efdaf8f723387c1ea9501a157f7dbf74694c1b6f7ddb1e6ae",9.917710196779964],[9202,"844855f25687c898181aa70868f17e0c6feb91a1c05d724e8ca6684b7ba16cc3",9.917710196779964],[14670,"a287437b0077343f14c10448214f0b4d9a67afe2b7ce725c926ba85e916d6985",9.317957166392093],[17574,"0b834178f645d868f8f648b1485b9d54aa2ccffb3f496b08ed6670a4f4b5cc45",9.317957166392093],[9532,"fb41a63b4ec440ebd81a64733e2a6af37d35b91ad434c46d1b92168a060a7bc1",9.317957166392093],[13519,"9e0bd3d55c6ddb078f30c12274016ff576cc246267ccb0c1530552ccaff9669f",9.317957166392093],[7242,"13d073359ebcc98b1a9f299ecdd4bfbe20d0e1d11e6bed369d6a7c539bbb6ed0",9.917710196779964],[4457,"6f5b33a7c2ea41058b8a7257b605cd262f8b4c30480501fbf45410aaa5f4abe2",9.917710196779964],[14775,"0d39acc26a03dbad6a7d5bc825fdf042e28a906e53d91c10be342af326516983",9.317957166392093],[6602,"ada3d350527adaf2248a3a4f15ff140415dabb405086dc7c030910a3abd3a2d4",9.917710196779964],[1192,"a54d05553f8cf987a8c671a8ed5a75ab39a3f1feafcb8a0507c621318cbb10f8",9.917710196779964],[17814,"0b3969cca1efc8c2d3b1633b8e745b39838c5f15943050581e981e81459f0541",9.317957166392093],[19280,"e882faf569bb4c5d54ef8f59207b46ae19b114d371304071364bc488c2e57115",9.317957166392093],[12601,"7abbf60a54ee276fae9434ba7d47647e5ac2546fb0265674f9a65bc2bb4343ad",9.917710196779964],[17489,"98a25ce5231e7a2bd0c58b03a70a60d846e997fd49a76f19d8a055b7b88ad447",9.647446457990116],[10789,"8573eaecb6808e74474d23489412aba40ef8b66c31bd4710a31c9303326a5db9",9.917710196779964],[914,"a15d15b6b49fcfa1fe7faf4a3d4ac9745db3b664f3cfea038a8e7357ec40bbf9",39.13780918727915],[17373,"2869685c8ef9030cb6e76b484ee8049ec927fb9e3c2e85e3984667ed12cb654a",9.317957166392093],[7320,"43ecd37ce8d5fc513da913e7ccab13345c8e495612e951009e7bc34c1fe8f0cf",9.917710196779964],[9423,"ba368600dd69f6e0cb1e43463960a21a52fba1c4a007746d9d4acc6a3e8f2dc2",33.842293906810035],[2465,"271c22e47b204b993da49077b3f0bdbc04600333934fc75a2d5322cc547114f0",9.917710196779964],[7667,"e0cd0994f3a4b3e1be4f32f9add072949b60de03f895f63effd36d8670b8cecd",9.317957166392093],[1086,"259dcb7413f0a557ea2230bc10fa6c50959c0d9b345ebebdc405920e65a4a9f8",9.917710196779964],[19207,"88d2c08604a86a6d155ece37ba5fef03172bc24cc5dae14d2682ad19a34f7a18",9.317957166392093],[6151,"5f965d4142aa09de5952bce810a82d042e91d6dd0bd73174830dff96049324d8",9.917710196779964],[10179,"18a7bcc1fc3578b3e6201a3b4d63616f7da3a06b54ac0e2108a50bba8ddb2abd",9.917710196779964],[19256,"6b3337710a9ba2b2fa1f85b882abb0857f0ae88cb5d483b331d77f10746c6716",16.975265017667844],[6635,"bb2acb305aad5a04da0819e688c316e836d9a15b25df589f3afacd42bdf16fd4",9.917710196779964],[7788,"4f575693904261b62b3a2ad059785e3b9b3342d5c57335299381cddbdc92e3cc",9.317957166392093],[13988,"586b407b570f4a70251b57dae817ce06140d04264b764c14d3d48cff88b43195",9.317957166392093],[14256,"7d2973c8560307a07b0b077169bf7495fff3841af68bd9a1790f60b95f10c88e",9.317957166392093],[2925,"943e4a717ec94c0912c23bfb2cc06bd39089b1107ca081599fd4bc9dedf3deec",9.917710196779964],[18154,"fc1b781452ff809cb03e460f8cb27faecc51bd730355a1e62dd779bb3a203f39",9.317957166392093],[16198,"5d2102279c2c6fd65874970322916f5d7ee507ff205549591b32d907b2610764",9.317957166392093],[11273,"652fa5808132038b41483db8f96d8adf4cb3c8cc0a80ee54d679593fa2bb37b6",26.090592334494772],[18183,"4d1b4638a66e10160fd070a974544b626b336bbd82da1773630d0bcfb1fb9538",9.317957166392093],[9521,"f89bb5bc0022f68c0d4f64eff3008753e0e69deec784a8579c3d199283338fc1",9.317957166392093],[12416,"ded23f7713c505ac98f48a049976eef3dd513203ed642fabc6658dabb5307dae",9.917710196779964],[15084,"0cd34c54b93f4fe1f019d31849b3e5d0b370f38503d0dbdb255528a0e159fa7c",9.317957166392093],[14188,"797f691ff4b4668e0b3a6cbb55474be03446305ad5ffff545a1171d2a211a690",9.317957166392093],[16266,"b4e64287c9d8857ab943ab6a969d9afd373ecc79b15299c837cb972a862ef461",9.317957166392093],[14576,"c06abff5a61fd462a365dc82557a45c076357323a5014b69e2df5b6f521a8987",26.062350119904078],[8730,"e47e250a7d387de20b032cd49cbaeb995af95e8b4d814c352146b902050785c6",9.317957166392093],[2425,"88e7f0e94ef8a78096d2b35f6c7373142d75f7a316d6e4b378b742cd5ce251f0",9.647446457990116],[12803,"a99c0147b50e44c028ab223c444d960d4e1c8f5557fa34d41b56e41b4ae8e7ab",9.917710196779964],[11203,"84bf96628a0e62e2395d0d0358caf1dba796bfc37e705b0d0f6a9a90c14da8b6",10.013531799729364],[16895,"4361cfe0306a3b1c5f19e7c4aa0cb6d32a99542d8e6e7322d8c3cc9ac6865054",9.317957166392093],[11452,"9da2a14b148df39976ddad7d2a2e4975d77d2ab37fbed82b38dcfe53486becb4",9.317957166392093],[6640,"efd2eeec72fa6f595a25d2ece5d365f98cb24f20db0c850887742b1dd62062d4",9.317957166392093],[15469,"be83a6908138f7aed984d3b1a205a4f115c05ef5e453b618389c8eafa42bce74",16],[13074,"fbc9583f58fb8e3c35cddb5ef99d9ff25afd0b8d0d2702a630a3cb575f681aaa",21.654135338345863],[13172,"6424093b9304b308360043423c8df6ba029d2109fc5dc3d1c309b4b3be5d8aa7",27.07125307125307],[15725,"dbaccedf96f29d70d0de69b4126d4db395291cab49b57a66bd8b91353de0f96e",9.317957166392093],[1397,"a830dad94ff278fa67dd4404485b09e9256b72463fc7fec56e40f68b94f4d0f6",18.57963446475196],[1687,"f14f98985c6e4ca924022275c5bef850525e3c2cca5710ce74541988b75102f5",9.917710196779964],[3888,"fc422fc2a6708852e645726eaf293dc9fc5e4fbb6dad722aa83a2427a8cf6de6",9.917710196779964],[14295,"106afbad1baa6182106b76a08291d4bb5247475d59c9e0daf9a971ac3865c38d",9.317957166392093],[19477,"5efad0f4c8a4e7cc860ea0807b91a63b3c70f9c973e5093dbf77c40d1fad3c0f",9.647446457990116],[1538,"c2059f21b4b77487ca32843b3fd3fc49bb122a74bf45505b9fd4836a3c77e6f5",9.317957166392093],[7604,"afd58fc9abda9bd01980e7b8e2f57a1e2b7f32029e6b4f226e2f266947b02bce",9.917710196779964],[13280,"f2ceb6064a23860eb3d374c0283c09837778fb324055cc6bffddd90f577a05a5",9.317957166392093],[15778,"abdb4c4ec05d94de74411bf95797b030b435cac1e6be7cfbdb5f52320372c06d",39.13879003558719],[12352,"db062fffe7fd81096b9a3c06e83a320614b44927761e3216b1cb47e0c958e5ae",9.917710196779964],[15224,"1e101e6ba694281803bea50909e1465bb85a994b554cbcabe54d7ec5aa9e017a",9.317957166392093],[18448,"26724d13b2b4b99063dbb7f665552c7c64166ea52a4f9ff86d85830563acad32",9.317957166392093],[15028,"5105ea75407750456794efbc51076c53253b49238adc599762604e542346dc7d",9.317957166392093],[18888,"93e0667c1970cbf2aa7169a2519a3c8d64fbf2fe6174ffeffc7ff9c03546cf23",9.317957166392093],[19545,"b0bcf1ba15fcc9354826368c9930078620787b3f89677b1893df08a09f2ce90c",9.317957166392093],[2477,"157e419877c4c9d2b03fc3114320bbdddffde717a98a484d3273325318ae04f0",9.917710196779964],[6674,"cc13f90c1f363194bb758556061e2b5ae90458437be33e8d6486f9f0c97028d4",9.917710196779964],[2542,"c9cffca9e3f64c4abcde77b16611f0f13121b4ec88e49169e37f85841f1a92ef",9.917710196779964],[13250,"5f736c2db69721c1952b7ff57c05c30cac73351c51e1a09b41da0aa4b04fd0a5",9.846153846153847],[16242,"4715cf6b1be682e10a9b28584bdaff47bc1b40ad9ba3d0d849a95034bd47aa62",9.317957166392093],[339,"f80735817f73ac72638b292d0fe795a9a64808b2bbcf8e72ad6868d9e6fcc5fd",9.917710196779964],[18087,"2c9692531a4c232fbd538c8659644b0bf25ab094369911fe99757f62c513503b",9.459854014598541],[15158,"6fa7b1786e67dff481d18bbf28cd2731395a3f4bb8e1dd6ef487a4c457d0507b",9.317957166392093],[946,"a3ba087d3f4505cefba7f3d0aceb291bb222e48c185a768e76c425c20e9e84f9",9.917710196779964],[12530,"5dc5d47216df7a1914a6ba0354d180207c4cb54ef0846927469f4a3f59b7b8ad",9.917710196779964],[13420,"f7c11bf7ba9cd7021e96afc8b59b279552dbf600046e57733912c5b499f1f5a1",9.317957166392093],[6842,"6abac24cc37961976994992a4177343e68c7edfb848641847afd767b2c8e01d3",9.472566371681417],[4940,"83f4e1c086966863871acca568deb84712dd9fd21b5ed9d91f70fd772b2395df",9.917710196779964],[15961,"45293ea426ff60ecf8e9c12a715e1e971e96ea4570c507c9f0d8d38d93b38e69",9.317957166392093],[14232,"0890816b93a44a1847d3f7ba57e1523ad8b5751ea6bd00719f27688b5c0e698f",37.93594306049822],[5299,"ad23bc493b1491e2118627a62fde7945848cdf885677b97abe1eccbfc05866dd",9.917710196779964],[19751,"9a9579e42708c588e958cbcad837b797b636f98be6fa3bcb367ac336467faf04",9.317957166392093],[8533,"bbb021a170cb29d76e43c806b587dd2a7b55086b41ab698c4e3817bdf92cd0c7",9.917710196779964],[4770,"4524af49b9c109f412cef225e0cbf139d04701fd7a9becef6f065a90f05e8be0",9.917710196779964],[18555,"810440daf0e8b4fc10b5f696086890d838079b7762e900c7e4d07dbeb2245a30",9.317957166392093],[4715,"09261dc0f968505552c5c12814a28c01674422ea241e7a28384bf596c27cf1e0",9.917710196779964],[15960,"7790e9b393116bbfe7eafb814c4af880c6abfae1e30da8a00ba11969544fb869",10.052724077328646],[4384,"70b079844c39f53a6ce56817185ede2fdcb3813713b6b5e2adc286b33f9c2ae3",12.013387876534027],[1617,"5b7076983698848fb3dcd5864a614bed7bfcb34872a6ce87504610f705a175f5",9.917710196779964],[11575,"40c801fda5baead79f2f947eb5da97b78fdfe9b429194d09336ad34d8e3b18b4",9.317957166392093],[8745,"617f628224c6bd99b7d32b732bf295eb5a1ef7132fe57713c0d00a3bf7f669c6",9.917710196779964],[497,"de12723a7419a86e2cf5f2a0650b129e869c87f12d7f2c74de2475930f9ab2fc",9.917710196779964],[9482,"0cd18ada8f5787d6f579803f5b042964731a927751d6f4a263318b80387dcbc1",9.917710196779964],[5554,"f1edd25936be9ba7796329d59cb844e0ed580888a4c29b41ce24d258b10be8db",9.917710196779964],[19291,"20e27c9e676262854b6a0ac463f69b6b0956e9db6a959d0362662627f0f20e15",9.647446457990116],[14538,"7340551c465e0542ecdf4d9ca6b4110cae3b33e30643c0e536041b8292537f88",9.647446457990116],[13523,"588f70f4c764b28a78c37ca8f0496f63fbad7f6d76610ed2c80312778927559f",9.317957166392093],[1357,"646c2033c943c79f8edf1feef89c0e679a0998357316db1b47c572dbb744fef6",9.917710196779964],[3900,"90f6205bfd3841f1fec9aa5a253672d5cb694915d62e7e2351d8f36621975ae6",9.917710196779964],[19197,"3384de65b9e4ffeb56ee99a7cdea3568f51c6ac5caa3bb8a4d3c4ee4b648bd18",28.09964412811388],[8175,"54f62f148e9dbe54d040dc122a1876c55ad0e3ec6e2c36ff7cf67600e5c924ca",9.917710196779964],[19603,"49e5f6ced7e6c05e9f3955d1f567d89cf77bd5c82f33b4faf4b2c3956b5c010a",25],[3193,"ed1783aa0ace20f02c4804031d2b869d30c8dab05a1ee437fd745040438916eb",9.917710196779964],[536,"e8a1db792152e1f3b86459f2b5b0cec181cfe04ea411a17816ec4dfe28565efc",9.917710196779964],[18347,"4583a6371e9b3a8a0f2c18d7a9c04abcc1b84ef4c198ea5e387ff346a7bdd534",9.317957166392093],[8569,"d0f3db06d1c6bab5701c1a9f67909ab33540fccd057330b9df19715e8ef19dc7",9.917710196779964],[791,"76f2c4438a3732d98eebbcaac428a9e84d557a52eacaad29a941036a2d9295fa",9.317957166392093],[6703,"4eb607719bfbdc95cf68263612354cc3a6c3067dc4a28206bf167cb153fcf0d3",9.317957166392093],[10012,"d56013898b43c861fb53f036c94b02b1e5c6e7524df2d7c37381a40ce10a41be",9.917710196779964],[2263,"be92501721327277f71e69bd950cbf746b8c8af6bc031dedfce7fb7fa72630f1",9.317957166392093],[2201,"28aab29238bb68f5e64f5c6eac76d8a2d76f445964794c891c7b6b4d78fa86f1",9.917710196779964],[2411,"9268493202908b93f079091f68f7397b8e5c027a5d751f2d1b4b070a5e9960f0",9.317957166392093],[12903,"40ef83a24dba3b6dc64365343b3d629594804edbd06329d4dc42e729e8514bab",9.917710196779964],[995,"2195b60259009db02428afe6bfaadcee0ae32e12856a0c40f73ba24336d542f9",9.917710196779964],[3338,"544c4113b0d4d7ab62632eb56c320d2d20296d080e8b8699fa1247b3aa9216ea",9.917710196779964],[15752,"2c513f365cd87b1e5a5cd8a46140bd1628c7f0150d1c2058da1cec611981566e",9.317957166392093],[14397,"37b0469b41887bf1bfee3305c79b34ef97f1675074716f767b2638e1c2604e8b",26.091872791519435],[16882,"890805abc6ac4ab68b0ec7bfea014db3566fa5b252bb637abd38276a01b88c54",9.317957166392093],[15453,"4ee6704b549a4a56b8214c2ca791b775e24cc72659d65bf23f0f929e7e811475",9.317957166392093],[3453,"dc85d044f5506b70b2ebb7af3ef5d054d521a681fe59df4f0b9005959a4058e9",9.917710196779964],[4548,"36b0d1894d02d6eed767750b85586a9e2a6ab8f1a3d0d2289a0728e9e6e805e2",9.317957166392093],[17819,"02a94c7110150d2bc17ceaad84e16c5f555d1759808e50c73589e54fac6ce340",9.317957166392093],[19308,"a06cf666241199b7934985e07f364c1a2501d71221b574434d2f1b293628a214",9.500303951367782],[13777,"9d57b04d029a5e5e67c97e0dfb9385a1accf2f1d1ea2d75a99526d77b1d0d799",9.317957166392093],[1948,"33bc17bd4c304d0d75c4d258e4650011282e5f71940bccaf92fd85c982cd59f3",9.917710196779964],[6810,"8936e828f350418c9a0e7691b8f95206993fe9650666a9d73ff176983fdb35d3",9.6],[14963,"eec1e47bc72b4d368a14ecbf792fc99d78e128b5153cffb8af6dbc7d44965d7f",40.71301247771836],[17513,"766b361bdf75930f503a900059f261831755720857939dc653e4c84768753c47",9.317957166392093],[5760,"3420595fc3f46d8512e04c70f94924d6a8bfb3b358f62b420a9ae978cc7db6da",9.623651508944421],[3516,"f547d02fb118066a24f5730c93de7668c1ebad156d7f25f2577d33394991dfe8",9.317957166392093],[6004,"a70384729d224b85461f0ce1068bb1a158b8b81fb57745b8886b2e90d7e50bd9",9.317957166392093],[19793,"2efda2ba360e0a524e2f8acd65367e868aa96318c8e168e0b8fad664993dca02",9.985857670497452],[12378,"f87a595657260d8a7addafb149597cc7e9ca3661a75c6e15c5e02feab1f2c4ae",9.917710196779964],[2152,"baa3ff1bbb4c2351dee052409222aa365468b822b44e55c37f741b8c33b1e3f1",9.917710196779964],[19143,"0e3a01773858675b0c0956df49031d9a780e95237f014a3e2df39dc3394bb31a",10.052724077328646],[13758,"559d29ed26316fcfbfa6a01023b5dcd3967861fda9688c0e1fb55533dc7a2c9a",9.317957166392093],[1734,"1b13aaf50f1a9b42d9aa3fc2ba4753105a185d9303f985ba479ab2878627b2f4",9.917710196779964],[18279,"180d8dcd056c91727d69adbd96c9173cfc62790777f26825a1cfc7d6f29e4136",9.317957166392093],[8280,"f2b3ad0c24597dc3b105657f3c98a354f8844e4a99c558e89d432f59925978c9",9.917710196779964],[4864,"9aed35962ccce8de16ba02d09b9bd747e519383911256b90fc4619d2a2dd08e0",9.917710196779964],[10478,"db69d1a3758223b2d90833b644791ba052ddb7b8c0670e2900e4aa4ed24348bb",14],[16681,"eaa275aee247de757f3039b763377806a8b625d7df4d7d1ee244c43d0365fa58",9.317957166392093],[7343,"7151996019cd794d91a5f031cf2b4a67fca74747d2afee46760dbce8fc03c0cf",9.917710196779964],[8210,"be330b3b79200540d54515ee19a54fad3864e70e08fca5636e99274fd98beac9",9.917710196779964],[18871,"7025ea897994aea627748bba87cb07b55f97665b72196cf77197241ea7b85324",37.936094674556216],[19185,"d68ad8e9b8078238b3ccb93141026a53506d60209e44351176b3b28188ab3319",209.45454545454547],[14896,"f17d7cf317216e7b2ccf9fb13145009fd7408e0a8f0b6ce013d0eb7ff03cf080",9.647446457990116],[5556,"8e24a1b0eb7664bbadddb4eba818d07cf8e6719eb707a412791f0f4eaa5ae5db",9.917710196779964],[13398,"687814f5e71b772326a852db6458e537fd40075b2b20699015a50ffac06755a2",9.317957166392093],[14093,"874dfeddf09731a96d796c355c2a4a94b6cb459b6d2a46e1f74cd3e50392ba92",9.317957166392093],[14466,"e2478171877b146dc816c1b71c29ebf53116ff7f9cf86870193583e35171f989",9.317957166392093],[6060,"42055abfdb5616ec290d8171d872f65654f0c6e12b2fb869e2c2c957ca4db6d8",9.317957166392093],[5513,"18d4e4bbb626e7faa9b27e2547095de1be72486d2e31af4650f42fc19edb26dc",9.917710196779964],[1383,"cc6ef79b195758b403a5b3fecd2f8889d77c244eb6a695261f7e8319de39daf6",9.317957166392093],[7585,"cdf726f5c90801fb0c6cf5d1d8f4ce977fa58c4445d9542bcc2c6dc0604a46ce",9.917710196779964],[11315,"4c24938ba7820ffb60f4b43281c59b098e7a620397fff7f0d66aa0144764e4b5",9.917710196779964],[11394,"d73be1ad51874090599ee653e8324088e7b385b380fb9c114f040323847a64b5",9.317957166392093],[7256,"74c706619edfb02ac898051b910c4806d8b07c1dc2957dca75f07b81c49656d0",9.917710196779964],[17695,"0b1aab4444d7c85abd0420a1430193669e567a40991effbf79da258b3bb44f43",9.317957166392093],[3809,"9d35d5c18ff03c07b090e6804428a4f96cd5ddb905e4a2af407c5ebc75bee7e6",16.00182565038795],[2204,"42245cddafc452aec052e4f5871e64a1d22a5f9237a9144c217a03bd66db84f1",9.917710196779964],[15494,"fc69db47102fd8b1c3002d9e896ad2c7257e7aa3d57569592e18f342cd532c74",40.977777777777774],[4818,"6ed541d75bdd450d4b02b9d7247fd516b56212361e9d537ce30cb795b61d52e0",9.917710196779964],[16099,"66cb563335ca8b483a235c5ff0700c92a66bb56b42f7df09409a6750155f2966",25.401769911504424],[7218,"f73cd31d82f1ae436f697d631db4816888fa28e2619af4b8b304737965c48fd0",9.917710196779964],[8637,"e86a7f831b93b54a7fb49a7eefd5f8cff1806f8a7db2acec90b7206de20d2dc7",9.317957166392093],[4181,"e80370bd16c01d7a9ca79c16b83566cd9d2b6ab26bb64b1babb4c38138898de4",9.917710196779964],[5092,"4b1d2c2017b804cf2343ec9251aac40a9a4198b76cd1cc893872eac18a729fde",9.917710196779964],[10472,"4072dccd1013034bf188a279748013f09ed52e4d4e601e34ef7e45ea15184ebb",9.917710196779964],[4430,"f73e0a546887e7e4d90c8b2ef4323e04e95031b4348c22013d771ded5510dee2",9.917710196779964],[11066,"8b6501a946da29d7cbba99eeafc50d3ed52fbda295bf75206ac6be0229d490b7",9.917710196779964],[3624,"b3a225f28d00ee4ff49608c66ed456b3a307d486c5eea304b1c5ff297a6915e8",9.917710196779964],[9227,"d367293f18052ba771f6b65f8e414382422c0b442c24fbba75ee490d29fc50c3",9.917710196779964],[806,"b1ad027bbc81a1a3c5298564ef877632d6566098cdde0746b0b271c97b6082fa",9.917710196779964],[11477,"b247c95977fefaadb0df31bccde0cf7de01b8542a6cd2088ec6283f4dd8dadb4",9.917710196779964],[14776,"af076b37ffd88c0c0c0b837274dd81a81dc660e9250a4566ddbeddfddc6a6183",9.317957166392093],[93,"9bc3d757032cc3903fc9822ca43894128ce57c2efc2294a0b923679af7846aff",9.917710196779964],[2382,"a2eef1e8796a6e88f7972588a82936ca351e2cac44c8750d427d26d37dba8df0",9.917710196779964],[3665,"2ffeb1d67657b7268a105dd6458d08515bbce54ce6f050afdbff53d2dc09d6e7",31.577538551061973],[6099,"012812f3bb6278fc1dee0e53f3704dcd6baa73a75ea5dd279bc35a3901f36ad8",9.317957166392093],[5402,"7e035f100d7b0f83c7b7c642afcecbab26660c6cb54daa916d974a402512cedc",9.917710196779964],[1965,"27ac055c67eb4d2c083b6bb376805c6b79114249bf6a4944cb4308cda51842f3",9.917710196779964],[18121,"d1bb47b402bc7bb22d917de0076397679b50d7a0e69b84d03fa29f7530826c3a",9.317957166392093],[11430,"9a9097dd01b73acc204a8d61171d85511173d650a8e293757ba45105a8b71db5",9.917710196779964],[2840,"1fcd23cb90b287631f1a8da384737ff8d3d56c49c52b8bfca29ca1a676d568ed",9.917710196779964],[15749,"bc042fccaa85f154ed62cd88f6e983729389742afa0cbf179da71304ce3a6f6e",9.317957166392093],[6488,"526999b1bc371fc29f0aee788e0d659cb0a91a6297d728e8d26ab37a8ee490d5",9.317957166392093],[8272,"9fd125e9d84b2d7548ee35d7f1a68330de3dcc1e0f7d3998fcc7d91dafdb82c9",15.91459074733096],[3899,"ce183d8395d982916e6e1e9a3601c20318d2870c85474e5a0e561495cbae5ae6",9.917710196779964],[14892,"a374f9a0e8925e91e40b270bbb1ccb3be2cc88d606bb5dc869b5568b970e0181",16],[9317,"967ca2bc82e84f6a5d8176d711e932ad6cbd9458b215584a367e1cd401cfc3c2",9.917710196779964],[18673,"5aa46ae0ed5c36b46a369a3f270bd61d40b5316476708bb9f91b3fb1e0cca82b",9.647446457990116],[9823,"94ac4eebe50046b0466eb2f3ee6afffb05269739a218a636b586a055eb627ebf",9.917710196779964],[6816,"03607be079ea2a1fec45b70cdbbf5257f893a968295427e85860ff70c9bc2fd3",9.917710196779964],[2754,"16e811e983dd983bfe77bd938ed9e5bf0cd4dce4956ed733ee239c7cc8bb14ee",9.917710196779964],[6393,"da17cf71ced488b0dfb75e42e790e7b23c41fd2f1e8ebee86d65ccb6a91461d6",9.917710196779964],[9447,"0351d20485e31717b27751b94170ce4fcc820d4906b1ed197bfbb8bd261708c2",9.917710196779964],[3760,"76fc91e7bf2ad40ba43b745c1a2e667b22e2c292af69b19c79d6cfa6b86c2fe7",9.917710196779964],[3970,"43ffb427b9a58c8885e7afd0948214be2e09578e1af6cea77279aef7dc7aeae5",9.917710196779964],[4853,"62c9033e14aa1e3866c1ea6fa6415b8e3ef4262f6d4f77a20abf832321231fe0",9.917710196779964],[12052,"0be3b34a9e83a6aabe1fdcb1d7743e331b0e46ca9c0e056a6d3cc0e1a2cbf8b0",9.917710196779964],[10510,"f557f30c01ff4b296f864693cd2100e7acbfb09e0b2efa103429346f4f671dbb",9.917710196779964],[8894,"c2f79fe180ea42ae7164a1a698028525e35d2142ad422f7a9b6356fc8db877c5",9.917710196779964],[5809,"ab3188b735800cc35681f14bb4d565c32e611acdd1af6911b0333138d0d954da",9.917710196779964],[17590,"c545474d081b17a37b7fd9da57c4320547b75f7af3eacff300f6ef6449536345",206.6106032906764],[2461,"02178d12cf2e49fb910a4d47249a6776f56797d7d5ecd072e29f425742811ff0",9.917710196779964],[1752,"cd4cbf6032fc444def1c55825a7165a2ac35ff6da3b084f7842223a9c64599f4",39.20855614973262],[13273,"736e54c8eacd9db338be828dec1ecd4d3ba52594591cf94b8e1601cfec682ba5",9.317957166392093],[10763,"261ed340d66959ba85539bccbc54867fb5c8a8186cc51fe1e7d545a81e4693b9",9.997888067581837],[5475,"4147ff6da0fcdc81774eb0a28afaee795a64b55ffdca47a48ad57a5222975ddc",9.917710196779964],[11126,"332e243b6daa1921dabc9ecec0f52b45858149f708db99bf9ef938b3b7441eb7",9.917710196779964],[14878,"5921a0e881b8c84dc77ceb82cdc711755d1a30d89d4a5d7f72bcde3033fd3681",9.317957166392093],[9256,"11194255a97b9a4bd479f7e63cd29589d47ad3ebbd0290c1c2df191accc518c3",9.917710196779964],[5829,"989874c3f7c7d1766b6eefa12e3f725329dfc721ba645f97918e0614a22f29da",9.917710196779964],[3839,"29dca55aca2df45e9424257b0093f08277d76439390dee44d6b833ff6860cbe6",9.917710196779964],[14235,"97a03bdabae48dfab241813b76332457d2c61b1f6cc65f61520f710ab7f7608f",10.052724077328646],[2448,"28227a59c9d2738f28cdef20694dd96d658c7056ca43ccdd8ddf82bfca6534f0",9.917710196779964],[16377,"c221308ea659edf480a17493aae76e82b8291289845a4c665ef22f397c6e8f5f",9.317957166392093],[6333,"cfaf11474873b5e0ba03a387dc0cb847220535922a01791a272118a645f0c3d6",9.917710196779964],[19100,"ac9d1dfa9ed767c92f1d2b659852be5435414929f95582ccf85fa5a93c12c11c",9.317957166392093],[4714,"6ddd37f76bd242fc1652f372b140b2d8386617daedebde0e523e6b53419ff1e0",9.917710196779964],[19492,"6886f1f38f84a58417379f6a28348d6df5bf8644ef7758b88d7b3b14830c990e",9.317957166392093],[16674,"2d5df9cafdcb4d5cccfdce272c424041097b00b71cdf72be962c89a3d25f3f59",30.90024673951357],[6927,"a8d38e45e6c1255a782af078096e75cb0eb241d7e2a213292b64a5831fc973d2",9.917710196779964],[2417,"65b87a3975b4203f93780bfaf603d49a4c40128d1769be4cc6b53d9b346e5af0",9.917710196779964],[19334,"7d8c4f2f261e6a5b85b9c3b43a93573a5f0040e9323b47f29191110448331814",30.297777777777778],[8666,"9b8ef07bb84116d6c690aca01ec68815f295c599c23520eb175cc33382e0e2c6",9.317957166392093],[9497,"0bfda7c5c7c5322f35a52b7d1761ce01c01269f33f0b1a7b588ba13c8defb1c1",9.917710196779964],[15023,"123310247be90992883f92ad0cef7dd29e1c9310a89c7089527d7454af4cf17d",9.317957166392093],[10239,"a925fe31c3ea0090547c75019336d2e4e698436b7dcd12c19720fa0aa78bc2bc",9.917710196779964],[11896,"924d1c286913c8f229218fa0a78866d2c7f9fc7b16ee3c92ef2abbf040d30fb2",9.917710196779964],[7288,"befa3270b8b75165257174903cb4b992b8fb3341f2304470383e9f6b175826d0",10.052724077328646],[16689,"e6240b9727e7c94d0402b8dd023a6b3c700d4370c78065b39c94d03e9fd1cd58",9.317957166392093],[2879,"ec1a566f057a075a1ff66266aaf200076c2feb14a6fdcb773b5f4b3da5ea3fed",9.917710196779964],[5463,"98337574905f60c24bda0b74e5fbb44df8dd32137d53b4a9613e7cb3d8446bdc",9.917710196779964],[7514,"de1efea852ed59e40b75490210fa0970daf627af9b96a132352c231352a3adce",9.917710196779964],[11621,"ca054d4aeb093c72802686bc00c32d0f4d43c8cb49d24678007fce263b54c4b3",9.917710196779964],[12387,"65a7b71741a61fe96066d623b1fedd9cd16e09b3a7d5a62c11fe1196a13db8ae",9.917710196779964],[14770,"128bcc0686bcc91f159c891b6b6fd9283f281ea7fc74c88e9ce4a53efbd57e83",9.317957166392093],[17225,"945339d090c355bb01f1145e4e028119588d42be31ab6bf366e3182451c4634d",10.052724077328646],[2435,"40c414891a0c175989e707159dfd3c03e57cb218ad02b0eaeb3d1737a6b03ef0",9.917710196779964],[572,"68fa1b599ad0f0cb5eee86a2e604278f76c08355cbecb24ee9735ab8fddf1ffc",9.917710196779964],[8954,"2bbc48d0358c1dd484b458e7b5e26bb7e75f35ec0ec3670a8afae28b1cda16c5",9.917710196779964],[11357,"b9c9d9c6f5721e68a285a62b93468dde51e6e27c4f1a7cd3ea5619a06c779eb5",9.917710196779964],[14580,"c6c5c6a7b474dbb545e22dd9228dad2225eb0edeffbee2a552dd39b2d8a67d87",9.317957166392093],[2656,"9bb5034b50c5d1b2e250a65add1e3bcc4248f721184dea6d9662f25fdb9bd3ee",9.917710196779964],[2015,"38825c80a152aa549afd23af2ff43ab19bda8f0b257c2fc1d32250cf002ee9f2",9.917710196779964],[2697,"fae7e2c5cee679a7fca2e005ba5ec82a05b9b7d2852b7d68448c46db41837dee",9.317957166392093],[3720,"3d311a37b2d36a0b75b0bece77619d6131ba47ef19b5fc4b19dc7db2b55176e7",9.317957166392093],[12992,"312d0a8aa9293353b33bdd91e09bc6024f2e1b5025b89dbe685dd5eeb7bcacaa",9.917710196779964],[10825,"16dd579b3a19bdef56d21d26161b1b94112e78d25fcf01f61190be5fd98524b9",10.052724077328646],[120,"743b1f7344fb7ebd1abe08fa52b4942d866a4b6338f101ef134ea1255d9c42ff",9.917710196779964],[15136,"6a7239cc8ed0498b40b5f00c660e8dbeaf36994ef24812d8cce8f6272a5ff07b",9.654681381274475],[13767,"61ee477a91b271720308908b7d70492010fe6f84494643d89fda2c5c6600099a",10.052724077328646],[7383,"e7d0c70dc06ddfa9d0c57aae67773c8c2211f0a5973241a5d321b937f36088cf",9.917710196779964],[699,"b8d1ca9b68c8de5d7841665de589bbbab8a5f367356da84de62a60158f1f40fb",9.917710196779964],[17057,"67c49f1a27eba5cf27d2048c992b8b7b64c595bc6a15579f84b13bbf2b9fef50",10.052724077328646],[12063,"c990b101ce67c06568a3e92c76a80db344f9ea61203fddaf733a75eb70cee8b0",9.917710196779964],[6309,"0bd9c7e8e5d989c42bac739722fe447d188562f2a4c2eceb01f0006dd524f0d6",9.917710196779964],[18007,"39b23ca945d6a9944f6549fd727fc404957e5a4fe49ad5f968d6176c22cb133d",73.19778188539742],[5569,"6ecd1cf155da702bbb7cd6426b566b150b443a9bc50829e1200d4a702885cfdb",9.917710196779964],[9123,"964ab72fb8a25e3f7dfe3623d98deb1f1d0e82f6a2be8f88844124efcd8fffc3",9.917710196779964],[17128,"5e5e09f5fbdfa65c033ee78c21bad65010f1d8455d35c347c1500f532ed86e4f",9.317957166392093],[11918,"dfaf49e0b0f71f8b7fcd9773054df4f0f3751ad0c176dc96702abcc7f8ece5b1",9.917710196779964],[7246,"b4be06b7b6e1071c57e4801dfd2662f2da697d9948405ce9c1ce1f0618fd66d0",9.917710196779964],[6811,"62be37483d13716ebae3f7dc2814dc543c95111b781411a57823d05a900034d3",9.917710196779964],[13731,"d2a49e5c85203a39e70c01643987872f8b2de5d61df57dc50bc4b118c8edcc9a",9.317957166392093],[940,"cd28edcfe3e2edb6bca6b876c97329b2b0afbb01e3ca1d01a206629d49fc8cf9",9.917710196779964],[11729,"305aa1370c534e3cb5a65c970776f71383a9f88efa911b480668e107440e19b3",9.917710196779964],[18210,"7ed09e4bc6c7c0837b5b12c16e889b5862da915071656c74ee075d80f282d837",9.317957166392093],[10690,"5d363d21a8c693646966493359150f43eabd1be1217102068c23aec5109613ba",9.917710196779964],[11695,"ffb8923e61f69842f084904d408a155b8fdb298e9055de4aca6f4f1d2fb553b3",9.917710196779964],[16233,"51bc1628d6531e6bdf0bebf6a6547b8c0c8b0ab9a615aa9bc4e31fe869eff662",9.317957166392093],[15366,"ad9d5656df4d0da1ca7ca99c16d6bc3d3e962bc9a8d2b911a518edffbe140577",9.317957166392093],[5837,"9b23e6d0185453fd85c9ebee06a2d7bf6f48c37dce949c960e1d6550695019da",9.917710196779964],[17291,"9836e8d0efa38c4e0a59f5d044b522df47cb5daeb5614fec928abe45fc26644c",9.317957166392093],[7783,"5dcfbb594c89a798a8def86ea6d4909c5af6ec8832d34c41b4a768f3e04eebcc",9.917710196779964],[7854,"cfede7ef7e132aa5ea1f1062abc8cc0e22b94bb902ac84822d7cc18abba17dcc",9.917710196779964],[4227,"58e87106324ed75abf75dc81049bc5a31db4f1900fe849c4f1e661615f113fe4",10],[2946,"141d6801675b607850fea899d5eb97dc046337dd53d8105d31a0e1682b90b7ec",9.917710196779964],[2065,"7cf3742a83eeca36b9089d14d8ce42668c9ad22b3723597f070d3127d19975f2",9.917710196779964],[1858,"dfd1c0580fc3e8e9dc1b02b8417178fe47e7e8e5d8be74f7e9bc32ca608de2f3",9.317957166392093],[16203,"22658e6d30788a72d5ea9c8ecf157768578ba4251d6d5dccc15813187f6be163",9.317957166392093],[18375,"510cfecda327d7a9cd02ecc1013af8177a33a8e563f353c710513e3eb31f3334",9.317957166392093],[373,"858c070eab6f7b809b9187fe29e969e738658d64d0bc68653c5562ded1588efd",9.917710196779964],[2246,"a1cba7fa1ee92ab2ee759aafb455edf4ad3c87db7b28b46e1c8b869bf1ef45f1",9.917710196779964],[19599,"dc136d3682d5196d099c0b0f7c55623a0f0dfdd0001b55912f2e16b5776c100a",10.052724077328646],[19609,"000bb9244b045dc42e1e7a34beef6d9275ab5637f8341be4a23dba46697c8d09",9.317957166392093],[6689,"a5d7488702c7ddc2e505cd2beba6bb8f3c88d6924e5491a6779601e02dfb06d4",9.917710196779964],[16048,"7cbb72e74618ffd1b62745531511486a08835672a3b1cc65636261f893757567",15.94306049822064],[3783,"b9a923b212a2ede645e61686ee30eb7a41bb7ea6e0fe6dcf4f43a5298ccd0ee7",9.317957166392093],[1378,"57f5294a922dbfdb1a4be6e3a718df1f71e7b1c9cb0a8208f8d450676c48e3f6",9.917710196779964],[9179,"42c73d72d79d3b07e74842749628e9e43758e790dde550a90e999d03bac29dc3",9.917710196779964],[6473,"4abf0b4cdd819a8c34b6fa6d263bf019eebabf8bc4de6e0fdda3d1155c66a2d5",9.647446457990116],[3514,"a152e55fd9e9ac2fbb83a9def9f5c0cd015e7fd37415fef2369ea5a08bbde5e8",9.917710196779964],[16502,"d54161e6049a6bd4301db5a5f96a438c0ed4622c941c20e3a1d768991b6a2c5d",10.052724077328646],[18362,"d3e714aabdb3ea730d560fd86d3c1b0aab2bd3b509b33cb4c9b174b3ea877534",9.317957166392093],[5914,"74b7b0be67e4fa588aa1d273f863e4c7244b84af5cf1b1670210f46b6cd698d9",9.317957166392093],[19343,"dd93493a3e8e1ec87e8ef3223eb4765ed789a9c4505da9084d886d60971bc813",9.317957166392093],[2905,"a9a20c4e7fdbe10ffa80e8952c61375c3c1075ab8f5be6ce6fb8696c205017ed",9.917710196779964],[6145,"25f0796db918d7c7958d76a25354db552cb6625646a65ffb2e18a9cc6a1c2bd8",9.317957166392093],[192,"21eccc0df556fc504425282cc1bf5a435c492f25b05386e0f2f7d9152814bcfe",9.364928909952607],[277,"9f442bdf0b82e45f19a02da8cf34d2fd530a7434491a9eb3ebaab0f789a918fe",9.917710196779964],[14303,"8276ebf506ed125102bbfcbff9f9c7ebde427d3540ddaacba23bf2e71a89768d",27.796363636363637],[9247,"e3480409642e55b588618ffa45a4f46088711ffd75b33c52fc933c537f3b23c3",9.917710196779964],[8484,"099f008a98f949d4231e8b351e2d87e7151891982a40da46ed3ca6dcd20e1cc8",9.917710196779964],[8557,"98a32cba82c38eed267140e8630199595080686bdb16866c0e8a43257f17b0c7",9.317957166392093],[5044,"ab557fd4a92e6e3ab963f2d8dfd57627ff0363d1f9702a0b5b6a44e6d0bbeede",9.917710196779964],[2895,"55d994a25fcade595571d3f21beb29aed0724b2679b26fbbc67add5c45ea2bed",9.917710196779964],[11741,"b593173964a5bb76f0db08a0c426f0f296f44e2044b97fad48a88988b4d50db3",9.917710196779964],[3270,"d295a24be5bba33dfb31aa19a6cd83c4024a4543efe5a835f399480982d591ea",9.917710196779964],[4231,"4ac168797572fa2237cb09554be7310685c7f295fecb0cbd0f403cc6029b32e4",9.917710196779964],[11555,"8c6aa7a55a0af177a19976ec97d48ac12d73d5ab4209fc82f1ba4556b87332b4",28.111910471622704],[10776,"0f4649551f996102ed33808431d803bbdbdbf0a9482e8e3b1f087575268b73b9",9.917710196779964],[3286,"15692f2674c796335ecbf3602b313b4fe5f35aabe12fd268d825842e896e7eea",9.917710196779964],[6718,"5796f42850e269e3edde68a695fc7833c0f04f050899d1fee1e5b4b346c4d3d3",9.917710196779964],[9814,"9827aca5ff3487bbd5ded4b9d6f0b89288fff661e12b04134745abf9a91a8bbf",9.917710196779964],[14512,"ab6511769073d04020d6885b7d9e27e1723cb5d18c2b7c344263ddfa4e7fe288",10.028741985407915],[19038,"66ff17d690347742f0a452242980dc3af94c346e513abd06e12ca4ac36f5581f",18.201680672268907],[11038,"0b9de60d1f8e54120142bf83d559cfe8b803ad3f0d705381a7ef20b524b7cab7",9.317957166392093],[12042,"888981eeacd0247837b604cafab1a73025193a113aaff299de719e9fcf4609b1",9.917710196779964],[4555,"a0ef9f91cbe841baee84c639bde428a1ace277e05756685c849dc3ed671af0e1",9.917710196779964],[3183,"3e8c55ddfe1e7395bba65fd43ac8b2b149861ce442f2a01dff22c927191c21eb",9.917710196779964],[8748,"907ba9413324ad2303834883e320b5ffa97fce2dfac0bbd7e5c893faa25c67c6",9.917710196779964],[3687,"b8da57568c936ab9eabb85a0ae3800122890dd0674e319386ea727080892b2e7",9.917710196779964],[10400,"21262c7ef05195c4d3912e57c8b23b6c26a49c947ca438ea00cf2b03ce64cbbb",9.317957166392093],[8965,"4c6477d9dc90c5b695cdfdcd54e19b3bc99198870dbf9a84cd5129d6b6ce0bc5",9.917710196779964],[10657,"cf1cce6e78b2a8a1ec154d606b24b271bbea0bfb5f79d705cd6a4c16469c4fba",9.317957166392093],[12729,"c73d52abc20cf3a5e7bfaf75be82319e4c4a0660eafefbe2c0ceb05ece8467ac",9.917710196779964],[3051,"0598f045dfa840ffbd9326463391ef1d66c6f03aad9ef7dee6e357e9cbdffaeb",9.917710196779964],[12668,"28a5f3a04f4097fd38ae398c69f6b4cc1662a095dccd1a736c7d03601744d0ac",9.917710196779964],[1853,"200b3bef45e565a0e62d98d9af8268e279d6f58a4c8453145ba869f34369ecf3",9.917710196779964],[12939,"988236a3f3a9dd0d2224a05bc5e5af6f6c8b603e1526f8072d28f19299affeaa",9.317957166392093],[13395,"e5049aad3224c3aceddd494852770de2a94b1c68583e9b93ab30762e7a6c61a2",9.317957166392093],[9677,"0d43a583877b28bba48ab6bd1a810add05026eb117e0dfc0dfe1b0f1d8f68ac0",9.917710196779964],[7922,"886c33b0d1c38451bf5f0fa3fbed7ca065613853b7332d4076c50ec2046917cc",19.964412811387902],[524,"db049d495c03cc9df148b8ee1bf35cd168ec538c578785c7da34b007c7d47efc",40.64262295081967],[3647,"3c0b462b3e3d85c94932784c8fd5def3b8286fff179ff749b398ba22f755f9e7",9.917710196779964],[2202,"afb56f6cde97c9f638109bbbd4a9f9a5992b6d84db1ee6abb95472284aae85f1",9.317957166392093],[17947,"4a4b0ad31e126cceb0a40fe55847fbdac8d5bcb7455071076c8f258165fb4e3e",9.317957166392093],[13657,"0ee2ecb654849606a4e6298f9b19f4a0cf1ba6512198e1a18151a5b5dcdc149c",9.317957166392093],[1823,"c67a2c2b362a018e477eda41629f10ddac6e80485632bec5947fcb07879016f4",10.022779043280183],[2924,"33b8f2cb33d32d41c17e2d8b6bd028ba88572d3a7c80132114f48cb81b07e8ec",9.917710196779964],[7758,"604f5b27595ef999378c35ebfc5c991b7ea1f661aedcf440dbb2e669dc7f13cd",9.917710196779964],[14137,"d432d2133dd529db9ffc9eea1191e8f1adf63f631f3104dbd01aad58c556c391",9.317957166392093],[7317,"da9502c15c2a7119276452ce61cb6d43986c72cd7189b9b4cd54fbf9036bf7cf",9.647446457990116],[19596,"64f501d7f132a46e65a60b2e2ae02ad86d90eb5bdd2c4851397439d7081f420a",9.317957166392093],[3972,"c9f323bb12faea5d380007b958300e35d0c7a518a3bf9452b8cd54c8860ce8e5",9.917710196779964],[8505,"37c6ec13de912f02e952a1037541e7dacb5949b572f823453bff93b941ddfec7",9.917710196779964],[1486,"ef0bdc8ab265929d3c4355809a99214a4ea09922f0017a692ed698086dfc36f6",9.917710196779964],[12801,"8dbf6f69627dee623418b943667cdd86e086712ef907798d098ef6917080ecab",9.917710196779964],[12790,"f688474322f394687a356e8c946bf86797f463690109dccd7dc201d727a6f8ab",9.917710196779964],[18587,"fddf595deb9e8bf4cf59bee9cbcf710734b67b898f9acb5f6d032db57989392f",14.188034188034187],[14220,"25a524cc255a3148182e48218cda6e3c20e15581c07a5927085c21d792c8a98f",9.317957166392093],[5267,"e414c01ceb41f1a917dbe1e723d73ea2fc06ca37741b504ee13b9de22eff94dd",9.917710196779964],[9223,"0828247fdcdde10511e52f3225187c25a74631406e366034342ad17b4f1e53c3",9.917710196779964],[16562,"efc4b0574e6249ce3fbc67e22faa3b966f26720a94ef09ded96297950ed7da5b",11.048175182481751],[12362,"537af3b090fb554269e1e9fedcdb018ceee6ebcf8f6a656c4613964f4262d6ae",9.317957166392093],[798,"d8a2db0b5aba8dcc0aa0c33b4d7771b5d58ee282c6e24d36bf052ab1d69b8bfa",9.917710196779964],[13705,"b449566d5ebea9ec2323e727ccd9ad6f5f22b6a43b0af5f2d22af7b588d33d9b",10.00349040139616],[19755,"46e5f5e1d9e7ce6a5227168b38b98873c47ca42fcec762940b4053b817748504",9.317957166392093],[3254,"959d7074b9f600ea6d66ada01ee28ef7ff845053370fb4663a479d3c3415a5ea",9.917710196779964],[1843,"6891805333b94a64f4eca1d8cd912786fa015eaa12c63b852f5e3cc265a1f3f3",9.917710196779964],[6026,"c106f09ea3850ad1940aaac7658ebf810abc90d799d723ee35716a40f78ce2d8",39.20855614973262],[6308,"c901b48e7d23875142001f93d204995a5a50b12d18848a091dad80a7cb26f1d6",9.647446457990116],[726,"c35c7e16275c543776bd69d61cf3ad7a9d8f06fb0c6d48abbcffc6845b260afb",9.917710196779964],[11947,"16b047541f2d9e1560dd765b1c97684cf1f5cffd7fab2d0d61355d9cfe0aa9b1",9.437070938215102],[6392,"f7157a9468300ab07b2256269a5c974cedff4261ddad798df1e8e03b8ae161d6",9.917710196779964],[3768,"eb1493ef529370d333bf037388e7a3f18b15dac9d9806af93273adc0d37c29e7",9.917710196779964],[15056,"ba29040c4341c39cbd321a204380c298f64f116ba670464b7dc588fda3c46e7d",9.317957166392093],[11366,"594c2173dd6a361b1b7b3f7e4a592df5f2c919408f42cd19054730a7da5399b5",9.917710196779964],[19037,"31bfcdc52c451a865678cf0c5e04f36d518b80f585b0ab9a347257eb62fc611f",28],[1733,"10d0dd35c929c121a761923a1b7ef52be01dc1e2df272eb4a9ea4e38d33db2f4",9.917710196779964],[18567,"d7c6859aaa3a3e3595b7981fbe3483c11b9e7e8ac19d081aec37f2705afbfb2f",9.317957166392093],[13232,"25e4818059acd4b2e502fbae2de0754b38f986d1cb244809da596b5bafaf44a6",17.99859254046446],[7793,"b201a0305637a873168a16ac7dade43582f3f04ad8f271dc6a89c5a1167dd9cc",9.917710196779964],[8311,"402ec4169b44aa445390f6e3ebedd60f6308a367138639818cee0471d24b41c9",9.917710196779964],[8498,"d4ff458cecb11d8da7115c5108e3e99516df755645a7d9621d0d84b6cb5808c8",9.317957166392093],[13738,"02e3b41930b6d396b7e276e727882db08af378b4f764779df93c4c3ce392b69a",9.317957166392093],[6935,"0b9520e3497a3d86d6d015eb2b3bf82935fde90c93e9a7602ceab3840c6967d2",9.917710196779964],[119,"1db8180254d922ac2af2329750e85f39bb4d08adc9c272c90b8dc5edca8743ff",9.917710196779964],[15011,"79d6c6ca4eb6f16fc2c170701fdb2ba62976825a61024164fdd512ad47351c7e",14.188948306595366],[11655,"5bcb76e2c7fbb132d42c05f2b4cd280ea7572ea2ced4c653361487b037d990b3",9.917710196779964],[4786,"3c28bfd079ee964d6a9084eb1fa96509108525cc17bbbd6c35ad8482117480e0",9.317957166392093],[671,"a4f718128e1517fb4d0bf53b101a44dc41eb321af7522cefc7edcb5a4e966dfb",9.917710196779964],[15798,"65c037a84e7259ccb570a478d8237798bb187b97fc399d80a418c7236438636d",9.317957166392093],[12624,"6a79757797e5b18edf03391e3d171fb996552b76c727ecfecdce8722c4a21ead",9.917710196779964],[8739,"d3447eced93515b15eb0cb5f9c26b968e0a98c4b632181b173047812d38677c6",9.917710196779964],[16073,"550bba2210907642504dcd8b10421719ce43b4d6288f38b0e8a7e37bc341c166",9.317957166392093],[6877,"ad9819c9989eace3dd6af41eb42f01d27cf51058998158d81b63bf5c5f45c4d2",9.917710196779964],[14231,"f10eed4db81b246689212670be8141ebc9cd6433df13b26b6b1e1f18ae34718f",9.985072827911031],[7135,"c249506ed783057be601d9be40aaa41931ace1abb0db5e001582c7471c491bd1",9.317957166392093],[12520,"cadbb8907db5681d48bbad9c53cefa3c5068c59e8270a1db95dbd39107a9d5ad",9.917710196779964],[11012,"66083da8f9d950963892a26c873710c9c3e795303ea17c10556fc23aab8cecb7",9.917710196779964],[17245,"c67509bccf41c20be4f66b739a9e27326da1f3812bb71b15dc940fa60a5b0d4d",9.317957166392093],[12306,"3451d95e1942d0385b8e4cee8031bbab23264f30aa33fbf7d1715d4c806330af",9.317957166392093],[1576,"12e2acf7ff91c54a8fbce9b666e78c65795a7804c56802828ace166d86e7abf5",9.317957166392093],[18610,"f4875b5c64af36bf162887f78e60f2516f19486cbbdeb7575b0f86eca4bb5a2e",20.07168458781362],[13607,"132ab20264465aca8cfa9ee6fbe1a08f7533360714fdcb8231925490ed7f4a9d",26.124401913875598],[13483,"55eabcd38f2e7c8231ecee6094f6d0a2757fdb212844028b9e955741739e3ca0",38.87414187643021],[9007,"582fd2a557e555607059646de3d40e8c0edc4f4e175dbab521ad8dda8beebfc4",9.917710196779964],[1017,"0541ea1d2f04ab5ff832d936a0fb0631ced33cb16e3148f09786b3752b2e1ff9",9.917710196779964],[15218,"f7b34293d6ba53686d49ae3e11822312e60aedd00da7709ec387e282090d1f7a",9.317957166392093],[19168,"e8f10ca3de011d355ea91196b63d348f57cd53f2a61a48d2ef9a204d5d0fde19",9.317957166392093],[18441,"554aa03fbdce1b9e2be06c284cb531f22a3530ac7132e25e7db38255a260d632",9.317957166392093],[11943,"cc70efad125045dfd2b6dd1cd52f8111ed73718f8e181b60b2db60c2369eb3b1",9.917710196779964],[587,"60b65e5eb9ef0eef3ebc623b8ecad19a532d2ad48a410521fe3fc070393301fc",9.917710196779964],[17663,"e0b2f305158481f8c0478fe8482e2a5b4d5c52cee963fbbf801ac8e45e20de43",9.317957166392093],[3955,"1f33e32a91d96ed38a56c078a4115e434b22eea8fe4e737391eea87ad81ff9e5",9.917710196779964],[15859,"6cc555ab78afa572c5f336b7ea98cdab42c8b5b77647125dcc7be2a26d16fd6b",10],[9857,"9cb2c3d84b683bfef9710e51e3412b4999fd863c2e9f5c9b31c641be9a563cbf",9.946524064171124],[12834,"8fe1e8a310f100b45782a2d7d43b15afb7bd2b29bb5f3f4de870e3fcc5feb6ab",9.917710196779964],[5193,"9d292ece3a7d05513377b2f37c5b28c8ef8e6fc77632c08f1f431191fcb606de",9.317957166392093],[16175,"6db7db9422b3824cd0aadb51e2df86a2f4687861c9e0c96d9a7cc1dcb6c77c64",9.317957166392093],[11503,"f3d1165bf7e10d95b35b6e72d146106102f3cecc3f9b732ae36653a3be6f7cb4",9.917710196779964],[2401,"5a07336a2ce67175b9202d01868aa4e8b0c3017d1f2979e8e0e00229dd0c79f0",9.917710196779964],[18786,"ff96eab4a7dd3413b1d628d5c0a426ab1d765ef3b4381ab5591f40c955798627",9.317957166392093],[15118,"d5ade69103b72f3c1a38baa7dc35a3755e60c5ac3aa76b4dc86d5d171eca517c",9.317957166392093],[8491,"fcf731ea5009a23e526789835932d2d2adfd1df46f7736971ef0050de27b11c8",9.917710196779964],[6536,"ae543056ce4c39227af2617fd24154c96b5bbb4e56c364f8db4f45e19bfa25d5",9.917710196779964],[19320,"7e015ba1aea2a33f2f54701a3b362644858e1349f979b937eadac1042f0b5214",9.647446457990116],[13099,"696c2de1064afe9fc8670d768c81f25c2af0f4629386c27133221bb1e0ac52a9",9.65680473372781],[3285,"be65c09bf91fbfba95c1dda7f98f5f37ccc2e3459520332199ad11310c4280ea",9.917710196779964],[13917,"5275a9fd4cbba881fdd78875d9188df8b49e7fa4916fd07c35edcbc88318a796",9.317957166392093],[5800,"85f375e813c81b0ba3b1b2e193eb574542a62b36a41ba07b07e65271f8f76eda",9.317957166392093],[9755,"f0002a9c752fa5452ba7ae6fd3c3796ac008f479f7b5f4fd45ed7c7ce565f9bf",9.917710196779964],[948,"73b8b973d28fa7e14bc6af87b7c32c1d60b4c76b9ffb84386f2350b04d3b83f9",9.917710196779964],[16690,"362b47ba04669e1a88670eb0bc33cb172726e08a615f7334dde59c8e413eba58",9.317957166392093],[6050,"2ce52428e3458fb0a50828002882f5201bdf3eafa4eef9e9fc12de54ef47c0d8",9.917710196779964],[18988,"b1012c22c4d6d638ec9b5df68b9446193eae4a78afd2cce6112126e7b2b6f920",9.317957166392093],[7939,"aae1254360d01a42d6ffda5eadce7ff74c3c80b5c197336f1f0a4a75008bf2cb",9.317957166392093],[10934,"4ebd1676c0b13bbe4e9fa6c18a812bfcd537b5b266cda0bb07cca072df857ab8",25.60096153846154],[9389,"ef59338b5e1c98d8f64fe804ee48e3e4f27ddb4e1930dcdc5aae6bd99f2c57c2",9.917710196779964],[15947,"02fc55e82026116eadb6c154c4d3809c6d4e879d395585b7dabc8d5d3038fd69",9.317957166392093],[16719,"c16bad1edb37460b5baf45cc6f1f11c765bc0f969f875b02032e454e8bd41d58",9.317957166392093],[8122,"ba45c63386823818991a906e7a118e9a63a7c0db44cb0def1ead35d79a3e9cca",9.917710196779964],[17708,"938071b631d6feac7f685f56be568d4127913a555ed0b33dffb3f006e6c71643",9.317957166392093],[638,"73e425cb2e4513709dfaee8bdd54bd6309375efd168d4350bc2610f1e71ca9fb",9.917710196779964],[11869,"18dc19425c8bba04e48b7c3c8d110d868dd0cdf776b2c41dc4a84e4cf36242b2",9.917710196779964],[1605,"4fc38672eafe362b70cf78d9f84e8aec0e946970d4d325995e71380f1e7387f5",9.317957166392093],[12211,"e7dd63ba1c22667eb1c5d17178ae625a8d794250263673dde861677727e005b0",9.317957166392093],[3359,"ddd05c22c943195eb236b75ce05340cd6422da94920f0737c0350c9f5660fae9",9.317957166392093],[5451,"83227105c8ea18421802df345c90673d7aeea6808ddf8e22f555b4659c7a79dc",9.917710196779964],[12047,"247877c2aa924774633e1260a5b3b151e5c5ff6288f3d4072915ce7a335700b1",9.917710196779964],[164,"774213ebcb5c21275d026b1453df6c3a48def2c8a39f5eec74afa8d50730e7fe",9.647446457990116],[1428,"6b3b11a8f473df7159fe96f915181193e76586ec10335a66c083c0a9495ea8f6",9.917710196779964],[6267,"f93b2f610781824e61bd1c83269062d7aed2e136a380e83e7ea33cadd74f4bd7",9.917710196779964],[6638,"2ec47c46e95bd43bdd7cc72656d0280a863fd4a0da40d9f05e0ab9f7058d68d4",9.917710196779964],[10046,"9d4771f01b13ef5a8a8b982fee4e9431494452af1969fcf7f0070a32dcdf13be",9.917710196779964],[3579,"a49d849adb2e4fe5fabc7d26c5ddd0690d4150f9f367acc82cd2d928058271e8",9.917710196779964],[13632,"35836eff5ab72cb1ea6035150269b68087fafec36d2e0a8250a7f60b4f4fa69c",9.317957166392093],[175,"0ee16fcf2ba3c50d631eacedd7db223f0af9e8cbb8dfd91bb02fc028566ed4fe",9.917710196779964],[19405,"2ada6a65270f7c87bdcd4fc99e0bc7a3ca77aacfaa885d3ead90a4cd2aec4711",9.317957166392093],[15144,"c11c6089da18cddfe6435547811c54374563d5516d3052813b74b90dbc81a37b",9.317957166392093],[9241,"b9bbb3b7abb61c1fffff9e95bc98779e8c1596fd9e877994a6871831cd632cc3",9.917710196779964],[12876,"763bb49a290d175faa1762faf8a1a492cc934cb8e7d174b1840f5fe7b5496bab",9.917710196779964],[3521,"ca90f37c28da088438f4e441c9f0b9914d9d9800d94be351c3da85c2c7acd5e8",9.317957166392093],[12398,"cca671ea6923ba385cb4a229178099aeb17d416e3bace27e54c7b08141919fae",9.917710196779964],[6952,"34fa0276b381447d77f36ce8ce2e9c5b00df4733223405db7048449b7f033fd2",9.917710196779964],[10402,"3d095a0d2ba3ab4bbe92ed91357e9e19b97f7e45b2cad79cc2cd42c4a510c7bb",15.94319526627219],[9974,"70be1f0989c30d768f74506512463269a1838c34931f48a550f5c0aa0d5c7abe",9.917710196779964],[9903,"ee92c85e4a8380e1d84134a684a8e3661a92cef5d340cb441e85845ae8e2ebbe",9.917710196779964],[4028,"d9e30b3e6dafe33699ada7db2b54e8195a63bd6d6063ccd90bf7b3a01fec93e5",9.317957166392093],[3424,"4eb953b19bb97b94b307a8b2a228a6212e808de9567bae686b1adf8d86da7fe9",9.317957166392093],[88,"77094634d9b1fb42ff2bf13cf52e223bd0f171086ce3cb63aafa5f8bf07f6dff",9.917710196779964],[17109,"ba4df45b410fd1d988ceec544174f22ff97b31a3efa7be1388ab6a978917cb4f",10.052724077328646],[4359,"3dc667e0d480632b48d129eddf6dee26e1ca5b0acc68eacce75d705730625be3",9.917710196779964],[17631,"236dc9f97ff3b74285e5b7a0920d9311ea06a39f1d12c2f80f10dfa3fcf59c44",27.558333333333334],[7647,"2eb17a765c74d2d93123b6cc8c491e4c09d561e50c7ded15c96fdf9f13d0e9cd",9.917710196779964],[1151,"55854e0edfd31381b52a783761c545586b0852aada0b21d105a73d4776d14ff8",9.917710196779964],[16595,"cc3dfc427e769652bc55bcdeabcf155997c3150f3ea1c71b01d7c3dcad77ff5a",26.863741339491916],[2628,"30df1f962179fbf1a1f7a6132ae8ea3ef96e3b7f84aa727cf53f61a4b0ec02ef",9.917710196779964],[14521,"12c6b948230c0a150965391d0f9cd551e711881235b9d01ca0594cebbb57c488",9.317957166392093],[7533,"1efc3ca6da749bc910b567d3136152488b2e742a0a0f2271d0eb95e9a59c96ce",9.917710196779964],[8302,"93019d23fce2ad3e25aedf3678e9a450443757ba770cea7b7e7cf8ac25ce52c9",9.317957166392093],[4365,"aa4727e5f26b0aaeb55bdfa7c11c7e0fbb4fa9beedf994b93c8a66d14cae4ee3",9.917710196779964],[6415,"21af0ccb44da96e8b6f9651226b18bced2214ce8e4cf051017bc3d78634e3ad6",9.917710196779964],[3699,"e881c6c81d49972e2b93270fe0582deb1e7f51c0dd2a4634502f8c1b661299e7",9.917710196779964],[15818,"ec9b59185765c621059ebbc9ce94509c6680fc1698b835cb6c2cf89e1293096d",9.317957166392093],[1723,"df5604ebc001e4c57bba576b10de33326e9ff05516381ae7433704dfa8cac7f4",9.317957166392093],[13026,"7dbd861de6d49b41c8c123656b00143a344b486213b5a52d3339e9a3f72d6daa",9.917710196779964],[2931,"8d43bd243fc804b2540747d18ac4ceee5d24e581372b4f578f0fd1e7e0afd4ec",9.317957166392093],[7053,"9fafc866d4ffe92f8baed5e8ff114b8479e99cd42a4701ddc5576843c4cca5d1",9.917710196779964],[18304,"e9771ef5bb8d018e577b5c308e70aa565114d63ff0cfaf1db373f31b7ee3c435",9.317957166392093],[3974,"1fb90777bbcda1a58a932e5171823e00d6144ab31e8a725bf68907d708c0e6e5",9.317957166392093],[1746,"cb2c63448bb3e56efcaf24fed6827a6e84bfc5fe766d6842758f3110dc32a3f4",27.900178253119428],[17621,"cd1e244ed3ed1b61ed0f1c462b4bd46cc1fcdfa9bb8fa60fc237a8a4ae02d744",9.317957166392093],[2938,"d01fbba8279fd1f4817560cbd110b3467b7bd3c2bfe4e8bcb3941ab51d72c1ec",9.917710196779964],[13734,"e620a5868892403a85d35af77047ba5b3aa7e9b7125a8d9d414085d22990ca9a",9.317957166392093],[9904,"84a68c4fbb5dd2c63d3554aff2cc46dc3d2a413b361dfbeb124789659208ebbe",9.917710196779964],[4111,"8ea72461cf74da944914ea2fb9f43493426548b149c4a1cb82a2b5b8f486f7e4",9.917710196779964],[5419,"eeb7e617b24b4b921f192dc6ee7cab61d49c7e22b3d5a99e648a9fa7f8abafdc",9.917710196779964],[1515,"621dd238913988acd78d633da24c44f00d8f7f71ea8e6f0024536dd04cd000f6",9.917710196779964],[357,"5328a42b7e982d8b54f7e3558a6d96ac0dadbbbec7b53b9d8666c5315c2ab4fd",9.917710196779964],[3110,"a965f59c9f463f54c02a8d98de280a4d7a8a051fa447c23ecde922902b2699eb",9.317957166392093],[7991,"c405e813f85cca1d3975a6d3dbef4466a74084bb8c846aa03a4ee0704b4993cb",9.317957166392093],[11878,"7a5e47aa7da2d83bdf97c45de7886dac0b14f043b866722e0ac4670d8aaa32b2",9.917710196779964],[14627,"86b1c6dfb2ff2e15fc903cd2d6914c46ed7aee59925d7878e0064397bcd57a86",9.317957166392093],[14766,"af56b9b4b63640dcd1dbee2d0f056541e8204ce6f0a7a761fb9e0d1b34e59783",9.317957166392093],[469,"97ccb74da378e2338db62db4d60727a1c8e032ad0267b2d91a3a04beb192d8fc",9.917710196779964],[15617,"b2f40d83ed24040a91a2b355986d1f86e30c52f0614289ff8651b4a6369b0c71",9.317957166392093],[1738,"426f0271daf55f718ff80e46f4cdf83829050db7bb748ca1db135b8a8f8ea9f4",9.317957166392093],[6520,"172e4f3adb1c1f3c5623b2ef0a748c0ef7dae8ab8846fa95ca50017f9f6d45d5",9.917710196779964],[14216,"79d52e06b6544d101496383a3cb343c4550f816eb499d86ad826c03581e3bd8f",255.38020086083213],[17666,"e5fac9ac9d5cc316ac15ea42367333a4870c4639fdf2a85af455e1b382cbd643",9.317957166392093],[19668,"3ce3e99c0e76c024dce96fc16a8c9e2183db0d679d01ffe5a73fa94feb3b9007",9.317957166392093],[3870,"5349472ec06fff2938594e68283fab20992eb53f3bdae8a4b0b37969ae988ee6",9.917710196779964],[19670,"2c4179a77ad847c5aeaf2fdd1516f21703b4c903cd43f8f612f751ec00d98d07",25],[13986,"80ff145856701007b151c88da0ef3caff58ca0ef1e405e4a9f8a8dc391cf3c95",9.317957166392093],[10114,"e554d9aa04c565716df518f80b8f369ccde4b307bbefc1b15b015ded71939bbd",9.917710196779964],[16561,"c47e1dc2551dfff6c54745ef839c90e6274cdfc0721f8723b72e2f2c4723df5b",9.317957166392093],[6032,"92be754ceb573d8187c92f962d877c90e9b82aa295a5cd737f0572af57b4dad8",9.317957166392093],[6284,"2bef2d0e11d0f08a11a1cf0267e0ef59f9e1207bf967915e85ed56add80d2ed7",9.917710196779964],[15085,"2487c28f671853391fa819474bcef0c408a5c643933dea93d4747cced88df27c",9.317957166392093],[12389,"7bf5fdd0d028a1fbaf70ae1dca04af6ce77d0c2f3ddbff28eef1e2890e62b4ae",9.317957166392093],[8187,"4ef9c3ccfbf536677eda98745e6029efa3191d45efd208d16981710baed813ca",9.917710196779964],[7057,"1c4a4164c724006de31fa6a8f54c1fabe80bdd65391857423c2d5f16b93e9dd1",9.917710196779964],[14408,"c3274549a3603d1770fdce2dcb20cee1ad0943fa7516b7473f38a99632be288b",9.317957166392093],[13335,"6c172e6123aafbc0633ffb072ecd63efc2ea3cfeaf3dd2f4acc05858c3d4f9a3",9.317957166392093],[1130,"6f73c4d9f65d2e82d9b24889eb51555ba9799369393007d98c6e4986606d67f8",9.917710196779964],[4362,"c07b738c143d94082795b17e1720ef907a72128bc608e97850105e94985f56e3",9.317957166392093],[18711,"fc898d1fa8b305893a070e7a2ff41d7c53dcbd0c3adc5ebda7f9c49eaa98dc29",9.317957166392093],[11616,"b0a6da695651b7828a5318fc977b59e2497233b4f27ec625bc53978376dccbb3",9.317957166392093],[6753,"6fb79b5a277b30a5fdfa050c566989935232f44cbd5445630ba90672bf3592d3",9.917710196779964],[8195,"23734243801d500283f15ef8651f817e024dc30da909029ff552e20a379b02ca",9.917710196779964],[6059,"3f026062be82e2b019a973758bc4cde9e1c721983505d38220bc70d7c34eb6d8",9.917710196779964],[2347,"6ff66deb2049a5ac885e31542a3f8a36ef3e8f542c0ac27ae1f0d842ea7dc1f0",9.917710196779964],[16109,"5ca3c17e92a25fa23a3a239010a7292cec385675e6b8e53e157b8e7efe07d365",9.317957166392093],[8615,"bacef0c79fa63ead9ff0eb0019d6cd584ad8a8e5d30c981684656b2a05e854c7",9.917710196779964],[19866,"59c0a488bf816d6976d2691a1fa43271efb9e768b5ba850b48c91979dbc24800",9.317957166392093],[6082,"ff07662a5393e00381df4c0ab6941c54d4c1d3f48dceb62dd2c243c13ea17fd8",9.317957166392093],[7908,"5d7b8374af6e32e05635658433b8309015fae3f04e1681568fcfe5e1b5e72fcc",9.317957166392093],[15408,"ab38556bf7816e7195294e0f9f2b312753cd89a0bf280a0b6bf2a4d6ea5e0e76",9.317957166392093],[3217,"62a5f7ab099b17a5e1f1fcd8782445e673c68e9552d0b5b5e7e9dc0ffd03f5ea",9.917710196779964],[10807,"4bf14cc7a049ac0c4e4d051324740c48e85cbaddae9ea36095267b2ee9cd42b9",9.917710196779964],[4633,"3777b512f87b1f18b73765841be4bcd97a95f606c8d4706d6bfa9e9db4486be1",9.317957166392093],[4361,"20b6e662f1c1b8ed5eebfef385d2f13862ced99bff9cc944ade78f18759a56e3",9.917710196779964],[509,"6853ccf1339f894041a9d483ab2b490ae9ce3acb31b2f1b89d215798e2dc9efc",9.317957166392093],[4980,"372b6bfe61ba24fae5e240e9bf86565f0565cc17a4152c21a1b60f0ec05d51df",9.917710196779964],[2643,"fbef29938fa8aef923e95dbbd602be58cb42ef96074cd1e8e01c2c46f9e1e1ee",9.917710196779964],[16399,"ab639b92678c2236f4774595e8509f08a7294466f9c20fc46326df89e069255f",9.317957166392093],[604,"be4f451deb0e70e67058316305b5ceb997af0ecff3bdca7f424d60878e13e8fb",9.917710196779964],[13723,"d3d6ef2c57eee4ddf91c7f705bf4c50ffbd5686ef97c17f4262123aa4c17e99a",9.317957166392093],[6612,"aa00002ba820e826125e0ab287bf86435b3618095b4f20a9d6c8a697ac2e90d4",10],[14942,"7ab90d5813eed8000afa1015bf37a2ff7077357b501887590b5eb09c36e7fd7f",25],[5903,"34b31da2cb2568f1a74d03a3e24e17fcc7bee82aa1c000bc4b3a68e70d8bafd9",9.917710196779964],[17316,"856e31f66751d0b2066366131a56c8b9334cd5832cc53d1f929ec36a4d0a994b",9.317957166392093],[5526,"c28cbd6c7ae77282c2f080d42af2e3eb0119f832757243c6e637848912280fdc",9.317957166392093],[12746,"d04641b0227e1bb2f47aa188c2fd600859af6c356538efde8ec1e94a8a6744ac",9.917710196779964],[16386,"3ea125f3d382d36620dba554008cb670b87faf024ac27d4152c5aa37ee645b5f",15.003322259136212],[15116,"e23ed0036c464b46cf62d2be9b56615f424f5cd6e9b4a24ca6e1c081597d577c",9.317957166392093],[18148,"49746e7466f34551dc69666df0db6eefdeb3022726ee0ee9b57c884be86d7a39",9.317957166392093],[10693,"dc4e2d5313dd71bdf79511c9d1dabe4ff794741c87892b45a80f4f92feb60aba",9.917710196779964],[17966,"5cce0cb66b167c65f03cd701244051eecb3aa9fee4b03bf5c24d8e9859a6d03d",14.864253393665159],[9402,"b5ef7cbea417291988b93835885872c5521f7cb84c23167b8e50397c23b844c2",9.917710196779964],[2381,"657e136c45bb1ecfe76e64164b42ae057d25d4ec633f4f44b0bffaebaf768ff0",9.917710196779964],[7692,"8b818b833eab3fc9d3b576f17880a547295091b753e6cfd864e2aa597d9c9acd",9.917710196779964],[16003,"cd5bee60699870f9e5d2651b35fe3b193005e1ec8fa960f7b6df18c16a496f68",9.317957166392093],[16495,"b5a7ecba16a4f13cf2c876e2ed58d75d92d37dac41d2a8af3c7e5f62a848525d",9.317957166392093],[16727,"b7453e7c509acfb5be1bfee2dd526069bdc9228cc9538ed6c9e0aeb6d6d0e457",9.317957166392093],[12062,"77237673e7fc9c457ff8eb15010da94bd3275cf8dd421a6746c28f549000eeb0",9.317957166392093],[18716,"9382cc71fed46bdd2092a03d26c861731fd2f624f66090897f5a533836b6c129",28.09964412811388],[1267,"15a6e55b69980a26aea35615d5d74cc8af1af5c7e2e0aec25f3e4b214f3090f7",9.317957166392093],[17474,"45e0f0c7b7be84f2452d622c0391f90d4bddfac417b0e41ba5d903fe2adb3148",19.532327586206897],[11013,"44515131d9fd812f6b3f8711aae44edb4194e18218f1a70cb627905012a3eab7",9.317957166392093],[2482,"2fa5b58380c4ce1832e5fa61ac56da041d060eb6e5aac6e3d9819ed04bebf6ef",28.187082405345212],[8074,"002f4339f4895e9db138fae13af6515ad0a2119df8905936315b12f6e07cf1ca",9.317957166392093],[11447,"b00b3bf16c28b820c44dc99f54851fef03cfe1db669a8f8fcf4ee50834d8f5b4",9.917710196779964],[5239,"3d1f3a37aac0629edf42580a84a0148d82636c55ac3f7d306480b765a72fc0dd",9.917710196779964],[10535,"e294128e357a9e7c1f110bc0d422a6f60a65e80d6f9c21fb413f83b670d2f8ba",9.317957166392093],[12326,"fd3eb231942dadd6f6ace4358a7d19190c6a1da2f6b757ef0cc13de3599d0daf",9.317957166392093],[5925,"145bc5e7500b8f6bf5ff63f85189ea9511b16b7384a0edd5aa06fe7576b987d9",9.317957166392093],[8294,"b880dcb4ef51456434c0be7d25622cd1374961fa239684baf421d1b731d25ac9",9.917710196779964],[1049,"7275c3c66c44819ccfbc00584615ad72e02b8273091a4498cc61b8ab6942f5f8",9.317957166392093],[14199,"c5b47631ead8c7ca750cdfdbcc3940ad366cc986f0f1ca286ddfe5d32b864090",9.317957166392093],[16912,"336054982f54ae17b2d8c79c935709080626061a6d262e96133f1d68eeabd553",9.317957166392093],[10083,"0c39b317633b1cb73826a867dcc905af8cf9ea4dc951f8abc40d8c620ea9cfbd",32.78872983412861],[2344,"3e3708b0de00e533053c79adf1b60c273f264044a81baf4a3f84d2611b19c5f0",9.317957166392093],[11280,"8e453c986b34b31cf70d35e20ced271f07247c95dd530758ccfae56794ba2bb6",9.917710196779964],[3612,"abcc53591003a035bd097918c52df4efa6737b5bc4bfffb4e24f9a33c5ea26e8",9.917710196779964],[16621,"212ad58cfe1cbcfd8b9c6ada41283d8f515a2f1bf4ce5457cc6af569f6886a5a",9.317957166392093],[10909,"73094e76bb678244e930a3798e6601b8c33072fdc0511f8f4a6f2b0498ea9cb8",9.917710196779964],[5736,"8666d077e585910370628897c7a13c4c98f3b708ff0bc00180a520db7d42d7da",9.917710196779964],[6977,"a9a0ffb94a764f5258dea077514e3182e9f831a123c72ab3b357ae9f596620d2",9.317957166392093],[4705,"05da750c489ccfb1864f8474e1a5f42820ff62c33ef26f0041e6730a920cf8e0",9.647446457990116],[7943,"8b4c52fffdb95bb93e839134d0c6b6f15523d82d2497a5250aaf199d7a24efcb",9.917710196779964],[10214,"440d97c3277f127ebb66ff2b075fd30e157a3285d6ed29069da2ac996eabe0bc",9.917710196779964],[10098,"1797a49d5270fd7661ba1a01490d617af766fc15cb57c2f5c768c1766548b9bd",9.317957166392093],[7484,"78111a277df781c1a26d4af11170a3a7892eadf45da6a5ee381ffeef3db0cfce",26.13903743315508],[8358,"dd762dea2587a97ea0971d338c3b6fc3c65b1bdfc5c7c0ccf2f307f1b839ebc8",9.917710196779964],[5847,"268e194df80f289ff61a00cda9449702d409911bfcb9a4036559db41bd6c06da",9.317957166392093],[6896,"5d8a729175becaf165a1e48ce38bb82d61c1d9a0496e085f43f40b238378a3d2",9.317957166392093],[14078,"12c81059a61518c02b73b47f16dc4640d2cf04b0dfd905b38c75a919a6ae0e93",9.317957166392093],[13883,"3eb90312aee8dff7f7d40531e7441d6137c05af6719707b13e89e306862c5f97",9.317957166392093],[5143,"ef21ca39e51bbaacdb469532f608de928a05a5679cf3cbaaa51d713771bb58de",9.917710196779964],[15579,"f57906c2bbed87a91a5e08cea5715bc8968778452d82603c29cfd83dea6fe471",9.317957166392093],[4272,"9a97684ee71187dccb57c2b93b3fbb4e9ca193c692a8db8c1dd7399282a5f0e3",9.917710196779964],[19818,"6442c99ac9b073058c286b51fc1e7ac2bb4115f16a9680b9bf41aeecb408f301",45.10313216195569],[15411,"b937e4b6b5253991be8730952c4b0b08b176f4bcd92d163e7435bc0c46770576",9.317957166392093],[4717,"f486d5ea0491f42a3f339e580f0d8e0fa0d2338cb2f4d59c41d6a8cf5971efe0",28.097560975609756],[14208,"179f4512a22261d494b88b2f35592e547e0af4aaa788e835f1cb57f3c2d31190",9.317957166392093],[17064,"a5a8708b427cd36ae11cb99e19c5606ae68b9480d952ff922d9ff1c98b4aca50",9.317957166392093],[17898,"766e6bdad62c4ed39ec0556c519c3d3e737fcaae589d9d88b23d27735ae5323f",40.69230769230769],[9628,"e2cf2fb3aa8b430a4dfa72d751a634d24263c2715e8adf0a6db88d2ce088dac0",9.917710196779964],[16120,"e145f933f2571f2d2d427f73984b0bbbeefb1ee9ee320be093b581be807e8f65",9.317957166392093],[5977,"8356a012a8e525e1a78148476f5236b13e98a942eb1781e03f61f0599ab33ad9",9.917710196779964],[4112,"4ea37baaad02f3ca13cb3f789deea50541cece89b1b61c8d300742acfbcbf5e4",15.003322259136212],[8595,"bd79f1ea69053adcda1072212bf91a58532043f48f3bd154ac76d7e2482b7ac7",9.917710196779964],[12946,"0cb208b14707e291cdcdb8a81d80e9373b145ee6e6c31e61efc50d9caafdf4aa",9.917710196779964],[13263,"746551e6d6d53ac8fa04a7617b529d8564a7afc495d4ef15319cdc71c21763a5",9.317957166392093],[13096,"3617238f1847a82f7bae44dce044660da198021354693a2190cfebaf83fe76a9",9.317957166392093],[10295,"b7eff4d18e51102ec88063a03969b77119005cb5ab101b01991004105b8c65bc",9.317957166392093],[17441,"d47f00abc5639c23295ab20319bb1367cf4ecce50c2b3dfe0cb3534d2479db48",9.317957166392093],[11513,"354b7a0525a7d76d4007cea14c1bd22bf207659eb5c2acbd5b12ef761ba96eb4",9.317957166392093],[19783,"24e1e5461bc3c170cc0b15c82663f0ff574672642de3146b11e9852d2b895303",9.317957166392093],[18435,"ce01c8148fc733cac134294fab97bf80dacda3d6bbdf4d07688e37a6a9f4ef32",9.361256544502618],[13452,"154e44e0bf8680ef0762f974e5d2754ff475d1e2d42ba7712a946e4124c802a1",9.317957166392093],[2453,"2f51e8aa7bf06978d9e151e5c46dbb89bee4e04dbe4c91bf654ddaed90c92df0",9.917710196779964],[10298,"3fba249526939317ac3dbaea0c693d27d05ea63c7408dffbc3504f62795a62bc",9.917710196779964],[8740,"daf51a33949ac8f50e21d6590d0b869a81d798287ab3ae8a56a256f0853274c6",9.917710196779964],[18042,"b656fc370b0ff4bedf3b7388da2dc6e3dea34e242b1eeac322dd1c880a59713c",9.317957166392093],[9025,"18001301a177fdf6a34211129cec801c4b1414662dc411e1ab2466fff32ea0c4",9.917710196779964],[16350,"6d1c69ad8c86438557c7e5875c716e6636320c3451d36a2bb8b1b6adc7651460",9.317957166392093],[17709,"bf1415d6d6e630d2a8f7f03d9097dbd00b5fc2fc2b452606e3edcf5d405e1643",9.317957166392093],[5982,"a5ec4214b5221852a6a28306435a407b32950dba36444fe1dcf77730bfde31d9",9.317957166392093],[10815,"145406237ddc6b040d6a62579b019974a71666e2c949de0c2548debc818033b9",9.317957166392093],[18577,"a9c52fdfe5e92904e9289ac69917039e44b85f200f46aad7371c74a6aaea792f",9.317957166392093],[7980,"364ca3462128a209b7b77146b7a6122384d87d28a4f8ee8a275b935f650faccb",9.317957166392093],[8647,"27dd0f122e0ad868af6bbec0c58a0f2208210c4e30ce21ba74caf2b04e9a13c7",9.917710196779964],[10830,"2b8a5f100fa03325050307589be8d92da690844f8fabcb6828dea76562c01ab9",9.917710196779964],[14054,"0134dd7e51884620e67c72185af8fad3f01eea2e32704adb901d0d78401e9293",9.317957166392093],[4551,"f1a9e5618e1503ee3da1c0ca0f6dcf45c59f2e7acc9a7851c870c6e9bdaffbe1",9.917710196779964],[6430,"427412983983a1a30bbe4fd2314a91dede36606bf155b2a4014ed59b383e11d6",9.917710196779964],[17660,"fc45e1934c3c5cbcbaa566e6373b6c8d5ce3ac09f8dc9f3ec6e97fa9960fee43",9.317957166392093],[11422,"5870bbf662bd8205fb1d28ccc1856504d3b303454ee3edb8bb65a120c40c2db5",9.917710196779964],[4425,"7ec10f882363a884fea21c3b1509439804ce5d232e8cca349ef58a1198abeae2",9.317957166392093],[18056,"9e02519cbfb91ebd2eed27ae0439da9ca161e67e150923c650cdeb818883173c",9.317957166392093],[3667,"f36ad766480104dcf06bae1e706379596a09832bf94230ded9d90020df28d5e7",9.917710196779964],[10048,"06e077d1f1633b277eda85b1ab1bbc9e5b4e88294796402aa6ce1f4e7d910bbe",9.917710196779964],[3943,"388e4c536cafa9ce2d51098cafe29ce0621dac4da0fde6a077dbe3ece13307e6",10.0355871886121],[2028,"b378e891dc0a4e5c5dbc366f364a4a3a261e760dea855bd2b9b1cd57d583c8f2",9.917710196779964],[1387,"f4de7a5d4bcbab8d7c5d036d59b1c145fbefcf704a808fb8fde81d75f691d8f6",11.050228310502282],[8092,"533f47e40df18ea992e36055f07a0ee3f32edcf925437b9ca56790fb790ed3ca",9.917710196779964],[472,"adb04d89f1cb0e661bd52d71916b5683a1cabfa1e35052e5a871678edc4dd4fc",9.917710196779964],[681,"5109759c4477b056af17d0155a1d204d426f5f2180fee4fbf2fb409ad3a75efb",9.917710196779964],[2104,"a57ebf90ad4afe4938d3d8a072671a757ba7c95c7be341c6be64e6ed7c9535f2",9.317957166392093],[5997,"1f9eea80f31b8d8a06987eaf019a261cdccd59e788e7db4bd236cbfc789e17d9",9.917710196779964],[14888,"36287e863e9de3cf5c9adfeb34c75392c4cac178f68c7acbb1fc4942437b0481",10.049586776859504],[8085,"c830daf5b78236e6371d5cdb5547521fccf5f805808b620683eb25932b99e3ca",9.917710196779964],[9044,"8b88b0235b9fb0b41a35109ded5dafdb8ce2d74725c256b6f0433c93603381c4",9.917710196779964],[16566,"f7c63f50e1e6c7fd71ed3e62a1e10149984d2831670669bd788af0dc4ae1c75b",9.317957166392093],[2519,"306aa4d3b886576591a110bd50411b5b980fed5c634400201109577fb9fbaeef",9.917710196779964],[19488,"76f4f9b853a0275d55ccc3d8dcd272596b193b6c27fef0f8077442d6c625cd0e",9.317957166392093],[16784,"bf85e6b63299a906fb1ccebf7bcfa28e3372616723b462fc2090dd621b8dba56",10.052724077328646],[15528,"ba287dfd30813085717f02a5af0f189c863e200c0ce4b45c1af5e6ba2f956073",9.317957166392093],[1558,"9950c6edef513a7c05158ab9777014c58588fd3adc4b044571e1a4920151c5f5",9.917710196779964],[5885,"3dfcf020849f6395e37374919d0b1af61cda330ca6cd455ce9c38d41c567c4d9",9.917710196779964],[11047,"b43cb9e4c28c934c14779a89631502f641c66e3aa43d134af9bfe52fad9fb8b7",9.917710196779964],[9449,"702a726c7e910fc9e590013d775aaefb3057853c4cf12795545aebb72a9303c2",9.917710196779964],[2729,"0d905026d5dbe88bf25d3c9d3195fd68a0a32917baa528d20baed896cf013dee",9.917710196779964],[17014,"cd3c4c700939446dd370b28299fe3a002a2041091e6f5703e0416ff014a7bf51",9.317957166392093],[8629,"9321ca476ddbb9f8387f1446150e73db9b27f8a0b1bf184c8e0737f4bcc340c7",9.917710196779964],[5038,"765063ca59f508ddeeb602b5f8b8d5dd864973b5bff1d6997e7f54782b36f5de",9.317957166392093],[19177,"34a4cc3f318f635a8d9296468a77cce93adbb469b054245fce23f1103e2b6319",28.187082405345212],[14518,"0b7e5d60afa78b23b07c3443142eb11875abaea0df9962b52c76180623ccca88",9.317957166392093],[19551,"76e987b8dd3870c29660c4a322f4043b727cc60c57c5291885716a64eccd930c",9.317957166392093],[3296,"8c6b0136cf92075111cde3b6162ee928f317717eb15bf4323f680d26ca706dea",9.317957166392093],[18641,"8569f78b1514f91a4db6dd218a52fc86f345ff20422a161adcc70891a39c1e2d",26.173719376391983],[16873,"b0d8fc958778362e422c50898bbe3725539cbc8b94b20e9e78f05f38af64cc54",25.98780487804878],[758,"95c36fd29c8cc53f393b3d9f9c10f5afdd7b4661dbdaf97a9672a6cd24e2d1fa",9.317957166392093],[1524,"5a68e1a6cb30aadd54714e84cdb96e38495bab3786e5ff2a63aa14e493a1f6f5",9.917710196779964],[16964,"6970181103accdbc0d31550a9574a32db63163315d423ec0913aa362d85bda52",10.052724077328646],[15492,"28add1afb9ef7c31ff49901b225ce80485863b8001f3cac28e11908372603f74",9.317957166392093],[656,"1a4d5a6af14140f75e3584c146136cd66fa59c44722ef0bd339eb79459b687fb",9.917710196779964],[13507,"65953bdcdfe7792a1a66c9ea1689fa3d7f708bed355aeb535273aa9bbb3ca19f",9.317957166392093],[15684,"ef50bf9af9387ae704bd6eb727195d49c5406b5c8ca7b80f59309f1de8bfc06f",9.317957166392093],[14711,"9528d198699ad43ac2f01c8117077e85bbddb78009e3046482c58f2dc1d8ab84",9.997888067581837],[19398,"3ad0e0ac6ee4511ad5356be2389ee8fb2c93c8a7e6a4b15e03ff7b5a1263c811",9.317957166392093],[7867,"f59b4b475b550857ebd84a672221801eb89ca95eacb75640b8ebc4b200ef72cc",10.052724077328646],[14304,"2a8c5e7ea81750947b892b205bfcf26461167210e2c9650175557265693e758d",9.317957166392093],[1961,"e72802a6742858ecc8a210a212970d5e4589441ea1d3c1e396da580b9ad746f3",9.317957166392093],[2525,"5f1d09520f3588020a32fda07a500335f0b2539a529faeb649913e275f6ba4ef",9.917710196779964],[15389,"d2af0ec7973d3ab95581025152bab1c3881b5e435337384ba52c482dbd017776",36.992136025504784],[11820,"f36520ddfb4e32859be255a74e3ef78aba5a435c5861e3e8ab50aad6fb1392b2",9.317957166392093],[13508,"4cdcfee3afe49c9bcee51bd23bf68f6a06e1256853e28ade35a54cc67c6b9f9f",9.317957166392093],[9079,"ed40705daaf8d86c4cf461b1128c0da80a66186a4c29c916c87b7bc8146348c4",9.917710196779964],[15799,"87532039a4710c2ca5fa6f90040fd0c389b5433ae877f762d9771685e165626d",9.317957166392093],[3003,"2387d9cb9eae5e2ac0e6fcd214f15cf1f50e603b81413a25daa5bb185c6042ec",9.917710196779964],[4883,"de5256ce474f788c138239a02ecc1608007e3d4b92f09cf5b8e3f87c558beddf",9.917710196779964],[13267,"3d59899eed107bd40d89993a5f300660f1aff20b504ebd36a3f8ff0b481952a5",9.317957166392093],[19433,"a6fdc509fbdee822366b3abb703c09e095b06e3826cf586a47907b9d5bc06210",9.317957166392093],[12561,"9d07d4d5830607b63aaa6c4d2680190ed74913bdd7e0c152c5f9f3b8370095ad",9.917710196779964],[15729,"0f162825fc8793f4060ad1b4a9ab33009425a128d8b288649b0f5ac09d1df26e",75.55555555555556],[13121,"bbd839f46f60556025f9c05ef0315b5e8a033204a6166478c8b94714b3bc95a8",9.317957166392093],[10032,"2e9ef40ff97eb09d0c67168e9d88fa586145ceaad5e8a3d519619719555b21be",9.917710196779964],[11118,"4ef9bcab55227acfa250c16cba25c019e26beda108945882c9ece6b6896425b7",9.917710196779964],[7236,"60177de75524391626aff50443c44af22be4cb9fc5adc12cafb00c69c4ed79d0",9.917710196779964],[13530,"d64a39c32bf06fe68c8ece2705222dcb2972a85982b4c0c42a3c32d3fb57319f",9.317957166392093],[278,"05b4e5a12a25addb0e07fcddd98aab0f99f3db2f3107e206eb5d7e2793b013fe",9.549738219895287],[7017,"6f1c40d05522ac833ed669e2335ecb4a69e90ea8636b02bad33722a6b39de3d1",9.917710196779964],[6197,"e18571299378aa4a73744a10f7d5ac8941fccb344bfe99d53cdf5890a8aac8d7",9.917710196779964],[13472,"8c66e295b8f5eba8c22cff49dfe7ef8425f047a9dbd3db5b7d72573ea6df95a0",9.317957166392093],[3594,"22b7ff4c0d3b1ecd1517ed2f6ca02c0b42b07fd07aec8dc9911c7ea58e2d56e8",9.317957166392093],[1562,"81bade95968a723b05dcc19a75dadde891a51d6706ece1d1e6e971d817eebef5",9.917710196779964],[14404,"1713e76aabf8f7339ec6dbc3569b18cb5134b6fe0d8324c7ac44e0c92974348b",9.317957166392093],[9883,"ba286bf9f1d3a30e51c771c505784340a964a319c92d91d0547a3cca60a10cbf",9.317957166392093],[6720,"4bb835deeaed2cd7bd352497e3efcbf4acfdeff98caea6291d5bd3204036d2d3",9.917710196779964],[1067,"9b82126e3724f9d612da7ce0787c9cb4ca6a6288a37f0e8a82b4f94853bdd1f8",9.317957166392093],[11880,"df38b097ad95875ea531834c8e483b106f0bf6a1faae1b156ab3a62aeeb62db2",9.917710196779964],[1431,"db2bb21dc1ed67778a375c7d76a13038de27445e268e2702c66d497dea57a3f6",9.317957166392093],[17570,"3d15b11e617dd9b04c4537ff8b7b9ae03a09ec911e47228624f608c07c03e045",9.317957166392093],[3758,"a243fe56c49fea328cd6cbf9ba14e395e73e472edf64978cde4f3d77dc0834e7",9.917710196779964],[2489,"1299aed962d3b870b42141cd53fa465510b3581e6e8d33ac7d8f628f2287eaef",9.317957166392093],[15564,"d32445a7c92202902f5ae5c99bd83e53b207f9a9483c043c140863f5e0d86472",16.798623063683305],[85,"e00a74ed79c7ee03181243a336ba506dfa7651c43a579b69ec92216b036271ff",9.917710196779964],[4006,"f51b95d019dbf3fa735524fee412bcea3c33787222976b54e8daa3b884bcb0e5",9.917710196779964],[19141,"af4bfbd27bd39b4eafa494731fa2865a6f9c98da5c0bc81d183a9ea7bed7db1a",9.317957166392093],[6170,"f79c5cff4bc8c22dd2cd2a5b9bcaa46bbe98634cc03b15c8bf98a857b58900d8",9.917710196779964],[15731,"d363acc17456e9df13105eac0ed43762a241b687ae293f377f8ce6af7ad5e66e",9.317957166392093],[16713,"de9dd49cf500587a5d7c27c52397ac80b8c6882439a22d0cd171c6f92d744558",9.317957166392093],[8075,"009a1751f91665e23f54f576ef93fd040b04c1998d780f6cf860637ce2ebeeca",9.917710196779964],[6477,"28fab6b9bef7aeff8fdd82b04827ead40dddcd8d6fc6957ecfdc9f39b1329dd5",9.917710196779964],[12873,"b1f10de8528df5e85e4fa710a42b1e3177ef84c329f1fa1a964e197609206fab",9.317957166392093],[1929,"4bbf219d7e1ec29513a2f293a5b8e0884a980661ed14d42035e35ca268ce80f3",9.917710196779964],[18133,"6a462c535dc3a64c03fb951375158eae06371671fe9692b2069766348c06183a",9.317957166392093],[4906,"62b3079ed029c7ed1147a0e6950058bce55a7f0f691ad01c1afd7cc10323d3df",9.317957166392093],[6314,"adf68e4b566c28afed14ea96eab77c1e5607ce40dc0813416d03cb5926dae8d6",9.917710196779964],[18264,"87c8f3901548f47220544156367c46fb594cd4ab38a144da61b4cf47c484aa36",9.317957166392093],[8298,"97cd5412e47ac4f13f84699547e666316b30f5c605a10dd8c008894228a956c9",9.917710196779964],[10354,"454be10733edbca9fdb49cb9ad1095bfb202244473dc33546b8dece08cc005bc",9.917710196779964],[14440,"a0f8967b715d11d5c695e83fb3121edb424b1465078414bdea551a6ced06698a",9.317957166392093],[14561,"afe851ec72177dd5aa3f74c9f58c834085f17e21e75dc78f77c828c6fea5d787",9.317957166392093],[7398,"a3b634e5cbd441e563a7efc3c6a1f2a18b407797cea63f10b470946eb54f6ecf",9.917710196779964],[13585,"a963cb0a25ff24a0b368430b03279addcb74dd879fd4a8b7ebce7c364fd4c79d",9.317957166392093],[12482,"64d91f02a682d24726d65926ced976d5a8b317a65e96a997b9d8bc2d57290aae",9.317957166392093],[19420,"6c8d87bd82cbd1f1a7beacba5f848c3704bb43dbd5a800f2b76af04a099acd10",9.317957166392093],[18797,"e8d08baf0aa80ff9eb8e9e8f7baba70125a94c421814cd0482429edf0884f626",9.317957166392093],[8119,"352f9f32de1e50e3e1ab06b9187fa4d8a9237f48dd3ebcc8205055da1d65a0ca",9.317957166392093],[12273,"fcf1af158604ba0e83c825de904ee1b275eb1c8b6be16da880981890c2d27daf",9.917710196779964],[925,"6d662ace7a75fd79661eab3eec3cd9e63bf1d1894b97c7b7f5fbb14f8d30a9f9",9.917710196779964],[1794,"9a5ee5c994b2c0abe6c8ba7180e42b213c7c4df8a34cea2e333acc69e79146f4",9.317957166392093],[17058,"7a573b985325e7ddf409cef16e6c1c1aa2434e557d3c48795b8ed67824a5ed50",9.647446457990116],[1787,"3efc762e364b79ab7a0b2d652bd641f0669ea9397f74d438212d2edd66af52f4",9.917710196779964],[6235,"fae6f603c8a833091caad45592191b4c863059f0890c5742b9fccb088d927fd7",9.917710196779964],[16520,"cf56c244972305d27627e2ed38c094a5743519f4eebd84140f03ca57f77ba85c",184.43693693693695],[17457,"4f84a3f2b9ddeb36effd5d2fbac97b087c0b0305478b8670538bdb12b95aa048",10.034527113939475],[3670,"a47ac819b096c4e406a0329669389f3d3348c62738c3252431f2a474fe9ccde7",9.917710196779964],[15074,"96a6b80075856a996ec7def03bedc68fc24c39c0bc8384e7219afebf36d7267d",9.317957166392093],[5948,"a23aae226b81b167c08a483c49c8610fecc2ff7984e9aeaa3f91aa3309226bd9",16.96969696969697],[3143,"19e8d0dba8b39a845ed99c6de308a3f3fc777a4593059eac198727915ff36ceb",9.317957166392093],[8556,"07b7979954d9e30c9c5cef11837f273d0078770929b29f58a8644d11d99db0c7",9.917710196779964],[582,"0b1bd511568bd716ee38b721d62c6c28989561de28496e9e68e0a68d1c1b09fc",9.917710196779964],[13076,"171cc57d686e506d7abcc4e70cbbb9c29bf7068ce8bbbbae3b620f7d7a3403aa",9.317957166392093],[16543,"fcb8f5a4d6956c167eb66c01a35771f465b77a3ce0191478ab9ccb5db9c13b5c",9.317957166392093],[14900,"1d027ee50bf81e6684743ec18bcd80599fc12faf6b833086fbae34a8cb56e080",9.317957166392093],[2328,"21cd66b590854c06a64f0481d1634f30d24c893a097ca2d4b5eed0b9493cddf0",9.917710196779964],[8257,"90d2e946ad4ff34c3dcc472ce875c28ff62ac12492d8a5458e09b77a8ff39bc9",9.917710196779964],[10867,"9ebe8a449f42da4e732fbcb11f74656d2185eba7dfff63dc2b821da48f7cd2b8",9.317957166392093],[4267,"e4b3feaf5a1f0e04f516556ab0c81f322c2c17845a4ca70d010fce893a75fee3",9.917710196779964],[10612,"13f3baa05ad1f9e5b24405738d54e972fc35fb3e5eedef4b1d985f2cd23496ba",9.917710196779964],[4834,"bcd3e473c2e444f903c7c8f85b66c37df20d4cb3ccae310e2f2dd7831c6138e0",9.917710196779964],[10624,"f2c8fd7b5ee32b5ae773ea792ba24bd0af12e8773e16f371b0eacece80e588ba",9.917710196779964],[15039,"514979fb3a3c67e077eb65dd5038d148cf7078ed21c5cd94b011a3a43a41b87d",10.052724077328646],[441,"ea852cf0b4d12fbcfc7785a3d74de1473fb59c04641349fc10882287820a1afd",9.917710196779964],[6136,"a71a70d15045b3f3d53ecc2d6e6b084693459160aba806e468fd5028d01d3dd8",9.917710196779964],[18492,"f73fe94809622ab90fdcda3c7c8056f8f77f5099403f50494221d1db87768931",9.317957166392093],[10379,"76ebf1d0b9fbf56a8d8fdfa3be191d727ea1e1bf6f89cd5ada324c596f72ebbb",9.917710196779964],[13785,"b312e1323da1700b596ad137c467f459cc9b655263bc24e7fe19e0332f68a999",9.647446457990116],[16723,"be71554e24da80aaba212c41134bb79a3f5d050cb55ff277eb6c4322bf480558",26.09252669039146],[10556,"1a4b858a725e38aac4ee48ec0f1e8f6faab5b64e67abc724efb10b225358e6ba",9.317957166392093],[4779,"f5197f5abe76042b81eb4059acec3816fa4d996f57ffd1e9e27147b4b36a85e0",9.317957166392093],[19328,"6caafee46b53ef3d12a300d7b465e4fac696b3ead4f79963b30d09716f872914",9.317957166392093],[9329,"6843cf9137f805edda26604af661375329e632f35693fc75672b5645e4f9b6c2",9.917710196779964],[17389,"2c0e98a0d5c995129678541b33fda7e4211b4efcf02d4ae7168ce83e8fd5fb49",9.317957166392093],[12119,"c1df9a43ac24601c2a08f73d6248429fec9bc33edd84d88105f645f0bf3ba0b0",9.647446457990116],[10484,"467507987e5afd824e53b74e0508840da784debe4352030d3eac147ff71a42bb",9.917710196779964],[14519,"d2851374efc2fa5265632e9f476082b1aee5d97749ca5b2906e35aa55930ca88",9.317957166392093],[5961,"a62f33fb90a365c31358629d4545ecf256d5332fb80e63216046dcf2958358d9",9.917710196779964],[15336,"f619728d6717d139a9e2b8108a37ac7af0a556486ae005fbd2a64478aab6a777",9.317957166392093],[3365,"99fb3c680c7361e7dd8c3f85233f4a641131a058d3544f316c6706db507bf3e9",9.917710196779964],[13921,"ef73fc46461275d05410161bb65a64fca9cbf4f759a4808a50330ae426728196",9.317957166392093],[9831,"976663e80fc1eb7ddb44112d84725e0079344ff49a0836653950e1f6bc326abf",9.917710196779964],[15578,"bfcdf365d13001b90e0e23208089c86233b53915832d7c5dc0efc5be2d09f871",9.317957166392093],[1602,"2ba666f069fe611e3268660110e1debe064ac5149525cf0bbc0f313d7e2c89f5",9.317957166392093],[4618,"6f2908b8f4760c952f6b28b0f4a957d1522ac854cd7eb572ba7540a020807ee1",9.317957166392093],[19084,"6d5b799b47099a8a64010c166e6625f32b7325c7df01dd1dedb9848aae0e6c1d",9.497326203208557],[16673,"b444bf314119ba1dfaba8273deda1de6f11384c8c7f9417313919cc8286a4159",9.317957166392093],[19133,"cabc8650931ad76d616f9e9c364684d72f58f35e2ca6f842f52ba1f202550d1b",9.756272401433693],[16181,"097ff06a127c400266c638ca6449fec4ec9ced3a3b4f987336275145f9576264",9.317957166392093],[6495,"22e85cc2dc96b63b9c49fc031522d807eb77fce1ca59cdb7690ebf3befa684d5",9.317957166392093],[13394,"eb816fc09ce40710e3d20a39234c3410c72981d6047d7b6dfd9e44942f156da2",9.317957166392093],[10030,"ca6b1ec1a7ca350d177322b50cc2b084674d86ed5d394e71c022c116681a23be",15.915194346289752],[4656,"8e9f344771333cef35eec63a1dbfec4ebe90711f3ef0ffa6c7d87cdf45ab42e1",9.917710196779964],[15959,"1e8716d034bdf75de19909d87b4107904c89902e249dbeaaedab11e3b69fbc69",25.403141361256544],[17765,"f642be964d283d18df522d81ef1806471cdc1b3481a40df8e8078be2bea0f341",10.052724077328646],[107,"981c3e4af8a4cc0f113a6194f442f3ec8142a7d73085c5f406428a3e30fe55ff",9.917710196779964],[14293,"ef516ecbdfd2e23944e65c4d670d2fb2525711cd2f0704d3e89875f8608dd28d",25],[10870,"96d3d5f4e826949caf9e8686675669b00ff0eda5eb35923852b8da695892d1b8",9.917710196779964],[15198,"cfa7ebd54ce719e40c866b18613b2599420d7673b5b676556143b2010041907a",34.838938053097344],[3333,"942aba7767afc3598201f82ee0de3784a64f75acacca14ba6f975ad8dd6f21ea",9.917710196779964],[18510,"a63ae36cbf8063e7beff5a549916a23922fe92f167a0c5d17278908b67d74031",9.317957166392093],[15485,"44ede340e2e2a7b4c5049fd776a8eebb52a19b6982ee28883bbcc292f6cf6f74",23.069486404833835],[16796,"45e84acf841be90faf96e3bd02e44f4fc4cfa9686eb169a4f8e437d716526856",9.317957166392093],[5144,"1662511d3a01a48caae739e47e5d0d9b803ca4493ff78b0ad14414ac063957de",9.317957166392093],[1181,"cdafdf1891855c8299e1961de0a911d919143c4f47f02ce54faac5fb15ec20f8",9.317957166392093],[16736,"8d6cce1135fe2788671ffe354465bd4e8382bd014fae90de014e1758a915a157",9.317957166392093],[16504,"82b8fd861c6d1e5f0906736217b19ecb932aebe866f67e3c6821f5a4b7cd285d",9.317957166392093],[18249,"765eb237444bb190230528f3113333b1499858fd6ffbc6bbfcb9dc0745f90037",9.317957166392093],[4434,"58995ae771bc9c66e3e56884dba9b09d07bc6f8937b3e7cd3f7d1f97e55adbe2",9.917710196779964],[6085,"94d6d7b5e7c539911bc49f0d87522f8054c23ce87a50c6ffa214a44441b77ad8",9.917710196779964],[1968,"5881ce18934042260a38b6372e54b6edfaab276750015545885be34ba89937f3",9.917710196779964],[19091,"fa063fc9f3f7c6ee599154b0cf878bb212a385e5125b546c00121d19c3dd011d",33.144525547445255],[8961,"b012219bcfa81243bc6a11b291bbb549a8dcc26a16d93f309aa0ddcc54cf0dc5",9.917710196779964],[19457,"a014c2c1a773d08d03f28d812f27506d15f1fd1ce45b387a881fc40745b6ad0f",9.317957166392093],[7215,"97956ad75cd84c099de857d5fa3c0e738900dcadb69a94f8bcd7671456e195d0",9.917710196779964],[8295,"1a96d10a97217f8b959a04ded94ba2c95a81fce5ef7d65315fc8a9f71b975ac9",9.317957166392093],[3824,"32401147d7ad7ac65c4f9895ff5b0091ac944158a512e4d0829afb894eebd9e6",9.917710196779964],[11318,"2e4cfff81b2e1341974a8abc4229577ab1e413281bdbeab3c60f66e730b1deb5",9.917710196779964],[16944,"cc88f4c5070cc02f013adc774c5139bd0b16050938185a19becc499ad9bc4353",15],[3717,"b7b8ca5a451a2f12642d8430aadd561609a9230d1d2568601d74cb9b85397ee7",9.917710196779964],[9021,"e8bfd6ebdd085ad6e4b0b2c5714d899f0015ff980e1e1501c95774d28a11a5c4",9.317957166392093],[6423,"82595a4f8b6d831c69f2daa0bf78d7891b351b10e1ec393d480eb5136d0120d6",9.917710196779964],[18313,"93b687d4c5866e7c8a674c8b9c83ea3c1eb941845c71c22409581898f4a08f35",9.317957166392093],[2964,"ebb3a3e37f43952544e9c382eb33065f2673b7bea67b7a01eca9e558a22689ec",9.917710196779964],[16531,"049bce6cbfbb4522cd799791583de42886f8763621b1c7b4e94582bfd27c6f5c",9.317957166392093],[6315,"4ffa2f687f1be77ba633ce0646f2a52c7ce29a901138c7b231868d5ae38de8d6",9.917710196779964],[15451,"b91a018e6ba238ff2886140c87514d3b367571b73e4c1abc3777f3d7960c1f75",9.317957166392093],[5802,"01dc957fb520f0ade912243e89f1777619a1b909fea0edb8f1c30077712e63da",9.917710196779964],[10090,"1b94497848ecbd3e16be6ab7c6dbc7f730c45ea3e462d2103d0bbe664b9ec7bd",9.917710196779964],[13964,"b76f880390efc8d2d0c43ff6851cbbe8907fae584c8a5d7fb24f319c053db095",16.92391304347826],[5938,"e5ed3ab5db1354abe7b85bbcdbc1b04b16f11cf7ce3158571ed1a5f71d8075d9",19.0727969348659],[1799,"a66a94792b3c33b87711ac482b715bbfe7eef74c8286b3d3c96e231b1ece43f4",9.317957166392093],[14456,"28cea429d8446768bdf1ec124805c4c134dc9360cd9edf6a7654fe797849198a",38.2140221402214],[8031,"d5c52cdeee7247f17b78dbd6423bafd14d35c676c8d97d30a281bfabee2f5ccb",9.917710196779964],[9301,"e63a3b6296478e5deb069fd840a2a6d6169918557b49acca36cfc345ac4cd1c2",9.917710196779964],[4068,"81f090bfd3c2ec65e9de5f3867a6d860c8ca12e160b0becc404ba9b320754be5",9.917710196779964],[13614,"e2dab0436d1300912c12ef40169142c55ba936a94ef724df89baff8185b2119d",9.317957166392093],[16121,"de38efd91ae729f183886faaf49fa18580233f0437e03b2609bfb0f13f0f8265",9.317957166392093],[19595,"8ad35a529f39d54b6654d7df6af3f25fc59319d83885adcc2ab2ed4b8c44540a",9.317957166392093],[1541,"a739698e215c2e34614f84e6e4ecaad958f19b898c71dfcb00d2852b4cdde4f5",9.317957166392093],[149,"9abece57a4f1013a946c2affcf70e51b7830d5f8d14b0f7bdf5a726975c7fbfe",9.917710196779964],[12616,"17f5a7ace8e7ec71a8cdce1a6d4964cd750aae41bd4e52a4174199f059ff25ad",9.917710196779964],[12239,"808dc08e2589c6885e94d8e1b0fa86ef875884fcffb28f3fecabec6ab0b7bdaf",9.317957166392093],[2177,"9d6d179def2664760a9033ccdb160d66314c942b76357f16d35b154ac568baf1",26.13612565445026],[17530,"99d609b8b5cc951c883097076e86788e1f32af65bf99339739d392858e0de646",9.317957166392093],[5088,"65731154d8f3631d398cf66f78ba36ad1164edeb3d4bcc5c25c3e37e6d22a6de",9.917710196779964],[11875,"bb648508316287f49588e45c4fb9ecee61f85af831c056888b72f5b97f063cb2",9.917710196779964],[17454,"f54b4fef317175a0abc70ba042849531ce393bb0792ec1a24a80f0a8bf3fa548",30.62162162162162],[12835,"e95aa28bac931264b94b9634a9722bf40e801793053b9c74b23d23d2c2a8b6ab",9.917710196779964],[19190,"0b908f1a7fdbc3e64ffa781ceac93ec9ae01645191708c5fe6f6f5eb58daf718",9.317957166392093],[16618,"03c6fd60b7f7651e8d9449644ba7edc4079e2e3329a56b610f4cf784030c7e5a",9.317957166392093],[11338,"a4dd6a415ecfe883823c7bfa78008bb03b615f8b2e0b114c0811f6f7f5f5b6b5",9.917710196779964],[4258,"b15b43d4302ffba2d5f54ace48bb3e55aabdbf10f22f3eaf96a661f40b4009e4",9.317957166392093],[9193,"8c79cc7234f679a6bfe39d7c0eb211deb0c57c8e9324f6bd6e205f4e32ee83c3",9.917710196779964],[14300,"07d7bf7d66e568422eb3495ceb5819cb0c2738ae2e7bfc450842ecd6d2c98d8d",9.317957166392093],[1106,"64a384c9f305303527374cbdc1e8b1687740ace2ad6f4997e26cffd8345a87f8",9.917710196779964],[17793,"e6a709ee7034b8c9323d4458ecc3a9b571895af472bd51dfbb80ad871e267641",9.317957166392093],[5638,"18f956a5359663cce1a1c4519613c870833969790baad8019da2a540b45068db",9.317957166392093],[7209,"ede377734eec64629cb471a4a9c7b58c2665e16e16af085acfb925a88232a5d0",9.917710196779964],[2669,"b97ae6e9b5b5446c41c6ebe879332e7c321ef3ce0d096d5b9f606b6be333b2ee",9.917710196779964],[18946,"caa1e709b744852558f78e7a8951722e922677910bd10e6fd08226a3d27c4c22",9.317957166392093],[7856,"4c45615d4734ebd4499dd3933dd8e7935e7ae699b6567e4de2661f490bcf7ccc",9.917710196779964],[5029,"55360ebc59739780a68599b00bfc6cc506293919fb34a36203a66e37715dfede",9.917710196779964],[2730,"de7332110f496477fabdaada7081666608f609ae1cb1e6f874c6853c01bc3bee",9.317957166392093],[3495,"64e4355808d884be3edb124e1381f7b1ecd2845025b00bb7bd3e096b511003e9",9.917710196779964],[8317,"6f9800abb7c4c78200bf59b1c48bdea7b71852432eca88b7172aa893b6ae38c9",9.917710196779964],[2916,"d819ffb108d909b6ceeeb87abab64da3c461c5bed1387098fc093ec626a1f8ec",9.917710196779964],[12454,"f9e03ed2e0aa213e2f8407af897ec934e37c4cf6ee7c47727c991c99682542ae",9.917710196779964],[19350,"2f36a274a113ae130cd11d4b36143c3209b94e5d500677eac6b7403145b89513",9.317957166392093],[4972,"5c55aa0521b356308a8ecf9a8fcc8d0d80dadcbf0c51bb29b0f6b22a38375edf",9.917710196779964],[10611,"3ea5a9923485bacc81e50b6aecb517fb5c7f23f5ddf8126426918ec9f21b97ba",9.917710196779964],[1704,"1136598b54bb4f3d39cf0eb0471cb03b26686aa39ed05d0e582a26b0028ce9f4",9.917710196779964],[13223,"6557c8700ce8dad64f14dd714a55214a97a6d5d5b087c38516da4940b00972a6",9.317957166392093],[679,"df5ddc7a17fab51b358f2ba87d942608061e2f278d3bb8ac83bc0178201563fb",9.917710196779964],[18858,"0d4ab43a9e6821696fff55c6cc6a01757d13fad483a7dc8a2d5654f19ff0c624",9.317957166392093],[17242,"a6f3645cc94c250c25208175d7a091a9043e13f0b27d2a8152571491d239144d",9.317957166392093],[11210,"922d2a08c1882cc54773264037edd35adf85c4be86753df30cc5336179d6a0b6",9.317957166392093],[7359,"1f07ad775f3c31a5f3662ed8d1cfc48ef74a9db79d9a663a5175a22ce4c4a9cf",9.917710196779964],[214,"75b7dc6ee6f2e823a554894e43bad2e8277a7df6d4674edc209223720be58afe",9.317957166392093],[6298,"c7aa7f9bf53baddfd0e30f8132225a8863f4a4706c060f5675f159e9bc260cd7",9.917710196779964],[6350,"d03e497bea7c5755670de1778df571d58324f69703457deb6e251b3fb1d5aad6",9.917710196779964],[2380,"70cf024d605a55a60bce1cb437b2e5e1e18c7f78f9addb33267fe4dff8e58ff0",9.917710196779964],[18036,"19a1499f54da73d2a0826e987a3b08c09a9a49a75548ec5906a2ae5aebb3a13c",9.317957166392093],[15044,"012f75e0d0ccc3e6f165cd0b15dbf0d9e2d158f3afa348de6293e7a6b6caab7d",9.647446457990116],[15018,"e4204c400e85faa0e14dd4e5f7036876b2a09b81d4a9353e6c3eb27d7a99047e",9.317957166392093],[14088,"4fd29322f139b19f811445cbee63bc0fd2481690682a9cb3d785eaa00dd5df92",16.973782771535582],[19600,"3e1318059c7793a3c8e72f990f0328e3c65b3e087bca3c81e4994919aa7e0d0a",9.317957166392093],[12153,"d18458613c1cfab0380c5b7c6f066c16ac4fd53c2841986f94446521479c51b0",9.917710196779964],[15719,"b41870d65c441e39d30c724a9321cad0fb0a11c036f9633e3cf9a1ff2b7b1e6f",9.317957166392093],[968,"aa10823f36cb8250273af9237218afad76d91982fd8f662e0764cc06ce7e64f9",9.917710196779964],[14540,"4fc69a8f1d0fa0503d4b596d9070a4c8eddec8638807270d5748292a70795788",9.317957166392093],[11583,"f7c971d4c34dfaab6a8bbfbf89710c53c724d0895d804abb14646ae10105fcb3",9.917710196779964],[6795,"525f9fc36405829a42f3d907e9311b580891798b714fe07af7765408956f4ad3",9.647446457990116],[7005,"e68539ca17ef5f917a48062accfe35d83dfd3ea6f3b718137c4bb4471cb2f6d1",9.317957166392093],[17159,"5164015e9ccbd56c419d4b477d0060e3b582b7a28f8388273dc49ae6e136d24e",9.317957166392093],[16098,"2135d051130b0a2e26ede68dc204c36e7e244279e57eba595b29706f066e2b66",16.17081850533808],[15421,"25df81eeeec235b703ec8929a23de5899267c60029453307387f94694950e875",9.317957166392093],[9300,"5bac8b1274c10c1b0878ec279016a645656b790bf5ed48cd64d0b1a0d947d4c2",9.917710196779964],[6898,"8621d2bff787ab4a11b7886978f64456e1fdd42c957d418482c7f7beceeaa2d2",9.917710196779964],[13441,"812231237477d274593b7ebeaf376af4cde7ef859fa6293623488b68116c48a1",9.317957166392093],[4059,"f8db81cc7f03a5ac3548d45073ced4af7e96c48e4ae76f120397d61259e45ee5",9.917710196779964],[19549,"56f8b7d9520c8f424d848827203b459338f5757e934f693e99fec0e450d3a80c",10.052724077328646],[8664,"633e57afd46ca4404b029f1c5d04eb14dbca3e82428c547604bfa3636d1eebc6",9.917710196779964],[19323,"7d2b6464836fbd29af8deea7e3d1583c0467027a123fa2d03cc2caab90e74c14",9.317957166392093],[14021,"9ac6f1bf910c6a85ee163062c2632ce07fb78b5437356a8b7f4ffb7283085094",36.948306595365416],[9754,"568accc5e1eeb6b10526c41d865511225dc999c3909cfa845f063b1a0b61fabf",9.317957166392093],[870,"9f9caef86033f5ace76c53ce2ae27773cbc0a99eecf88367f84d7cfe49d817fa",9.917710196779964],[18745,"4fe400413f17b2036bbed03d388f950b4ac2a7a18233507982a16dfcc35fdf28",9.317957166392093],[1296,"9689e05093398dde24314388d03338736e578121e506b4648df523a05b0467f7",9.917710196779964],[5440,"17fb131c054898199a1fced4fee32dac311e018dbd92c7230918bd3db2fa88dc",9.317957166392093],[6582,"698b14a7ab6a9b1860bb8f9f23d596fe3bbae54ad6b59bc1f79a587f3a3cc6d4",9.317957166392093],[83,"6f32c41a17c01db32c66319e9f6691e67fca17d10504475015aa6d14442976ff",9.317957166392093],[16188,"2121304c75bfbe573d307d95fa52c262e26cd0da3ce1595dd83708c33e1e2c64",9.317957166392093],[16192,"97c9ca1bd96c63a76f9149ebf98627c203c5e0b8521aca9ae8b5257c24ea2264",26.79150579150579],[9209,"996d48d62e1a8a39333521b96d23cb0b75dae8e328b4188c3ea4ff6c7c9963c3",9.917710196779964],[4027,"ab0d75fd619057f27ebf6aae2d35438d5ab915c4e4d11c501c8a79384e3795e5",9.917710196779964],[14412,"d290bcc62ce56728e31f6bab49c34aa1d176bf7e0b5691380fd2c73fa53e268b",9.317957166392093],[11518,"66f0f5a57913c8bda6720fe6d2b7082f2daef98d491713adf7c3d93fdb7268b4",9.917710196779964],[9369,"8e9146be3073a34f1b0d93f64c4e6b95c058171c82fe7b65e33eb1ce60e468c2",27.72192513368984],[2405,"92ac47eff7a7a775e5bebc53a117988327de8aa31c87feb1523e64fc1d4872f0",9.917710196779964],[5649,"04c4888e0046f454c09a9f8ed4010cf0f7779c3869e7612375e7a3748b8557db",9.917710196779964],[4833,"53a1c25b9532a9cfd9f7a578c7b126e749d161377509bb1fe85390079c323ae0",9.917710196779964],[6706,"873ce2e2d9ed8934e81a87136645dd3f7089b49dafacbbc68dfe0bb7eb87e9d3",9.317957166392093],[7790,"5efe5d35067e4c407d5a33cbf2fc286d908c80be44fcf982cf6197b0f9e2e2cc",9.917710196779964],[14000,"6e0c3076be4105c41b593d2625180d8b008a355fd9d24bc3b0c280e890c8e394",9.317957166392093],[10020,"56921caabc1cd3af1baa196610da9e1513de16f1b17af3d3c433fa6aa25c35be",9.647446457990116],[11763,"b678dfbb3c722105d632705d3563b99a8f72a592d95f37d20ea1c7be44a9e8b2",9.647446457990116],[13365,"6de05e1429117254315a5fcce89a693365711c679921fde4fff2b8ca6f8131a3",25],[6304,"617357e93c7804b56e62f7a0259465975775ebd8f9119f92172da5c47b0dffd6",9.917710196779964],[11798,"e4b9a3068f0aaa7e318d90eb44c561ee1797f3daf1b4ed560af8684e673eb8b2",9.317957166392093],[11534,"ed8c56076dd99d2773d200babc7994477c174cd81cf4fc5ba22abdf0829152b4",9.917710196779964],[9686,"fd4b4ffebfb5df0ff5f10f34e3ad0f14a0f5e853a7f315ead9df2c23dd1c7bc0",9.917710196779964],[12731,"f9d8788d27f114eff5a576885570358494c79e99debd4323f079ada3228d63ac",9.917710196779964],[6490,"ac281da8ae7b7e6ae21148629a0287996820c49d6d9ca8cb11e90f2f2b038dd5",9.917710196779964],[2474,"71e2f104ce80e837b3565bfcf9b63b23b05197e57111a404b44741a8018a0af0",9.917710196779964],[13727,"85e88ded2f7b0ff1a78062e99d98d17aa7f54a2f89e2a9cb4ba90e082a1dde9a",9.317957166392093],[8235,"a8958cc1f321ab51e075916881c675e72bbc336e68d3a87993af9eee7528bac9",9.917710196779964],[11344,"a3d3ad24077a2501e3c9de8ade5bd1390165f41b937b7ab7de7e73076831b3b5",9.917710196779964],[17632,"3c429564a512f7ab0e723415eb0404be97925bfcf0e0d1ae7a6a9a7790549744",9.647446457990116],[18005,"d0c7bc320842bf23d7216efe4cae9f62f384a5eaffa8ea89c2518980b6e22c3d",10.032925682031985],[553,"6af0d1bc1429a6fcca3e2f0295e25ca8309421271bedf8b0f613b14803a83efc",9.917710196779964],[14459,"e099f23f81e036232d59b2d25af813b2855401baf6908828eb0ce983ceef128a",9.317957166392093],[13869,"9521203fd6c50d6ce636983957b5c9723f7e2e71ade074dd974e57ee6da9eb97",75.21936459909229],[6909,"e3ab3478d325af220577b013b15d9c049792d8ed5fa75a9cefeaed3b53428ad2",9.917710196779964],[7502,"78e9efd85526d4ff7c3cb2acb5afe7f43b5aa77b66721c6143417f83bacebcce",9.917710196779964],[3280,"d89fc1a05a237feef02dc917dc57b80215221d610c37989ae29a65f0fff284ea",9.917710196779964],[9682,"07837910885ebe4dd2e3a1ea25acf6f3edeba12102d24e32e55c9d032c9881c0",9.917710196779964],[15179,"05d7704657ce7d2409980840cf454d7ce2d4161a7564be0adf326ecb3fc6fe7a",9.647446457990116],[10007,"bd1eeca2a55171e00948b12d889a0c36b8947569e5faf69e6b785947145f4abe",9.917710196779964],[15271,"583d1c8ca941171bda909f2a69547f8e8fe32e58aeff62b5be73c188d4f2f978",9.317957166392093],[10659,"a16627ea9babc41f3aa965d9fc0deca22ebc9d0fe466e3f1acf087ad85ca4bba",9.917710196779964],[7128,"149e254104a43e0a6a416c11daac1321a9fe3bdae05bf1db53aad9ea488421d1",9.917710196779964],[6835,"b7a020eb1e1f626c80b78d8b49762c9230859b06e5f420ab88451245029307d3",9.917710196779964],[6782,"88ca3c62f4f4ba41d2ff349d4625a89b32425c8cdc0a960949fe5d25c9ab64d3",9.917710196779964],[10340,"350bae35e1b947d3fbdf9c3f280bf17c185f06d3dbcc82d69169ab8f074c15bc",18.20689655172414],[10255,"a045f1ff7fe5dcf0a382461fdc84f371a55972b527286cef9d1c088e3d06aabc",9.917710196779964],[17455,"b37d723372557cdea1d708e76e2d771849a0668229cd0a40f40c75552f88a448",9.317957166392093],[15935,"68b992ab01f03078c52cbbfa90381ed2cb6559e927ad71ba82dd689e645e516a",9.317957166392093],[8345,"f6e1105e286e50d4e8806adf956c1874add7dce42715dd38580b058c273f07c9",9.917710196779964],[5478,"6e058da23a8eefce53c8f5d7b399b728c993ff1c1c5b3c9b817a024834f15adc",9.917710196779964],[18359,"c8f5faebe054e0b1f5417be6e8cc94516012624261294e39cf08fb8ad8898f34",38.72791519434629],[10520,"7808fb8c9b9a732a82309148fb384ebe605d7d08e8ea63b92f98c099a5dc13bb",31.036203722642668],[9627,"9453a44563b6bb3706757f96370ba3ae0d9a89ad60b214cd33ec203afec2dcc0",9.317957166392093],[14555,"a698ad45d305d1962972491d81e7541c37140ff576a0cca6e3b4f802c519f287",26.11764705882353],[13793,"775e112948e1bdee9bbe305a54aaa05945bbbf2f7c9242337d6861db4b638299",9.317957166392093],[11700,"c56cbcb6eb00d7891d58912ffd5ac07495b45f65c87428a7d6db63cc765b50b3",9.917710196779964],[3433,"e68e19e8af1f6547822464424fc9605c912922351b85c9f659e96b2d15b576e9",9.917710196779964],[6180,"f2a068f5e0781a55e010e5c4fc1e938c8e286f3b6ad8fe9c3bd1945a9779edd7",9.317957166392093],[7291,"27b83ce52efa3937a6d12a4d9f308da4a3c25635ae8a84f18041f1fef26f21d0",9.917710196779964],[2940,"90810bf3ccc46fc00828d142b5890eb6587f9eec807ae11a7db85f27c142bcec",9.917710196779964],[9251,"a8e94c4d3d452e9bc780b1acdcc9556a86dd0fc7b201418347bdc1d13b6820c3",9.317957166392093],[11544,"33c50a601809ef6e84b03de59e660df62da277283d67382d2be63d68d2e744b4",9.917710196779964],[8056,"83a9dc9b86bdf58090c0eede66eb43065c027f99caefdc55ca7441876b6e1ccb",9.917710196779964],[16596,"bc751c6c2e4e11f8e7387243f6cee6992780161ef1abc4bd58fff0b70051fb5a",9.647446457990116],[19028,"35bb0b8cb31e32e8b9bf797983455bcc816db1f2307c6b5ec91607bd1908ab1f",9.85781990521327],[9274,"2bb7ef0e946f8f039589eb2d09516519cf4c9d5ec7c7390e291926b0e42cfac2",9.917710196779964],[12083,"4cdce46ed892606c58c9d9ea86b6f7b4beb455d30378148dc8962cea1f32d2b0",9.917710196779964],[1119,"0d6020b65b0965a9a3df44a77ec6896032afa462f44982b753b67a67a9b679f8",9.917710196779964],[18647,"6b0710a0fab17f5e62fc776c6bbbe162fac03af93671e321d0a2e77a2304c52c",37.092957746478874],[11163,"6c9e01aae168653b502cc453862e5c5df01dbc9078207ab188ef8ebed8c0e8b6",9.917710196779964],[14357,"65e14555c72232fa577ade888a2152244e3187d59df831eea335c90ff802428c",9.317957166392093],[17503,"72a5995cd4b32ba2d522cd6ab49f71e54dd0d915778a188f81a70b43614b6e47",9.317957166392093],[10893,"6df0e631f95ed49ead171c01cc76f1a68bbd2904f8cf803cf82720453308b6b8",10.052724077328646],[15604,"680908b9abbfd344a6c20575bc083dcc9ffa737f1385a183ef48faad6e185271",9.317957166392093],[18131,"e50e11cba9f19a9b8224478eb97f4c8dc4397443b57c04b876c9bf2f2637283a",10.052724077328646],[2238,"25a928f6ba7cd609bbaa8f4cbf369198e7aaf75eabe3d37ea1d090c9d52c50f1",9.917710196779964],[12815,"d045a5cbe9e9fe007cb352e26e855a8ec59cbee8cf2a7b582b7de678adabd8ab",9.917710196779964],[4953,"d9f079885f97b7f64bc2ea679ed5a3891709399e7d4e9e4f7b5cc7e9bff986df",9.917710196779964],[1340,"1b4c31253f8794128e391c9c4b5bdd274899caf2f3da9eec5a45d05d6cb825f7",9.917710196779964],[5991,"ee9a2b5fe154cc7e7e5423cf6c4a8f3c6c588d739e07e5a2bedabaac890e20d9",9.317957166392093],[15340,"0398175f3e9f9e30edb2a250f7b30d898976b7274c8c7ab88bc83342e5ae9277",9.317957166392093],[16975,"b21d0cc81db4e2b3c29fb3f4644533828acf895ffd8e7b0fccef49b236649752",9.317957166392093],[18973,"89bf3d0f600d71814ee469362e5bfc97234d975d7628802e1fec615a3beb7421",9.317957166392093],[8380,"64b68aa1488430ae9bdd530045c9cd07b62f78113eff5e9af775937555b2c0c8",9.317957166392093],[9374,"69374f849814b36840724b7216c08f8df1eb7785ba6f27eb289055eca5c465c2",9.917710196779964],[15423,"904b65106f2403d610877fcdc8fb9143b8ccc9ed77ea46742a956a17edfacc75",29.32959326788219],[2198,"2a4f5321492bd21e73e2a879242490f18b082d62eb2da3ac69b2c92382d589f1",9.917710196779964],[4813,"cee1a3089ba499c500bd4df2c5649b6100f62b27687713e91fc1564862c255e0",9.917710196779964],[8164,"fe70564e242b003c18e79b232d9f7d294e56fcdfd58e08f585af71d05fac3fca",9.917710196779964],[8401,"8ff570b76d5c4d12f39f768cac64ba50f014198f6c24033d8e126f26e21498c8",9.917710196779964],[12360,"9e65a14363764a694f78c8cc156bb35b0d539b9817a02814e210712ab4cdddae",9.917710196779964],[1535,"b5375b6ff7fce41f7f12d6df973032da0313a7a4fe66877ab49433810af9e8f5",9.917710196779964],[11121,"243085cf47d8762364d6f8ce1181f1df103794a42f18cd8035c388146c5520b7",9.917710196779964],[15126,"31d53bd66f670077c5589b5052709174c1d4a9c8d0cfc4501fc2399a8797297c",9.317957166392093],[2070,"1b88cb966b5103bdb0cf9c5e86820222e6f2d14344e8e351575363d9ad4c72f2",9.917710196779964],[15488,"60b9dfdf3bd716bb906118c5df7733a4da635ffdf07d7228d3f03508d3015074",10.052724077328646],[6625,"7ab00b207a5be110c0537b2b2e70d502c22f7db5bf0ef823afe708a283ba7cd4",9.917710196779964],[1287,"2acfc0edb20240d87b66a8438bb9ce9e35d2d1aff14aa01e34db73b4909874f7",9.917710196779964],[18022,"8e95ed18e88544a14c12d4fb92bd9d0d55027848d510096bee6952369ed3da3c",9.317957166392093],[12846,"9efe41e2156936b47c2f6b512e2903da7254858c4db7ce5003aa2bcdfe31a2ab",9.917710196779964],[2260,"2249fcbcc5a2a28e43c89f8eec89f20672e82ac1cda01c5d880f2e6ed36c33f1",9.917710196779964],[9590,"a9d73618d7037e32130d46f1a1f6f58fd0c91144257890547ea7edf379350fc1",9.917710196779964],[14615,"fd0195d45f4bf441b92b974b5163407da940d98eb3ca4ce7386d35ad929dc286",9.317957166392093],[16682,"84cb43dcb60ccaa426ed028165cd455f08bc418e2e2e5dc974d2d148f657f758",17.005309734513276],[3043,"eb03cae02b2eb04a8135810d923df4701cb95f4a65d6ca926dfcf2c63c4807ec",9.317957166392093],[11028,"9b2998d2b06002540803a0eff13888e58cd03a67f4b79cf48a2e67fd172ed9b7",9.917710196779964],[17899,"d8bc14e70b15f7ce10aaf6ecd9c634b1a9afc354ff31a524ca8e74e54de2323f",9.317957166392093],[3463,"9a6d342a3b71fe7bf841ca854d070a04bcc4a239846ada669a7e8868d76249e9",9.917710196779964],[13803,"1c62ceca20257e5e39fca09ea709d98d53e5897d4feeb64f56500080c7ab4c99",9.317957166392093],[3574,"0522f041393218a885e4ae36747254a9b379b5fc66888fc98a78eabca18477e8",9.917710196779964],[4144,"24020ca076b55433894481226c5b1ca1543af9c84b2ca7ea0ad45a503408c5e4",9.917710196779964],[13673,"de7c4f9025d80028ba4a9be3fbfce0c3a7c03e07fd59a71f8a9beb377ed8cd9b",9.317957166392093],[13701,"6d712c02c46d661d792dd81038dd33ee812cebf275554d097f63e3d7bd02469b",9.361256544502618],[2711,"a3959445cd4cfa8f76f4bfa76c2a30b6bb7bd14e22f6e00603123f2c27d063ee",9.917710196779964],[2835,"2b1fb74ac9e75420c37029083b30185b39ce5c384723594f1e85391782376fed",9.353846153846154],[7358,"dfba4514a2622699f98af6e0c071b997a26a4fed04194f422bb7ccd01710aacf",9.317957166392093],[8362,"44673c9752f0969e1678697aedba07e0e79495ba5f066f5ef35ef0f37f00e3c8",9.917710196779964],[3628,"5923c9285e1f885673a32e0f9da8bfe03b91186c11a69cb174ac240c035e12e8",9.917710196779964],[17063,"e0fd8d48aafda219f6bd8a2c41c2c1f565fc750a9a5145f3eab3acf1691bcd50",9.317957166392093],[498,"65db65163fffcbb2ca07d976f90a85fb5c601618a63fd19bd02704f1de8fb1fc",9.917710196779964],[800,"8f24d044944db2d06bc62b3752119bdc409c20a03dbc0b53cbd7851a8a9488fa",9.917710196779964],[3313,"91deea6285cb6b5614d4ab6a146dae89892c4876d3d40e3b6b1151759eb949ea",18.130434782608695],[11475,"6c4e5373eb026bd71ad7bde0f978322e6229986ad673405f092212056e35afb4",9.917710196779964],[9409,"a3b434b22aa6285939764d36ee5d64592389741212e7d022d88955b9ba553fc2",10.004566905160603],[10522,"177d1e0eae418599d86a6b865ae938bd216fb4bacfa06233871ba5f3cafc0ebb",9.317957166392093],[8742,"556214adccd4381fcb45edf82d0861370e19022d2533ffd509bb9bc1785c72c6",9.917710196779964],[10336,"7a805cf540003206d0cec72553208b9bfd76c59305f15d977001ee631b081dbc",9.917710196779964],[2613,"0b3242f48fede8f3b2e38fbfe6676ca7a1785d8fe922febe37e4f7344b7311ef",9.917710196779964],[7701,"f17b004889a16534848049c178d462e86d63b4fa8b28d0c3182f2c9e79b588cd",9.917710196779964],[9359,"00fa1528f4ab2b46a941420f5bd677837e443948e83bc3787ffe8457802a84c2",9.917710196779964],[8833,"bf3ac075e204402e095e898e156c9de23eb31361c65e8219fd6d1337e575e7c5",9.917710196779964],[14846,"f362c867adbda074c53a9e25425c29a961f34be32a857bb2b795bed1d9f20082",9.317957166392093],[2595,"88aeb6e298905c0823f99386fc2bc1c00ab9b49b2df6286ac75f9ffca7bd2eef",9.317957166392093],[152,"722a7ec2ef655504a4449fd6c65d2379f4c7862ef1ca2f0fd3d4fb806c01f7fe",9.917710196779964],[2013,"c8970be4335fa74b806f0926f281154de0880521d70fff1313b4b81a82e5eef2",9.917710196779964],[14402,"d271af8c7458534f9b8825046362ddf16f2e5591fc66ebfd7d37f00d379c368b",9.317957166392093],[12472,"b89010bf5ef521a20e89ebaf03a00a153edc30b2e71529c197cd63de415f26ae",9.917710196779964],[206,"b413652041f5d181f9cd7c4b4c04f1a57d95dfd1d52d9c4d2605efd71f4b96fe",9.317957166392093],[5364,"8ff405eb0b4a1104830e179b499579d0a67bb406baefb101747ecb255c220ddd",9.647446457990116],[10073,"164335ac82f5f5ccfaadb752a071ad4a0ecb873210e036115236c1aae4bae3bd",9.917710196779964],[7373,"332b4d77597d420f92f8cb44bd17048fdf04dd0cdedb414c4e0df3cdd62d91cf",9.917710196779964],[12871,"77984e40bfb30d35abdf33cc394827d49813c4890987ea8d5b3e40115dc56fab",9.917710196779964],[16118,"2a2bb6e09fe3a1976542b953488e6808792522e82ddec7f2881403911c409d65",9.317957166392093],[332,"64a95b1142b4820b5cbbcafda14734d6e2a0155208518561d419bbec7fa6d0fd",9.917710196779964],[15852,"bd09a91af1c5222085ecf6822e6cc6f908c8d3b27b4437b656ed35d6e88e1f6c",9.317957166392093],[13104,"5550cbeeedb36db0d14fa57469f460d6785482d1082623742b335bad89511fa9",9.317957166392093],[17176,"4bee050694ecb91e1dad51db6645ef766bc781bb7af94df1fcf5dc117b7a4d4e",31.652173913043477],[13378,"24f63f194c5a9e2def6701c096001b8eec85364e6fd44aa3ff3e49348e92cfa2",9.647446457990116],[2980,"95e61500978f1baa85535f39312be60062d6e5a4cb714d9b696666f1abae65ec",9.917710196779964],[2312,"f9b09fb06fc61440559ff2103a51183823a4efbcaeedefeb288dabbfdda8f3f0",39.20855614973262],[1711,"11ac3a7532991321ff781087c3b1f62479f9397b2ab5ef0b554fcd9e1b6cd7f4",9.917710196779964],[3695,"38d8a4c52e48293991c497a372751290cb5892a31a9291269266463fb4fb9ce7",9.917710196779964],[15417,"09f97c8518e4d4a941d6b4a8cbea6fcfd798f70fc1d9ed750ed39252a374fb75",9.317957166392093],[4592,"c6dc05a9884aa455ed918a7ace51ef7394f15dde3785fee2ef3086f71672a6e1",9.317957166392093],[17498,"ce99dc297c3f9ccaabadce211a9d05ebd5434a953389e317b5c4142cc4f5a547",28],[13651,"968745850c2217ab8d6ba6bf3db3095f1cb29192a5382108caf301afa9af399c",9.317957166392093],[19411,"5b7d763289491de0d8f62534156c7ef7d3c61637a10ae6a15112125b35952b11",9.317957166392093],[19044,"7219f2a52e858adf28be8ace2b675ea65df3af3a8a38e81e31a236038ae20e1f",9.317957166392093],[1578,"dd43afb9504229561b30cde0d0a9940f183b95f80e0a86825b3a3ac2e56aa9f5",24.931506849315067],[8810,"c8eaf3c7661e423d24cc9cc5b6340e482571c2fbee619e2405eee00873e406c6",9.917710196779964],[18740,"f13d01fff5698d45e3d909bfeeac6f8192c88f0ff6fdeee17129af5e65440129",9.317957166392093],[298,"bfdb8957e4c9009d1120eb428c725ce4fd377bf4bc573343f6587f5643fffbfd",9.917710196779964],[2303,"7135edabb5f346bd8a2629bb456df22bf2255df6a7c2d9e588c1fce5650702f1",9.917710196779964],[11765,"9905ef51c1a763db59ec02d57139ce05756361121d7471a3e4b61cf83e30e8b2",9.317957166392093],[6590,"04bca1ee120b2e643e99a1ef1de39748f5f0c46b3b9f49358c40a9b7192fb8d4",9.917710196779964],[6510,"604184f66d357ebd013db2e902d7cbb8648c4e39c521b094a3b9e249bc575bd5",9.317957166392093],[5957,"17a915a6f6410978c83be29769989db64981d466801d133b5a3bb3ef3a9f5dd9",9.917710196779964],[19533,"77784ce85e23572440376d33b7e84b1affad1f1f351fd98690134eabce38570d",9.317957166392093],[4159,"c4796aad4a83d568f18f6791d5b4fce481bbdb3e9fcd761e9749cc7c2874ace4",9.917710196779964],[7092,"2ca93efc33cfb43c44f48830af5cf3fd4669c8d79752d0402d9cf10beb3360d1",9.317957166392093],[3874,"6ea41b88f44b2dca6b52e4775167580cca3f5f369e9e711a9253bf467cf18be6",9.917710196779964],[6760,"7fb82fa576af0d157f1e15c5ac026ae2589aa813e25a10bf9c3c4a0409ab84d3",9.917710196779964],[15425,"3de993dca62099f92d995425479f785c6c9d228dc10b3fc6ad01f24be05cbd75",9.317957166392093],[15506,"936f90b80b8ed8d6d0f176023a1a612cc78d06d09f26d57448d069165886fa73",9.400063755180108],[8613,"ec255db334e823a5ad5c7d25247b6dc48cf3ac567a567a2501d26705514455c7",9.397642257991386],[8694,"42d76412aab24e8a97683171e4a71c99254afa2318d905262f4ad2bbc213bac6",9.917710196779964],[15812,"c3c662592a0be0e9c303f64256eacb4f9a5711ba40761b0ac7f4227783552a6d",9.317957166392093],[6873,"4c9bc67a2fd883b17e6100fb5576d6cef1f07c8b57e9b5eb0a31b724b7e8cad2",9.917710196779964],[13787,"9b7b223b54b60a6b31ac8dc24ae7041ede96f4a264fd5f06e45a73630213a799",9.317957166392093],[8789,"905f7964abdd8fb6bef715b6c5300cbdce31dccfe990d1190b317c45014823c6",9.317957166392093],[618,"1ae5b343007cc6d113deae279fcd1c66b057ee591560512a799de50a2ddbccfb",9.317957166392093],[9462,"77c5655529e3fa1c41c0cd3d0b6cbd48fdfcc6a7c2c9f55509319f251f3df6c1",10.022779043280183],[16201,"16cddee91805c1eb3b9a324c07f31ccf78c265e9f767a72296e35b17e796f963",9.317957166392093],[5787,"ef7046a3873b1a72ce355e9b6b25a6b73fa5697958b8d4b7c069a6019d537eda",9.317957166392093],[19859,"1747a630d2af89c1e7627c45e968e9e305da27c3eaec7a37a9cccad9ee408800",9.317957166392093],[9566,"1ec396eb9e38fef781dcde08bd03d5e4d0ee168ac7814a434f17db7ff92d32c1",9.917710196779964],[19060,"adac5e4d3f9b2e0e42e6e7de2746b95ef1b8854ba2738c8ffd0dea6621a5611e",9.317957166392093],[8384,"b20695861934946412c170d0777730740e8d261bb1148b94d541bef8203bbbc8",9.917710196779964],[7273,"3c6a2d892edba246a28971a6ff4eb7d6821105fb258e6c999357e946a8c830d0",9.317957166392093],[2578,"1d61cf43d9a6f3bb8d6210cdf6f5da882b95892fda674783f43d8b26006653ef",9.917710196779964],[14743,"92a1c7da14a5266c6c27006be7de2c7f316450b04822330737040b51e1680084",9.317957166392093],[368,"de9089b40b1fdd8bcaf874fc816b15304c1dcf5cab364ce9bc998982eb8ea1fd",9.917710196779964],[10026,"c7e732427425aa25aa214dea0bd9073821a515886e1c51dad11c4e4b78f229be",9.647446457990116],[4251,"fa975e18cc03902165d7e9b2f0d439842ab1d1107adeff5443bd90357da71ce4",9.917710196779964],[11850,"2bad1a3ed63f644d9c9eeb63f665ccfb11a557993a552851abbc2cac2c925eb2",9.317957166392093],[2586,"773aa9521328913244a9488b701a90ffc65031247733a6413ddf326deebe40ef",9.917710196779964],[18033,"1f8d40416a6d508d6dda760f4918dd3dbea0433e4f98690d6036fe497013b63c",9.317957166392093],[12259,"683772b35adf43c51965d283152f7636eba0d331496990a65f54a0041989a2af",9.917710196779964],[15344,"c5ee540eeb41708aa55e44831084c7debfd517fba752671d79a5635d3c847477",9.317957166392093],[19188,"d0ec76766fcfe2ff707df46a427eb965bdcee53bce8eb6f98ed645f3ea171319",9.317957166392093],[14987,"6eed15c0403223d740e2196b6bf43e7f7106d44d2218828c479985e1e743cf7e",15.961722488038278],[5789,"86b320a9a9c7895c27fb7933cbdd3a19b6ce3afccf2cf200c9e9ea3b3bdc7bda",9.917710196779964],[16827,"2e2fd07e2b8387862ab8a5b923837c96debc8b091beb6293c362df0420ccbd55",9.317957166392093],[13969,"7a90b926aa96c40fccc58ee624f28150a5773b33fd7e72be5b745c68d48ca495",9.317957166392093],[6573,"88f674a2d31cb4ea8c9a778a559b9d79cbce6f490894616ea05e8315a59fe2d4",9.317957166392093],[2584,"102bf46d2f2614140699fd0b34095f41004310703d70c58064140234aaea43ef",9.917710196779964],[19517,"b8708e6ca4767b2a947500a6a94dbd78e92953e28150543d03f5798ef8acdb0d",9.647446457990116],[11845,"f8a0e5649eae6c0f8a2c02d89c95dec051f30ece2d16ebeb69ba3f12a4d96cb2",9.917710196779964],[13987,"f0cbde94aec093e4eb6ce8e4fa8d25dc09508d79345b3e245aff478d2b113595",9.317957166392093],[11580,"f913159559890e5bf6e8d7a3a5e62a67c4e1b0a1d8fc9e4d1e9907f974c900b4",9.917710196779964],[6120,"8a2befcffa87e837d6aea99b2d3c35fdf5c8e6a5327dbc522b0a8469d1e54cd8",9.917710196779964],[6507,"691d33821c5c6e7a0d2c11120113d4d286bcdea12eeecfad743b00e184c865d5",9.317957166392093],[4728,"7b4bad18ecd72d1a8917756edec37745a06ea64bb03397320b2be65ac70cd5e0",9.917710196779964],[14158,"d614d331fcf1ff82c4b078c352e6405f1b02b5e81d07e88d424350b7bd654191",21.05],[11806,"ff24e8b9b346c8654610d71af4d4c1433b3e8e292ea8a51656ae12c7f7a0abb2",9.917710196779964],[10806,"8ce69ba57902c132b5f98509012231d34a3420dd4f650b3e65d51f24f13b43b9",9.917710196779964],[4649,"95d3a5438e5220cb329ab31b2474de3f2ea5f73f050583324ff1317e485d52e1",9.917710196779964],[10956,"564bc4dfd6fb28fd3ecaf57bcff72678e6861fd7ed9e71843a635b6771114eb8",9.917710196779964],[15479,"59a3bcab233a232e283fa502befc85839417be43e698b7436b4cb1f1c60e8574",9.317957166392093],[11739,"618651ee39a1c6eb7ea38490bcb4ed7c6fa84f58a23210665915c0c3f21612b3",9.317957166392093],[1725,"61073ed0d23de8f4e92cc0406b1270bdbfec36bfa9ffba0dc37c36def038c6f4",9.917710196779964],[468,"55ca018c5aa7c298749c961c63db94ea271c97bb201007d67cb6746aef63ddfc",9.917710196779964],[5467,"239dd76544c9c8b71181e081ecb7b5319695d7f6aa5d82c314cda826343869dc",9.317957166392093],[17509,"79cdb884ae1ad5a8fe2b5b6e1dd062d09af2de0b815655dc6e43640576d34847",9.317957166392093],[4039,"63e26b4c024c76a640fdb622e9cab02b8948e4556e1afba289c31e0628c37fe5",10.052724077328646],[10420,"8e9b3808e781fcb68aa2c3b2f1cf7387d0a243ef5aa74dafc25b9e37051dadbb",9.917710196779964],[12209,"e11b16975df72e2986a4ef2570999f593461136bcc6c3f0ebaaca297bdac06b0",9.917710196779964],[9460,"7844b5300bdaed93c96c80db174543409034c3989d262c31b9b7fbaf27eff6c1",9.917710196779964],[864,"3431adc9aa9cff079f177457002fb8b78313640d5249d74f9e30b42883f320fa",9.917710196779964],[16431,"42c227b47ea107e193ea65d76decb0f68f6e5cde8d0ba4fbe460d8b4855a805e",9.317957166392093],[10113,"fe5001d16ef9899b78695f5a1ef1e8fbfa5cd31903decf04d44229a5a4cb9cbd",9.917710196779964],[18607,"ff5b21367dcad1a1983b33037b005e2aeced26d65a5b333337d8daefaea46e2e",9.317957166392093],[769,"7d166191a15f497bfc65eca5f13392cedd2ea82b748b43df49404d89c360befa",9.917710196779964],[1132,"b31b1670844b5b74738228061e9f5804ebc24d8a1708ffb861270ecc5c5f66f8",9.917710196779964],[5400,"8ec83b782dbc9562d8b9a6875b75411be83b54b0f5a2ef03cad4a5a19038d0dc",9.497392881432782],[3713,"fe9b26dd2ab0292b547ab456fb875ad0c8517b8ddcbc1b3b37948b946e7d83e7",9.917710196779964],[15415,"60016e614c3a9ecdfd59c93961b5501d997402805abd4d582ea5935acc80fe75",9.317957166392093],[17815,"74757d2b3ff91bdc8954ed800fbad98a9f7d6bfb40aae776ac736d31c4e30141",9.317957166392093],[10267,"d045b547ec10e5a864cc4bede51ed44bf20857cdfd159194f0b437c364f79bbc",9.917710196779964],[12863,"fab1acc11055ef3369c5f62e086d4e7af34e2d933fff321f8dc4ffab71127cab",9.917710196779964],[19554,"f0c2547823aaa18cc831ac8ef07de9a750b3dfa947b9ce5580220f05a60e790c",9.317957166392093],[16942,"a7ad812c82c1d2353b5f0686dbfdd2ccd554547a8d43f20cba74be04fa9a4753",10.052724077328646],[16164,"46eef2fd855942c07bfbfc1460dd760e525b18dea020ca06318ef6ba13dec464",9.317957166392093],[2203,"ebc10a642b345bb5ac104ec93e616b3c635556be504e27352e79a3aaf2f584f1",9.917710196779964],[18779,"470094a71ea214d0d779ded806d1a5089f7f70920f3a8cb756dfafbd61b4ce27",9.647446457990116],[6128,"b09ecb885d5ceb3d0c50ea4dd22893e2d716bfbc263ea1d77b3d165491be43d8",9.917710196779964],[634,"0cc228fac12ec245cd9d34aaa2d5cf0c0fd38cf21c2980b776d422054b1daffb",45.2017937219731],[10203,"88d2b25f5c2efd61968a92006bf8d748f20e1e0e4016bdacc35489782896fabc",9.917710196779964],[12866,"24822407d7bd53e56c960ad11dadab5153fcd838fbf13fcba7f459602c0877ab",9.917710196779964],[17122,"f7054b7052ceaafd36afbf89d104b9d58fb5df7cb3981a7fa741204fab26914f",45.20423600605144],[14393,"dfd0815db26146d0d1862667b80e23f418d12660ce27ebe6d868c1fb7efc5c8b",9.317957166392093],[17232,"f4723f7d39764d276a5c806342729025ff60db82a9775010a24266d7d9a6424d",9.317957166392093],[13791,"f573f3efde79d601805f595419bd8329a1fc0255744e239f23df878f554c8999",9.317957166392093],[5480,"fc560d30faeb71dbd0fff49624515f77a6c0f32cd5fc43dcea23cee57c6450dc",9.917710196779964],[9766,"4a9609b9179904d8d355e3924eb7516c042fce53bb536e8a1d977e0740b4dfbf",9.917710196779964],[6661,"a0fbd62b0e3e6c80b3fa570f6103d79829b5f20ba2b0e2f3ffa04bb963f43ed4",9.917710196779964],[5928,"34e5dfa0bc7be8b8ada2e17836aff01a67a82d1ac6fd37bec852b2d36dfc85d9",9.917710196779964],[6444,"20709ce8b058c1fa5678494a4dc436d3a4074aaafc2482b9cd65a2ab28a8eed5",9.917710196779964],[18277,"e7654164ea113ca3506c4d61eb9ef70af74690f0507e734c0f0f9ae376fc4d36",9.317957166392093],[11868,"e057f9a925a9283def4f57f5998e5993730df75f2805d271b396f12db1bf43b2",9.917710196779964],[4122,"8fe7f9ab1472257e914a88c4a668046075070003b0d99332ea96bc48a755eae4",9.917710196779964],[15511,"c50c3271171259b795eca9a66bd8d204775f44f4b22ddf84930f01b97bcae373",9.317957166392093],[14025,"1a003a1289f0cb8d5cfcc6d41a735ca6450a7d8d7080626ac52af3bbba503794",9.317957166392093],[11985,"16b7a8faf0c7a0e4474b7d2bd91d6174e20404e4d6f5fbd59ed07c720b9a6ab1",9.917710196779964],[12797,"14d1e6e27c217bba0f834e6967f258b0bdbf3934527a405c9613ff4f07f4efab",9.917710196779964],[5009,"53593d8b7b885c72234650d8ffdc21987fa584e4abf93b2357e2b1c3bd751bdf",9.917710196779964],[2119,"541d5cb63b7804d4f3971213571a888003b2300d628494683187ece21a191ff2",9.317957166392093],[13568,"e14b9348ebe3fdae97626e516deeafa7bca32458373f0f8178e95f274ba1469e",9.317957166392093],[11911,"2d096bfb549fe94429ee2930eef1b54f229d3df85b8d96388778988866f7efb1",9.917710196779964],[3173,"f2e572badf024c355dc70e7d9106e565b58f7c12a0021aaf16fe16544c8631eb",9.317957166392093],[17111,"3efa37754cc59210d6b0d8dddc6edb8be98799ebc8c62ca4e07028c03f31c34f",26.13903743315508],[12603,"596098012bf310b33045425bd262e6a365865fea1ad2a04edfd9fb1873653cad",9.917710196779964],[14386,"d1ad024df8ba963b0b242502f3db088cfc4028ad4affaffd747f195379b8928b",9.317957166392093],[16902,"581e4f0057469bf97623c1ed21e0aaecf9eaf75309c34b39c7545f0aaffa1f54",9.317957166392093],[10158,"72dea1029cfaba2c385e24af25f546e1ebc378ac5b7a89b75be6514bb6d55abd",9.917710196779964],[14197,"d9eee2c3ade74c0743e48c9b1a0c5209b6006b3fd1aa9d57cc57fb6b70134c90",9.317957166392093],[16351,"abedae6e68169c404e61b6ad449575368c843d6303a2b704718df7a272590c60",9.317957166392093],[2222,"85e8a5fbca41bc0cccfe1a31b94deb84f2029df394acc133e39d1745cdfe5ff1",9.317957166392093],[8721,"a939e47c24b8ae1120a1bfbd8916561749087e2f1f7507b59faf96d41bd08ec6",9.917710196779964],[4089,"221647c31afa74a3c57f991c2390dd4ce30b02e0949ec8546f25f12c893123e5",9.917710196779964],[11541,"6aff1f1d62e3542978b1a8ebce6ab780c2e9c1a82d6673477120425fecb846b4",9.317957166392093],[1904,"ac53006377d6d85b8b6ed9c84d296466fd40c5f92d141ab79324f152a5d299f3",9.317957166392093],[18206,"4eea7d7f73720fed1fec766ba49233cbeb864294d9769be8b7dec81d8ba4e337",19.13550600343053],[8378,"a5352da898d82dfb96f02c1c491e617c32d69c6b09e9432c04e14c73ba3bcbc8",9.917710196779964],[2497,"ec14b5d880fbc89547c92ae79787205a46a78d11ee5a742cfcaac37c1bc4dcef",9.917710196779964],[7546,"00cbac125c7c997bec79ecfb05ebecd4a21d2032da6a55088fd11a6991f28cce",9.917710196779964],[13577,"4b0d0fe9d8aa1a6b6468d5802acfd18e1d01e2ddc935c825d8d9ce6190fbf79d",9.317957166392093],[489,"e99066ab98ba53150b7e5007b38e2d62b076dce6279e47f74018e2d7472dbafc",9.917710196779964],[16898,"8f867170cdd08f25b93c1069763b19ff9660b579fb8d9803f1e35e40bf423b54",9.317957166392093],[14321,"f76307588a304d27626f72cabd92788ccfe16d8861d647f48bece246a708168d",9.317957166392093],[14411,"208e2ced4cfe72224726f52f6f728033a0acfbfa233bae2c7709d362ad85278b",12.064171122994653],[8191,"e11ac9a7abf7ee4c3656ab2ebd729547673b1f3dad61c225235aa3a1a5f70dca",9.917710196779964],[340,"b4b1efcaeab722a397cb023fb85a31df76a34c13fdf2533dbd7167f574f9c3fd",9.317957166392093],[16387,"1098299cbe8aec52e5a0df563ef9cf77dd750c29d2e1c41ea318c48d250a545f",9.317957166392093],[7451,"b6a6637a3aa1900b30f5f7edd4b4cb8619968c6eedac2b338efbe76555cd12cf",9.917710196779964],[18454,"7e24185da4de20df0b558214943d9c1e6a4baedc7287556ff5913d54a27d7f32",9.317957166392093],[19560,"71761f86033367b2c1a8e6f81e17ba0ddf441bf847960d8526b255c8bdd04a0c",9.317957166392093],[6166,"cfc95194954bb62a42761b575bf08d816c7fb6a441425eef4f08b6198e220dd8",9.317957166392093],[18241,"73844ebbed6e5908ed435669085868fb2fdf2beaabdfe9765a69b7983fd01f37",10.042313117066291],[6261,"24ce1498baa20f74eefeb04faf85fe7880d059d998f3533f6648ec6bdd2456d7",9.917710196779964],[18165,"c7b4d3bfbf69d95c6c2eeaca3ce49f04a26523c3152bf0cd2c02c4b1f2d70b39",9.317957166392093],[3109,"8f9dc33e5472167d7828b50a71525592017be295f151a09e1d3b7ea8cc4e9beb",20.009128251939753],[16748,"4df7f3da14e1d3e193056043edd68fa63bbbae68103df4c7a8a1a6c213ec8057",9.361256544502618],[10008,"622af142a09bb9ae73dd3b53b3e248d43ce7de763718a3c45ce5980bef6a48be",9.317957166392093],[3645,"2769ce9ad4cf3adfe162ce7b9b816a4676ad86a3425229c6957f2d245a68fae7",9.917710196779964],[1354,"0b5db3a8eab4f5b62231a53dbeb9cf0605b657a0fe92c460032eb8fc0df707f7",9.917710196779964],[4132,"71c0a0393582365d184e62dbf6724800d23003512e855725642d45641c1adce4",9.917710196779964],[16196,"ac5b0aaf6b44ca6ad776209bb0bae1fb8dc27b40f9a49815a959785ade441264",9.317957166392093],[17710,"91417ae4698ebdca6e98f658224c127042c36501c9c64027f5fbe040ab860743",9.317957166392093],[14259,"7f988dcf4176ee7c6a0c850ac323120fb965f427d2b34fcbd44acd06d2d3af8e",9.317957166392093],[10694,"10d81077180fcc922bec26188ee9ef6694b64e504bb8614dc6f06187693c0aba",9.917710196779964],[16660,"35417b217319e1caab45f97fcbf4376e3e73f782cff13f70d8c7fa4175687e59",9.446518076143755],[2392,"a91b955420393b2e4f903e8ca5193217887983c7fe0b9df16ae591816c2786f0",9.917710196779964],[13744,"070d06d528547d70d8185ce2fe33c9773e746bc9211e9d41660f4653412c8d9a",19],[2870,"e7d4b4e8a144254d6af345a011c7e442d40c4fe4f078b01bcacc4b0c76ed4aed",9.317957166392093],[970,"1cfaa777974ff5c61674481359f98e223318c8701315d8b57deea475b7ab61f9",9.317957166392093],[15103,"b2813c4552553e0ef98d5d81b4ef22e81e30871b75b76df2579a4a9fed258b7c",9.317957166392093],[15231,"13a024c12e9f7fdad6b25a517b358e21a6d274bd18896fee9cc7af2917a5d379",9.317957166392093],[17135,"3fbb90d836803e3b3900120c0f9e2c9a86ed4259edb2727ac6368d6ad109584f",9.317957166392093],[911,"3a2d9f7cf1165113d8507926a2ada22184b8471a7f2cc874a19d9c6f768abdf9",9.317957166392093],[5367,"7090128be8a8a24e8484d0814ba41b3037539d1fe0c9f47f7cc34108bbab0cdd",9.917710196779964],[10869,"d929061baa0b8861e771a457c5606d5435cc61349e2a9d3d1143c5553693d1b8",9.917710196779964],[15732,"3513f8fde4e271336d9596ea1a9a6d6d38bbd0e9e57f3c4ab10174a8852bde6e",9.317957166392093],[17329,"811e9d8a78b89177508cf18644c0b80e73ce10f5b488b650e0f8f4c54efe434b",9.317957166392093],[17072,"4e4f0f54d2e72bd6569cbec3766bfb974eec2bf1c4ab265d5d119e2fdcdc8a50",9.317957166392093],[16571,"e745bcf072bee6d54fc3dfe9c1d93b0fdaaf61802f791fd408833e26c864bc5b",9.317957166392093],[7581,"3120a0da24db2ff1299b8cb4771a4330d004689dcdee002beacdab85416d4ace",9.917710196779964],[16807,"dcef9e9d5bed7cf8708b711477bef796fd2fea760c32de3795224b98d3ce0e56",20.19704433497537],[8462,"561dfcfd00fea4574fea14e294ff02d4ae261a9498ef9d75f33154341c673fc8",9.917710196779964],[4416,"b87c248986db1d04ad26ffff8bb936c92158e41eb7c55ee4dcb306b627d1f7e2",9.917710196779964],[3178,"c88cabcb497b429e8f065984d62a41fb76cffbd54bf560e2b83c9fb6136e29eb",9.317957166392093],[4235,"6b6e521f151f7c136e204ad270f92f87d97a5bbd6d4296d01f5d5bd8ce9131e4",9.317957166392093],[5479,"24f3799769abf5f779b5534c6b77436c09c839d6190ab7b8965c01a1d74254dc",9.917710196779964],[11371,"7f3e2f7392ba10a0ef5bcd2ad05d43505b3589b4d8f56ba0b0b057246f0192b5",9.917710196779964],[16738,"f62cb108d7cd089bad27bff2c31ef80e3ad00f5e0bf87720bf1dd809a5bd9c57",9.317957166392093],[19523,"461537cf1795866b3d07381b56e5c1c21b9f760bf582ea51e5add558f039b00d",9.317957166392093],[1875,"3274d07d28c04b07ae78a23ed2acf06e427fe66a892ec9992c3f460e923fc9f3",37.39153439153439],[7722,"c962f49da51fa3d60f2afd9784a5f42c4fd9b0c6fda28969becd9987243258cd",9.317957166392093],[19453,"dcf0ab2f4d835721bd336fa6ac0972e8b6eca556697c0960017e8643bad4d80f",9.317957166392093],[7377,"eff039267d94e2bef37afd6830b584c91f73cf4cb51f11bc582810013dbb8ecf",9.917710196779964],[5107,"e649c7bf017bf7eea8c9a931782c621da315f455c6a63efc000a80cfba4e87de",9.317957166392093],[12854,"96ac0519a09c4f3ce1c8253130d0fe5c2525c5ae5054a466bed1b61adda38aab",9.917710196779964],[13297,"21bdd032c6e2098c36c2d5d94735bd43ee85d1ba827dbb134b49b608466698a4",9.317957166392093],[16443,"acdd43b5d97f3c029331d9a0fb198ef9966755339bb14a5beaa628c7f0b5525e",9.317957166392093],[3528,"513be431e7060529ebddc8ea272cec3030f903060ca311afe4d67fef02b2c4e8",9.917710196779964],[7685,"082d386fee80f9288bb20e85dd2d8d8835d5cc6b1ba73fd10a08a9f4d2ffabcd",9.917710196779964],[15424,"768d08d3affeaa8dd08d29f5afbb53bc858cf6f51f33e506a21037ada844c175",9.317957166392093],[7405,"e1156bf6b184da25a273b2b438e257f763b285a1709f668efdba27ddb7c765cf",9.917710196779964],[620,"e61890600bf963827389e3ad2bdda00acb432a4979bc08967474c5d3dc47ccfb",9.917710196779964],[19257,"dbe93212aa432cef24e270f6305c95b6c5297eb4209e2733c7c4b80e5bbe6616",10.052724077328646],[9472,"971cdf2a7fed002a8951d962a7ed83ee4b6f8cab44205284324b9470cc66e4c1",9.917710196779964],[2996,"b4f44723af59dd853a65542a71659efe5b369fde9b70e6aa79df2308b5384aec",9.317957166392093],[2281,"1633a2170f956e9658ea54f27f11ef518403d34a04b6d89821df8e6110bd1af1",9.317957166392093],[19795,"3cefe9adc8a50ba9bf69183ec4ba9c05a3989809b69ede46dcbac65c9c5eaa02",16.787185354691076],[4825,"64da5d8b98f11aff67b2de8458fe18a72c2d9f1b34041aad8c00c95edc5541e0",9.917710196779964],[7885,"65d54d4ab2c7e60df0387819219d72ba6985c65db5055218496e0eba972562cc",9.917710196779964],[5157,"6aa36f004a6e8166c8342f37d7c4033200b93944161de8483b02f43ac8553dde",9.317957166392093],[3074,"bcfb0554c8043ef497971003c09c5ce007208bf25fd8e651bf963a86298cd1eb",9.317957166392093],[1780,"b3be531be7ba08f339147fbe4ddce378b66c7c8d37adac73a2c355c8b7d159f4",9.917710196779964],[15384,"ba9693c1f1c13f9d4ce29e6ca7e8266d3721548f5f5cdf1a63c7109d2c019a76",10.052724077328646],[7318,"3dc7597731824178ad2bb86d240c4f72f545ac0b4ea70334745163b3642cf7cf",9.317957166392093],[19355,"6d2468c31aa3b0361c1a8e372adaf24aafcb6bd54dacbaffe2207eaef87d7013",15.830388692579506],[14960,"a05d892b45d4b307ce490646fcb74c07ea396d3bd2b4b15a5d8c88c19b3a767f",9.317957166392093],[13616,"d03c489060dbbd1b37dd019fe211522a81d95b723da67897f536962fa3640d9d",9.317957166392093],[17691,"e5b9cc2002d1c0e1c9adeb292e3f7168bbc72536c9cb0dd5718a80a65eb16243",10.052724077328646],[902,"5956204ff5b75314936ef673ef39bed62ca942d8d621a93c71999e56d350d3f9",9.917710196779964],[5184,"a31c348b590cb4e0fc31371fbf888425970d4b5180721f867cf9ef93d47012de",9.917710196779964],[16877,"3790b83c53866363f3f5dec4010953360385c3ebf4f487bc36dbc8cd71e1b254",9.997888067581837],[6184,"fbb581c6c0060464d5588ce6704160356532d5e94bb0e602d2e899659103ead7",9.917710196779964],[13085,"24be8d7036584cd93999ee96b637f50e65d8607f39cdd0a11fa68a00bad4d0a9",9.317957166392093],[8473,"12c8c629d7dd984154c67b1c6f32d74b7ea5d94b84b8d00a3882de42dc872fc8",9.917710196779964],[19214,"df5f74c86eb48b9406ee6fc548c3f12d4934d7e5824ca2653056902e5ef03518",10.052724077328646],[611,"1606cb0ba3647eb7689adb7363860019ed0f75aed71f6df459ff645cf338d8fb",9.98764317945158],[11810,"69a8446d243af9968ac24508bb09c23abeee9c0a83a02c755d92a3d85891a6b2",9.917710196779964],[1976,"7d5a0ac2bef8008da7ca7e458583f8372cc8113c09142ea688ffb84733c425f3",9.917710196779964],[17414,"e1f8d495f5431a10f549937289e032b3b44c69a7df5201ecfcf7c25d8a4c8b49",17.005347593582886],[1730,"ad26b6a9a95f04144e5b03e4ec4b7aa193890138ed0f64c8fb6bfbb2ade4b9f4",9.917710196779964],[2495,"7b2c6b060e2330ce5a16e05cac596b451baf9e569ae78b240fa42e6efba3e1ef",9.917710196779964],[2141,"63a4695a2b9c4a0218b0d220b2e11abbef995c634ee301aa10ec8aaa9f9efdf1",9.317957166392093],[7330,"5d7b317e817203284e06ce5abec40a67803418f34559a04dc404b919b2b4d8cf",9.317957166392093],[14943,"6329ac5b119ded02837f0afd43181997e6bec553c9f589e8a8bf6dc7e641ed7f",9.317957166392093],[11269,"e45d595bf747ab98d84fff3c1069db91d76fd76d24369ad1000dc4576fac3ab6",9.917710196779964],[15133,"e14a5861c9487f3c568ccc51526f4ed2abd893f4cea018eb45643f70f5fffa7b",9.317957166392093],[14101,"2eecfa31ea551657423c52295292475d66133cf9d0966d34da448d88ff638b92",9.317957166392093],[12867,"eb7bd6df65479ee6a2986e3a749c70019e10ae04a178f61e601a46e58fe875ab",9.317957166392093],[9575,"d540e06e0cae77e26b212e57df116045360182761610c02f92705d2de16829c1",9.917710196779964],[16088,"c5fd9004868ffefe12e6c018e72c066ce4783676147ca1daad47e687f9e58766",9.317957166392093],[2284,"1ca4190b29cda641f4be7e156265f8ae8b7c51aecf186a6f465a3fd4463b17f1",21.71964461994077],[18273,"344359b8af1afab544bb035e9291012225ee604627850e1b8ddeedb180bf5e36",9.317957166392093],[4959,"b66a55897f785311f315b05c2ef85e309dbaaabc385c9b3314927724f33a7ddf",50],[12096,"14d8444d35468ce423276bde87a6ac059767c89231aa6b551fe126ff534bbab0",9.917710196779964],[766,"b39bc586672e6a387936a764d462d4e2ac8a131a33534c76b81e434c3ad0c5fa",9.917710196779964],[361,"58ab9f89f6bcca0a9a9dfc98be64a155216b84f15b952c7b77c41d4c94ccaafd",9.917710196779964],[9609,"a0dacee14368a5b707926fb8e7404e340eae692130f2ca625971609cc6abfbc0",9.917710196779964],[5083,"a57b0ee98eaae7ea126441f37bbc4fb9554b91b4110c3ea5d2e9a4724924aade",9.647446457990116],[11393,"4678a5d90bab7ada0f43e51bf8651d5c587fff0b6f431b75043e2b3df53565b5",9.917710196779964],[11172,"8c7206292d7bff67f4978a187339ff341464e4743d250202dd2efb7246d2deb6",9.917710196779964],[7108,"03cd2242a254dc1880bc386eb2125eab7b885cf51a78b62e4b847644b7b64ad1",9.917710196779964],[7519,"701530591673dfca995db8ea0d713c5b41e7520562726f7de4ee8eb18228a8ce",9.917710196779964],[12175,"ff6d6950853ab528066c8b84ea7faadccd8aec158269e5c34b84fb5c1ab738b0",9.917710196779964],[2410,"4011cfaa767e5e75f3097f4dfa6b4f29f12c141164ca5e9e1406dc9443d360f0",9.917710196779964],[18691,"77141dce7ba2e1f93b5faac13c0742dde2be274bbcefd6f95b75eb5078e79f2a",9.647446457990116],[928,"00b585755c06b30e3c4dbc4ae69c68f3da4cdf420f83b0f2199f907d80a5a4f9",9.917710196779964],[17224,"b8c1bf522b8262d609806ee7a9d88b8d2137f37bc4f2065a49fe13152fb3684d",9.317957166392093],[16375,"a74a4aded3b9b90981cd620fb1b00bc90668797a7f312137cbd6f5d56a2e925f",9.317957166392093],[3059,"e1fd49e7eabb70ec6ffc710a9d53bf838827c67d8db1dd89c7a0ed1e9c29edeb",9.317957166392093],[2432,"f1e09cd4628c3df91d9b5644e175cd2c646745ae31af907b0f1fa06fe13e41f0",26.173719376391983],[10986,"4033661b4abd59e272f29530c3606495444c0109713cd23d381e1d88914f13b8",9.317957166392093],[12970,"0a9a70145b85556f681772563671b076c501cdcb3b59abdd9f93c00c2a94c1aa",9.917710196779964],[6376,"7373fb7f07e63c3515f3a31c16892400f4bdf8389ce6bd1e986598d9ca2876d6",9.317957166392093],[14033,"e82da01d098912a612aadcf5786345310cb39e63855bc0f19d4985da5a980294",9.317957166392093],[16633,"bc52e649451fd4b31aa922c5a44aa7b5e495b022d868376a93c39a2ad235255a",9.317957166392093],[6189,"77352b34068ea644d5fda83e7c7725bacaf3078894059b618ddac09f1e04dbd7",9.917710196779964],[8061,"78fce97cc198d252ba503e6f11645158b43f942d0ab952aeee74e23846d409cb",9.997888067581837],[6997,"b060d9fcf091a66d233cc5b14382fbc17ca8109e66ed0449b8e52227768706d2",9.917710196779964],[455,"5a5448ab0fcb03a8bbdabb74734aa644252484b3f3573c40b554312c8d8f03fd",9.917710196779964],[16773,"13072fe6797073c22939c9b15a96c7db4a355b576483bd51455cb7ac33b6f756",9.647446457990116],[11496,"c87529fcd7918d4399eec91187e60bff0a052b69a01f82dc7c33e126ceb08bb4",9.917710196779964],[6305,"4498ab7c738a497043625127c5643b50f5a24392b480c856fdcd89b77ccefed6",9.317957166392093],[3762,"2f9375ef3b394443c2d1bf68f0000d098a450eb98919d4e1425b938d87752de7",9.917710196779964],[10404,"942a554a78649cb7f32dd58ed7b5a451f7f1fc84cc23924dafb9611c1361c6bb",9.317957166392093],[17444,"470536feebe9d642d8c65f8651cc9bbec10d1058cdd966fcabf8817bda47ce48",37.14527503526093],[14809,"174bbf4b86fd03a2e4e3e01be3baa3c8b60bd932c42a96e6532d879b50229582",9.317957166392093],[1526,"27964a5fce79ba52459d9862339a899c1f1befcd75c9994ece15b2f2a5b5f3f5",9.917710196779964],[10401,"f952331151692a58230cc451a8a92c4381f8a7d7ea9858623a43b536c8c4c9bb",9.917710196779964],[12914,"1797eef5ebe86db02a93e6f4e88b1525eb0a2103b38c732c45959518e8df38ab",9.917710196779964],[7843,"0d9e5559f71ab5f52265ea22ff34c6084bad411fbcb1599c94793e0aeea78bcc",9.917710196779964],[4266,"4b588200a3ac870854e4689d17f02e6744c9bb1db02288d2d2c54b9fe7aafee3",9.317957166392093],[7941,"edc7f41ffd97094f244706f4c326902197e64a763e4953ad393ae45e64a6f1cb",9.917710196779964],[15779,"1c5ee79b4ae416655f8b7e7a3b094313b93ad1300d0662af36183b717703c06d",10.014641288433381],[6296,"5a395836b895eb88208aad9d911e5020c33b56e2f6891125f89b23e6ba9a12d7",9.917710196779964],[1986,"2c2cab02bd40d4d38e3cf2f8b2612546c22d722ba8820c26decb50b7b1df13f3",9.917710196779964],[2334,"d9f7e925008b6884c7ace4314d0ddb88c4b7f63366ddd0822a89c106f342d4f0",9.317957166392093],[17091,"7979d70d669258ff4bbb23c79afaee297e783010ad56cb19d045bf9240de1350",9.317957166392093],[2970,"50fccc932e62c99489b18de49e057d4dbce092e4ff926cfce2362cf8134480ec",9.917710196779964],[3644,"679ce0c65eb35b15f3a39e7d75ac2e5d4d14948a7cb14d5ca0275024a973fee7",9.917710196779964],[1237,"192da5d099dff092ca73a8e2b58a38bb1ca4159586178da4a66879e01eb2c7f7",9.917710196779964],[3569,"ddd759d8694e1f744b9ecd7ea53551a21aea5d0555e731824a36404451237be8",17.16883116883117],[16184,"d3470426b64d63a6cd61f6fe555b59e03230f2b441189464a434400e1ccf4564",9.317957166392093],[19852,"9c4496cf09dd53ae8834b7b0610675a93a1a931e6d9dd838cb83b95b0748c000",9.317957166392093],[11778,"9c4e44d55d3fb545b2086f1037b79d44de4a6d44d15be826e05c74ff8593dab2",9.317957166392093],[14450,"758e411118b5ad6c9ea3ebdec387f89963c512b82871de2e0d221aad0598448a",9.368983957219251],[11856,"d87241a849860d2446d690b5b95ee56ccec6737fbe8b8df1272995e95a5f54b2",9.917710196779964],[14394,"7ba9362ba158a39bad3c60dc2cd576a395d9a443e2a344847b8f770b757d588b",9.317957166392093],[18559,"310a6a618fd75f592bc956803098ee9e75631152660e066db877acbf0e2a3d30",9.317957166392093],[18588,"d2a55945ab1f04a308a3e4f16fc385af3c3a8d88d8e868f76f3f65b4038d352f",9.317957166392093],[11379,"6f324283bd0ae2f56cabfa69562b86d9112f157ecbc48ccaed75528713d587b5",9.917710196779964],[6246,"7e37d28bcc48584547a2a6cad008ac48beada13a1741cf6f15f87f9684086ed7",9.917710196779964],[12850,"b9c2d9a3d96151a6dbc5a0d8c96ac644909a9767b54c9770249c595a3e2b93ab",9.917710196779964],[14120,"47e6a4b91523c50e260d95f9e2f875842e47cab7cce11174ce5001b0e12e1792",30.166371681415928],[5344,"77a66d2a723f8f8e63ff3b13167d8349b9471eaec11e8a9fa0f2d253ea672fdd",9.917710196779964],[15909,"902991c597f0c803c4fba9ca09b80bbe0e783a2e27e3ba2050e3851bd6abd36a",9.317957166392093],[2760,"d4208ec49f96c803fca16bebcc72d7dc0b54527c294352df9bf2e567d3820aee",9.317957166392093],[16533,"93abf314d71bc04105ded5769c885dc53d702d5d2145dcfc05a631d1b98b6b5c",9.317957166392093],[7894,"71f45d79271f459ec3addf7cdd84efadd5af3422658ce0dc3f0845f0be1448cc",9.917710196779964],[12977,"3e22a369903b3757aeb25c1c4906fdf6a533d9c825364cc55906930fa876bdaa",26.03713527851459],[10672,"edf99a919c47960ce72cd16937f85e556053db713a217d96a13ee0a47f2d38ba",9.917710196779964],[16113,"8fcb87233243fb85713528307f93788bba0264f5936c61fb4928bd9642acba65",17.16883116883117],[12715,"8567da7368c70e1f648a7c223b7a7c2830d403aa78a3ae61c9dfd2d5fb717fac",9.917710196779964],[7043,"9885b3dd51995ca005855e49bbc8a51c8150d0ada93dbe0b4781a458ae7eb3d1",9.917710196779964],[17069,"e532f8622df2622ddb50f8b79b9cec0805e1ac82fcd1f89c8f1e9b979684ba50",9.317957166392093],[5706,"55407e90d075ef67d7dd5f74f5d4bb08a67ef52bbe9ebc2102f870e1bf9504db",9.317957166392093],[10289,"0bd4cd0919bd49b61dcaf3e82dfb30ae8ed5065cf2d46c4d51c5d0d659d073bc",9.317957166392093],[4729,"ba5bbdbee5dd8b4cb9f24a5a1ece9f66bf1e5b329c5a953fd4df15b941e9d3e0",9.317957166392093],[7065,"9e81346ea9935ef64f6a09a65bd5a48501e6c3b7139ca729c2082194feae8ed1",9.917710196779964],[22,"5c2b86b3ed94fb70e1246331acee5998cb2ad8766b433812f13cdfc8079be3ff",9.317957166392093],[11224,"ebb6f233fa5468b71a8af27e74031452bb86af922f94ef4942d1127ab9fc8bb6",10.052724077328646],[7641,"c245aa889f01339db6488a618ab6eef7f55c5987f4f07f3715e3b3f2132bf0cd",9.917710196779964],[18590,"b6b4b64a583126dd5504364bb9a82c94cbb287ae2e92644276d2278656152a2f",19.066666666666666],[3772,"a943b1588b1ad75d0d2a4b44daa22dae0b99cbeafe5043ca297940816b0d23e7",9.917710196779964],[14480,"689b56ad7695634f00721567e2921e24d94229a98e01127fff31c8d7fd8c9989",9.317957166392093],[635,"64941baa140845f8815ef8bb0efe4fbc54a70fa7cf564d295c0a6a2874b3abfb",9.917710196779964],[19330,"3a909e08c53b591231a8736ce11564cc990081fb928646cf49d591e56aed2714",9.71386430678466],[3753,"2f05b13a4e8fb008ebf83a838f7529d07e60cb4a47d5910f70397457fd443ce7",9.917710196779964],[7988,"1b5ecd107e64b6e4b90fe9057b9af9cfa326dba91cd77ec763b6d35e949a98cb",9.317957166392093],[5046,"b4cd0611382c4bbf0988daed2bf4850f36df92a32003f850dadef4d32cd2e6de",10.052724077328646],[7122,"87b468c766526500e3b7c4c4c386343d478c6700d954bb0f96e445fef90c30d1",9.917710196779964],[5436,"fc733c7a699ddcf9e8849e0d23bbd6a4d5929faf40f320d904c6a3c94e1a8fdc",25],[16238,"ff710a29d8cc4fa0bb9e79d98ce6a15aee65ff4fc28f068b170d9c981896cf62",10.052724077328646],[6023,"ff4ae06e625e7e8dcf2e8bee9b4cebc7eca102f848655e16919166fc1764edd8",9.917710196779964],[4042,"3532a78047d52d00904ce09ceac7716112edfab6288e5ca4333ba527fced7be5",9.317957166392093],[4321,"c7b9c928e0ce70798c44cb9023f7edb5f27bd266bd3d61ffb79ee46d2fff9fe3",9.917710196779964],[9249,"e3687889ce752ee5510d5bb0b62dd1ef781ce4e12454883b787d76afaf7822c3",9.917710196779964],[531,"c9b9d159b2e0a18b9d75e85ee96e6edf5a2c6a27f9ff1cd25d831c712d0c79fc",9.917710196779964],[2755,"3f918d4943c7ac58a53fa3c2c8e11d7b3218d5cea056026ebda32653117f10ee",9.917710196779964],[5300,"63ecefcbb82a9387976b85d71a5c5bdc1d6d612015a84b3ab8f6da63732c64dd",9.317957166392093],[2973,"0d59c503f9ef466d6167abed25e6578c084770a5cc5aba593825d86efe6c7dec",17.429473684210528],[10344,"50a63ea5cd69f19527d3d390be91d93c1a298b7a615eda9f4655a35f855411bc",9.917710196779964],[1592,"292423b3d972fb88ea07d39bdb1e6ba6b9580805beb5eaa97ae6f0e1ac9596f5",9.317957166392093],[18137,"4191139394244c7ba9cedb33bb5fe0933c4997ac7ccb3b6d6a88be304c1afe39",9.317957166392093],[4243,"a77e16e58e4645674fc4c36cf0371e1347ea0d9764d96b9de731e05261562ae4",9.917710196779964],[18332,"5b101395688efb9414731110f092c6193ab800140484d7faac08d50caf6a3e35",9.317957166392093],[9231,"e50b79af53bb21132e709057c2fc21a58650ade4d3cd9e34e760369b386939c3",33.78010471204188],[7739,"64aec422bbd925a67889bdd46ff701fe275e28c56cc8d0dc2692b3d220803ccd",9.317957166392093],[16124,"03a7ca3e674366d28a4d48e7a28738e9a626f306ef5121945f95df6fbcdb7565",9.317957166392093],[5186,"8a3006df34676b88af058d9094604c48522a41a17abd65a5f26dbacf801311de",9.317957166392093],[9946,"ab10536e0cb11d64be9aa11b8ec572ebb6f8fc822e9168b8678aa07caf00a7be",9.917710196779964],[7568,"8cade9fcc35f90a220907eb396fbf0543eee3a3e8a6e2231792a57996d4863ce",9.917710196779964],[6198,"ea4ba596201366667c77b5261300225c85c41652bece4f01a49c33fcd2dcc5d7",9.917710196779964],[574,"7746125673bbf9e719cae53840a134676370266843bf80862060ceb26fe019fc",9.317957166392093],[3467,"da055aa891ad56ef485c8276ff0211af3ee6acc7dc171a42c19bccdaa88743e9",9.917710196779964],[6493,"85fc143824a11a1f8d69063431b13b5f729a2e767cf31e78a2744c3241bc8ad5",9.917710196779964],[15317,"0a4ff63593aa19327e8ad852bed3691d1aadf5d8a30fe6f1fedd3f94594c0278",9.317957166392093],[8240,"22f269785115d939edcee4a14e26b55e6f6978a5ca8e90cab2dd89f7386eb0c9",9.917710196779964],[3374,"2ba7cd1c6c7777137fb61fc12d5f4c9b39b34a30ab60afb07755c9fc1ee6dfe9",9.917710196779964],[8887,"e6ec87a86da66f0285a62167f925dcbe217b53b153252fc5e9717b4d855084c5",9.917710196779964],[484,"c261a02f98b8a0607b121bb6b3a8218de573f9fe739fcac16c6cd33a367fbefc",9.917710196779964],[7477,"fd9006963128cc3c6036ebcb1c9b98ec3f2339f367791b6ff8c1dc4d2cd8dbce",9.917710196779964],[2780,"2173ad6a286851c7207f5a693436811fe3663aff3c345506ead871a53b1ae5ed",9.917710196779964],[276,"0829c0813b28a71f91295f53e9e072840b474443275392aeafce61e81c2a1afe",9.317957166392093],[19479,"43c220b8eb579a0ea8037b19742bf4cc859f45d7b25be44d805a87ca38c6350f",9.317957166392093],[9287,"016f898eb26e79bc3f32a0ca14f830ad52b61f1fd98e506c96cd3f5909e9e6c2",9.917710196779964],[8855,"310c2795b758a79726e289297266064393557b0bf20b5ab8d36091cd9641bec5",9.317957166392093],[15294,"c206260973aa8a6da2d6ab5827524a40b31d6f8bcff77ba672c0adda7cc29878",9.647446457990116],[9706,"319fdcb18c06e6f1ec56b7d23d6f5922d212f14c832174309a7c2f6da69f54c0",9.917710196779964],[2852,"ac69f2723fa3ca24bbf44dd12059e2244bc383fac8aa5ffa4977940f4cba5bed",9.917710196779964],[9722,"c24f2669dd35cae84747e3f1d0d7c19a2a878af3bd44cb1c810405e4285634c0",9.917710196779964],[4718,"7a0640c7c1f4532876c4b487431d4becda537e1878559cd399833974d054eee0",9.317957166392093],[4025,"17f74e9140e8dd1c016d4364b8eb7e98deabdb3be6bde038f790e00f95b097e5",9.317957166392093],[5359,"e62219337f7c471c484783cf264709ab04dfd71475e554fd713f1e4526bf16dd",9.917710196779964],[10307,"aa23021d29cc6b90e13f6e1774da8d38269e11a02942b26080aaa6ab70f04ebc",9.917710196779964],[16574,"65ba434986babfc38bc41d72e957630050ddd9ebe48f726ad33e5cd20d5a9d5b",9.773123909249565],[6724,"46d2057f143fba1eca46bb7a19a2bed9b494771a1a7dede9f1858bee2ef8cad3",9.917710196779964],[8001,"cbc54a188e4dcc5ca16158695c7acd3e47165aa80fad1892eb947130d17e85cb",9.317957166392093],[11706,"8dd0ee2c1413e7d1cbfdd5bcd729c7d43519df733561fa52530cdde5f7da43b3",9.917710196779964],[10837,"535407996edcb22fdf78305e12742f5f0c796be1bacdc3ede8773b1cbfef13b9",9.917710196779964],[14414,"65ab6a51d05c20b355e04678aaa5e9d8bbf2fcaf132d2366981b99b46163228b",9.317957166392093],[91,"96084ad56eaeef26b4565b88b5e2877c151dc1b9045500b311086919e4c86bff",9.917710196779964],[13029,"3da4bdb895d34d42e9b7ce04ea5d60119d838a243443165b175bcff8c2f365aa",9.917710196779964],[19763,"8ddbf4fa5b627e76c5921b26177f36e21c95406d8cacb60907413d7b5450ed03",9.647446457990116],[4875,"ad839d91a405575093bf0121ac8649156f0b0e84757c4f77dbe6a35b68bf00e0",9.917710196779964],[15420,"71200d8c7527db911c75fbc7b656c82ea701e7bce66522f3e967e02cbaafe975",9.317957166392093],[15237,"c305e4b59e8754f349de9001534df2882394e1e1d3854beb85ecb698a55dbe79",9.317957166392093],[10142,"619be8fc800f0896b7a25e36c68d5ca78b1215e49e3b53c0e56b2790b2596ebd",16.155844155844157],[3212,"50571919557eb65187bcb26d4826356768c31053134c2967ee16ff187127f8ea",9.317957166392093],[19055,"bdfed747cf4580a8dc89ab8db7ba87d3a7b288efef08f71e2d97da887d27a01e",9.317957166392093],[15181,"dc77618e6bc27d52b009b8abbe970098a1a614f1c7de3e91f03c1887d6d6f07a",9.317957166392093],[1334,"8e6392e88954b0c07a8bf332c190b30e509066a5b9e5079c9394c9867f682bf7",9.917710196779964],[2269,"06ad1f99190ac56f86aa3af06b476f99c66613683f3bb7feda1c1a17727827f1",9.917710196779964],[1449,"49ddaa402626472b8cbe4dac248bf9769ebef1899ab0a58b08533fa9601280f6",9.917710196779964],[10953,"6f4fb5b2b8cc305244ff195ee8fd629cca74811863c704ed94af8718484151b8",9.917710196779964],[10947,"1668645c08bb79a952be7b20d36e6bff969a3016528426c01f28e3c3e64a66b8",9.917710196779964],[889,"edc8d3410201be8d1c2275a10127101510596982f22196782073e1bbea48fcf9",9.917710196779964],[12783,"479d005bd8c7d307b3ec3cc5ae8e5dc072fb86de6c0d0a0391aa514c4dda04ac",9.917710196779964],[14163,"cd6f2109f56c283b675fe2773061e44b963f7293fb751a2cd0d9c47e8bac2f91",9.317957166392093],[6534,"7c06a71c1260ee915e73ed9152990ce9c13da90e2ded442f3ed480965b1e2cd5",9.917710196779964],[8089,"9073683e50854a673cb2ca8eb4059431a8669b96c36c2467c375b8dc3893d3ca",9.917710196779964],[16876,"4b48897e65ae9a3fb6108f7ab8918c18e492d0f1351e41f7788bac906c5fb654",9.317957166392093],[15954,"b009035d0b83a90ee1c693a333251ac705a6ebf64a10d0357142d61147f8e469",10.016260162601625],[14840,"a62745e3799b318c4aa5f494fd4e06fe4fea29f4dc9120119c1f501368502582",19.2],[14097,"d427efe28d0600fd355da9957890320a9e5f24079a98646197c94ccf3c9a9a92",14.188948306595366],[12920,"b47bbeb9be684efcba7e84f65ae74ee2043f19e1a6a2961a096de317e04c29ab",9.917710196779964],[1511,"49be06fef9240b9313d3574a2bad98a7acdd72a01401f4f9de28f5622d9d0cf6",9.917710196779964],[18766,"14f5166b54e8c63345b33df9d758c9d7e4ae841986099f2b3641023873841928",9.984905660377358],[5535,"7c6b157f65c7955ded2565296ba60aef5b2f7748a5081c4fc678f077fc4201dc",9.917710196779964],[12432,"37f2c2e3ef36c64bc9726e03827e6dd4a938180858be9ebc6c825123343c5fae",9.317957166392093],[19377,"138f193195984aafb8baf4302b77ccc8d88f3b7656f592f5108f616f5a63b012",9.647446457990116],[16623,"20de6ed38b16544d473bbec96d3d91a37a9ec66c4106670301ea151221ec545a",9.647446457990116],[2277,"d450f2410770c65fbbed2cd59e849a02838bf96ea79487eb3caa658a88161ff1",9.917710196779964],[14598,"6d024784ea694f1f1526d9d223728531300323ac336c6afc31dbdf6d7cb72a87",9.317957166392093],[11696,"89caf3e73e1f26118e2608aacff2c28aff18b4688bf927404d506a5531df52b3",9.917710196779964],[3020,"0dca1fb6264dad521feb37380bd245620025ccce38245c4c9ce9890da44b21ec",9.317957166392093],[9235,"df09f091201dd9d491ac2b659cfa9966ddd8593c18d10eb6d9587367f57d33c3",9.647446457990116],[8314,"f52d4c8b15d3778218dc8c56add25367c673144764e4eb6fbcca5d560a6b3cc9",9.317957166392093],[5654,"9697dc5668b2c9c9eb3142e134e0bda3103f7ad16d04eefc345387a20d834cdb",9.317957166392093],[18263,"3c2756bce6308c2df3ca7216210ae033f1e78bbed2ce96b0e31b37fbf53ab036",9.317957166392093],[1371,"ff4081ab83c0f4825a5a410697bbe13fa6981bcb1215b1d0d9db80ec1ff4ebf6",9.917710196779964],[7526,"20a70c140ea60ada40b33169d9a01f14b2e1e827e92342f76f352b47173c9cce",9.317957166392093],[18202,"5b7f7fda14867714440f05c467ec613f9fae8fd1909310ae8d7580178cce1638",9.317957166392093],[1270,"0a15f916c30d3a2813d7a6b3bcf0ff7edff234b758c15b6694548da8900b8df7",9.917710196779964],[11128,"021f83ebdf0af45f53b92784bf1f3deb1c313fdc2570aa59e5888694839e1cb7",9.917710196779964],[16122,"6d2726999457831a70656ac9b7c468140442b22e504f9c2d2612ad02254f8165",9.317957166392093],[12272,"60599fd2530b93fdb0f6a8b5f8334dcc84201a5b049ffc345af3a41e198f80af",9.917710196779964],[5494,"8e0f463516a8055c6980a9984399f3ca56bd4da4acefb50266d81d7f606842dc",9.917710196779964],[3938,"31943763876708fc89505693c050e6039dc8c6d587e1f599fd7d7c80195716e6",9.917710196779964],[866,"4bcb17f55edd1ce2e54a61dc9bedb53c20e5529f1e8be754df4aafc1045a1ffa",9.917710196779964],[5115,"16477e2ec341fe21a8274b4d236b7a49c0204255ad811e210c15e4d308877bde",9.917710196779964],[8516,"8e3483de61e9d4a65fd1e864baf04a7ab755d83f320f79e5272677d144bff4c7",9.917710196779964],[3840,"c29a5d3608da7d94a0da89030d31b10e410db82b593c15baa10e6dfe61d6c8e6",28.097560975609756],[8550,"47079b86f5c9907af77c1fc2c2489b1ce80d54e1988e15fef588ab8065e1bcc7",9.722983257229833],[10524,"64c278e3b13a081c591e6740859f4d332ff3d90437772b3f9fb49f70b9a903bb",9.317957166392093],[9873,"9702e65e492fd38f0703ab140380c22d087953f2d64bb4de9c233838fc961abf",9.317957166392093],[14410,"a7548d70aafc898f17e01163946433152fa9209d23c65ce5a291c3b2a9b1278b",9.317957166392093],[15157,"1f04250b62c3d58a663164b18a6440a3b89359def00378b0e3c2b52d77be557b",9.317957166392093],[7334,"d627fe8d52303fb91a099a814bb16031b39d4b2e55bf233518a3df2dce65d5cf",9.917710196779964],[12955,"7623f5ec0a6a848d4e19e6e4bef0d831cf86ac86beace6df33ac91d22f02dcaa",9.917710196779964],[6452,"c5f9ea75476d1b716bd4890187fff5290a719717f114e6e3e683bf1b7cfce2d5",9.917710196779964],[15069,"dfc7fb7a32271b9d858bbcf8cd60cc61482732b78927c04f318610336db1377d",35.91236878137837],[11127,"52fbe6481c4c09db331190cb01ceec7dac3bd18910d64677e73bcc8c4d6a1db7",9.917710196779964],[8143,"4c5f12a4a2ff47fbb1668544746c804dc9bd35dafd0d7abba13f26cf0e6469ca",9.917710196779964],[8416,"13dfa62e441017e78b7347ef646ba5e511736cf2fb56697bf58c57ee770d87c8",9.917710196779964],[2131,"65a3fb6f6ffc0d2f2fa37c9de71da102429521291a7d3cc8948a8fee77d909f2",9.917710196779964],[1273,"76af9ba363387e7d2d6d13305e6a6ab53df01f0cb9c5ecd962114785fd9787f7",9.917710196779964],[19260,"0180f47f94e251c8c4ea99bf9b2b06c63050088a80fb69b74ec3b8166b4f4316",22.896860986547086],[6639,"28cfe5e8f27cc0a04e96a10c786fe78a375427828c3751d129dcccd5afdc62d4",9.917710196779964],[163,"38b351a186ca046785842a89e5af8e80455f752186c3b1c3c41aee86cdabeafe",9.917710196779964],[6854,"5e0d6a705601828f02825922679793aa630066c52ca7a486027fdd758e70f4d2",9.917710196779964],[14915,"cde008cce4badc590d5fb7d657d5edf1c6e995f4613c3cd2a0fcbedd0833a480",9.317957166392093],[652,"8669c8ab44098fc5338ad231b9ca34a443901934c010208600bf475921438ffb",9.917710196779964],[16470,"a0931dec0cfbfb2b10461fbb8fd9f493a117cd95b0b5bca7b132466a1e82e25d",9.317957166392093],[7921,"e842177886f69ff735c42a4fb5fda3692890406a0c2399fe079648464bbc17cc",9.917710196779964],[12641,"db2df84d30e3c0d475926acd296186432c1973c5ad84cea20701d9a139c4fdac",9.917710196779964],[11334,"088cdee64d8ab0374f459ee94ec8dacbae6250fd9d89ab3c197d756636bfbcb5",9.917710196779964],[6702,"a943741f58d60c15bd88dae21de89b8ac9e7196cbc7c5d9f513ded716c9af6d3",9.917710196779964],[102,"34b2de002fee74fb91617aef42fea461444822dd7798ca83689ab01e2a8d5cff",9.917710196779964],[1347,"95d3c91b0fa94d92c0e0b97795a2475b86cb8186a97c87053b25184effe016f7",10.052724077328646],[3257,"c4b1fc1382fc6f822695b525f8a06ac57beecde4b5e9708462ad4a3598cea1ea",9.917710196779964],[13195,"442d0f89edeba2297b391c817afb7f76fa6833557939f160b552180564affca6",9.317957166392093],[2573,"31055a11a044e7bdbea3297d9955a250b12d845ff4f4f3d3016fa2e8a84b65ef",9.917710196779964],[16397,"bee417248f654540b0c819b453ba108cb44b77767dad2a73a4e1ec1495ee265f",9.317957166392093],[15005,"92054813a87a00fc7417a688ebbcc329c11859a69218d5643707b0b448bf417e",9.317957166392093],[9635,"1543ac0b2fbe012fb6059f0a732e9de8fe425964cb5354b6cf403e643271d3c0",9.917710196779964],[4730,"7a91723b4a18c72f3ef8f65d2de75165b830867e8f009a9e94d851790de0d3e0",9.917710196779964],[8883,"7527d2496dda610e45b92152f5a234e291177c02f0c876de092c05e05e458dc5",9.317957166392093],[1423,"fb4b7e41ab3e0160db3d683ae23adb1362c8e38f6acb258e7522cbc7f4ccb2f6",88.54166666666667],[10816,"32c436fcee07a472d3328062b88fdccc79b35d6aa338743ef38e3089911332b9",9.917710196779964],[13931,"2c2832a9054c4742237f8fbe30292ef18b41d9a8c0cc4f2d8992954d64ab5596",9.317957166392093],[10623,"ea0e45f6cca29c07eceddb5a77d94442a67ec90d53444fad0a995ef916088bba",9.317957166392093],[9349,"9de12e2fa8b9b11e51f0ca2038c484f5cc59ed85efa62169e632d34963ee95c2",9.917710196779964],[5763,"8ceb053700e9da00dc47985330d5d2734603fd719a3b0d565296a8a73964b3da",19.11319394376352],[2744,"fbce8f062ca68979c6af9500030df7c74a366dcc35a60a4773a6258b569527ee",9.917710196779964],[12837,"6119798d816b0c004934ca428843a65ddea1d4a6815a2e5ae30956cd0777b5ab",9.917710196779964],[16123,"9a05409c9756c62de39922fd9e62ce78a8c0a000d51dd227e4bd079b64147b65",9.317957166392093],[19238,"2857fd90f03d1cc9c8790166e980eb1fc3b3f221d935e94f478d53ad89374d17",14.188034188034187],[684,"45e3185cdd3738b3c8f64ee3087f7b41da936ac4a13e4daefc4720a098b459fb",9.917710196779964],[14002,"3b76f3f7ddc1db92f7c22227f746321b1f1affb8191eb4df126e095ec33dc694",9.317957166392093],[9689,"b0437a5788c54a5d97159350d1a9683b1e0d580b68435b98cfdc6e9d6d8a77c0",9.917710196779964],[7643,"09ae8eea67490061b7285412f89e80b30b9f5a9eeb4cccc6738edabde93deecd",9.917710196779964],[17816,"d22885afb6a1228b820377008f96fb950ac1f1a9e9b65274ea5bcb7b86070041",10],[11392,"105d76b48f7f665c5135b787e9481678356b19f6c772bee1fd870655293368b5",9.317957166392093],[1355,"1c74b50b2063aacefc012afb95f735841d679aa3b0b639d941223aa82d1b07f7",9.917710196779964],[14119,"e62a6c0b9a32fb3356cc813557b3cfb91c98285aa52b9e043c6e5ed953b91b92",9.317957166392093],[1870,"2a98fdb46b4ae3aa723c54c36d6e5fdba2b05c67209ec068e255657c2ab2cdf3",9.917710196779964],[15363,"bc9a013fe40e073d3b2cba8752d5d7339be533d1485ea69e4957d66ef1d61677",9.647446457990116],[8478,"966d6284c29c75562095b2645de9523b6b42095fc84735e995c1b9886f8228c8",9.917710196779964],[15747,"7d66855e9b4be513b656dc80271bbb0f3fbd31eb49ee6b263568077248a9776e",9.317957166392093],[16987,"57d360d29db459fd9b13d397ae0609a173853257411bc15df6b25751e4534c52",9.317957166392093],[1147,"ab85c45bdcd96bbd78cfc27298a65fc3489fbbc7b987578b42ff2550451f53f8",9.917710196779964],[2774,"815dc53ea419670216e93bd80b06317c24da393758a1e5662a6afeb3d1faf3ed",9.917710196779964],[3069,"d616fdf3fb9f58f584050c9a9e2dc69526ebfdd485df98162648dbe1504fdfeb",9.317957166392093],[12642,"3a7c1cf14f51a90a7d7de565e6766ff795c6c92153b203daa027bb65db5dfdac",9.917710196779964],[10630,"8b6b1a391f6bb0c75b7c88819e1432528763efeda0c7174ce1f9adfc9a6b7fba",9.317957166392093],[14060,"c2ddf12a683f6d875672992200e31f24585fcede0fe6612b0f2160af55596b93",9.317957166392093],[15100,"3ffb979644c41598b4ee7db2c08190e867bfc111b5200ed7631d5a216241957c",10.052724077328646],[5656,"16a91f288334f7e12fc2aa69c0bd2d8983b64a2b52a1d037b87c9e9b027b48db",9.917710196779964],[12630,"69749294599fc6416b38a4bc6b5d6afc01b2593971a19f36f99c4d5ba4e414ad",9.917710196779964],[739,"44391240f697c5c98fe653dc8839f26499b78597a88dfe26818e46c005ebfdfa",9.317957166392093],[7312,"12c372a7ad7f9081c72e6deb4af4b331975c0e589001eef9530e23727bb5fccf",9.917710196779964],[19386,"ac251fe94d5c73ebe254843c3fd53f4a9e1b053497526c23d9c987445e5c5112",9.647446457990116],[10937,"ed65f8192a61f23ed4d49081f6df55598620771fd4b88d45b5f44506658677b8",9.917710196779964],[6440,"8ba932ec5faa8e778217fdd560483c11b0397f91f67a88d54027223fd06af7d5",9.917710196779964],[19873,"9e99fb0c3a4e028b6e9100438775f18a4ff03558d8a58282d43c06290cf50500",9.317957166392093],[10481,"79e645ba73d05b138c72f6799b71493c0e329773614b6fe9a3f28da0c5a443bb",9.917710196779964],[1466,"4b55e1c5d9e442265ebfb800845a04ba82ea5d214f8b545b47b783e4cb9061f6",9.917710196779964],[13235,"763287fe5ead7779cc06f4b76cc36bd95c358da98bfd72d7772ed384cc902fa6",19.796387520525453],[14253,"235be4a7d7fe1f3104c9187d15c3da23fcc93e127b2a8ca0008cb4c83a26e38e",9.428571428571429],[5285,"4dea11ebba2a315061ad6e5d2e1762673b016f99662a7f798f392e69637f7ddd",9.917710196779964],[16211,"4221acbde7cbb07fed7f52a6fcb09f459236514dc0ce869b6efe664a69ab9c63",27.850267379679146],[8507,"8fd75292554c311c46bc0077965d8a0866c9b380c156722165c40c86c13afdc7",30.71174377224199],[15230,"4fed5b52cf4a5809e9359838bbac9cf6534b5278796486d0dfe708bcf169d679",9.317957166392093],[14787,"5ee27a19e0b86ae0f258db72663774455fdeead922e9e36542cc4f2079852a83",9.317957166392093],[6726,"8eae36fe239db2d24b2f9db258d555eec2be5da55b2031db326dae25d48cc9d3",9.917710196779964],[14946,"dd5856de47406d7922e6c7a05ad09f677fd28b3d93643a014f8b131b7a3fe87f",9.317957166392093],[19093,"890025de81e0fcdffa6382164e8bcbf16b5b53f1b9360bae91de639b4c53f41c",137.34553775743706],[4087,"47e397fca519b5c2949f682d0dbe6b6a5fd3e143a46175bf87dd120a5afc27e5",9.917710196779964],[7146,"6129fdd27d0ee2b76cedc050423e60f83468ec8b1243d271358f5cfb8e9209d1",9.317957166392093],[6399,"4a4518fdd5f89c04ac87ba571e539d50b017c3438a1b197c6351dd09213a5bd6",9.917710196779964],[8684,"df4c14dbbe08656531ad2d0dc6067c04a67ee42926b80a8e59e6d3f3abe1c7c6",9.317957166392093],[5010,"6aea62ceb2d061216170ddc8a3fa938e9e6fe8cd524ab102f89a4f2adb331bdf",10.052724077328646],[12031,"4b99e9f0f4d2abecb4913453f12fac23854f7ad338ff45bef3e5b4730a2f17b1",9.317957166392093],[7539,"cb528d1e6e2534a2da7d302ce51e2bd7d70847dae71a62b77140e1fbba2a91ce",9.917710196779964],[1543,"b01ec4096d2dcf6c45db803a30b6127cc7f61677195291aaef85a12fa934e2f5",9.317957166392093],[11928,"028b7eac287e297222576511548a1faa2b2d0e4d8e15d3d141520b846053d5b1",9.917710196779964],[11188,"9d3a8e962cbacb57a93b0fed56a3cc9dc5d3c9073d4793a8b34296adcee0beb6",9.917710196779964],[18386,"523dedef7de144a50d3b57a4e3cc22c9a0ffb254c50a90ebfd09314111a7c233",9.317957166392093],[15033,"02751cf5bbc6982969c814d1579b32e889f452a337c155fbda05fb913debc87d",17.760351529491295],[12260,"769e5ee86a4c206f7a98888367fedfe8686c2e8b4858e5f26a2f22db0040a2af",9.917710196779964],[12141,"56c48a80c04619f20d68db207d6976cfc8123e493a41e89bcbe50453e87365b0",9.917710196779964],[6636,"a6e45f6f0873717642faa8f90aecd0d812b1ae81f4533a40be0691914d226fd4",9.917710196779964],[12636,"5b7b46a803d44449f4562bf7c2f939a4c35c980494d833ad6123b63ab4b10aad",9.917710196779964],[82,"251e6a25eefb85f9f094f796a9676751e61aebf6b43c443488f97f6daab077ff",19.115384615384617],[6057,"a5fe225a4bf71335d4cf3c57076b01fbf54426db88f3c9bd4148155abdbdbad8",9.917710196779964],[3288,"915698b3141a308c47d4a7eb187ced0e3100d6f85ee2430594c6262066667bea",9.917710196779964],[10311,"ea6694619fd4757628da77f3a714d2728ac185feb390e612f4e15796827e43bc",9.317957166392093],[1022,"7d727503b430e452b4b8879a0c1743c702eea69c33b79eae8ac8b81b63551af9",9.917710196779964],[5648,"eee0b2eb5dcb2c44a78bced438ca5fcf75bf49468502b90ecd341ef17a8957db",9.917710196779964],[17397,"8e2ca90c691d4856c2dcd802b4e49e6da93c25cfb3e60605b2c484a02e1ad149",9.647446457990116],[3703,"c0b9a49ddd460968a75265601b0080b204c09860e688d204b0991cf396cf94e7",9.317957166392093],[1857,"382ad7adb1e2c01193adffb4c22845998795ed3cb42f3564ebe0620f4f8be5f3",9.917710196779964],[2842,"b171b2deaa7ea4911b9b6db084dfe63cc350a77893e77b3d4a1a2bb9a33a64ed",9.917710196779964],[2445,"472d31f8f53a076d2b6cd0569eb2f0b6aa14e58f3f2975f026e51686efdc35f0",9.917710196779964],[13448,"13b6f10ab4402f345b24c6d6e8884fc5c75a8c9f5f9da480c7c6db1fe76715a1",22.066869300911854],[6069,"6e7e58d540b391c036403548f4eb49e7ab162d7962f45d00f483972dc5179ed8",9.917710196779964],[19552,"5d00c57924a531de05fe1c475e2df20276cce074f751f7ec5728f27e03f97d0c",9.647446457990116],[6966,"744710738abd48bb95ddeca536428f94b7b152f5517ddbc1ab4eecc873362fd2",9.917710196779964],[15109,"367ee94ceccd8f22c31bd496319d98f5513d19b60efe56fa002f6c631917637c",9.317957166392093],[2023,"8fec6a7d36c879eeb861c3d39ba582690a1bfe509a8bef94074b14f2faa4cef2",9.917710196779964],[12242,"4e5fad6a329ea97973483b9bef4c0b8ed75030c81ca6f8f72979ef64871bbbaf",9.917710196779964],[5089,"b8150a7a90d210491ed6db171c66e528813e67ae9c6e6461ddc0b813a72ea4de",9.917710196779964],[14297,"8b27cc92013ccdce92af4a4a3f605e2401b61ef19abc139fd02a34c8f4d4b88d",9.317957166392093],[5964,"d0dba0c3116b67c226bb6f417f3984de08f6b60949eabceb6b0b369ddb1c53d9",9.317957166392093],[6713,"d4ea05c679e4d259db1b55ab64c8133a6ddfed8dc00c2e8dbb2418cbb421d9d3",9.917710196779964],[19823,"b3da5d2f12667e5d169a9fed67670241966597b55609ac71b0fa789250f2c601",9.317957166392093],[17961,"cd954f539cf4b33851e3bc6d57146f69476c4f802b5a849ea1657d3093d1ed3d",9.317957166392093],[16270,"542492f847d4ba4861999111892639fa110b8b57e5793ee78e70f7d756e5c661",9.317957166392093],[15121,"494eaab5966b8adc4cb5bc1bd1c544dc751a780c37b2922b74394e27afe5457c",9.317957166392093],[10191,"b8306f684de30bd77c777cca27ba6d51ced82f23c565488543f267dd94920fbd",9.917710196779964],[19284,"9712d40714517b473798d8795e51231af991d3ed567152880a9c9f47565a4615",9.317957166392093],[8057,"fb93574ca01137bda4df06442276651035b0ffa0f157d00ffb47ad44efa916cb",10.052724077328646],[12587,"c218c5a7a4d74be88915fa636ed984063d863657a622e59d09152fab5dbb56ad",9.647446457990116],[19215,"e2d4025169f815c78de44b255de1dcc450635a54e42a7360339c42e9733c2018",10.052724077328646],[534,"bf74533419c876537c8770a3b53670e48afe2420306fe23a1270c2a651666dfc",9.917710196779964],[6464,"0db023da991de761d8ef6db9026b637386de30a3a5195e4825fbbce998f9b6d5",9.917710196779964],[1937,"95f0394df1d2fb4ba5f9155bb6669e27f6ead5c4bcc0233115596393b19870f3",9.917710196779964],[17130,"cbb0da41f1198d5eaccd905faea19aa80913b2de22a2d4c3d1f26ea280f8684f",208.15196743554952],[10791,"62d1c710fdaa655dea4658671c2ea74536bf03ee202328cb4a5f274a2cba58b9",9.917710196779964],[15724,"d8455a58b3d44acd0410342d2ff45fbb512d36eb8db03c045905c0e27248fb6e",9.317957166392093],[2979,"7e4fb32819c19a752e6269a29c199f77a67f7d541692adac90786c6996bc67ec",9.917710196779964],[13693,"efd96f50c9de303a32acbdc91e3eb33e056bc1153dcdcaab675ce8163da5579b",9.317957166392093],[5593,"643c3fae97196d440a5dcb8dea704bc5ea70324ae6c171061d42d7540f89abdb",10.052724077328646],[8098,"ec6e8cc818222248476e34b27fb994c03129ce8f245018a4f8db9a900c91c6ca",9.917710196779964],[13495,"d0961959584f8d00400255d5cf3e9a8c71e596bb546d6adc05547493b138e89f",9.317957166392093],[10364,"e08c92b920df9809f3267479f66ca68744edcdca2c91b77c0da434518dbef9bb",9.917710196779964],[2054,"01b014e276bc80ac23435aa945379f8bb45a3eaaff3121c84b039039be6896f2",9.917710196779964],[16728,"04e617a9e0334917b643eb084b07955616b878438994eb0ea4cd0a9ab2a0e457",9.317957166392093],[18220,"d1570b060f3f27551d8cd700ec3785c96a9697c6be86a2dbce4cd80cb25aa437",9.317957166392093],[3229,"ae4620cea1c472940b7daee502a1f57e26f1f68468bb373c1abc40c382a7dbea",9.317957166392093],[14323,"634b0884abdeace92409719ef7a4efb67f0af04e80090688c41d17deaf0af58c",19.20142602495544],[19674,"7b5d6e450b631ce4e7e7efb4c49cfa941f4c4d0a5b16a403c280d4c6f5de7507",9.317957166392093],[4446,"909f9dfe31bd27ce2845f49bc7ab37b7e18379f8d469365365e863231816c4e2",9.917710196779964],[12382,"dbcebd1e87b82387b55d2158816122912c1d8cf3795bb5c3bc0b8c711a36c1ae",9.317957166392093],[15748,"b79709d6434ae816065b743a85602c2d4db3aa800c3c5dae16fd294f8de6756e",9.846153846153847],[6744,"3dbd468449f28dbd9556959edb681fe66931ac1ecdddc74529aafd5f501da2d3",9.917710196779964],[616,"0e7e59ab98a9f33a2be68f3659c649bd2e94cb86c9a28c7ea9f754671811d1fb",9.917710196779964],[9069,"a37bc6b0fdce84e91dd1f7979f1c6e4064bb13d084825afe6ed578ffd1af57c4",9.917710196779964],[2693,"81534adc9219f735084a7248551d0e15fc6d50ec19813edefae59d2a017684ee",9.917710196779964],[8926,"6ff066629b8908893ca663bad3f5146416870289c57bbb29938759c3f23754c5",9.917710196779964],[17342,"6460807632bfdd2aa272add4628e54e14c03534a50be64cff385453e3528094b",25],[11146,"f184a64eb8f2887c511781e0293bbe1044080113cb289141761bf2f91189fdb6",9.917710196779964],[2161,"a6a55968a035f28268d6e2643f36164325454f4025a87ff9e65c096402bbd7f1",9.917710196779964],[11329,"fb8060d0da9b629aa5d90dac27cd2ac1b54762439c393ad4f67fd76dc8aaccb5",9.917710196779964],[5994,"073e13e9dcee3c1f897bea7979675517f20d9bca1c6b6c773da6228ea3081ed9",9.317957166392093],[4166,"a36a633b2d54be2f588a70bec56505811b6b4f75e959ac80417fd7c1410ba7e4",9.917710196779964],[18840,"df60e8888a24b0f90b8092ce90b01c3ae6c1329d30027135304f3cf9fdf96b25",19],[3919,"4e8dbcd751980b30636a3eb68f596e81fbd254a290ab6fbcbda1ad65f3013ae6",9.917710196779964],[13558,"af90698f0ae5fa591e8bc35bd1e0f50a6a20f557064d0446187148ce0d20919e",9.317957166392093],[14335,"c21b147413676433d299d145479983c37d6ee8b18b726df85697d1e192fb958c",46.24424778761062],[14917,"263292cb365c7082507efd40026e0c913b56c5074ff462e243c1e16e5f839480",9.549738219895287],[1864,"c12d8200f24dffc6ebf3ac13c4b6379375dab5265eb4816e6ebe5a0e8318d7f3",9.647446457990116],[14634,"0578821c0b4609f53f613091a9b077a03574d1b5de7d227a958a316bdd6e4f86",9.317957166392093],[6112,"7eafc2708804d30c196e50b55c2e8f0e5a5e5c9aef734aa430b9c4de43fc5bd8",9.472566371681417],[4921,"901990c33fddcc067f86105b5c8ac06956a997ed903755b8a43359d29db2b9df",9.917710196779964],[12822,"391b2bda14a0a5f68cf83ac63539f09e18b5bbc4c4699ad276fe1a954e36d2ab",9.917710196779964],[3933,"0fb32e6c93c38589d71501eb0f0372c45ed0689377d6cef7fae80c2d438728e6",15.003322259136212],[3523,"d6e8ea9f0f6534478c873be4d1ceca51d0bae91caa0d1d4b9c440b1b37b8cfe8",9.917710196779964],[19380,"5060bfb2393e9835a25d2bfb3a6ebbc192bb79041c3fa17eea00720864a79612",16.161458333333332],[15205,"e784b1c29f0ba3db1b6262d73fbd28128289cf05a610debe4f885fb056e8697a",9.317957166392093],[5040,"d5bd3025dab159ee9486053db0d7d2bed99fca12bd5db810ecacdfd0aa60f2de",9.917710196779964],[8916,"1e14ad250b1725e77f2874ed231275e18f036dd309041fca50d54b61be855dc5",9.317957166392093],[1530,"1e5528c6e206fbd0a5f735fbf873c7b6c00f9c394962e1f04ed6c3521cc5eff5",9.917710196779964],[2867,"6741bf8ceafb38cad55b2d08f4e900394992d0c3604f73f6594afdf3ed7e4ced",9.917710196779964],[17833,"061d0c2f04609478376d9b255e4b57c03072e12b86caaac96b210a4ed4579840",31.05169340463458],[16204,"24082a094f0d4de539b502dd8dc32acb2806467056b668083e382dbb15d2d663",9.317957166392093],[9205,"ba1bcf3e2f1aa0179fc776877b929fef48202a5c6d549133959df48c8e6266c3",9.917710196779964],[12162,"fc279e035511140639b5b65cb3b318b3054cd06b9b1784423f9a5d5d7b4e48b0",9.917710196779964],[4554,"b798882c356f9a6cd7bb3df7bf4e9097adf875a442de53d33a5b31fa09bff0e1",9.917710196779964],[571,"e405585d5e40779d6b35edd4e15f32cd76c581e3eed02176b6f38103443120fc",9.917710196779964],[18029,"dd8b86370ebf5a7c76ad0cec66ad1dd79aacdab08880a23744b91ca39876ba3c",9.317957166392093],[13353,"e98bc417164943f1217bb1b487458af151c25d94028e91e22148740c34816ca3",15.858407079646017],[18307,"ea286caaa5b666a346db82c93fd9ab1a32de5858f34bda5589586f4446aeba35",9.647446457990116],[3960,"a3b0feaf504481103a5ab00cbf93681b9ad32c6abdff1566b18de59819ddf6e5",28.100840336134453],[11938,"7996a2b2f0e972b2a9673644c31144e64e90bfe3bbfc942a0d502e8bfc10bdb1",9.917710196779964],[18136,"86eb8010fb41793023dfcede1bd61dffee91692e5155c7cdd6a07f46753e013a",10.052724077328646],[8835,"104c4327f7c57428f48435748d92a4b0f35fb0d7d915e0cd2e1ee68a4d16e4c5",9.917710196779964],[18924,"2587d91aa79286521f46e6d367d8cfd3ddc0cb1fff5b03bfdb06d3c69f38b022",9.317957166392093],[14997,"73336234dbf6b2e95f9bde8c7fdffad2441350821ef21a56eff773011bbc927e",9.317957166392093],[1330,"053511aff2d6f1a895b76cb204f884122d040c323d91c5f1a28ea7152bb93bf7",9.917710196779964],[12505,"4505a9307ff06c569bc2362ed34b2ee6641cea75e3ad551a735ed14e9975edad",9.917710196779964],[15737,"5452b0988a1b3a91cb6fbbbe693fdd4080e911daa5be5e6901bd79e4efafad6e",9.647446457990116],[15843,"77db77634d51085a8caae3dd1ed3c1aaf9ac0377d7e3107ded15027217306f6c",25.94061374083737],[3565,"caf19a65b6c3df41f790d5fa087667d1e901afd150cc4f81a356b1e161237de8",9.917710196779964],[11412,"38ed9e63a4030f85692800c4c5abbfce89879467a78d427409aa4567d61149b5",9.917710196779964],[4510,"a66f6a62da8de01b027a00e41e1027b90596bb5fdcc375e6be2062be7c8549e2",9.917710196779964],[17344,"18c1034460f3430f5e7011ffaf0ea0e24bc8ea67a93b7378b57f90110977f94a",9.317957166392093],[323,"0551a4eb5614abee4bd69263de7a968adf7f4e50eac12a28de052647729edcfd",9.917710196779964],[15290,"bbb5131e3f9d639263db1aadd8b209b57d17aefeb6e50c34d6f37f9795579e78",9.317957166392093],[17326,"b1ff9b34b20218eae3bb6e9e944a77aa8e3d9e9c369d5ca9b6cbecc880fe544b",30.851063829787233],[19593,"9dd7fb54dd5084e1df36371745dec630e9c7fc70c16ba6b404bc3c8c04b1690a",9.317957166392093],[16825,"ecd420599de9d2c9a2f9afbd8b4a37d0f5845c7aa4d13eaa882a05db3b45c355",9.317957166392093],[14890,"096a40099fd37b0af55e939efb4e24029702009966b6fb16589c892128f90181",25],[17605,"f541d890bc48553487137336cc106209d1c666a06d1af0482927b8e03339fc44",9.317957166392093],[11637,"c51b776636126b6063ff3d44112b26a7f9eb999588d8d330ac4e754404f5abb3",9.917710196779964],[8708,"009e7b664467de3283527c5783b4fe873a28bef5246a21400d0196f3ec94a2c6",20.07662835249042],[2681,"5e4ad37132fc75a1603156a1dde2b7d9f7f5d36bd2c5bd05ea5227f6da569fee",9.917710196779964],[13119,"9cd8c53ac8f71326d0794bfe0cb2d5b8d073ae37f3d3095783d583b1ced89fa8",9.317957166392093],[2601,"f6d9b5b98ff70831ca3385a85cad5815d5aed9a9b93229513fa67054085123ef",19.192825112107624],[19186,"20c106ad9f27b17bd39cac690d292d1930f0346946681177f7b414aae9582b19",35.35828877005348],[14042,"a50b0c554bf3443943bcfbe0d31c23ba309dcb0ef1bb8c2f20fa4a2de65fd393",9.317957166392093],[8293,"4816a24128992fa21a05f2bf80aaf64c8c9c8ace68ca8b4e221bd2b095805ec9",9.917710196779964],[5988,"f86ca5ad18e9ea60bb5809e65b80b1d46215f098abb2b36f643c203f654529d9",9.317957166392093],[15763,"2f8fbb36b0e26ce29af59538fca3e10eda278ca9dc46c03b8c025220f52f216e",9.317957166392093],[8947,"6b34d269150d561d2888d0bb9f15ee6929dbf4e8ff12ff60ebf7bc33addb21c5",9.317957166392093],[8601,"f835bcc9906e5f237cd8b44ba74c66c7c1a97a3e2b0b374caa3727a174ac6dc7",9.917710196779964],[2625,"7ee1dad4920123d28d9f1e73b7ad7af9d080c2b8aa02fc67ac1d6810cf6908ef",9.917710196779964],[18245,"0cf7aa07ecff0eedcd19ec4b74384981e6edbf81f3d560cf8c9e63ed3ff51937",9.317957166392093],[10973,"c5ddc7a0c3fe2fa4b153ccf62e4f6d4ab0c2bd5ba0fc59d8b77eb40c372d33b8",9.917710196779964],[14873,"5513d25a9d985ea4470fd2f5dd9b19907ed89c59345721cd6e4fca6b54e55681",9.317957166392093],[16232,"955594dc2b847001f4847284df35961db73deac5eeec84865e5742510bddf962",9.317957166392093],[19073,"803ee4626c861954eb0e3b499dc6818fefb2d2d3b5bf7849b1127f4e083bc51d",9.317957166392093],[1420,"78c7b90c2f723005c5c4049b34c78990fd8669a297603faf433cef275066b5f6",9.917710196779964],[18863,"c36c46b5948a3ee38cc73fe0d6cbb53c7b3412bd51c194fd9c6f307c3f139e24",28.097560975609756],[7180,"d2df3868b7a1f1f701163fb2ff93438498296aa2f9e60e15dddc8f1f60bed3d0",9.917710196779964],[9501,"68f067b3c27a2b741c8a71178457218e36a0362336a196b201f0c9b77111b0c1",9.917710196779964],[19529,"5464dfc06fa21de103ddb6aef7680fca7ba28267e5364653fb1955e2df737f0d",9.647446457990116],[13668,"d32b9f8b706bd279103a6b82980064bab70fa1cd00e978925dc6697d1e57f19b",9.317957166392093],[6729,"2167c42821cac5024f07f6992518a14c205734bd7890b5967106814c65bcbfd3",9.917710196779964],[2804,"2557530ce53120cd9db1f128187c3896039ef6632db36e3312aa7f5e402faced",9.317957166392093],[15640,"9eb153cc2043a81dfe954d6bdf08171a1fbae0c9b02df32bde5b096f938c8770",9.317957166392093],[5691,"3b439881ac1bee6002f16d35deec3dffbc9adfd93a1367067bae682f5f3f19db",9.635658914728682],[6705,"58d602645fa6bb617cebd8a2b1bc9640fde2fee014bf811fa9dfbd612d55ecd3",9.917710196779964],[11027,"3064958cb6d49b1253f6818c361bb5c4476031ff4a283deb8a537ff1892cdab7",9.917710196779964],[11999,"30e3925d9ae793fb2fb2174c2d4ba4f1e4196359c270b336791b6bfdb73353b1",9.317957166392093],[9031,"ade9c7e03406b970878ea8b777f524e727da2e194b9820192ae920d11bf096c4",9.917710196779964],[19546,"59c33965325cc0dff574aeabec347fe893b553ba6945a0b8da650f6d69a6d40c",9.317957166392093],[17719,"e1e2d9f4e129dcbf1d7fca01e9010d85f68e169ceabd1e612cc7117ae660cf42",27.014099216710182],[14452,"0bd742ae537c30860d091968c573d9bf9598133c41b1f2c37bf9ae3b0fea308a",10.052724077328646],[10752,"1bd0d939eab3e936a173a752fbb64ef344379dc494c999a89b6a7f2cf7fea7b9",9.917710196779964],[18502,"9fbbfe737ab1048bd477a07aeb3defc34a7ff6101d299d21d3b6e4285dea6031",9.424083769633508],[13277,"d9cb747a3004c311f68eb373c02fbe2c28909e689fa0acb080b1c98b78611fa5",9.317957166392093],[18849,"44e5b710adf71710a3e8aaccaef1e7cae2814ca22ad25bfaed5325dd649d1925",27.706806282722514],[16883,"c4397af88ceb3670cd500aabcf91a35fa1e5177ba5ae9a3ad6845d78e4a58b54",9.317957166392093],[932,"e372136debc33756b48ce926e703adfb76d1240a6bc1cc90379fad19e76f9ff9",9.917710196779964],[14511,"27cc0ff29bb0f1d7ad42bf2c7b42dc2ceb7937d268e1f69b9b485a0ff16feb88",9.317957166392093],[17775,"d5aae7b0501a9fe99a9286cd2040f421ab7bad2e4dbf45cd040c3a34ae24d341",9.317957166392093],[15867,"ec1dd6bdcd70166f5e586ce92dcf5170b16b0d5376972a0a545001f0de95bd6b",9.317957166392093],[2554,"85bdd226c4a8941c9f6112ca3269ab02246ebd52d01b5764533fc96427aa83ef",9.917710196779964],[16055,"19637460fecaf369c004c32998e3e85b3e52a92830172376e00038485caa4767",9.317957166392093],[19796,"412859f19076d7072915f2897875104ff8783ae68372b5e24bbf958a82b6a702",10],[9730,"fcf65eb32c3928149067f7e690bc2608c68fc98e8a9b8ef0047b702760dd1ac0",9.917710196779964],[17756,"05434e3ce5657e50933af088f01b3a9a5646441322a794971e5a2036a5821d42",10.052724077328646],[731,"d98834e8afc02c16aae3f9fe758c0334163621e54e2c01fc545aeb33d96c03fb",9.917710196779964],[13914,"3ee19840af8c3fbd4391e585b2706690a284c549fff60c719b413b3e578eb496",9.317957166392093],[12370,"08e4ef103c64110183b4094e5afd8ccbdef1f30ee953631d247313a50f48d0ae",9.917710196779964],[5041,"538374aaf40fa7c75b06df84170e966ec2d35f5c0e7720d7f48ce1099452f0de",9.917710196779964],[11317,"76a32959924fc2401a7e80342f24f767efc11f062df02b989a8de303afc7e0b5",9.317957166392093],[2005,"6820a036d486590afcd9ee52623ec50b7a8ff15184519a90c2301331b14800f3",9.317957166392093],[12140,"9913fa3581feb781e84a4e249da026c0830ed7fc3fee99b7a93ce501270467b0",14.188034188034187],[15318,"b4eb9fb717ab7e7d14d15aa8310269a5f1a95a5d736ee9a7531e97c607b5f377",9.317957166392093],[1047,"966c11b770944e7c6e7eb89930f39749551e65e1a6224b6b858b439e94f2f5f8",9.317957166392093],[12289,"7cb79a4993b2575c4580fbb13d1f1c2a64b463ada82ce0d149427db0079a55af",9.917710196779964],[10155,"5702a3cac6f43d2bbd413c019bb38c7eacbab1bd905b7a24cbfdae0d120f5ebd",9.917710196779964],[17856,"a627c8e3a5f6aa2e2332882567899d3fe504dfa41488bd308fd1f586333c1940",9.317957166392093],[9214,"91208450b9a1c7e73d34642ca5bebc7ad6ac9cc83db49298f6a51467869561c3",9.317957166392093],[13469,"c9befa48d8e2193617f1c50175ab629772008625fe7ad349f7bf20f3fe0aaaa0",18.20689655172414],[17934,"95ddf8ea3840bb01c0be1b3ec8b81c86359c0f8dafc505889e99fba9c01b923e",9.317957166392093],[6061,"2341f7e7b55462fb1372e29de52979ff68cbd240d0ca546cf56e60f2f277afd8",21.217568947906027],[3904,"f78ba28f5785cc455d93552eeb2321badcf3ea16264260e43fbbfea3844959e6",9.917710196779964],[7460,"4a1ae4ef483f6ec309b86999035d950de7f4fb6293c9efff5048cf53f83f03cf",9.917710196779964],[5283,"c8426029760594c872677fca29aeb01f4338dda9f4571274b2da301c6a7681dd",9.917710196779964],[4155,"433e54ab05dc2ebec982a60cd8288a92999be9796ee575e1bf4e242f7ce5b0e4",9.917710196779964],[7275,"4e77766e1fa8f62a94e6f1596c12f473f52e2250682c99b6385538a666472ed0",9.917710196779964],[9536,"91b29c4c7c64fe65bbe539a185195963451f60195c9e4bb1fe11ebed3e0376c1",9.917710196779964],[9485,"ec52c1419105b4201cbe59a9a8eb94d8f018ca073b7fe872fe57ce57d274c7c1",9.917710196779964],[96,"17af2c439ddad436d86a023b078eda6b46f1f662deeb7fb98d63b432300865ff",9.317957166392093],[17018,"4ae937bc30c148571870ec9cb63de668e41ce4ef9c9317d116a21e0943759e51",21.842931937172775],[6776,"7022c9337376c8d31f96624d930537fe16ad294011b743ab60800cc8556171d3",9.917710196779964],[8743,"c8d69107183410ce9ebe1f32c7d8a24a8020b83fed18d3f21a7216afa16070c6",10.052724077328646],[5840,"13baeb9a67353746b3e7b8d705d4eb25a9397c1be9d2e4e44f79ef4f23a70fda",9.917710196779964],[11987,"37d21ba35c375dbe411dfcfa5d0bfda107e10eba336fabacde9d8d09dda464b1",9.917710196779964],[16499,"efdeedefd4b01f3b108859d27cde03fb3d5a20c7c9aa7dae841768ee7e33485d",9.317957166392093],[16864,"b2b8ab159193e025a70c06ecc94d6efe828fceb350fbeed0c877c236e052fa54",20.106951871657753],[19279,"4a3f53a30b4e2297a619e8106ed9ffb9f4317ec15778d8ab04549c691b94a015",9.738819320214668],[17890,"e55a6096effe46d6767d4bf55714e885835c5b4a32eb2bcdf66f437a3df0733f",9.317957166392093],[475,"908839ef43840636db70e718c519621f1d7ec7cdf9d8f7ad42740f09cdaed3fc",9.917710196779964],[7551,"1753bae957bc6ee96d6f59b561b890291adbdd79fb82ed52885d28ead8dd81ce",9.917710196779964],[7276,"371441ec496032fb656027b79df051af31989084663a981a91a54e70f02f2dd0",9.917710196779964],[530,"a6cfbcfcdb02d94b871490c51678437caf41114b115e873b5c66f1a44fe77bfc",9.917710196779964],[8850,"db508c64ba47dee69e705bc7bbf9f72317a2b9b66e557d367252008829e5c5c5",9.317957166392093],[4755,"2efcacfe67c5bf88c2576169e12b9f80f273a37dc9db651a70ac60028b639be0",9.317957166392093],[17985,"a11cbd646a24357cb6a24f66f6e71f67496ec89649d5a266e81c149ff2e7773d",10.014641288433381],[7016,"5ea02ebf3b2a199cb79279413dc49a1203bea513cb6833da3b1000504d1ce5d1",9.917710196779964],[8704,"b238ffe412ef480fb665e358830c4e0601d62d0ae6d3795cd57d1853e66cadc6",9.917710196779964],[19348,"aef4632e0d56e7dd4ef827182f927433db63bacaf8ca05ef4bad4a4c2dd79b13",30.167420814479637],[11209,"d869a64522141e1e35a0a7d27d9b006e52430b67968a0a86a55fabcd3098a1b6",22.0297699594046],[14008,"97363a26aa63da51a51e78e20cca30a0a21540dd19a25c5389d253a07a0d9694",9.317957166392093],[14930,"4cc5aab08e230c076303936757029e5a12bb3194fe03a8cea412a8f1f3934780",9.317957166392093],[3971,"44e98aa983289189017de34542b21fd72cf94ab5426ffa4a2594aecb4f81e8e5",9.917710196779964],[11750,"922eb2f51fbfc270803ef65cf8fb2e0eee42f39eb0a6f3f5a86279de7a6900b3",9.917710196779964],[14611,"b39e05090e4d38de11da181356f35a36b182081c6af5809b6287cb15f882e686",9.317957166392093],[19532,"08a2fd0fe895ba56c4995654d0c4ae8d329e09fcb16775022ae07b781d6d600d",9.647446457990116],[9535,"26f862539772dcd27f193ba45223f0aec4a8c8983aa7bc9ad625bd3e282f78c1",9.917710196779964],[6617,"2aebfeb125e3d821c4e3753f129f582d76c5ad46cd715fa6ad248c0f1a3e84d4",9.917710196779964],[6412,"ec753975d31ca8be67789ddb5c85b42fcd8b5bbd0961f2d873a1678eefb542d6",9.917710196779964],[17645,"0d3cc782988de21d8ceea3f953297cc54ce5cd1e23275ee25392124c660d5544",9.317957166392093],[7933,"4da9b859bc58b5de733504dcba5e2c695431b36bea8859a2bc6785665daffdcb",9.917710196779964],[18710,"90b657e6c246923cdef3beb2cc896e295ef7bda292fd8df2d2a43b4c5484dd29",9.500303951367782],[826,"0121f21bd4aaea4fcf18a1a2badd57fe333a0c982693f7760592820c87f15bfa",9.917710196779964],[1638,"b9caa7f8785b3daf4bd9e5fa782aebc57a626c7d5a9934e17b63e8b34b375ff5",9.917710196779964],[6957,"227731ae7a06ce106c6a39f9830b8f0f7aa4f42c52fa8ad9ecfe1d6f355639d2",9.917710196779964],[5487,"90616085900370cb69227c2ef4221fa314c48605e3d4b0c5180bf1b645344cdc",9.917710196779964],[18106,"66a36b235db773f46f630bd9713afb7fc420024286ff7d0cebe9a8deac5ac33a",28.899115044247786],[16483,"5b3074920f8e991fb3ed82d0904ef3899e40db16ced9228a5081e29c0712935d",15],[8775,"a80b478e220d1f10176be742a6ec6cb136485d5c3ad3fc528436d1e781c135c6",9.917710196779964],[17475,"253f9754d25ff27c9f2285883d10eda1aae2b427586e19d21b9ecf9a9ab22a48",24.396815967684446],[8918,"ff5aa71e1bc173875352bfb7afe929314b23c9d2cda37f67818b0059c8be5bc5",9.917710196779964],[9988,"00c1b1919abd40e89e0c5018cabd765b8300911ca5d2ebb06d08c1b5658a62be",9.917710196779964],[13990,"5291f12fa80ac003667ac56288343e971a9dff66c936779dc615d9da1cb22d95",23.62224554039874],[2491,"f872fe69be4cc4eae7d95cae37aad80e77591cab843c1c965370df49960ee9ef",9.917710196779964],[12166,"dfa95f4736a0128f4c90307e53622877e0aaefcbb462bc164fab1563e66a41b0",9.917710196779964],[3376,"1f4f09c8b02f15ed47a6def4a12adf4793d6e2e14d9e7cdca0ccd78bdec2dce9",9.917710196779964],[6413,"3b7ac72a1c9ff315ba1547bc65cdc95140f35936820b93251ad250afc3a941d6",9.917710196779964],[12779,"4e0ec7d0e165a6ce9bec4b53cf5ef818c02a80f0196343b5d1a1015c98d10eac",9.917710196779964],[13220,"8fecb97b2114f9e16ee9debfdb54eb49cb3c4923882739080827130e628882a6",9.317957166392093],[7515,"d3c6b4362ca9004b5ff68f8072ca496206a0e89bdf92ec451a6b2427aa6eadce",9.917710196779964],[7726,"08263d1975a7d6d82ffba8ae42c34b4a098a231b5639b2c81d7d87fa000352cd",9.917710196779964],[790,"e731c02ae01d4634c043090ccc00721bf30dfe1f18540caadce98ec6b6c995fa",9.917710196779964],[10009,"b4e80ed7b925b3141c001be83877827da6eab1d701a1bb34d9c5b0a5ca2344be",9.317957166392093],[3981,"0e279b2bac2350fbcc8457cca7418803491d78ea7d78eaf84398eda8a1d5d9e5",9.754010695187166],[18942,"a9cb538493299137bfe317bf31882c0cb5845a914a7e8e1c1583fc64052d5622",9.705383824033705],[892,"f3a7daa530ede5eeff36490d0cd3d07134bb7882b1bd7310a46c0b18671ffaf9",9.917710196779964],[2807,"b577abc99ff2e93838307eb27d75054e8bd0414bbd27f2d28cd6ca6bca74a0ed",9.917710196779964],[19406,"e359a3bc274abeb52053ac68e5d37a21f4e3c96862f86d5a75f30e8203ec4211",11.027199737833852],[9593,"255b9903e4e5acb7c0458904464d5351adee0c0af68b0946f0f93bff13270bc1",9.917710196779964],[5429,"1c000f1f9b2f7dfe156b7fb7cca53382b5edc29f2ffeff138b1f046fdb209adc",9.917710196779964],[12714,"7ada6ba6349eb4b9be5a251136cd56cff2cacb38cf7699f229c5324e050d83ac",9.917710196779964],[16427,"491c761df1f3320740e9d268ba05d1dd505f24e237bb45d454e47402f15f975e",10.052724077328646],[437,"bd01ec247c14340a0fba14cdde13d20bd8bf507875313ab200200d6e6dd120fd",9.917710196779964],[12483,"ae947669fa21c83039518397d97ee261b092f68522ad706e50f61e0b7e7f09ae",9.317957166392093],[10180,"a1596450cf376152ca7e54449c51abab021d39dd26dd1024386f9e25a07229bd",9.917710196779964],[13114,"22499f5905dd2ab7d51294919b36eee15fe4d321ef884a160899c7898b99c2a8",9.317957166392093],[8136,"fd91d53dd06d4cefa8d985d45f925d897fbf35b83058692ab61164afdf8177ca",9.317957166392093],[517,"be30d4adf0dc6ead658b379e8b8cf044f6d6f9d9c7acde16f17143e24e0795fc",26.115555555555556],[18358,"6f8709f1d5f9dcd7ad52f5e4976677712cb35295855808f10c2de060d6029334",9.317957166392093],[12620,"e3b4b935c4bd8fb813c6bcfb2834a7666ce62885dfd67341517d4ec6994922ad",9.917710196779964],[663,"42ec5f89a1b16f2cd21336555fadc20924a9fdfee9fff2dd0f2b8a3b9c4e80fb",9.317957166392093],[13851,"5ad05cf9b30033601a21b8f1c6e5b1bc77792f0a3b200b6ea7b8d9c2ad306898",9.317957166392093],[2140,"7cd40c1994ff58156c07419fbc8ca154a9338580120fa5800f6c51516079fef1",9.917710196779964],[10235,"e772531281cfa3363e77b9093050fa1cf2833c72bb78c3d2c15f56bc157dc5bc",9.317957166392093],[7105,"67c1fef094e39dc8379f66ffb60fa3b177a8f9110473a29c5770c96c79c94bd1",9.917710196779964],[3736,"68883c815b613fbb0b9b9985808114b2f061785e9f4a306a50f354163a505ae7",9.917710196779964],[12440,"82c50382f701855bb5b4ce92a263e112911c857fa24ba1559cd1992d482054ae",9.917710196779964],[8421,"c3ffe9471c0007225fed55d4a79d88359f1c81f1d0ff35e48801d8e28b997bc8",9.917710196779964],[856,"52c5c11184da0abe528f8d80512c6d48366b0595cd25427e3d6c0b06388c2cfa",9.917710196779964],[15180,"07fd19b36c2da3cdb17cd3c24fcb7ef5291ecdb9d9eb6592c4935fca5184fb7a",9.317957166392093],[17134,"c62cc6d01935fd07f6f76d02a092f6798b8ed9a63fa5cf0168f37ffb01f15b4f",10],[18065,"4f676cec5cc45c77747a75a750613b75ccd22b63550f207a02cca184b9a2e83b",9.317957166392093],[12371,"c2b0c7bf347197a49ee41c5adccc6b1cc3f278eccd84f8313887c025e25bcfae",9.917710196779964],[3090,"cea6e49c0680565d7cea0669b6969ad2382c8c1d1cbd09fb239cd7ef990db5eb",9.917710196779964],[6474,"ad62669350ae9bf9bd755702e7f760416bc14ea32a6c5cd55bbf7578dfdfa1d5",9.917710196779964],[1554,"46a65a6be3d40ce6c22aae42e4bc1e41bffaf59da165b1e9ff7c87bd8d41cef5",9.317957166392093],[11424,"72d5878f49e26bb4801fd567a21f24bc1fb85eadf53ab2ff1ccd9d368cee2bb5",9.917710196779964],[8534,"3b0ff0416178d390f65d64329da3663e09b8acddb479b4efc05f04943f92cfc7",9.917710196779964],[1547,"1e0889c3bbf893a98559f771fbf0b2e7ee03d3088bb9c01204cf466df41ddaf5",9.317957166392093],[18549,"edca8113ac68094a22b942fc8eea1a85d2deba0447c501a40472d780c0257a30",9.317957166392093],[9168,"222b2514ed8e840a3f8841e5a8f161b90571d1098fd13f038f9495ad72cfb9c3",9.917710196779964],[16526,"6437fa9687885fd4780f4bd443af4bdc4b453a9ca59385b5a3500d67e9808d5c",9.317957166392093],[5414,"06db38ef1eaf603a356a17f291b020b2bc5b1b5dc391781848d9702c73e3badc",9.917710196779964],[16817,"a7f0b1d3698aff06a3e3e35f4534c4672bd3903e8fa3b398b0f78ddad78ce255",9.317957166392093],[8674,"7c3f73f414cbd556fdb22d8f5ca02a8022b33f12a89216eea8067ba3f68bd8c6",9.917710196779964],[13623,"e57a76adb0fc702fabcc597a1a7a1d56b667b559a51d2e0a96574e17a684df9c",9.317957166392093],[10467,"396c45d87190afc15c0899ea5b4c10e7acdfa21ed3d32b6bca35b82fa05054bb",9.917710196779964],[10117,"4839306dbe51d79d34fab0e74bde5de9c82d8007240ff46e1a8af82b706e96bd",9.917710196779964],[9030,"f1871e55054f60047a269b7a3fd35e2a150cd3f72af9e1d5123024cea9ef9bc4",9.917710196779964],[16049,"3b693884345aa6c691bde458deea74e835eddcd00e899d612494c91ff1ca7167",9.317957166392093],[16649,"27bd129f07278b2dd34a011c3f8c196fe8d8828d6f2ba59622c4c72b8e45cc59",9.317957166392093],[13543,"26c69ab8a807176b6fbfccdbe5c9879446e8da7eb7a78cfa12eb2018dec9df9e",37.047872340425535],[14901,"9fe9fb268fffed360594d587fddc8c5fbd72abf1aab66558cdce233f715cd980",9.317957166392093],[4795,"31bde144cae852a2d234883c58a8b7ef359118d488b05b6db12e60a1598e6ce0",27.85053380782918],[4180,"24b88df061be7d1f9d9b86048b112cf1901290f3435fd42d5efd8fef888690e4",18.130434782608695],[13097,"3be683a00debb142e64d8bd06524a6128a8954d8701fc55a1bc50ba89d3962a9",9.317957166392093],[11605,"80d9c9fd8f1d87053ebea2cd8c90cc6b52c961e3c02dd98483bbba00500de3b3",9.917710196779964],[11291,"41a8f57440cfa88fd3860cfc8ea41d2e2b7e183cf47433099913923f44ad17b6",9.917710196779964],[12018,"89ece2d2669d94322c8e75ca7c96bc2982d94cd4493a73852b92079956d037b1",9.317957166392093],[3029,"3ae36985731834d0e1e61d8bef234b6a3fa19f82838ad124979551a0f62e1cec",9.917710196779964],[14436,"6cb962eaeaf5ee66f9805de3ee1c5428c296fec3edfd966d6801c1de8bf0908a",9.317957166392093],[11917,"33bc4b96092c166542d2cb4e4cbc32c9db461efd335d7e1c114eeb80d61fe7b1",9.917710196779964],[17486,"686d0a35200744a60dcec34a52c124e1f56fb537451c59ff79d40ba9e101e247",9.317957166392093],[4285,"054924c98c09f5d3fce5fef7ab9810e347e328439dbcd632afc7d49af5d0dbe3",9.917710196779964],[4785,"9f2ab6ac92385c99dbf75c40e5ad5afeb16156ed9ac056af2b52760359cb80e0",9.317957166392093],[19507,"eb74b113c91ee036607d7023035be6e480ea6f9eb700059255c8771ddc35100e",18.031496062992126],[19222,"1f4d054e602978b45c558ea9a9bd58f219b3b2c3d828599b53bc5caf37d9e217",9.317957166392093],[409,"4bb03b7462408031242ed75ad4d72996d67d566463960c1bef79922079584bfd",9.917710196779964],[6926,"89efac600eafdac53d71b09884f25d0cecd867e5c11a07e102620adae5dc73d2",9.917710196779964],[7042,"92ed6a0e497daed07cbca5f86b0e179932ae324ac7a700f86c00fc23da8db3d1",9.917710196779964],[15242,"906eaa6b53d11f8ec845580f62763585f726c988f9d68a5c58b1547533129479",9.317957166392093],[2011,"5cded5cf7cfc3e2f5fcf4bdfcaad84f54f07bcd4ec6ff986d77cb99aa154f5f2",9.917710196779964],[8715,"192a640cd2bac8da871ec6a61cc156e150d22cf17acbcfa16053dba3fe2899c6",9.917710196779964],[6682,"bbb06033bf311b6a6843afd2195adeba6473acff878cdb2c30a2a4c21f1017d4",9.917710196779964],[12638,"552e749d3f89065215920b347c3db6066e4b6b7671736976f9989e5c6c4206ad",10.052724077328646],[8038,"fdaaf58361872e531a376584f4bec85f7c61beecd8ae3216f0cb5fb43e8c4fcb",9.917710196779964],[6401,"fc2640feeb9429c8ee3163abec5eac4d9f460651a1bbe7a4b18ef4413c7158d6",9.917710196779964],[9407,"b630e3a5bc3673e30d28fe4f52cbbee5de0571ed74e31a540a065d10c8fe3fc2",9.917710196779964],[4670,"cb22369f91498ee5120c7316ec24035bd049561de8334e21fdf1aa7f46512de1",9.917710196779964],[19315,"d8588bd5b45907a341a8f65216f50ffeb90fc2eb2ecc5abeb6638ecded817c14",9.317957166392093],[15945,"2762c13620663c3c776dff1be9ff805a0423875d3bde335f028b3dd6d48f0b6a",9.317957166392093],[3539,"9f81c7c72034d365bdae420129cf0b191d8bafde4a465de0d566b3f96bbdb2e8",9.917710196779964],[5824,"06956185c45eb4695098584445a1a1e30c75ea012456710cbb42ddebb60d36da",9.317957166392093],[19535,"56ac20225b2883c1b7a1faa013367da5c09b05e496e4180525f19c45f2c94d0d",9.317957166392093],[10408,"00c16ea4e50993a464c1d584f1d9701d8b0bf407f89e574a30a20938e8fdbbbb",9.917710196779964],[17241,"de26fc0ef3599e5909e45c9f15dcc435e491858a6654c258265ff1b41c09154d",9.317957166392093],[4671,"5e014c2f0acb00c25be5d2f0c8e554a422044615cf3d0804509b3b4bdf092ae1",9.917710196779964],[11589,"9f6b1901ee95c364fe4f03e7d2522641a0079b787bfb890f2a23f22a095ff6b3",9.317957166392093],[17430,"ef7592d5d7b78098d0255f53387e0d7cc2b598caa2f3151133c45e185ee32249",9.317957166392093],[16318,"88ca29495b0458671d42ce708aee6ae24efcebc6e3525eea195d57c51e1aa360",10],[1691,"85468e3c42e33f3d698861198d107bc621090a50c08161d0a7add5880f97fbf4",9.917710196779964],[19383,"c6b880fe6a6ed91eb430054a86750a8455178bb1e3056ee7ef50a8f3664e8a12",9.317957166392093],[3399,"844902d1b8a222370f33f6545224b10d06627b8f2f8930c66a6f0fd478e9aee9",9.317957166392093],[10498,"ce8399d1551c4d2cbc3076d2f33df3f4914e0ee9c14fa130fab6a447fdeb2dbb",9.917710196779964],[5057,"56689fa46122a351884342a98f4d4664db6a8714b7fc75190f9c44ab289dcbde",9.647446457990116],[1114,"d5d017228663072b93b519dc9cf57f63408f1176a796d3938b51e83a89297df8",9.917710196779964],[1006,"66a9e0fffc6d81e8aa69a5822aa3a87cc741552645c243a37592872019202cf9",9.917710196779964],[5495,"2ddf649f83b9cac9a8c5608f247ec66d8e9d9059288e1b37ae2fc8bcf50142dc",9.917710196779964],[9399,"9636c64fcc21a6e29a2cdc7bfc7fc603b1f406b5b83c5e82bed76e30b9c846c2",9.317957166392093],[399,"cc2511f3bfebfb029c5d8722338993a9f1140abc592ccc3a8126c4fd40495bfd",9.917710196779964],[12966,"2d909d657c99fc8b820faac53602f0d17fb63da782ab3b76440a5117dc54c8aa",9.917710196779964],[8593,"f0ad29a99e8a2e2e97ce09ed0b359f493c0e35a5a09690accee7338c35327bc7",9.317957166392093],[10285,"9fa8ac8bc9ac44ad4c093eaf9f717487f639ac957a0218b2c78740e7bbd17abc",9.917710196779964],[13391,"449fd13d34c21ed8e82b2298cd910aa0012e645a021a7fb07d6f09e8964187a2",9.317957166392093],[2915,"bfbd664cc8235dc576f07ac01b8d60bb95be7e42126d0ade33ac2d82cf80fbec",9.917710196779964],[10232,"0196fc7c995d733ab0f945d169db25518ab72f1067611069876ded11d82bc7bc",9.317957166392093],[6041,"3c934a46de59fb158468f232a42aaf5d58da1f0924e13712f050a8d3be41cfd8",9.917710196779964],[14894,"569025121865e262302ac8f748559324025e53591b5540aae94a0d997bf5f680",9.317957166392093],[104,"804128c73bbea362a7dd809d8eb7221f5d7a4984d7536f9c2e9e077391a859ff",9.917710196779964],[115,"15b8eec0dcf16cd3e9d528c2dc2545e6c1cd902ad8e984d0f01eb9ecfc1149ff",9.917710196779964],[15309,"aa95948b2c082639970e8410060b9ca9cea8e8c8424d0792c96ce92dd7503078",9.317957166392093],[2620,"928bac9e1b28322fe982faccb9e530ddf7f22babab05dc17f46e77ffc3220eef",9.917710196779964],[16532,"17f5aa06c8afa25d847523b339827de40df469f8b7b9fd418caf4da0900d6d5c",9.317957166392093],[13439,"8b6079a1524bf833be87d3186edc00aa1ecd3c1b84aadaeb5770b50b305178a1",27.07663197729423],[12937,"f6b40954c824e8d9ad3a50470010f9a424c2931e5b2228cd068bae087af400ab",9.917710196779964],[692,"902add10c46abfde8c4ca8ae398e8be05a307f6a9b5ea0824409b87968e847fb",9.917710196779964],[7795,"ebc19482da38b1c7f9aae421f20a0a0b4f0372ea5e7c3165d240f6fff5f4d8cc",9.317957166392093],[17170,"9c259513ea772dde554a725fbc2cf1b8332e9faddc1a31256d3388e8af217a4e",9.317957166392093],[10369,"2115d75ecd6b94fe2ad2cc80c670c65838a7cb60edd3c15de995638c311ef4bb",9.917710196779964],[14165,"b0f694d86a1f9adc3b5c49a6cefdced1d7198345ce86d819c7cefae596091c91",9.317957166392093],[8368,"b0a76e2682962dc8a75c726217fa958cde8a7df430daa27f6d5f7e54da1bd5c8",9.917710196779964],[9955,"1dc31fd6893871ad1217c7dd2b00e3a286b728a901c5f3a6a940de0522e49abe",9.917710196779964],[2743,"045ff70eea0b1febd74d2dac269390fa0d50287f7b6e8c4e8448c339dd6c29ee",9.917710196779964],[5134,"9f65e06e7b8acf59853074dc3e6505b684d977cdb6ba1285c6f22b172d7d68de",9.917710196779964],[17179,"98a5a8014ef2205b850885446f07c6e1417f5a4c28ec3a253bf901f4d6823e4e",9.647446457990116],[9616,"0578423c61eed928b60c65a3a50c03d3745ff4cec6ab6938f2c6ba95a062ecc0",9.917710196779964],[16074,"33679b38c2240e27f3ba4fdfd8da0d985cc987af187baa8373cef2d7b981ba66",9.317957166392093],[1307,"1bcd32cd2322fb0737b0fb745295e6c9544c61f7b4e552401f2798391b9657f7",9.917710196779964],[13766,"43cc8e241db240b33e9c853eb0284e2ec103f2a3002bfdc9e3ff7d7958fa0c9a",9.317957166392093],[14751,"e3552ca4e517f4a8c8206bc67b66a1e19871bc5fb689d40313573f88ad15e683",10.052724077328646],[12086,"c86a579440dbdbf5767fa54da201f599ccaf925d7c7a9031d4e880a6380ad0b0",9.917710196779964],[17818,"bd48ac0cce6a95d9741dc23c450fc707e6c4c8d375354bf1a02e12aebe41e640",9.647446457990116],[18349,"e9d4b08e589bbfe7f917091cc6671824083bd61cf29415f850299982d721cf34",9.317957166392093],[4461,"7952c662c9eb4fee76249e9f7e7372c0841b98d39eeea70d178b7fcbfe58a7e2",9.917710196779964],[24,"3ad69a8071fba91f060342829defd74eabc1809423f518ce2f8a6ecaae43dfff",9.917710196779964],[15480,"07c36cdb6d5c3e96900756e6620ffffd6259587cc9e4ac000139cdf8ffe68474",21.115551694178976],[18789,"0e8fa6d6d039098ca46db32f0959d1360f3d7d7f33370877c2464606f71e5f27",9.997888067581837],[17715,"6a5558cd874ca1dfdb67388eebfdbbfdc59baa7f19d2981f2eea5cde3013ed42",14],[6750,"ca905c2380a5234fe6c662697fd62483618e880f149147111f9cd9d0170c96d3",9.917710196779964],[2438,"cc82c497378dd6daf50d144d4e518fede38b6f2f8f60dc30cd58a75f00ae3cf0",9.917710196779964],[9250,"042315efae42244d3c2559b4e5a9c4e065314845b3a5c9e2e0cd18dd7cc921c3",26.091872791519435],[16161,"3b975ec3c19d21e2f73cb16d4eaa1e6cd5fb080a017ea48c51208743ae83ca64",10.052724077328646],[16320,"1c1b621bfb7edfe0c0a8be9ab69f255434d44644fe4a1e8d29c3d70295bea160",9.647446457990116],[14999,"3960fbc2e3ada958d783acacde160a3fc3aa28dc4823b922664f3726730b907e",9.317957166392093],[3033,"f136e9d80655d572b2a07108df082e7f9c617a6302b0a4babb8614217fb814ec",9.917710196779964],[18336,"5ab47e8a12baf611345deb3be9937d87286712f7f98f999fa85726f5d6302435",9.317957166392093],[8902,"99370ea7497f8aab01d53db868e39405b956de4eee578b135da390f20c4572c5",9.917710196779964],[11356,"c44ed012a22aa621f3e57efeefeb7fd99848ee873535e8492d046082bcd19eb5",9.917710196779964],[8831,"257cab32f35acf51fd2a4d11819f1dc2760973865a08c3a65f6a73ad0ec8eac5",9.917710196779964],[11859,"835b6a131629e830404ece598f9e2701aefd42d780d0867d7cf4875deeb652b2",9.917710196779964],[11678,"9f442c86778001120047a6256ce58f4d25864152300c38ffe6ee0ea1c61e72b3",9.917710196779964],[15050,"ec24dd737e8d61caa8e405b071f465c0e2de40efe44af2097d1da7303196867d",9.317957166392093],[13467,"f3fecdd45359035d5b9c281f24fc4cafe0088cde9a408a20766f3d673ba7b8a0",9.317957166392093],[12441,"2e56687f18bee150b89bcaa54f02302d077003d79bdf6a121fa3625d42c853ae",9.917710196779964],[9393,"e72048bd3b947922254601c35e2d0297aa234796f6ba5c6279407976bb4b4fc2",9.917710196779964],[17347,"e612776306ec7c09fecf6462e18c7972cd70e72e09bca7ab36ad90bb58e8f14a",9.317957166392093],[6742,"b0f3f918c643fbf448beb1d7cdebaed58e3a6c4492575e19d4ecd9849ad1a5d3",9.317957166392093],[4200,"87dd56877a196db2818fee9a2611606c191d41578c6238065309848cb45c6be4",9.917710196779964],[12964,"6e5025347a626d388f01f13238b306b38fed40bf01a51aa826b121efd76ccaaa",9.917710196779964],[15809,"ae7ea3f08c5bd3588ee4fc9e8b577987f453d156122b279a4c12a14f7d9a346d",9.424083769633508],[2535,"e002e4609487e60181bc7c0b690b1e1a14649995f97cdf997e42a8173cc197ef",9.917710196779964],[7744,"32b3fa013fceb7ad29eea88c05229dda1edfc66ca333faae225073070f8530cd",9.917710196779964],[18399,"d5c119f76fd97ae695c98c43639827ea2b306d6506893394553ae684c5d97233",9.317957166392093],[18955,"6b7689a4c00762c1a9b88eb0d7168539292efef02c07a2acdfe6c5c2a987e721",9.317957166392093],[9962,"188050862c674b59edec25635c7e59853b8239dd75e21e3c38764af366a689be",9.317957166392093],[8425,"04be7da0c11309e19e119dec0fc9bc2bf7f3c5a60aff2ca1ea7d9e1a01b177c8",26.076923076923077],[4851,"e5235fcedb0711b490b4903f4b53e653bba97273ca4c449d56e81144516424e0",9.917710196779964],[7415,"0e77a62283eeef2437eb60078e5c49ea5be76922beef9e3b69ffd36538214acf",9.317957166392093],[3030,"3a19330d932b57e03aad7975451e87eee31a240b349202c25793269821cd1aec",10.052724077328646],[871,"51afd56dbe782902b939c160fb4a26e59f8e5ad8b0edee01636a1e9a1c2d17fa",9.917710196779964],[9850,"3c4e5cf9ff8667a1acb271d4a90ab137f994ef8486d80d653fbe1e19c3574ebf",9.317957166392093],[14407,"316795e2fafd2fabdae49d0bf259f77a19df405c519a4b4673a5f460e2122d8b",9.317957166392093],[9985,"70b7cfd3709d47098a39a2cfdd89e6264cc35d202e7fe4fa0ebb86f8ae106dbe",9.917710196779964],[9691,"b9b0a2b2087c8058b19267f33d716c2ce2637a75340a91d0b472a64d362876c0",9.917710196779964],[9335,"c5279ce4cdd72bd9de40caa56bb2c87487349fa1584d0b1a3c3343ad68e6abc2",10.052724077328646],[19110,"fd90c6327db8fb7db7c62be05dc3b7e178325c1aa3082fc29e4aa9f85031e01b",25.941043083900226],[10390,"1e441bf2485a18b866dd6fa87d183a889345728877a8e3cc3e7b0b33ee4bdebb",9.917710196779964],[16286,"14fa40a97af0b9ab5a1479166b53b5d927ec5e77b6e1556e25e3ed0198698861",9.317957166392093],[624,"6e1f8195a804d5f01d682e306e7ac5073177d329d18d4812a2d079f7b1f1c1fb",9.917710196779964],[4572,"f4b281c0b547c992323aef037dc7d70d2f77df602a704c26ed2831f99d57d0e1",19],[11020,"5aa7892f5a031f1d0571bba2ba12e0fddcb123e532ab8154f46138fb2f71e0b7",9.917710196779964],[12274,"3b6a307c41e4b32ef6c5915eceb6fa4e1520d86f880e1bfabb7180a51ab572af",9.317957166392093],[95,"a5909906e7c00caff3c93c7754270cba4839510e6f0c8ca2c1662941a73266ff",9.917710196779964],[10094,"06c1fb5873f06456fe994734c244abc8072694521f728c2fc9d7cfdeb476c3bd",9.317957166392093],[19459,"fea37c6d9b0ae332aacd9360410d881a94385155ef99bc61a5996a08eebda60f",9.317957166392093],[14624,"28472f3fa4a3b5d5653ad5a6ed2fd2f4cc7aa9a959980e77541413364cbb7c86",9.317957166392093],[2881,"201782baf8d9ebe94ecf1b771781c8bb5f0bb7452c82b9d20416a9aa70623ded",9.317957166392093],[4381,"4915f41cb60b3c77fbc354ca72d38fce3e459a07795271add4e7f6ef96ed31e3",9.317957166392093],[6195,"bef2f3c3f827e64a05bbb3dea2fd075d6f3b2195284d6f78b0f9a25afc39d0d7",9.917710196779964],[241,"5cfdf31fc5befa9b6fb5482706c1b9f9538d7b59e66ea986232ed08dcaae5dfe",9.917710196779964],[12357,"550c9fd801be26b0c8a360cc7bf5e85acd289e9d6c95bfa845a60034a610e2ae",9.917710196779964],[8559,"ceb783b0e851aa04dafb0aa73c5720e9afa5b5bdbe5f9c3b917d826c3aa2a8c7",9.317957166392093],[15445,"c982dfe0b5789e9b276911da14b6c7206d21715a2bdbf216dcac580d26f13e75",9.647446457990116],[2130,"efbf1a8b1b0728cc6e413f29f73b909ba92f2302f7b1d9047aa08e9412260af2",9.317957166392093],[4973,"33355111525672abf1d3e35b4a56a56b2f9683a83407a3df630ae889911c5edf",9.317957166392093],[1693,"f22d2d047d55876260d347c235482748eb3ec449bd2f5c899031e3779d62f9f4",9.317957166392093],[599,"e8a5cdfdc1f83f5cb729bd244fd62f050de9e8489ce4b8946ff7a11ffbbfebfb",9.917710196779964],[11211,"020c5011bdacd29a31482a9fbf7c4b12dc951010634764b372c73e8e2d52a0b6",9.917710196779964],[8981,"f388020eec1a3884ef81e9bcc882b3df2f0f55c081cf40e4656a2d2fa858eec4",9.917710196779964],[11962,"66e7ac14864b0daae84ffa2cb1cad3322080d69a2cbb34f4edac788d1c8f93b1",9.317957166392093],[1311,"21f291fcc0f737dfb2c24f195c16652c76178f4ba6d1e750e2afaea30c6154f7",9.917710196779964],[16206,"e6e1ef4ae7787d675ef1a9f319eeacd4fd057e4c7f858b7523205d71a8fac763",9.317957166392093],[16013,"9f4cc53dd9732932dd8468b6eaa43b4ae18a402a90f20ccbd206a7df34402968",9.317957166392093],[19228,"8a6df20ef50c83cb5109e6fdbe7c62d93a94ce9f4c12e03a6ccaec3c34d5b817",9.317957166392093],[3675,"6852e617f1a5e2acb68a8547b0e7f059ad570ddb15ef56061877f1069349c4e7",9.917710196779964],[17722,"b882434a0177cda6ec975580104d1cec84f144380589de3141e082235bf7bc42",10.052724077328646],[1874,"bd3888e36ab0e110b80d5d6ecb9018817d9e480c467a0bbb1de9265bd094c9f3",9.917710196779964],[15652,"f64eb11129faf389f1cc160eaa4ab6706b965870b23c73b36531b5fa46114d70",9.317957166392093],[5098,"deea314172aca1870683ee5069dc3384ad7c4bb51ce0fbe71489496dc93397de",9.317957166392093],[283,"e1a49e9a1a221a591e826f9b06c51a2566df7d9e195f5e43fc6e3f94f7660efe",9.917710196779964],[13525,"e9029bb8c8804fe3d97a6e0c51ba68236b8e6cc62c6d0502d88aadcfee404c9f",9.317957166392093],[2698,"8932db10f03ff0239f335037e6a1e065a674e637acd2cf2c1085a09877fd7aee",9.917710196779964],[8165,"c914078ce36328f30cae066454ef109f1115f6c86ca805a1ef7302ffec4e37ca",9.917710196779964],[5895,"6a7f3a13153036f275f7c375abc508e7ddd3ed0cefaa2a2d9825b9e7f52bbad9",9.917710196779964],[3145,"c075786e5731de7ecd23272e25abb3ecb0d9df2d539551bb2b07f861c74966eb",9.917710196779964],[19778,"6093423b998c971f3b7441527a945c6f1f03836db7e007d6db2b0ec0ac7a8d03",9.317957166392093],[10573,"311abbc049c038dc17658a5903174e2cfca5682c7645e9f86459ea76f238c5ba",9.917710196779964],[18017,"49a526b5a68297caaef95a6028372e5f086feb79e7614789814910e10f65e93c",9.647446457990116],[13755,"2264bb68ea59c0454826a26a60f1f501550fb34d5582a410b6c478934227499a",26.13903743315508],[4161,"38c936be591b33b94e78043a19cc88aff4818e75762aca6e1161546e884faae4",9.917710196779964],[17213,"1288221f69e275538a8c11493603b6248a2204f7e28dd5b056c65fcdd980934d",9.317957166392093],[443,"c6aa2b9aab2c0e4a36836698a1e81cf14d4480e37639b4588a1f694050fc17fd",9.917710196779964],[18904,"9994ae91cbfca955f6a74eb7195209150fc02adcdd79c0035cbeb0494bec6823",9.317957166392093],[18736,"f92c896f64cf44d85974bee205294a83fe34124a779487362d7aab3665f32c29",9.647446457990116],[12959,"c41f6f7144bf37d8b5022bbbb4f7d989e4c680a56f1bb8b610be84f8b4fbd5aa",9.917710196779964],[7708,"ed3df52b6e31965845f04e2eb0609b8877e1b67970e36be5c0d1011de8b17ccd",9.317957166392093],[7031,"4682f4500a3440bfe95ac9a267cd01f4929eacbaf8ec51bf605e7d6f5fb5ced1",9.917710196779964],[6836,"8f4b02d282c027003df2a07058b8af4224d1628db2e1eb86025a583cf22e06d3",9.917710196779964],[6929,"a272fc205c5e7bd6bcf5296757743ca06caed0107f59c5568f8e3ec0a5fd72d2",9.917710196779964],[9582,"b7ccb0797a3a2d88ea4fa6ffb86819b552a09b34de31c0130bf244b0353a1dc1",9.917710196779964],[14193,"eab2de8421b0182e410ff8b4add855ff3981a2a91064a8feb459f58c78496d90",10.052724077328646],[17453,"0113a2c3411b0edf4f46f5638f8846f75ac1fbab0671e27c92b7993fbdd4a648",9.647446457990116],[17582,"c3dda171e15d19cd5d8b6f74d50bf0e2771d033888f7192ce29bb29b5659ad45",28.19221967963387],[3460,"5457b7f3319154ddb04d12e141b2317c15337099f8747fa967f2cf1402554fe9",9.917710196779964],[11207,"e29a475b64cb3738206fb9be97ff4a6e96330a2e37d9f0ad661a3ba72075a3b6",9.917710196779964],[2551,"d99e6deb8b4901046f06b4eac5befb66d477b336f0e4e1ba3f08f5a37cf887ef",9.917710196779964],[1020,"f196c5ba1f6bedb108538f313e2593230a010b64e91d0db20b6905caa87f1af9",9.917710196779964],[6048,"c42a71007a3ee51642cb2faea3c1cdfdc031f6a6976c2ddb2b68f440a09ec7d8",33.42226310947562],[4066,"89fa1d840809699be9e5b0eac74cd435acbc609c8903ca05faa203b1508550e5",9.917710196779964],[1089,"bf0524039a362c3f9f06c58241e98a8ebd6530d3f5a4908402b5907bf1f2a5f8",9.917710196779964],[9149,"23375ef55e773e34aa1d72d760b3c586adc6c03850ab917d359e4fe8381ad2c3",9.317957166392093],[887,"1bf9114e167b9e3f1c1d61f061268c825d1e5ccc892c27153200563582bafdf9",9.917710196779964],[19513,"496b188b946a6406564a73c07abbafb16a2cb5d2fe7ac3faa73fd4db9d6de60d",17.14031180400891],[3023,"3f9cfada1670976169244378dda1a19e7115a17fbc1aaba840fd347ddc9e1fec",9.317957166392093],[12597,"a067e8edcf243fbacefed70a2bf5dd0e0e5b26143f0dbc48b48a7722e7b149ad",9.317957166392093],[4553,"329dbafd03ee6ab474d312506bb59dd5ad114169d31b52fc304db83efe6ef3e1",9.917710196779964],[13547,"cdbace6e2e3b83a99419a676de7a5ab1ec3414aea505196b8b2799f6e821d19e",9.317957166392093],[3390,"8a19d284c8784c886ed2f77a14c8a8097447217b2feef14b17a64ee6e3fbc4e9",9.917710196779964],[18596,"310337070b2f32d4472cb75b0fed6588f4a8ba95288fb7c4da98f9051d62ec2e",9.647446457990116],[17393,"7854065c29a60445f024fe3a01831ca9c224e1bcd5761f37e063ec743182ea49",9.317957166392093],[9864,"607c9311367bc11b6bd0fd76491ec573f23d76ce17a18093a9a3bec5b24628bf",9.917710196779964],[87,"9b519a5660cf1da118b4b3d8b5cc201fcc76221c8570489da669f87454e16eff",9.317957166392093],[1908,"537a68286c155bfa8ea6f29b9134b8f26b60f5769ec444103fa5071a9e4996f3",9.917710196779964],[7107,"87caf2f78fac3b57c9d90453d647967ee7c5df7fc6aa0071cb79bef325fe4ad1",9.917710196779964],[7041,"f15d744ac8b016908c36dd57bec97587b5bef2eea2ec4c002f2cf12f9c18b5d1",9.917710196779964],[1508,"73feae2c54562b4ad93d02d09bf208d96e8d68ed6e0edff482b80d4b883c11f6",9.917710196779964],[10368,"f3d7a2eb8baaf5e74d37b32fc8bd07b7c5b6422fa32bf1cc0022b2a12a83f4bb",9.917710196779964],[5974,"cc63f3713208fad351e845be6a5dd272409931418498330ab1dcafa004e041d9",9.917710196779964],[7249,"a556cee7b83bc1d049937c91d3bd5605fbb537c3501eb0bdbe62723c1d6561d0",9.917710196779964],[17300,"10ae34b1d694a9928f9d31706a447ce79c434b18aa3d7b7ca8431afb6d25054c",9.317957166392093],[13955,"65c24f8dae5a34c071ffa62563b9dcd91b6e8359b5657ed542acb205d88ddd95",15.017421602787456],[18126,"1c17625d167bbcf3ea2bf71fa217f9ff63f1db8e234bc06501724473d62e503a",9.317957166392093],[17907,"7be64e9496041853b22543e3a2483cb29f565bc30ee6b449ef6282f4cf6b1a3f",9.317957166392093],[19496,"36ee75e4e6bf756e496ed328d8c71bf23237a069fd86692fca7496e7c910650e",37.832614322691974],[11294,"175642242c5888fc38354aff575d5966c8d9f332402f88333adb0332b63313b6",9.917710196779964],[4880,"2c51c82e24a88dc16b904641ea80d083a6d68611a876200e38ec003cb9c1f1df",9.317957166392093],[179,"4d41d6e5e6ad235e2f610a1444f8eba6b10a4535c1c8dee00cd08ac85996cbfe",9.317957166392093],[18982,"640850bafe4f95de71a25bd2130b896bd156c2417213a4ed5fbe4f3118841821",9.317957166392093],[9714,"7bbfbbc65b7c97846e76206b27099aadb962b5c32fd4bc9de4ad449e5ac142c0",25],[19584,"764b561ac0b45e13cd00842b8b51c0556ecaa80e77b848649c9896f1369fd90a",9.317957166392093],[8590,"40f7f0e80e136470030142c17bd6a06fa74ad8b5a40473a70df182fe1eea7ec7",9.917710196779964],[2156,"be776b24a54d6b9e40f4a2b9b772dfe7f6013527e8699e1d8a1b2eb3c708dcf1",9.917710196779964],[5250,"1c5d8d525f1645d3a9f6870b8e14569a2fefb08708e3e42cbd8dc8fbf849b4dd",9.917710196779964],[11171,"09e182418ea7f16ecfb335b64b2452655958e76c39a451c35aeb217d1fd5deb6",9.917710196779964],[9794,"5adeac9a100bb0a906910b35ad5238a57c1a15326d4f5119188d7a63d7ecb2bf",9.917710196779964],[19322,"1b026f46563e7a187cf0fe47fb1347349a99984977c5fa1c13270484e8854e14",9.317957166392093],[8370,"00450e77cc39372bae6876f6da715bc6dfa1f62b7b78bdf64bf691a5884bd4c8",9.917710196779964],[19494,"7b05ccf3cc8a657d631d94291ef64ebacbf69336c82d3efb0547b1ec0932880e",9.317957166392093],[15381,"e674c6c02eaf73216a39d8ca06561b44fbb95d8944d0a02e2b86b6db200ac776",9.317957166392093],[6540,"5d12c5160ba1675002fe7b1598d4a422bcd9fc05ced3271d43d340a030b119d5",9.317957166392093],[11064,"e086d4f1f89649924b705c06249851176bfcbcce9d36f26d50bb3f61c5d992b7",9.317957166392093],[11288,"159035136e8b611939f8bc2c223f4a12d8b97ff08dd388e7615c5ca16ecd1eb6",9.917710196779964],[15900,"87795305b9573505e9ed5a7eb24d8a8e8dffd9b54df3708b6fa2ad35b3f9096b",16],[10250,"177a0408e96bed55c2c8bfe727b2c6677667b7edf1a5d1f89143c653e840b5bc",9.917710196779964],[13209,"77af4e1ef7626ef69e78a4b3292454e82bb9218013a06e6fb93e49274110bda6",9.317957166392093],[13506,"b47fc52bb016167dd2edd10b0883daac27a64662c90367c895f9a9831868a49f",9.317957166392093],[16850,"e1a94f0ea00130a647ad5581123b5fb1052c241954b1c6c39efd5e6ee2e64355",19],[9074,"f22ef7cd6d165dd2785421d81555c984fa688e8d4a4f22b350b7f420c46a4fc4",9.317957166392093],[1859,"7fe465ed88e47711ab759addda1ae0cd46f892b41d71b8c765a56ad25aefe0f3",9.317957166392093],[18460,"47a69bbca9e0dc938241acf10a6e0139617bd0bebb748f78bf7fa14c0a1e6832",9.317957166392093],[8103,"acce3fb67b28e6a5cb18de3a0ec59a1f1b404c71411c65055e74ce2f99f1bdca",9.917710196779964],[6864,"b208e8743f346bfd736c69a95cf554d320fc8431d42352866097e0e8d5acdbd2",9.917710196779964],[6924,"66c3efd2954cdffed6db148aea8d6d15ac3a2bee439e36913a0f9936e4cf74d2",9.917710196779964],[4429,"e32acffe1212ce3fea67cb5db813ab58bff98e1aad35f93ccb681d69e333e0e2",10.046511627906977],[2802,"beb02c64fb084fa9fdc581537acc1510e5c1b8a6934aaf61929b7df311b8b0ed",9.917710196779964],[14613,"3036e639cec422e7cccdac0ac33b914e929739341a00d8fe008440c74a56d086",9.317957166392093],[16016,"0c4600092c770a0c4ac1492befc415303279b6efbb05ac72399b5128bf111868",9.317957166392093],[212,"e5a16efa4f23cde376333b148ca336084d7fff0929433ac19100a8832e828efe",9.917710196779964],[1056,"8ae542cfdb53f1987f63669893827192507f418de593ec58a6bd5b5cc08bdff8",10.052724077328646],[12373,"6e0b50ef0c8c018ee5ea11ccd449107735dede144fbb617cb2806cd4deeccdae",9.917710196779964],[13704,"926032a7a43ea04bda2f4f3daf397eb2fc92e4ce9f667db87bc06f003dcc3e9b",9.317957166392093],[1283,"a0ed0691b93f2082487e74baa788288bd5d00c22e2ac5a58561bf2574f9a78f7",9.917710196779964],[6553,"fea3c23e0fe283947776edff97271aa355cd7a1a2e63e6949aa4fe1ff0b4fdd4",9.917710196779964],[16153,"2b624990a8ff3e009a588d6c9de187a96ba532b81018c89277afa7c84443f464",9.317957166392093],[9500,"128338b6bff378a4c78486c1e8c9e87741cd6b85f3ab93ec513688f8e415b0c1",9.917710196779964],[195,"ce88011eadf060b9e7d6c9defc7edd95f610b4cac3858af6cf646a10daf2b5fe",9.917710196779964],[2213,"0c4c4a4fd15748a0fb584a613a0d9d7e8091a6e6968edf7ad3f0d24d3c4a6bf1",9.917710196779964],[8327,"f105f40a9d2d5e2427e42baa79d20b92717a4759198558bdf2a2b324894424c9",9.917710196779964],[7087,"78995087a516dd2f285243a7f998702f77bb3f21666ab7906a157924d5d86ed1",9.917710196779964],[763,"5cf24864b71c8ec4f1f87ff6a791ba15d6195715d0a6d11e547096c8dfd9ccfa",9.917710196779964],[12201,"779da70406764181e642cf769ab80a14ee6e0149a94ce7f83ad058be739810b0",9.317957166392093],[11978,"ad89881550f1c16c9a0adfd2ed4c0a46e18c61f2d45b70b8a8f4091bb87870b1",9.917710196779964],[3485,"172e197b0bf7242bd614f9de56b86c5caaad87c16e7a26902c78918527a81de9",9.317957166392093],[15648,"51dac90c9b6c54836e03e011422f63b7f13aaca8e0748f0d2121c2b8c9005f70",12.0473061760841],[2556,"dea258a7ca65e0cbf04a114c5e691c3e2093b597325ad34cf7a414e388a581ef",9.917710196779964],[11390,"1f3c4672dd385eeee72fc60743c150f9642498a4c3f87dfb234302ab6fe76bb5",9.317957166392093],[3292,"3b6bdf8ac6e8fac58b4a8caa5706d6b10f6b74580b8f5bfb9a33625b280373ea",9.917710196779964],[15292,"38379c720cfd11f683e1ad10dc9d97307c01e66ae028bc64e0e7dd5ce0f89a78",9.317957166392093],[18427,"fb38e2432078f4065135f7cd553f2109421722358d8752c24535f2f0f5680b33",9.317957166392093],[11040,"12a0594f01d097f9fe40b4a6353e030c73ae49f5b3b8711096bf6ece5704cab7",9.917710196779964],[2317,"6d68f438f308da46dfaff532f68df3810de7532fb17a470c1bb306df9450edf0",9.917710196779964],[15639,"4e340e04d0725ebb03d41db3e8fade268be8a50c3c6d4782a1dd62c3e9748970",9.317957166392093],[15043,"0d0f4ede151a99e6fba4ca99a0a0aa89b7126e96ce500d93945058c5f558af7d",19],[18771,"b963a546150245f561e9662ebd68a31ade1f3c0d91e6938c84ebc42cd08f0a28",9.317957166392093],[11095,"61fb4f82db18fd2b28d370dc419c9e03bc45d62a57beabbdbfd4177824c548b7",9.917710196779964],[3883,"15953e60c6962fadfd3788a76fb89d8a10c3cf4073d9daa9a075605c1b8979e6",9.317957166392093],[3450,"bde5be8c9d3cd7f7813ee87bf0651a74b0187aac81cb30149392fe209aa45de9",9.917710196779964],[5133,"3c71b3b4f008170dd77ff22886f6c605e5c89c3288fc0749467b4196aea268de",9.917710196779964],[2763,"ca33a0992256b228278095c8198fb7c6f866e81e0912b573c8be50fe439d06ee",9.917710196779964],[8154,"6c3097f71cfe2f5c75b0270b47cfb9ee8c1dd41a38168a9267772e26107653ca",9.917710196779964],[17041,"8e79681f32ac2f2122310575647dac086448ee2f6c19c000b3c83483674c2c51",9.317957166392093],[1280,"a5fef465d145a1b892a50efd41cf145eee16cafe23ecd93202b5ee7f12827df7",9.917710196779964],[10844,"0e9a7a6ad2f03b99ea798236706a72944c090ff3f31c767d8c7f98ba4ad307b9",9.917710196779964],[2576,"d29096f00bad7029b9394bd9266b0921bafc39446acc1db5d08432a3959a57ef",9.917710196779964],[2571,"bd69b0a62769fc8ab1448fdf70b6eb915ccbe42ae7a65c0ab29befcaeb8367ef",9.917710196779964],[9176,"cff340ac46183e95d500a07d2f0fb7bfc91c2821866d77c4e3dcfbcd513aa9c3",9.917710196779964],[19860,"9e23156f38294003f02c0f184b58d0e6c4fc7e97ec683cae6be839c306fb8600",9.317957166392093],[9567,"e9c5f189abda769c84455784b1a8ec8f7c79629cbd97a9774b4c904c61e631c1",9.917710196779964],[13812,"cc4454a1d755e0d83f0a0687fc756c6ed3882d1a135ebe11fe2e9b219dff2a99",9.317957166392093],[2798,"7d99bae5fcbe460fabf49319f8cd4e0252a49ba9cd8fcdcddaad27bf621db6ed",9.917710196779964],[2506,"7b2cb9116e2706ab54a6669454ca174826fcaf5eda9ea92d4ad974ba1fd0cdef",9.917710196779964],[9787,"7321c60fc4ec5998a1509ad0897ffcbb4b55a2b045620effb02a5482e0fac0bf",9.917710196779964],[60,"a0d45eaa9a5670b487a31a49fcb8a012c571cfa05a471410e6aff2a3140f95ff",9.917710196779964],[13244,"c089a34ca12ff59eb63e478feedfb45b8841bae936a37f9dd3ef6409d501f5a5",9.317957166392093],[4984,"901ce300710cc6592a6f3edf2fbb744f3498d2c90a3cb3c1e7bcbe0e122549df",9.917710196779964],[10353,"95c7f8a5193c58ab0efb7a37f5bedf98ab662cad7f948f4ddd6011370a2407bc",9.317957166392093],[19426,"e44e2fe52b842b15b57f84c290e92abf5f81972f8a1f679d77d494ea89119910",10.052724077328646],[4002,"0333b82860c2603ab3d51f21232eff52a9de02ff21d62fa814231a949705b6e5",9.917710196779964],[9828,"96dc2e6156acf284ce8e31cf6f7ddf98cfd1559dedd1248a3d85eaed7b746ebf",9.917710196779964],[16874,"e0c1e9e2be0907f51b5059823635268e230e611c0648264f8b17de8ab2f2c954",9.317957166392093],[1637,"b3f96f8d891d08eff5d6d30aaefab3da105b3e6b1d6c08676e698a84862c61f5",9.317957166392093],[13801,"7bb7c7eb207b5cd7e3082db66a8f321ab745b735fd0ac65342edd075711c5699",9.317957166392093],[3239,"58bb29120f3a00d2b097a97fab64832ced2dbdc84173bf16aa60d8acfd0ec0ea",9.917710196779964],[4826,"ae99d6d63fa0aac3173fb7357c6c4124f78e8abd9867c42c6dec7c5492fb3fe0",9.917710196779964],[4799,"a87e30c85c767b9723081acb0c2b40d475e9d5864a62548d13f80f76136e61e0",9.917710196779964],[10444,"f1bc205fe8b104583c0d628361646f9ff43c6ac406c7a90b7210678e2d3672bb",9.647446457990116],[451,"1a237ff916cec064ca109eb69250673dca84fab0c8e7f0beb7a70405257e0ffd",9.917710196779964],[14043,"a948fb997b6f16c64dce6b3072f492c2b35991ff458805f00b5f44b56f49d393",9.317957166392093],[4379,"e5cbe1995f0f4d1d689e1ca58a44a8cf0fc23bfe9fc7e6f65d82015c566d35e3",9.317957166392093],[12547,"6f5c8375c333f891a6daa3219bbc886dd2ef505e1f68ad7c1aae7864633fa4ad",9.917710196779964],[8271,"12a80f68ebe82a09a790356594ade0f56aee87fd5bff23be3767a5662ce483c9",9.917710196779964],[18052,"366e6714c7419e12c3e83bb6f6ec0300c82b5c5a0a3dc2d134bfb6a41c90263c",9.317957166392093],[1379,"25bf50cbdf4786f9a757eddb78b5931f5ba345d1e22c51b99f157d375635e3f6",9.917710196779964],[3055,"4058b07869a8cfb662d24ece75b6b030a6a326b307bcade7aa10af4e8c6af3eb",9.917710196779964],[17071,"46af8666fbb6d6cc01ba70e2a1b6009b52c1eb2a92c73ddd24e89dd2269a9f50",9.317957166392093],[4311,"831a3c466546aede43e0be2108142f94af59c55c7ead1cb3edcc0bc7a9a9b2e3",9.917710196779964],[3754,"9a9a91113a0b74e31a94fff3c59cfd684a2def76fd3c13c5597aeb9dacbe3be7",9.317957166392093],[18886,"8d4bf81954d155ff71f6efbd45f3657d5cb44b5b2bbfa1c1993b6a06f7b6d723",9.317957166392093],[4641,"99524f481d30184d5676d0c00abf83febfa86934fea263875d0d38e82d4d5ee1",9.917710196779964],[2739,"d0a62f3bb35065d52e141a4570620111647ca9e3c56f653e05fb36207d602dee",9.424083769633508],[17231,"199bb8a75197dcc4d2e8ef37825e92fd3ba2e1d8e8b20a956cfcdc59775b4a4d",10.052724077328646],[316,"889b4e0260bc3906c882e0e8caff8c01df3c8f350b3826640d7331da05ace7fd",9.917710196779964],[13225,"3b8b7390162188cd4d789fda04e7ad9264c371f5e3e0c86f8fffe34e470b65a6",9.317957166392093],[11363,"a6e0a5824a1e51cf851c020b07862afb9a8d3ef578b0c422769c0a0ac2fa9ab5",9.317957166392093],[15466,"8620c798f90e20d8db2771cb8c758cc66e7974f86bd584336a6b712cec73d974",19.154929577464788],[5455,"99b25be49bdf57b2a6358d1a876770f9e3f023c027bcd566fa55b96f861a75dc",9.917710196779964],[7445,"8535f2aa88622bee1417790121626037f51229a40d4b43571fd5324e10321dcf",9.917710196779964],[12104,"0880c553d235ccf48d0aaabe4ab661008147f66e0b593211bcb5f529afa7b0b0",9.917710196779964],[2721,"11bdf942f0a706dc5564ac7ce369a03849957ed85e1b434181fd6db5777f48ee",10.052724077328646],[18310,"a6889ebb5659ab6b4f50432294876f972f3b5a17c86b85a65eb9aaa684c9b735",9.317957166392093],[19619,"3eadc7abe25c604ab29f3a7ee989a5ff217216894a21469b671ff841adbb0909",9.693363844393593],[18004,"4f932be9d7bafc2e52a27d68e9f35655eaefdd43866cf560bc2a5b35a4de363d",14],[18151,"3a2ec0764fca18df8bfa358bd3a82ce4dbc7a33a834c394a70d7d431d7c55539",9.317957166392093],[13186,"7aa9e48168dec5b76086b3539cd28862670b6c37ce68f30e33f40abb43e743a7",9.317957166392093],[5861,"b4b9224ae2d17092afa951b8e56ef43c061b1eda29c6f0d5790699108315e4d9",9.917710196779964],[15623,"1d59bfbe474ccd173e68faa4e0c5c120508f332782defb986f0f4b25edceda70",10.052724077328646],[5,"abfa42f4e6b196449b9743b5ec47e4c959f011a0bc0a7193f9d0b1668974faff",9.917710196779964],[876,"664d87f44bc6e85f5d3c13bad4ee1300973c47b2fe036bea69c46d9b026510fa",9.917710196779964],[760,"708504e3e4e7dc54a1bdedaf01d7ab70e134498bd628706c83e971129213d0fa",9.917710196779964],[11512,"08489286cbbd4ca0125055371fe821762ca64a1cb2cbf159659b4605e6b370b4",9.317957166392093],[5271,"c1ed511be2ff2372aebbf1e5f772a79b6560fc0462576113af80194cc4da91dd",9.917710196779964],[5849,"13aed8836ba137967e0a52f8cd52e848407f13c51caba4c22dbc4370f4cefed9",9.917710196779964],[5466,"89dc8d0cde27c8e8d64fc37687c4ac305a75a5348666475790a6924b6d6269dc",9.917710196779964],[1478,"8936809e848255c892a5c044180fc40cce3903fe33a62a572a8facc4e12247f6",9.917710196779964],[2796,"b70d9e3d57128fa5556de1ae414f8963ae38f1f6d13fc3314cec2e6af534bbed",9.917710196779964],[9212,"ef467faad81fb5a9c7589f45c720df794c2ee9d7f7473ca2c866d4779c6c62c3",9.317957166392093],[13315,"c4d8d36e7eb3079c71e99916164a858a5b51df69e05328b130a35f47686750a4",9.317957166392093],[17593,"3d5fedef020196c79de30953fe72513177ef571df5e2461ca34142da26225045",9.317957166392093],[16842,"5d734e8e716798aa3d11cb7da19d89d24fbf6eec56f426a9da8e1e580be76a55",9.317957166392093],[1891,"07763475b49bb440b2d85c684cf29d38876c088a0c9cf5b6118cfe1302dda6f3",9.917710196779964],[7965,"d3fcc1e00641b1ffe0edde3a1366a0ea3068a5a60eb9e1cc4a8121b3c04bcacb",9.729977116704806],[10405,"c5de667d4c9e33ae50bfe97cf56bee0231d48a996851691e57f7d0a11075c5bb",9.917710196779964],[14655,"c4bd88181530bbf602a0ba7f2d6e59332f9e123c891f6a8514216a351d11cc85",35.830388692579504],[9945,"3c2b5e2f1cea213ff92e908cb31807512c006c9fa84d92ca30f4b5bc8d29a7be",9.917710196779964],[14633,"6851cdd524eb6f15d50d046c2199d50ff04b7d3aaeac7e2819f62eba459e5586",9.511868533171029],[4676,"78acdfdf8e91d1fd36067fe98f6c71d2465a16df94befaeee5b65f9b036624e1",9.917710196779964],[15709,"333bef523b6d2965ff186bd9b4d86072b66782e5b6a5fcc2ae3a1254c916406f",9.317957166392093],[17299,"8304859820c28e4e00f1931393fc8a2ee99447c250db548ca8c98bb20adc094c",9.317957166392093],[3297,"842a4b1626fc16174162cefd516e8b73e71247a844b703e238230a3e41556bea",9.917710196779964],[12962,"ecfee29aaa2d7b85995fba139d34c20f9a923e421ebd55187bdee5c39815cdaa",9.917710196779964],[3546,"9d2000c38201711baa5280c3e313312f24c4b8a85cbbd72b2edcb9f19877a1e8",9.917710196779964],[2815,"f9b0f0fda3a17b69be8dfcbe9e562d7354967674b9fa4731e08b3c3d51aa94ed",9.917710196779964],[16699,"386828734275c9d8c52678573fb5c3670e4b21e9b4bfa95178738f5ba2427b58",9.317957166392093],[4444,"512ff899ec86cc3fcdf9fddd139399b4c7b5e865c34073c617f90d678642c9e2",25.136612021857925],[6220,"55ff7c96069f9a4a04fb74c2725463906c0db9fdbcff8c27abc9d77a904e9bd7",9.917710196779964],[3951,"befb8b7da6ddc5706e8e372cee7c48b118a6da1dbf58ab2a8e8697d80e4701e6",9.317957166392093],[6749,"2f7faebd8979432192553bf5d62fd34d800c1d78f178af22dd0b2f6258f396d3",9.917710196779964],[1960,"ea2018092fec54fd1ccf58a3f0b1f74d1a6775494a366c181d15748bd8e148f3",9.917710196779964],[1031,"039300f38534451454da20b5c84fe8b6419143a5cefbb76fed7a2f3a758911f9",9.317957166392093],[12495,"ecf0bbdf44067022ef589c80b5defcca2fc8ad123b401645fb0964b916a4fbad",9.917710196779964],[7550,"037b99638b6612c235603f8759f57e57e44ee0863d7b703080b92c54c5bf82ce",9.317957166392093],[4349,"34628302417f83c55feb4daf5f3bdc21575d8784814a6db94be26cdddf526be3",9.647446457990116],[18954,"51f049908a8471afa8006b52f62b57f50bad4d322e037ef1fc4f7d2f983df721",9.317957166392093],[7103,"4587317cd7714925af6aad7635f4c48971e45f9d8b170bb208718398e8b851d1",9.317957166392093],[14298,"489d245e2d8e7b95459ef0d038385ea42bd730c4fe8e079781f0e5734192a58d",28.187082405345212],[6460,"01e6e7ab25528928ec4dbc8544e7a98c29944dfdbdacf85662a60b7f1b01d4d5",9.917710196779964],[2765,"83b7d4b70a25ec99384aed58fbf4bd5981116ef400b6fcf4a86a82ccb2a8faed",9.917710196779964],[15520,"2099ba91fb6a4c78decce9f2e311be50ecbc09907ccf8d19650939e3a2839273",9.317957166392093],[3626,"2c661767f60745c833447457f4c5348d791fa711456f4bee338025fa9d2713e8",9.917710196779964],[2045,"b1313971c3b6e607afb429e2df02a7a6502ac57e3e5e370535d192fbdd95a9f2",9.917710196779964],[8929,"8a05990db9e7dc879b2e1254453a067cfd885d29cf65a59928f41e0f15b54fc5",9.917710196779964],[19126,"51a47ed6dd06ff75e2695c3e61e9b7f72f004a553ca444c1ac4a45e998993f1b",9.317957166392093],[1665,"df1500ec11512796ec113231ff872844c89b260ce73d5fab504ba38af9e227f5",9.917710196779964],[2058,"61b9776696d8e74dbfebb746c6c262b4f10d6752447aeb77c5a56b5824118af2",9.917710196779964],[2400,"903d2006a213dcd844e33ac3b62fdcce4b4f1e3745a5a5b4cae34af7256d7df0",9.917710196779964],[14156,"04ae830bc38a7886ae9624dc446b6ca644a835d8afb56decd797c1b3798c5391",19.386547085201794],[12136,"f0deb361d14830b808adcf90b94ffb9b253c24c28ddb594480bb199fea7171b0",9.917710196779964],[337,"5b0a0959d91384a3bb645d9401c326edb6053bb46300e33798a1cc52c369c8fd",10.052724077328646],[16420,"64ed6374a7edb96732294ee78c02c0300b8401d5f270a3873c2ccd1e308bb15e",10.052724077328646],[5303,"6d2f361a201e5b040c237affa46ce2313df0b940d3c5f8f62d1033d52cb160dd",9.317957166392093],[7636,"05ed831668496581f6d8a5566a1ed83677f321e6d2be74d813c3c3cbc142fbcd",9.317957166392093],[13697,"62c7bf787d111bac0557db4f3a14a3697bef5da7b80628fcc0380c303a29529b",9.317957166392093],[7598,"575bbb95ff63d3889f863d9f901d402d7fa97bf453ab2737f579edbd0b1d30ce",10.052724077328646],[3902,"6cc9918c0ce55beb2321f4b17d515f7f94fb40dab61a35350471496883115ae6",9.317957166392093],[3917,"218b7cf9a9e7b4943b0eb11e7d38963953aff7ab1589af2496e007b0e5b73be6",9.917710196779964],[15012,"8c773cfe853fad0a70da425a5c1c7ee2c2d70859de2f70869b5740166cf71b7e",9.317957166392093],[8134,"c5c1d2e2711d8b6929fc62d15b9a162359db548ad5a177a593c981ee89ac7cca",9.917710196779964],[8489,"98e34d66e5f33fee9bdc183053c4513091f427b38459b9b0e94977c0416912c8",9.917710196779964],[6378,"d85150fe3852ca640de7d9fbc16ecc64f6524afe0ddb8e5b5d3f5c67c4c074d6",9.317957166392093],[16276,"e5c38738bd9ad527e1f385db368a0ddbb7d49b731dabf5907e8a6218b0d9b561",9.317957166392093],[3661,"eda8ce055834e1dd83809d3b7e118e306950e4111a676eb74552c2b976dbdee7",9.720823798627002],[7009,"b5c5aa2f5ad1fd797388ea67d824308103ac3fbfac4e8676b63d9223de5cf2d1",9.917710196779964],[1641,"916e57f3861b8e6fc95d3985a84a876b9dff4202ff290d91d18b25b6cf665cf5",9.917710196779964],[7185,"054a1835b7c3724b77dad0ff229e25140eb73a5014cbda0935e9ba272d17ccd0",9.317957166392093],[15440,"d48174e0c000e6b216de877395400fdc9a3dfb5eef860bd873c7a5b64bd35875",9.317957166392093],[16493,"5361117b92702ec2a95197841ca4924e15957d1eb0ba1081a235da3d97ce5e5d",9.317957166392093],[5196,"9b6df63fe3db8084149ea3df81ea077f79b971881b076d855a884cca66bbffdd",9.317957166392093],[12084,"b8685dda935bc907fe0bc6522f186a0ad04331428b280df7063d68427a30d2b0",22.85610859728507],[5545,"d277ee43878099ad57a14ce973b51fe2b892e5866e0b4707c6ad5631c909f7db",9.917710196779964],[12449,"52129ea8959a33a85a7e7c42acd2d80dce7ce828335de5e33b4c5c4f259b49ae",9.917710196779964],[16102,"07b45256a09c40292880845d4370f612808849f2414dacc132b44529145e0c66",9.317957166392093],[13690,"2e69380a8ecf62beb71f947f38b247130f409bec56aeb21e5a7303d22e2e649b",9.317957166392093],[6855,"f094433146b6acc091fca31abec1e706044f4e9599ae4a8b65c87e62b7dff3d2",9.917710196779964],[5519,"464ffd04fef2aab09d514ddba78cb35ac4944db6bd6572960141fda385eb20dc",9.917710196779964],[3790,"3161764aa216210d5fa495672c4f54601007120717563718811527138e7b04e7",30.558303886925795],[10474,"04f2bf73903bd5cf22c551787d32f48a398caee4760b85aa09f01631e1ec4bbb",9.917710196779964],[8483,"568ce61bdb9368a48c3c350dd8887414585a1dfbdab873571acdfb64e7c51dc8",9.917710196779964],[68,"32caaf404cc502254f94eaaea3e1b62aa804ed5feffa0e0430443b52b66c8bff",28.124444444444446],[11983,"2c145c1e4a2a5262cd89255bc13cd0df53dfb635e62a7225d5446cb92d316db1",9.317957166392093],[12075,"0a35f6f7e04c4639a4e72e776c8e755ef9676a6a019ebe083c5723c5f590d7b0",9.647446457990116],[514,"83a365ee50e729560ebdb33074de493434adb47507b5e56eb5ed97fc163597fc",9.917710196779964],[6411,"6ec81878d6c71e9c186731eb0fb69e6a3093472039e6d07ae9a298f56c1343d6",9.872340425531915],[893,"689e08306ac215e124bf6468c82c5690f0d7fb0c6d4278c407079dcfdd6ff8f9",9.917710196779964],[16722,"5c27ac614ccf54d385bb89f2caec93ad38f7d53bdb293387303e3bb298920958",9.317957166392093],[11807,"a86fc5a3e2356fa82b14b45f1919eb0e76d9a8bea9d791eff3fe419121cbaab2",9.317957166392093],[16720,"8ab1afb36b56326558cfbdec0f6a1a7ca4378851baf5a756361a5362762b0f58",9.997888067581837],[10671,"a65979279a343b60174b3e8746912d7f3b44cc637068b81d221d14517c1339ba",9.917710196779964],[5956,"f17570b698da0152c5d1d9c2a68303b42e2324c3366cb5f36338e12830fd62d9",9.317957166392093],[10054,"d31fd00dd640d5d651b9dc98d91753e9e48f091dd1d68ddea1b5a37bda1309be",9.917710196779964],[12542,"5db45bc797bdf24046db8a8c8f1cb38a307d47b69ad851cadbc144a837faabad",9.917710196779964],[16887,"422c2158a0493a636ec95943a6e1e4cd1108407c14818d8cc6f2cfada4e28054",9.317957166392093],[7277,"f3cd65206b6fb9f0bbbdb15aa3bec69f046db4343920526ffbf2cb37ceb22cd0",9.917710196779964],[16956,"fbee9e2dbd754c3b0175f3a190e2c53fc86bfc4220875abe3dc945a51c010a53",73.19778188539742],[7045,"f8772ad6f1406373f29fad816d9cee6cbba8be0f70a95becb1b324631a5ab1d1",9.647446457990116],[6130,"5260ad24bea2474ea0d5811a7aaee6a8ccbc065725ec4c30459713e8317942d8",9.317957166392093],[17092,"7e603e9e720e199a9b7edfdd8ea4355c001f2b829b74f9ccc66881f4cc121250",10.052724077328646],[14795,"33d58f2f9d5cc4e7ce96d4c96e06a72ba512c53ef790cad86527dfae9b810983",10.052724077328646],[17368,"2c644774e6c3af82803748ef56ebafeeec1bb39eb56040f326a362dccbd5884a",9.317957166392093],[17744,"22b8716874941f9b41197434a15df737734b69d8536c790faed58fda896b4e42",9.317957166392093],[12278,"e8ccd51993d3f01b18795c9eef76ff214b9bacd971fae5a301a2be00ddc26aaf",9.917710196779964],[10687,"8bf3f64ec3e4da49f72029473dea83960a7f6168a97693a10f9ce2a78e9221ba",9.917710196779964],[15971,"9a9561c5896cc140e9c8e72cbcbed84d21116d73d823b5d5022bd94da82a5f69",27.302570863546475],[10853,"cd7fbc4757f528240edb0d6e2ff42a4b6fb6d5fe1979df02d765380c5005feb8",9.317957166392093],[7134,"8f75b1346c19a8f5563acbe2efb3a9fe5e7d763d16f8a1da2900647ff72b1cd1",9.917710196779964],[19534,"24bb4a607aaa0818d79dca8b8ef2e75e2d1c68cf1c73bee3a0079ed04ea1520d",9.317957166392093],[3926,"d59c0224a47ba8a8c62d82b7f9649a8774c781c64a6bf984ab083974e1d22de6",9.917710196779964],[5854,"e0822aa2326f5cc668f6b36d0be41d0765551443656caabdf619b9063d58f8d9",9.917710196779964],[12758,"9a50ba9a3083e7e5af1696326be835c0b6ea35dfa14cf3b8cfd124b63e0a2eac",9.917710196779964],[17718,"96388fbb91ea6a6affecd4a6d8a9dd53334ff412aa43af0fd0fec70b883cd342",9.647446457990116],[2857,"097a730e2010ee29aab7453eaca43b31e662c602d0011cb1f1c544fff71658ed",9.917710196779964],[8678,"ec84666f59878815de77268a14eb3515daf6440d9482305a686437e384ead4c6",9.917710196779964],[11256,"025308dd0225631bfb67ca29724045d00c0a76dab55f6d0ebc071062523c50b6",9.917710196779964],[12674,"bf9075000030ba388cc801d0efafc59d912165f9bb9c74e485b0aada5c31c5ac",9.317957166392093],[4737,"d93b22afa047480946328b3f882d430cc783cbce50468fe4346e2c58fc91bae0",9.917710196779964],[13093,"d3fba4fb2d65ebc86dc0d4912f326206b51039c661bb687d0d3416365e8ca1a9",9.317957166392093],[13392,"a49523778d6396d7a5e92bee6b9ba1d8e5db736e14689b3eb981ad060c7b84a2",9.317957166392093],[7734,"b10708ec88c07a2af901cd37aa0b032eebaf8c61f45c87c59c1060c6f66a44cd",9.917710196779964],[13003,"23b92ba218c3c4a978559a009a8203798fe2dc08bb02de3591661bcfedf596aa",9.397642257991386],[9669,"8576af7ecd69510981f62efc29e755d95dea0e059811742ac547c140f9fe95c0",9.917710196779964],[7424,"df3335281c6152775abc5ce5567fdb8c120ac2eaf47c94b76c976be600563acf",9.917710196779964],[9110,"8aafd697b4bfbb8eecb1952c0761b6978b8caa8659cc84f86ea6e784a28a15c4",9.917710196779964],[7683,"736ba3b5a377fbeb15f185c3ea34fce236097ebd15aec9fe65a756962697b1cd",19.198031980319804],[2500,"35d8514004d9e1f327578b13805930d44c97f98918aa201c17d0413c3dc6d8ef",9.317957166392093],[12997,"ffc9a28160357bc09b577545bc174fb9c2c60c90f3be6a227f09b3e3bb499aaa",9.917710196779964],[19690,"b55cd9d6823b8dcd2d8c9a38c1d1dcb46437cb645d13ef9d9d0ca4d01fd11607",10.052724077328646],[12221,"5596ab4b7c684c324d520129f5bd3f107c2dfc86074597cc1f276cfe3370f0af",9.917710196779964],[15319,"aee38756fa70cc645702c760b9fa6f1b66714f7d469c08cdd8be260e0aaeef77",19.225352112676056],[14531,"d6d39abf1813c39dc9e900f0e1777191dc43d64517f32fcfc5810d9cf9449788",9.317957166392093],[14497,"97ef271a3dd467a4aa48bf33219ee50ba5f4534d61b279c2437d538ed8765389",9.647446457990116],[16263,"9f8e7188fe1abcb5f549e95e50ecd55934fb6282d0b78270f6223782ac281d62",9.317957166392093],[8410,"f75383a5a7b0b063f57e278a45414525d664dee3124bc3f88cea1c909a968dc8",9.917710196779964],[4932,"9188213449d3a19686b3c4364ddc0e6491e14b5fb5762eaa9f330d5920ada2df",9.917710196779964],[1248,"9a4d4140eec874014231990eca5518fde5b6d8b9fee2e001b6d24b74d8f1b1f7",9.917710196779964],[9756,"34f0239d2d87acdb38d78bbbdc0583d4d3176e629c023cfba9fc6f723f1ff9bf",9.917710196779964],[4330,"d27d31a19673360343b50c78f78d7f9289982cd20973911df973c3897b5292e3",9.317957166392093],[12058,"217cd00efa451ff2027dfa9fed945f208f23bb7605f95d8658ddeb6f616ef0b0",9.917710196779964],[2040,"cdfb1159ebff15f37ddf2ed4a29d676d695ac4fc3648c930a94d387a3eddb4f2",9.917710196779964],[8999,"164483ace61ca56f8c8a2ee040f7772bd6f704c671fb60ff856d9145dafdcac4",9.917710196779964],[11867,"88df8808df8db8b34c85044ba627d4352f08468c2831d467d62d23d54dff46b2",9.317957166392093],[18643,"5989a8a6e3637af5f3ad3b1f6bddca26a4c2ab4b251e6e44c999ebf5d5890c2d",27.317073170731707],[1389,"9be87376b343876a0066b9c5bcc24961dc6b6a11bd795996888737067e09d7f6",9.917710196779964],[4016,"c98162ad9961f8d7201a200996c3bb833da03394d3a47dbcdd3caeb7d768a4e5",9.917710196779964],[16257,"c7c6254c292d05b31126b402b2e34ee2d6bc6e526f76e550ea775eeaf9cd3062",9.317957166392093],[16216,"90ab13776a95257b394b2824a74cbd20aac55abf029a5cc395c58eca2de67963",9.647446457990116],[16869,"c8ba45b1874c8c477c53fcf29b5b151d69b0d80877391d5f7e0927b52116d054",9.317957166392093],[14882,"de97dfea9d14aea57ada8ffc1345d2efe7655f27cbdfd158c16417cd9bb51e81",9.317957166392093],[5045,"0811328140d30238af72d203f79da4793baa3212ecb36ea277626120c9d9e9de",9.917710196779964],[4536,"0067a577f6803b084760371acec75b2f58d84a834aa59c5af0f999562e1221e2",9.917710196779964],[19515,"2fa76de1925473d46abb401f304689065efe834bd5824d8436b1a4258773e00d",10.00131535679053],[18672,"6bc6c0668d7ba9a35c6facc0ea799ef46aa9d6d5392adbb29f867a01927cb42b",9.317957166392093],[12335,"21956e787470d4d63e2386340f5b5c656a05baa2d65b5e04646a3ec9df1b00af",9.317957166392093],[12671,"83168072fc2dedc1b78baeba09fc4099ea9b1c152c9c618d421cd57b741ec9ac",9.917710196779964],[8964,"6fb6098edafa85e521c429434bea73823499d23e76c874ec57e32ada13730dc5",9.917710196779964],[5875,"1c83f80565d30e5315ac27750aee480367810379df9b36cefbb0675cd680d3d9",9.917710196779964],[15342,"ae9f14ee14208418c8916b5057f966d45136594a195f2eb5d2dd665394918377",9.317957166392093],[554,"d82822c6ae3a1641c11c0708c047a453f5ee0679a4ec5f125fe6b80ea9953efc",9.917710196779964],[10396,"76515455a1026690b07a6df48e200a8cbd8ec6c9ea92dea7c1e0f6c52927d0bb",9.317957166392093],[4758,"9a610a65ecd12106bf0dd25f1466be3b39ca47dd6fb34157f394a74bdbb394e0",9.317957166392093],[1164,"11cd246bf6f26f12fb9096fe4d0e9e734260f57c83f4eb1260c2f67b175c2df8",9.317957166392093],[19828,"3b53afe38e3b22f03bcf01bd7b940e27be5011e12321795796628cb760a09801",43.95744680851064],[10529,"442c59b72ca7c08f42a68608c6dc64fb8d9eb00c1882ed521d2ebaffccc2ffba",9.317957166392093],[10861,"9618c9db70bca1469f66cfa2966b2a83005b1957b9ba4a2822cf8c821dafe1b8",9.317957166392093],[17052,"f74be15aeae686cedc35f0396dcb8bd73487f630a220b9a0392798faed990d51",9.317957166392093],[4807,"2c9fa28b104bf63c2564525a0640e96832f5d7edf72e53bc34a6da683d2b5ae0",9.917710196779964],[10076,"3af19f2b81bbb9b151a03a3404c69caca622f821451d5244540486a6140bd9bd",9.317957166392093],[16445,"ba35bb15fe5b51cf1c916fae52c7f00ea6fef603d5a4fd518fda1cbddbc04c5e",10.052724077328646],[13018,"f308ca72c82e15c4290ac4548e4b5fa00a9553d6b53924f36d35ea1141b075aa",9.917710196779964],[18790,"7929668ec73114897ed74cd891b00c7f003da5840f26203607a148168fa54327",9.317957166392093],[3197,"6115a4b9a9440695a3b39e54d61e6f058004e7489e7e4e9d230010a9943111eb",37.39153439153439],[11471,"2627821a6b0a0dcabfa5e24571b0e443ef6da2e4861db1b57c0d0cd31c25bfb4",9.917710196779964],[10446,"d057b27cccfcfdeb2fe9dba1e3b2fa2895b4aafcd8ee7c4d53083db674c170bb",9.917710196779964],[10329,"fcf2813fd4362127306324b829ad031e6fd8fe986fc18cb842aeee3c10bc26bc",9.917710196779964],[8159,"9c0852ae32766a7ac18cf838fad915d446fa4781df7b21b652f9c5b218c747ca",9.917710196779964],[16149,"06b59f36846244064311444d78450cbc0fdc0ac7cc571615574ceb1c817e1365",9.317957166392093],[11328,"620fd4938f34dc586b87ab0b84851facb9c5045e222338e74ffce3e136adcfb5",9.317957166392093],[10773,"0f452a1626fb1532c8d726db402ff9540249487ebec309d6f7ffe86f452179b9",9.917710196779964],[5588,"ca6e4abf092e39f92509ef32af9d6239a4c55a1b03ade1863b0fb9500196afdb",9.917710196779964],[816,"926bca04e92f65ddce4277fb16591b988002065094712e2c3698ba87dea870fa",9.917710196779964],[5798,"83be1ac9b78e5e97dde9583f7168fed89aadca2c26c3836e739447ea0c7072da",9.917710196779964],[10626,"08930b7aa1956554d9041a979150d9894ef2c8c3dc3ccb170abc226f7f3685ba",9.317957166392093],[7845,"f9ab1a0d55bf7587ad7e1100d5786d2a4a0211d55afabe5746964b23050587cc",27.139573070607554],[16594,"09dd02e525b79e13addc943f3dea10407fb901c62f1ef583ebb2979c1366045b",9.317957166392093],[8944,"ab035034c90cfb77024c4232f7cfee6820dd6b56a4f3cb97bad87701c7fb25c5",9.317957166392093],[10137,"2b02abe9ea054bdaa664d4974c1f1f60928f1e3f283dc9b0d454a745ee1d76bd",9.917710196779964],[18081,"ac2f826d694bb8ffb0f79bd0e25d05ced0af2ae00bd6db6c2728293d7130813b",148.90330552981155],[10021,"3f5aaaff80ccf3fe5a2959cb0a0f4196997bef6a09e87398b5ced73a909234be",9.917710196779964],[19868,"857aa80220def100bf270a799093613c2150c8a978d360c05431c8f409e53b00",9.317957166392093],[10494,"2a1991496af3797119bc5ae709a93229a6caed1b921a34cc060629ed7a3033bb",9.917710196779964],[17766,"2f08948f542b3c3a9107f92d3fcaef56f7191294664f582fee475f5510def241",30.894063627418827],[17845,"4c3da7b490612666d50d927cd80fc6164460327bfbe003d632e71c6f847b5040",9.317957166392093],[13320,"81e6e794943529c7baf184afc07988f4d44d853676d40302f6b194f3689339a4",9.317957166392093],[15210,"f4d0fe199870d0b7df3b33b7ed4240b7c59f9a8a58b5e5b0a1bb7a64cff44d7a",9.317957166392093],[17677,"fabece26506fa8b5df40d36ad37803404bdc0420df27b38c997f71be04f1a043",9.317957166392093],[14052,"a80bd959ce19ef468587c67db49c57fc918b489acc9174c753979f310647ab93",10.052724077328646],[9958,"a8caa63c1a5ac7116bb6d1a905cda4bf1ead24966ac1f8e1a16485729c0c93be",9.917710196779964],[10106,"af13cda6f74309c0956cb9ee6a0475202101284f7db9fd2b4bbab9b47336aabd",9.317957166392093],[20,"51eee43f4e618afdabc3b4756cb49e4f774d16dbb9d032579027fd25c219e4ff",9.917710196779964],[4772,"d1635c1d1ac669dad3bb4b179fffdf7e146e6a170bc72cabc190b7594dbd8ae0",9.917710196779964],[14341,"8e62acdd6fc026f06418c0809575e7d959a9421008f98b560f44466cee28808c",9.317957166392093],[4578,"da952c235257b92d66bbd87a27b35d88806965066b597a41dd79dd468d4ac4e1",9.317957166392093],[14209,"26e7b1f20d3935f1ac305c82d5c4eab26180e75ee2757e7cb9b83a6858b80e90",9.317957166392093],[13561,"fe572677f6b86ea14f944e264603f9ce6bf7325b354384f3b6d65de25b54779e",10.052724077328646],[12780,"4be3b268d06aefa27fe93de4bf1a76be1879e7bc1ff40169fc28ef2036390cac",9.917710196779964],[8070,"265a997600dbcc774af2851a86948476530cf3ecdb9a602b1d9913b3e3e9f7ca",9.917710196779964],[13020,"559733e4f6e752d6b3a5468543a758efe0c8d6380509ac75677bad39bcfa71aa",9.317957166392093],[687,"0b7ee2ee26a311dabadb1986c75d689fb728a37e245b706479d18df57e5a55fb",9.917710196779964],[7300,"06b18a3f0ea8af4418aa32bfcc3fe7299111b42e7b0d56081297807603ea12d0",10.052724077328646],[538,"09a30e1dd7c89edc749d964f190ed8d161795099c93631391788583c26b65cfc",9.917710196779964],[6595,"98c05d96c8d5175b2501306970d451d1eb9935ddd286fd61c59e5db7c5deafd4",9.917710196779964],[454,"7595f63e6ccec884d520415865c88e1bec638ac0de5cb8f7d0e2dcf478a003fd",9.917710196779964],[7313,"ede0671e8053a8ca6d39aa3a4734a71b14008754c53776c5349c8abdf247fccf",9.917710196779964],[12833,"608741cb2165b735fb738aeeb5606993e36e6a5b8e405d1a28fe58f34b6bb7ab",9.917710196779964],[13241,"5a4ee70a52d5929343062806c366e1dff687639d7c276658a481e73ae76e13a6",9.317957166392093],[14325,"f67987e7b75d087687a9e8a917af5ee80c9f2a10431da7d33735286466beee8c",9.647446457990116],[8851,"8bf67766e2603c43761e776c08b3ba17ecff3929697547956ba7f2418cd7c5c5",9.917710196779964],[486,"1d877b343aef8a241a8bc4f0beff4af6d53c38fa7e09d37f027d29f3eb8fbcfc",9.917710196779964],[12842,"42c060dec5e0e71652af393c5cf98174ae8aa6a653989b1a5999d52758d9a9ab",25.338046840477244],[2875,"ba977b15181eaed74393cb49a8916162f4298bd0a188fa7debbc3c21712c43ed",9.917710196779964],[11377,"a10ddc2c7414df90deee63f8aad98841dc922cf973caa36a90d39209fc1d8bb5",9.317957166392093],[11093,"f83587c50f25a9a4cbaf64774547ff0f9b57c3c6cb5c13314d0d8b733b894bb7",9.917710196779964],[11547,"2fb9f54d9c4664282860623dbcb539a652cb3381567e51716edbfb2c7f1f40b4",9.917710196779964],[6533,"e9fccfe4a040fd3baccee4390d7af06cd115f8dfdad4038994d31c81c1052dd5",9.317957166392093],[3167,"d0211a1768345cc382812fb3b47caac0fe5580a37ed8fd328a61fca30d4f40eb",9.317957166392093],[18776,"300ca191bd1ce00b18a8774ff78d413759ee0ca6fb76833e0cfb25aa8264d827",9.317957166392093],[8912,"25092955ae3c8471f39f7d8961c64a5c82a40a24e7fb7f323cca319ad1ff61c5",9.917710196779964],[19173,"86ff517de4251c791d654eb3b3b3ba0aad3f90e0314e5e5b8272639ee0f2ab19",9.317957166392093],[4049,"f87ad32307526095d293d9ad96a8f68f0abaa7593f7c257cc610e36028ee72e5",9.917710196779964],[735,"fa12193a44101e41dbe2c8061fbc2d60762f83bfff30f4ffcec06f7a53ec01fb",9.917710196779964],[7851,"e8b35677d489b606c0c9df478fa7538d0244f475daf4c84f42c63b210e7381cc",9.917710196779964],[12301,"41e81a225816c37058edf4bd1997e8e8b34b708a4e8db433a3aa3d5c53fe34af",9.917710196779964],[14911,"36765d7ccb86576cb1b44600709d66b3a7736151f8dbde5d045744eff2eac780",9.317957166392093],[177,"4cab8161db66e2e3f114932a385ba4836d9fcebbf97e7d441e734955ed40d2fe",9.317957166392093],[5141,"a56aad2171ba6beb6fac205531a2c97c167cbc35cbd56ebd152568a4f34a59de",9.317957166392093],[4156,"9733b3fd107f52eec49e6539ba6472e8aa4bddcf93e053fbd9d17ed4e1d1aee4",9.917710196779964],[18050,"a4c98e3f116f1061c557066702c54af0cd019c9984a00e806a7843cae14c2a3c",9.317957166392093],[16158,"159474f0481e07063d4ba907b063a5d5efd3bf6707e0762e5a57b827f3e6ce64",9.317957166392093],[14653,"529127c3458bbf87c22fcdf693adc23c708b982993d63bfc88fe282cb429d485",9.317957166392093],[13840,"6f246d1786ce1e4876fa271ec375851a1b70728890cbd3b767aa2c46a4118898",9.317957166392093],[11876,"b9963a2f75dfabfe05eaa3f521e06139264b1bda7f620d2b400e403a3f7a36b2",9.317957166392093],[2022,"c3bc9b71396981583c5460400ab054bc6b6ae6f1e3a18519358e98557bf4cef2",9.917710196779964],[18124,"2d8f9f69b2b8db02ef92791658f3afb20dcad86ebf9550d8897a11763a6d603a",21.949656750572082],[3306,"f8777fc042b2b84f7b57156ffbae0a3c88c8cb019420c5bc7c4abb06050d57ea",9.917710196779964],[3339,"9359800a60c4b61a609aaeae31decc5a3e12c28d1d96bf3672aac9df8c4516ea",9.317957166392093],[12769,"b33237e79c639a95f3ba13cad5cbf819f1d4bf4879dd06f516e21ece72b31eac",9.917710196779964],[12655,"84d57d927aaf5b188a69375f0c1c87b3d870656babfb7468de51c9917ba1e9ac",9.917710196779964],[7556,"cc07560fbfa53f3fcb186ed96db577c79fec6fff08793f251ccabb1a91b076ce",9.917710196779964],[6605,"c7e8fb2bbe1bc13fc9f76ca13c74e883e2a0f5daa436eb0371ab2ae214db9ed4",9.917710196779964],[16801,"8452610ed4cbe755a0d33850b08e80a6a49ce652825fd5b7ddfe671bfeb04456",9.317957166392093],[5950,"a0d6cdff73fc0c73663f213574289192bf2d975f2bb59fe3b5aac72afa7f6ad9",9.317957166392093],[14177,"41784fee38bd2685742d677ca80585957bb8436bfdf7e681eb0292a40b4bdf90",9.317957166392093],[1631,"9559f6469ad0317dca06c37b397426ec889b58210b39e4f4057ff5d550ae6af5",9.917710196779964],[10216,"754360263e3293c2e4325e92b5549f55f650c8adfc110f40b0b41a11240de0bc",9.917710196779964],[8180,"8b3b457fd2b4bc281de22d8a457b197f1a93581a731f7dcf4379b241554b1cca",9.917710196779964],[9779,"aaa8069b2ed0000fb6e16719d79d97f08b1827ed9bc5ba1e2eff1c9bc30bd0bf",9.917710196779964],[2471,"7e7bd37fa9ce8ab6ce7698177a1e9c6f08184d2c910161933f87edac240e0ff0",9.317957166392093],[5685,"a649997d05123ddf3c84df142622b1bf8368efe89fc11fc47e3906743aa923db",9.917710196779964],[5723,"39b21952c8e82272fe211660d564eeb09e036c94707ee65a027bf99df1bfe6da",9.917710196779964],[12395,"06087bc213762c92742289ab59fd4507e8063887797aaa0959d31d972b80a5ae",10.081996434937611],[6035,"d0c2dbe5b14cbebc30c720ccb999266c36f5cb620814267c525edcaeba64d4d8",9.917710196779964],[13219,"843193ba0b787917cd6f4ec06b3d3cdf414c29c2fe4f1be0b75692a2bf4785a6",9.317957166392093],[8239,"448c0b2b47f11e3b4dd7ae9e405e99f6515322607d3829d69a9110134accb5c9",9.917710196779964],[6297,"3951f131e7c37a239d750051589e7e2aa43f9c97a226fd9b93573cf8c5140fd7",9.917710196779964],[1993,"077cd54d5ce07aec894fd63f99dabbac0c45eb920b8641945290704055570ff3",9.917710196779964],[19638,"119e4c8db4d1831f4b0873c47e3205f6bda8b54880ba0c341c64fe466e1a4808",9.317957166392093],[14681,"3601d4638b4ac1d80cec4dcdc42791e8af04c180c7f20b33be511ee70e783d85",9.317957166392093],[734,"8137141e7604e628893cae86bd51769694ab9f30a926f4bdef6ebd4a2b1e02fb",9.917710196779964],[19520,"0be72753cb86008343bf8b918ddf4cc3fe857b896aef3d698f329c1c7b60c90d",40.44090909090909],[42,"4482d97d071d4696348157cf91b70a5c612ee36aa2fe177ce686dcaa0b5dbbff",9.917710196779964],[12805,"3b6ee00ea12b1b6a34c29f1e67e90595194c98f340c8891d4397d9e3b446e3ab",9.917710196779964],[13134,"3215281dd0d93e04095eab647a94cac7ad20c85fc963487938e3867c2fe948a8",9.317957166392093],[10052,"9f2d5e6cefb6267d0ce539c8baea9abd669db1945cd0d37ca75f58fd34ce09be",9.917710196779964],[11623,"d56099e8508259a025c7c5a9fd7197810be8d086444af5eee4a6abfcff93c1b3",9.917710196779964],[5893,"919370143dc0fee3e8c251266a00c9dacaad85cd1ff35be49086af6bb73dbbd9",9.917710196779964],[10593,"2141401d58ed5139996d4c3e472f0ff65b67b906df8546c347e38f0cc0ffadba",9.317957166392093],[463,"63e544d742e3db40826102ca6f80d8d5d2025a461c2ca374e19f287e233de6fc",9.917710196779964],[5489,"e16c5c05873b4bae8faf559ac51370fd946523502563e9247373742481bc46dc",9.317957166392093],[19346,"b6666a8751b3c6f72ffd86f968c7f61bafc5ba7cacc4d9db24a1bf59d101a813",25],[12905,"11f7373da34942a1a3c25599dce8d408b7aee1abdf3900048f883485d2d248ab",9.431064572425829],[11504,"4e87d03a290583f2262c3eaae6ee33280e6f1348480bc6d514f0f86423937bb4",9.317957166392093],[3928,"876a77642539ff083cb0cd9a571875f895856767790a70910652dd6f18c42ae6",9.317957166392093],[12818,"5759b041f8a1c4186b0c76a73e1b2211f9b60014108893d573fd256c6d12d6ab",9.917710196779964],[10737,"492fbd5202bfcdc461f2cd5de3bdd7bca59eae3b7706b39e06b52fa9fc26c2b9",9.917710196779964],[10912,"046c98342ebfa13f9836693a130a6edc3852e4a021795ca6412a49222c169cb8",9.647446457990116],[9788,"676977a1fa6731e6626dd2bfa86623dbe0128c89bbe3b25f36b99aeeb00ebfbf",9.917710196779964],[15620,"311e5270ef04813e189897aa00f93e63e03812166a1d8d7a556b9eae6a59fb70",9.317957166392093],[11685,"1b48b2c1592d3d7f81691f967d7e447134750024ff145d8e44e1a705926165b3",19],[6087,"18d24c5ac742d133b449bf4871df7ef695d40d6a7545222835a868bdb35f76d8",9.917710196779964],[16714,"0549c84bc21e6976b438f09ed30db95fdd211937caf474906de39fe452b53958",9.317957166392093],[990,"b586101025e045a5bd130a731de999abf543d333f07adfd850b23719d3a746f9",9.917710196779964],[3301,"84881811b81b86f3f34c0ad4e9b2c7b81c65d7e0f9d3a40c1af93b3e9d8565ea",9.917710196779964],[11957,"0fc3ab9432e238c48ef9549b2f7128b22d94d4212cbd650eeae20544bbde9bb1",9.917710196779964],[10562,"b745f4c6ee721b448af8447c87474337fd3a7b2327cb8fee3fe8d951e70ad6ba",9.917710196779964],[7659,"7edfbd7181b03bcad226136a72f6abd68a5e00361e5ce4582d8037519512d8cd",26.031901840490796],[2143,"b1c238f6a4a1a5658117dd00ab10847db03ab356994210d214cb36f8ace5f6f1",9.917710196779964],[1482,"d735cdac794f838d062a82029b511aa946015ffe6ec666b57d6a05211a383df6",9.917710196779964],[13372,"f122478fd4ded88aa3b319306030382ad8dbe8da29247271ff52d41698da05a3",9.317957166392093],[7444,"f095b398e2367b44c04e16ce0e8d64fe3a8877f2884f84bcf324c634edb61dcf",9.317957166392093],[6185,"d318bf75ef89c560e83a39fe5036c6da29c8568c473bee2b14ef1df03cc0e4d7",9.917710196779964],[6738,"d4d3de10bfb66fc2aae4956bc22f0d50227e12df5e3b15b86a56896f8262aad3",10.052724077328646],[1213,"c051d66ab17cb44edbe97429d19544a81f03e4faed579400afef3309b1e8eef7",9.917710196779964],[80,"53c5eed4531b2f3da8c6e47cc9690bb6a1d506c6e7a6c5a2410b004ef33779ff",9.917710196779964],[18028,"cbf5aa79ce87b18cf46ea89fba7734fd48056e3c99470aae32e0c04b122ebb3c",9.317957166392093],[19064,"43b386d72a98efcf32e47ce46a14dff5758f85fb88ac59e88247e92b50741d1e",9.317957166392093],[2993,"481931f103b5fc41b0f085ffa9c12164e727cc904f4410df65b22d847daf54ec",9.917710196779964],[16004,"ceb2664c9388ea45c69f9ae61041aeb31f23d8e168b53effabffcbc0236b5e68",9.317957166392093],[15714,"8fbc646c9d638555885bf726fd3e5678634adbb0e00204a81251aff99bbe2a6f",9.317957166392093],[7177,"c7a34632dcb3b7823ca7437dbd5a87f59ec23cf99033138d88e16bd21128dad0",9.317957166392093],[16068,"f4ce5fa7b5c314b3011a12c7d79624730292b44c73c843a739b956656734f066",28.06746987951807],[16295,"5297e3168eb93d697d77eb6962e7c2707cc9c3c6cf879c38145d0eab76d53f61",9.317957166392093],[5880,"ab800139e3d3b6f3fe3d32cd3ebb5f961c185826071fd7670e592d19da1fcdd9",9.917710196779964],[19213,"4bc38c4a93d1446786594ea05682640e6e9fbe21c0cd357395da3040e7d05b18",9.317957166392093],[9808,"930d1ceae5c53fc9c29441972a0a48d96e847bf306b36cd9cdda304c920697bf",35.85822196397444],[19631,"0c810d200e525b4060a4eb67f2d3cc69d16ae814d04e6a44c5613d8678646108",19.16846846846847],[17950,"401305e234dd1b336692f18fbe3321a7fa5f0a5f242eb97790e6cc773604463e",19.100884955752214],[14643,"8ef38c05c63dc69ff95e47c37319f120e1043c7accc11e21a4df3c597b4a0b86",28.124444444444446],[17016,"8234b2ebac190d8135874857eed3056672a86a614cf816ba91132e48b6a4b851",9.647446457990116],[3630,"7aa4dbc1e4e0203b03a1fa9977188951022b61bb945e2aeb8d3e3e074c9d0ce8",9.917710196779964],[9987,"aef78239231b9743030e5011365dad3487f711eb2301f2359d85a1e4363567be",9.917710196779964],[9400,"2dcace3f321ab1f27c1c9f8fd46a83725f0b244f2440a73411ffd336d94846c2",9.317957166392093],[16867,"08596d4043e6f743595375c1dfdd045c144075a38ecc2509b5c85bb8508fd654",10.32],[7622,"f2628c2b701d4755c30f0a08bf329f723084587b620ce8fd0a2d635ddae515ce",9.317957166392093],[11564,"a9355a10688d0e9b3daa8943f2cfb26218de0013c19886aac1ea77b1158726b4",9.317957166392093],[8220,"d96341acbf0e26132b627a699f919d72561c390aa68774006d67ad57e44ccfc9",9.917710196779964],[19565,"60d90489ab5c45bf7ccf63a7a3d51d20acefef618bd1c252bb63838c2d31190c",9.317957166392093],[2353,"e823b5c51895828243fe7552575f5ca164a97ad2481069e273c52df9fc78b9f0",9.917710196779964],[14932,"1230de14ba41c69f307e217d0072dbde6741026126f218f384ba887143ea2280",20.064308681672024],[15510,"7fd62f8f8fe25df93ac4a5fc54eef90a1616312b8d22799c0b1e8690d620ed73",9.317957166392093],[17445,"e63d327504d8c4b011b863b99cc72f4f5d87e85800d72b828fcbe846b884cb48",9.647446457990116],[8764,"001a9535a3917f09928bb9ff1f8b23fd640e18281430fc23ecf26206e88542c6",9.917710196779964],[16763,"b8924e505d46b65b8a984bd5cfd735d16c8fdb930f60ba6a813f97bd75d22157",9.317957166392093],[5320,"35f23514282381d3b2acb9d7ba710d6911fa6a912ebc70ab6388a1ed2ee94add",9.917710196779964],[16247,"ec968cbd2f7a8963dcd140ede4baac378ad30489a55d81692626e64cee968162",9.317957166392093],[18494,"8ee9d38b6ffdf509d93956fce93aaed9755fd8c63d34d66808cb820c301f8531",9.647446457990116],[1217,"f9c3e41bb2a4d2dd3997e8c39557a3f0d7e74dfa465091fb5c0b88f3fc33e7f7",9.917710196779964],[12057,"0950004719df2bc173e49d885dca0afae77e6facc2c7a7d49019d659405af1b0",9.917710196779964],[16573,"48b94707cca592eb226c8dc70fbb9475fc972ef6be4ccfdc93de8e340877a35b",25],[10049,"7d52f36a1ae529c41b5386386768b81939bfde5ce1e3ab11a5934b385b780bbe",9.917710196779964],[13349,"7d35876ccd1aa20c56f6521232bf8e5a546085e6c34065489390acfd1a3e87a3",9.317957166392093],[14217,"fece33ba798f6a559cbd4a1d20f5bff8f08d818e8f9ca729f68857c090cbb88f",17.964444444444446],[17289,"239865e6c448b2afeb4517c18b003b2c77d6501e63ea985121c7295592f6674c",9.317957166392093],[7207,"9fd5b97ce8fcbfd2aad6eedc80c1b76965bae41fd7d2ba4120ae7c42ebf3a8d0",9.317957166392093],[18618,"d3c3645581bbf320a07d5b562ea25d4feaeb3a33f6beea440072b3a5ae1c392e",9.317957166392093],[18062,"31e10a9e1d156d5445b8170ce8ef371bd8e9cf81551296d61738ebc6e3f1f53b",9.317957166392093],[7164,"895af03a8a99ee518a2f3f34981959d9244aa04874fdbb9897f449002b64edd0",9.917710196779964],[6710,"1e6842b6a68a5581dcbbfd65d0ced892c4a55256b0387bd522ea09213156e1d3",9.917710196779964],[9620,"b1f8ef4194e1d14bc4e6a13d6a34c38b204ee58aa30c9da163d5d4f7adf7e9c0",9.917710196779964],[11008,"69ebd5b20cfecf57e3f88624228d7dec560951d0e337e403299efd0a0b57f1b7",9.917710196779964],[3036,"4c98deb445e532f8788f5f4423d1fd72a4bbad54e822e7c4d77116fa1b1012ec",10.052724077328646],[5528,"fc7ed1b59ff309d49ba2b17ab7a611c411f101282660afb6473bf761e3380cdc",9.917710196779964],[12106,"a087dd94eb220b1ca49dca5c4b0d11fe3121252b7b18b7b84725b5db8f26adb0",9.917710196779964],[8106,"956d5f0d472af234e71d7fc146765c91857a37efa5ecdfe455efe2310796b9ca",9.917710196779964],[7050,"d8caea9980350e3d41bdc3a2e2991aea371354747aa2de4d0f2b0b2b1648add1",9.917710196779964],[12975,"9320d37f51bafed0df35c4beecfb549928c2d64b36f8bff8926598a7284abeaa",10.052724077328646],[8064,"73525035abc2cb7214909b0ab2cabbb97ba85537aed3ca92e002ed26945404cb",9.917710196779964],[4493,"819dfae6640ceee285e4dfc1df6e82a17c9f7023b391736cbe318e9b55e473e2",9.917710196779964],[9588,"007daf0ea10394ea69dcd446d913d22568a28e874e8d421e9fb952530d2410c1",9.917710196779964],[17506,"f53f51095d4c84be377576ed7af719b89df7dd92a05cc6fb35388b9ab5895a47",9.317957166392093],[7384,"be8669b6f9e2cfc38b9b37c9bd96edce045de686779184dab0895819ac6582cf",9.917710196779964],[12570,"3252ef3d1390136db229729e518159c068b039551076e24cb980f7022d2b74ad",9.917710196779964],[16997,"5123216cc6c5b34745c1bb8bdbfb8dbe2b76d7935ce279862608f6aa27840e52",9.317957166392093],[11657,"9cfde9d4fc2e9ce27d2b63dcce5433572b911721b943d1745724a0f4536f8eb3",9.917710196779964],[1104,"751181f823bca2975397e57109a0d834ff66279c518116e9628af06fde3788f8",9.917710196779964],[15253,"1124953e2ab7957342e7fb28e41e0f92c753a76abf33ff6259adde263ce06179",9.317957166392093],[16128,"9ba924cba0dcfe149365d2a6188ea060a3a11cfc18e685e7856e85517c7a6e65",301.60427807486633],[985,"bcc8da5025e64125366a8a992b94a0654e6240e5663386c34b337a15dcbb4df9",12.064171122994653],[8017,"b9125d9e6b3d0c5e1420d31ddeba5e6c9cbb4cc43ea34e8f0031fe0d350471cb",9.917710196779964],[5596,"33d447385a1a591177403fc064eba0b8875f73a56e471687d4a67c53290ca8db",9.917710196779964],[15568,"926420d39811619052c6b64f264e537773d79af4ebf26dc9fa7ef780a2945772",9.317957166392093],[4440,"0cd47f11bf34df93d2a5bf405edd8b5789dfacb7a641300224befd23f640d2e2",26.062052505966587],[5552,"0ec3193127867ae6edceb858e9584d3d9867c73aed82a7cc6a40b18dfedcf0db",9.917710196779964],[4096,"681538cd647bd2198980d2545a6ef2dd8302e2e64f80a853c60509c0c3a815e5",9.317957166392093],[15241,"cf1db71b42066f727e8497b08d666f5f270968c7f819d7de0e899d7ff9c99579",9.317957166392093],[3268,"ed5391b3da0c85f960e79d2ae5092f0560e9da99a461476eddbe92a80db792ea",9.917710196779964],[8008,"08859f0cf32bca1a467c2150e7bc0b333d76e4b08709a1d4eb33a522727b79cb",9.917710196779964],[16838,"70c84df03f5b8cac3566a7890636ecc9e86ee197bc0ab492a196624c388f8b55",9.317957166392093],[17620,"e8deeab5db39800a9342c2340766025082a0dea1844a073778e9f43cf53bd744",9.317957166392093],[18491,"df3c44e30f1f5fa10b0f0037be7d28b35c3f0acb6f329a62f458403902b99531",9.647446457990116],[17857,"e1adec68f1b798a3876d4ebba852931cc7b6f1d03c0f6d0b6ff44edc637e1340",25.968141592920354],[17139,"754f78b8a1d9e8e7aa4f7b3cc7dc02901726721c941b9fbc79d782d8814e504f",9.317957166392093],[2776,"cd3868f87da50a4942f630bd796607d61b7beaf5a9cef7782268dd87b13ef2ed",9.917710196779964],[17633,"d4cd8191ec3da2639d87a46d8c3bacbca6944106230c7d67e24d107341ee9244",10.052724077328646],[5611,"ae74716c77153d896f91f7b8d950286ed6f9b6a10cc19022b5149d2c3f3b9bdb",9.917710196779964],[17438,"863e49f033891481a60d49dc6dbdd755ac4932f3c11816ab0f623e2537eae848",9.317957166392093],[4724,"f115d664589f6b6d93b4d219022961499df1e61633fe00d4bba1ca363921e5e0",9.917710196779964],[5726,"640cbd23f24ffdb7b5d779bdc43e62e99603f43ae6ae1dd49a62c5226271e5da",9.317957166392093],[3589,"1ef6d3f8cbe12e6661ead52842c1a9c33e761ec0eb2e57ceaaf403b125d05fe8",9.917710196779964],[3429,"14eeb2ac834ac163ca44a3e31e4e863dc5a546694e9581cd59ab02b5bcb47de9",9.917710196779964],[7658,"66da089431c80ef1ee126896e17cb4ae2a9e43158c075a09939beb653ad6d8cd",9.917710196779964],[4125,"4b37656d46f8c66b0eaf2d4efdad906e93fe84f5b4bbbec091a850013613e3e4",9.317957166392093],[19469,"a6334e09da800d98ade0c5f580564b05ac060c7edbb9354d34d396c31c50760f",9.317957166392093],[13976,"339e2c6784856d78a524c3edc07bc5a24bdffefb80f3b1a9db171b11fb958595",10.052724077328646],[6108,"b25a04a53e23e22ec59dafda5e1d596eae1f32cde1d6462398593bb947a661d8",9.317957166392093],[17611,"d4fe5106316b2f8fcbba2c2eda8c9b4822c5b6a1dcd99ef32663758d1b8bf044",9.317957166392093],[12826,"44a755bae4bd2d038abf95e4c042472726bd1ab78c8ea3d1e4a84e27f859cbab",9.917710196779964],[5990,"1fe94cef254ba775eef4e692b6269e05d95866304bb4b0c49cedbaf1f30124d9",9.917710196779964],[19651,"7719be5521965612165fc7c5f27fbfa146d4d3f9f599ad4f76ad3b9f3a0c0f08",9.317957166392093],[12456,"550f3af3df80d00458e0249912f28c0b3fe6f2dc830eab3daf5d2b87353d3fae",9.917710196779964],[10365,"82f0ae4110ae796dc06e096fbfcaf6efc7d3f51fcf5fd4dd695b1ae963edf7bb",9.917710196779964],[7940,"1b9254de12ff4c33163f5144079d95aab68474e5d6c11946b228948fad1df2cb",9.317957166392093],[9119,"4fca8cc016aac168361071cf9555590a21403bf72486f532e1335b18ca4d08c4",9.917710196779964],[15464,"33ba69131e408d7e022add5907c62037078f7c7b79adc9a9a01b6aa08ccae374",9.317957166392093],[17528,"57f549d54b7c0d03ade8b81c02bd1a1391404f3d51c7b46f94e4dc744dd4f246",10.028818443804035],[17462,"07625e96f563de6566e773bf7b0942e6665859cb7eaf219daaf6c817f1458e48",9.317957166392093],[5183,"6b2dcfaedd8ab838e1e5809963498d98af61e16f85e65084a035f1b12cd512de",9.917710196779964],[12078,"b3839794c42ec469929595fd2b34bf37f304e3ecabe88e290366fb34d753d4b0",9.917710196779964],[4262,"bc1548d262c2d4f697994e758c7bfe9f69bdd817346e70106138f873f70106e4",9.917710196779964],[9334,"36e8b9b90048f73ca91e7d647aef5c4c3726c98b4927b4e8ef60d8d90c90b2c2",9.917710196779964],[8843,"30db15836855c3524adc0f00036890b05733521b5cb702007865bf2744c1d1c5",9.917710196779964],[3249,"6f46e3ea719c5943ecad60eaccc3a95955b606420971286a52a391644121a9ea",10.051282051282051],[17832,"d38c0263fc8f13ab12e1fa3dba0a9a92babfeddfe9a5b9e30811a1b039fb9c40",9.317957166392093],[6663,"ea971d302d76e6b9f8ae3cd5845f90a98c14c1e24f6c097c37c46b0ee0633ad4",17.140983606557377],[14842,"3e6a146a31553980b1e038d5135d8051cd3b0d5d597da89992d101a2fc291782",9.647446457990116],[15475,"0e24f9136a2748d8d570fab3ce1753e2e7b8ced3f1f09290b27caaaf44d89474",9.997888067581837],[796,"173204971bc45582d3f9f706f8748fc8d6ce536fe51af6eed56caab6c9ea8efa",9.917710196779964],[15295,"a0d5c3fe7e93bcfd4789277b62c16bb2595c4feec6381de446c6de5a360f9778",9.317957166392093],[9991,"f7fe124b76d3e61c0c45d4cb8978a51bc6961d5e2d52ac07787f2eab3e2262be",9.917710196779964],[7523,"0138db5acc416af9ab2307d8ead4c327d8f2a0f4fa9ea40cd53c410908209fce",9.917710196779964],[2911,"6214af3c43e8fcd5b5a08c216e00a54f24f563f1c118dbf8005ba8e0dc1902ed",9.317957166392093],[9047,"d9f63c049d8aec18e6a15bef88458d3203856c9bb6805c61fc86f088281d7ac4",25.40463458110517],[12167,"bfb6ee17b91c57e1e8d1cc11a29004ec0a82e512cc9f1cf2946905826d4c40b0",9.917710196779964],[7199,"800f33113311cadbe0b13a344b6594a8d297e658e9c120219efaf293ff28bad0",9.917710196779964],[11910,"61d87843ee903290fb9a4425093fff7ada47724961ada0ea18d49d2e4a51f0b1",9.917710196779964],[12888,"859d173b1637c264e1da89cbfd8a1911fcbcc2ae6872003075d00c0f17515aab",9.647446457990116],[3728,"01a8b72f6479721fa9d82e39c323f2e5e0bf782d4b35b09e1dca1a7836576ae7",9.917710196779964],[10647,"1e10975eff89fd890b8d3f7d1325f4f99c22efc6fe64ac9813019179c9d364ba",9.917710196779964],[19412,"8cad27b8f759d605f947bd93d14acb54c746971a9a3da3ec6f305608a4502311",9.8989898989899],[15968,"56b45d67e10a760e3c48307d5773f07bc4d33efcbb981ced82c06ee3693d6b69",36.948306595365416],[160,"6181e7f2d9629a1e5fe0939432669daebcd273efff9e47c513e5c56aee61eefe",9.917710196779964],[12983,"fd4b53da4ca8a76fa2b541b3a1a2d88944f257f1fea20c01edd5194214b6b5aa",9.917710196779964],[12369,"3108f27a84689a8deba57099f681b26d91fe962df71e532086faa3890d83d0ae",9.917710196779964],[6328,"16ab65badca8a19f5f768428494e85c66bda29f446e0fb56f0532c1026bfc9d6",9.917710196779964],[17035,"329038764fcdc1a0d855757a5f1c9e1c29905b5544271a437cc2a8a2b8413e51",9.317957166392093],[6134,"2216a5286dd0b6e39f0198db647f41e3b9a0998adef2c0277359699cc4a63dd8",9.317957166392093],[7112,"6063c0624ff52ce07015d1b4b59442134b9bafd660a3dc49afd1a6622a9c46d1",9.917710196779964],[16845,"b7c12ee261ff3547c7fd1d9af1c474f3ca6a82a2d9555a162c64831d36b75d55",9.317957166392093],[5280,"e4933a2132c450ac29d308b2d246f9875cb05a7dc1cbc51c7106a0f776bd86dd",9.917710196779964],[3750,"10b27ecf6159f006685ab23d86a5691f69ef6411ac373954c32781868c5940e7",9.917710196779964],[10997,"9b0b7780669ec1a28ae82b51b9b773ca2ad0ac1a576cf4706375183d7f0a00b8",9.917710196779964],[10886,"eb556e752c9470c31536762987725714e0229cd08d719ae19cfbd6d1a1f8bcb8",9.917710196779964],[10882,"6f97131bf72458ade79c32dcd6dac17c2751d492975a301618b9c3710ecac1b8",9.917710196779964],[14322,"e6a53dc0e10efeb6be40ee7506cad7f2761f1d028dfbb0e1efc5a6780821fc8c",9.317957166392093],[3189,"b8aa2c3afe5b424e39046dea1d68476c72b57e6ee5054cb0022b75caf4de18eb",9.917710196779964],[14752,"697b512ebbb5d2e8ee3f850b798f58035cdb96553783a24fd98b437ce44be083",9.317957166392093],[15738,"cae4a81f4a7a0a13bfb01fdb50477fac5e70401c6af958fc33c477668588a46e",9.317957166392093],[19833,"f5607e7f5cfa8782f67e86e36742800de91f8dda6d22474a1dccc27885f37301",27.151515151515152],[9060,"52e2d517c79505a0b9aba279c3c2d8d341abd4a38dfdfa523a2050a5e80368c4",9.917710196779964],[2095,"c6156b62e55bb4fa29cc8ec1a8c64b2b3a4731b51e144811ecc97126a3c646f2",9.917710196779964],[7397,"88cb4da3857c57b27811c620a2ae5d0cb8068392318104ad35184dcf29996ecf",9.917710196779964],[7251,"87eadd74d8fd5790f5a0743351906f5038388c4bc5fc110c644a86bb8e7f5dd0",10.052724077328646],[14945,"0c370965a8694aaddc4f3892bc9933ce5450a9c8e05c41b57fae21a184b9e87f",9.317957166392093],[5983,"a4d97d64a8ed2b3104ac32c7a361218437b998093113f19cb695bcdd439d30d9",9.317957166392093],[12120,"6619edad45b8536c877e01f1f35d23adc90deb4c5957c8b30a2c586c5fdd99b0",34.83420593368238],[3855,"10ea0524e5395be298e06e5a0ef76ec4169151fc5d3c08408788681876f5aae6",9.317957166392093],[13337,"e8af1f49cc1b474cd6bcdb6f2e56c98f8c187d333a2c5fbd4ff43739fbfcf0a3",9.317957166392093],[5276,"0b343d2d9c3f79e2432ac128948021ea28c0ea384f9b16739fb41f1eeb218bdd",9.917710196779964],[7289,"dfc5f298d307538859473328561ccfd483067f69fbcea3024eeccaabb89325d0",9.917710196779964],[17399,"5624d8799075c84f0df4041a65d47d131069d84d6fa20496cce8d4dff5a3ca49",28.14242115971516],[1887,"d0451503aae05f341d6095c8cecbf8c7bc088c4f1947147ac91c38982960b0f3",9.317957166392093],[15681,"9a7f523de054b817f750789d0f7fbd5458d2f2465c16a5baff64c7d7ec1ec96f",9.317957166392093],[7576,"421d76809e57e95be511e8df86f3395f7750139aaf998cad7bec3f9e6f9654ce",9.917710196779964],[3315,"81c49f2c61e6b8d7f251cc3f3200a57d7f195178029218db710832a6c5c344ea",9.917710196779964],[14109,"c06be6194e7a4ca80425a83be23655ad6fee538a329a40a3ef7b708cc27e5a92",9.317957166392093],[6251,"8d61b5c149787b7f736256895e4b4c4f14e15b02b184d15c46b4dac6d13f64d7",9.917710196779964],[16391,"61d77c4a555d538d03bedbb8c4b6728309f4ff453b927724951cc0bdda823f5f",9.317957166392093],[18634,"bbc565bac017467ec6d1d554caa92bc8268a40de9e6d664847d3daceea51732d",19.1232],[6657,"d1f2a2c5b82447fcfffaac7c5fc6d7b08bb0ee66eeabd9fff95e5b4009fd47d4",9.317957166392093],[13726,"1aae18c043b96f118512649c356f3a86e18fbed92aa6f3876c1f7f19415de39a",9.317957166392093],[3734,"39316bd6e0a65bfd447c84732ac6a8da925b39062ef2fe2ebbd402bf4edc5de7",9.917710196779964],[6670,"869f9c2ca87d57791085ad6fe0d21385ca3e9f373caa74a3d29485a8279e2cd4",9.917710196779964],[6436,"1beb623817a8989784ca94282ecc6462a274bfea1879e77f5c77b66c98bf01d6",9.317957166392093],[13306,"609ae56f8a523c2197d1edbca7bc86f8bdd35d429b0bfbfafa8ec84201b474a4",9.317957166392093],[16878,"846ed0e6c087053cb7a354d32b631dbad0d93bfdad5ad2a90621c900b030a954",9.317957166392093],[4370,"0567b7859b3fde5a8ae2246218299907d808dd6951e813719ddf1dba01b447e3",9.917710196779964],[12154,"1f84c88021a6ec61bc924f520194c9263ce31ebef24afcd2635a6247626451b0",9.917710196779964],[18677,"2d1632e8fb1e3d18778b33060a2cf43443c811caa4c9a0827d2626312b8f7e2b",9.647446457990116],[12621,"8107175e17503c6f1a1a40a4e5446bb8ce3e80fdcfaf2035d1dd2121d82422ad",9.917710196779964],[16012,"5eb2bf46bd6f685bc6253ddd052424b643dc24d6abdf1eb6eb19c257559e2d68",9.317957166392093],[6229,"c5b1f4a702be687b282b7872dd049838aa57e3a3d20c28fdfc08fe2bdb5f8cd7",9.317957166392093],[6862,"0c8f0f7d0bb4d99a4e1ec63b56f49046904ab0a253f836a6eadd1ee64f51e3d2",9.917710196779964],[453,"94506ec1fc85f020555d5394dd9d8108d0a56a02e4ee08623dc9332e616606fd",18.117427772600188],[13364,"db985a9589931e483583c9843f14a0e8ac7dd49a275a500f2d53505a5c4535a3",9.317957166392093],[5314,"7eb5c881cebec57affad9c7b28edff22289ee5d8a55bc54188891a65917b4edd",9.917710196779964],[13470,"26eae290e0dd2b892d835f64ed1929af57681313bcf2635c3654664968e2a1a0",9.317957166392093],[19253,"8fe6c10d171d736efc93fa67d7c683e1b60c859d844a9dcec4b86f73c6be7816",9.497326203208557],[17281,"970b685834e9c32fd90f955bf8020a72c0edd609aaf1730ed2d54cac3422934c",32.46111111111111],[251,"eacdedf61b6d01a55a7cee095556d6df32dc8fd0f25756169db3500203a64cfe",9.917710196779964],[6389,"92c251b4d7aa7d7110b595e8365f792b842a588904bdd43ab7b1d6bd19a065d6",9.917710196779964],[6748,"3a5d0c9e1327b8607f8ca238fc89c6965c894be8b893fe6258185d0a706d97d3",9.317957166392093],[2459,"71cf24e9e9d0ac782d843f55c6b86123f21ff2b61dbda1caa505de666e7f21f0",9.917710196779964],[19654,"eeb6ffd7acbf96f45dc265eaf5ef9038b09ed1bbc005f76e66e2ddcf3ae00a08",20.194805194805195],[12675,"af5af506ae1de527cfbbbac493136ce753e865b0ed89fc7c9f189fa9b2bbc0ac",9.917710196779964],[9694,"3ac5e8a9ebd68d0e775ec005a2848fe0afc6d5c2d87780c5411c8f28db5571c0",9.917710196779964],[17512,"ad0be81970164eddb3305fefade47ac3a4531f9535551e97e5a5c7eb38274047",10.052724077328646],[5261,"abc6d2190172f997f502136fab4a5d3399665239235fd29e2d46cebdd6349add",9.917710196779964],[14265,"ca17955c32b03644f466c9d3e4f23dbee7d091ab0a8cd1bb52604bac375aa38e",9.633605600933489],[14693,"1ee15b91b9eb52cf537633a7b1da8b36fcbeb4429b6f7bb2b2240c334df9f784",9.317957166392093],[13798,"a34799cb2b7c54b57f19e88019426c0bd0957736692dd46ea62719dc317f7199",15],[13412,"276b90e786f04c2d312e2f39954051412a5616310465ccbad32b556b5b7614a2",9.647446457990116],[13608,"b215f66805c41cbad8e2967af65e4b2f63e95be781489038b07ab7128089459d",9.317957166392093],[2933,"772f655d9510da1ec92d897cf3e425934f397afbc1e785566bb0408dbf6bd0ec",9.917710196779964],[8338,"cb7ab51cd78dd3c833088135335f2bde98fb7ab4f5b43b0be9c60c20f91116c9",9.917710196779964],[17895,"8775870a8f83141529e2d55d0e818638acf4d22d2c28d1e3c4804ab7ec9e403f",22.08450704225352],[7524,"6a19a7c0d6c593f532489cc2e7a1e10479733768903088bc31fea1072f499ece",9.917710196779964],[6572,"8d1e2d4a65e4bbc10c5612139d76852271413ef9aed05c45733f216963dbe3d4",9.317957166392093],[6342,"61a603aa486b59f3fd63545fbd44e003f10be4064bc5a7f02c174028e403b9d6",9.917710196779964],[4105,"c3fbcbe63596f003eaf0ceb2b8e02c7bb81e9b61646a91379217ea6054d40ae5",17.008521303258146],[7816,"70c60ba3dbf40f203a3a6a80498290e47fc339cfa3219c046a6bccef8a5ba6cc",9.917710196779964],[4502,"734c8e77ebfe702af79359dcc2dc7848f94407164507101470958a44bb9659e2",9.917710196779964],[14084,"98f55e59dc9bec5cc5691ceb83470ab564b579cce9be01edf58cbd31e2a1f692",9.647446457990116],[1840,"e2f1569a1cc267a787477ffa301222413bdab7628dc07c16ad7badc19dfef9f3",9.917710196779964],[12952,"7c696c743adaf58da7bffd835291281cca2ba7f6cc702163ed2dde403710e6aa",9.917710196779964],[16692,"1b9353025063e67da36d1703a39a23aed646c264e9958b302652ecbc463baf58",9.317957166392093],[16476,"a7c0077adecfb93ba1fbc737899cc01fcfe38e826b562d6904a0c62022accb5d",9.317957166392093],[5617,"1f8576c9c7c5f8889b9f93a3907240c826bf5113f3cd70517d7a6fe3670a91db",9.917710196779964],[5309,"6b3632fa0b8995010a0fe2779b338b5583ec23cb34327c233b573fef6c1f57dd",9.917710196779964],[2512,"f25010c526800577716d62d9f98de424469b7f968a1a88adbf20796013b9bfef",9.917710196779964],[8844,"4b714ceb4d665518c7d324b0abc0d3f8e0e3114e8803ad5b7503a9e607aad0c5",9.917710196779964],[8429,"12e2e31386f97e4d92fc7769b212222309f92798606988bc752a184cd69b71c8",9.917710196779964],[8626,"ecdf736667a75355abe9d35abc3ccc19fe8461c5efcd3f1474187f30c94e45c7",9.917710196779964],[11266,"cb5926ef724458e1c1d3b9699d8772813fa1d54ed8b61efe106fadcb97813db6",9.917710196779964],[1882,"73733e74bc69f4b38fcb40346c691bbca4aff0e447998cc5e823284446cbbef3",9.917710196779964],[14113,"e5d704e432e1b3d57931cfa76906e357775d24062ee8c78126438f8188cd3f92",10.052724077328646],[13949,"d3cd57587a4269b9a70a3d13a4b944b0f124d98cffa8d1d5c3d2059e2f01f995",9.317957166392093],[6525,"54db2a024d19f4927c45dc76d17a220d2bba0a610c14ab0c6caac276082640d5",9.917710196779964],[14157,"2c5799f472ae75b37ac41ad86fc4e0f7c45612c6c31e9e286b95b62005104c91",9.317957166392093],[1472,"891856a82187015aa8c4e7e805065b06e82b5670c6378cd45f69cd81f90456f6",9.917710196779964],[12300,"531c45b2f1cbf8e224ff3df40bea4a71cb6a8399397c400235217eb1d57b36af",9.917710196779964],[3976,"8c16cd6588258d2968b5c883520d82b4e31e6432bef6460037f9457a5e12e6e5",9.917710196779964],[13722,"8b55ef277024e476227e695d92a7630aa1decb31b4697b381473c0fe2f7eec9a",9.317957166392093],[10475,"4f653d6d70b8564241a8409c8c5e173d12f9346d43bc9631e819b94944a54bbb",9.917710196779964],[19567,"f673a57687b00a1b642dc10935a4bd8f65e534c9f046e57ad5e9606df00ff00b",21.207792207792206],[9415,"a4beb95219cbed53f6b5bfd41cda7f58c9800977203c6965dbde97c2fa0e33c2",9.917710196779964],[1342,"d1661a0031a6d4ee57ef50779da1eacd5a11301de604924638ba8436b83222f7",9.317957166392093],[19142,"b9ef5533d75f4d0c354335f83e9c9f6b9b309cc253b5ef522c48005a27a6d51a",9.317957166392093],[9272,"7e80987a33faddfed5d8ecedbc173477f7664b6a5cade861a42a56ddbc7d02c3",9.917710196779964],[9928,"6a05ae67395c8121696a3dc6438e0c02c08d02dde4f4fff9c42864f42002c7be",9.317957166392093],[7436,"488922d385d22709e8a167034af22c3933a868a8b2a7605ee8de0cb7ce5c27cf",9.317957166392093],[17174,"db403c373adeb308f150eae13b775baa244a7b0842c05f11ce9750bda2f8504e",9.317957166392093],[12886,"b13851cf0a5555cede3ecec97f3247218941a7c5af57e483b0520c9d84fc5dab",9.917710196779964],[2649,"21c6e938ae9550bc7717036b6a97f6cdafe4feb6a69aa3f94e0f09092dbed9ee",9.917710196779964],[3009,"32d48ab26ff33e4dfd77dedad6f548880088c4f1a04afe91e16bb76213d33eec",9.917710196779964],[13354,"1ef4e84ca63ba246ffcac11f7198353c6d8b789f98df516c4caa2661db0a5fa3",9.317957166392093],[12986,"d78ced699f717d78289728e760d96f679dcdcf41c497f66639872798b615b2aa",9.917710196779964],[13081,"c33ac19b658e76bbe7111b6a24499ca7cd87aa0f9a6f5db55fea3ae89d1edfa9",9.647446457990116],[14443,"644d3e55cde56a58f64b48d7d25b0012cdb4faf670a2045628daefa4dd655b8a",9.317957166392093],[18500,"1deead6b5e1ea463e9602442108a52c309c797d8afe63b666281c048f5456731",9.317957166392093],[4368,"0018092a0e7fb4859c4842f3c91958dff55f56608276f9d6c786c5be67f24be3",9.317957166392093],[11586,"1213807afab707f1a835b2b93fca98d8b8df86805772d94bc9ffbfd96c33f8b3",9.917710196779964],[12338,"fea64c0f27a12611d6c4da37ae9c99551b9a80ac6a1b5ae30b6f989b25d1f3ae",9.317957166392093],[4614,"5543f791187dbdeb3904a6819b70b79eb0220702855cd27676ffe19e61c585e1",9.917710196779964],[15993,"152bfdc15c411320af8a7e043fdf52bf2a6e3ef4c9da8a7ac6320bab62089d68",30.879807692307693],[4074,"a7f8633474f03952bb68c6dbaaf2c1f3a063be22209b08205ff2b4446a2041e5",9.317957166392093],[396,"035bd1764d43edd90b5e08c8f0fe10fe121b9563ae9e8a1c61605bfec3ab5ffd",9.917710196779964],[15149,"ef37912248db2734701388eddcfb20740fef469a20e2f17b5fc383ef583e8a7b",9.317957166392093],[5757,"5edec677b455d3a1c66d0180a7333072fa248d7310feeb228b8078b6e1bfbbda",9.917710196779964],[1692,"70e7fff6784e58f15974e0fddf702c8447017401915b9bc175694017ec31fbf4",152.67561983471074],[18117,"4f9096ecec062a9a63481857008583a8174de85a88d157ea7bb50f1735f1813a",9.647446457990116],[3192,"ece618230a52828323ac2121049009b364586f42c03b6fcbc66e761368ba16eb",9.917710196779964],[2998,"d6c19ea5f4787b626b09b70eff9df480b9255f8fa0a684c1595b21b71b4d48ec",9.317957166392093],[16223,"138f527519733b66537076b95691e3095480017b267eb10a4776d9808d704a63",9.317957166392093],[16905,"65756cc637910dff32078400ece68c8dd8f4107e6517db07f8d94711ceca0854",9.317957166392093],[13158,"1e0018fbe2f89884f577275fa7b310a9840e360c6fe521d13a889e1644e0d5a7",9.647446457990116],[9432,"d9d5d16eb335baf6f0e1a9cce2aa848e9ff54f139355a69ec1268215065726c2",27.12],[1936,"fe0234353e7d9178d89c38a05ce590d8b65010acd7aecbe9d3ef1b12097271f3",9.917710196779964],[12684,"7dd0f6e3ea952983812995b30df5ce297a00c515319098a9d466e00c90c4abac",9.917710196779964],[13708,"4b0dc237d7c1ea3cfb3d5065dfc3af97ed3f7447ff7c149b5d91849e388e2f9b",10.052724077328646],[10959,"a0b8d8327f05b4330e2eb05558eb2b9bf6dae563668da80a8f7ee31047e949b8",9.317957166392093],[16009,"5a33ad230b9041f9dac402fbbf9adc8d91060ac8b5bf151da5f541b095d14168",22.246001523229246],[9333,"ae53d9f9e7d435064a337513de0c5c5c32c050db253e13cd62d07f17cea5b3c2",9.917710196779964],[3106,"0cdfb63c9b9f546cfa0dd86305c3e2811ab2afbd7d99be07ce8eae488e0f9deb",9.917710196779964],[9957,"58962d329f8d423f087ca875ac30304be88521d08e7287d9f4d3b5495a1094be",9.917710196779964],[6774,"64002a1801ac4b8ce257b650f064ad28daa1f18c06eb8bede97843df5d0477d3",9.917710196779964],[5305,"359b84021aaef6c76c66534ba7be7a2120b9bee817929812488b197d6fca5ddd",9.917710196779964],[4863,"00cfce60abcf45fc1b007240a616861f8da7af85ce4c279929e0425ea1740ce0",9.917710196779964],[19016,"35c20f54856ba816c70bef73d6707be28354b06986838d67aaacf43da010ed1f",9.647446457990116],[18179,"64ae82d2681a92383bd02b8d97123ea21234b767101ce25d3d71b3680099b238",19.50973172014729],[17846,"216573b8eda3eca66ae4780b9b04caa107e44ec741690160cf297e88cf164940",9.317957166392093],[15355,"7d54882760fb3347305b0e6ac478bb79de6590e577c107e106b891a65e0c4c77",17.26984126984127],[12646,"71807d6fa57820418df09bfe6572a81174d7d9e33dddfa0ea019b274507ef1ac",9.317957166392093],[3854,"851ced7fddbe5bef26839f6d62fe1b0a6d69c372c6d2066a902c9d33b40fb0e6",9.917710196779964],[2901,"61686cadfa63fec313d928a09ef391c96e8cbc7db88ffbb8bb9bd7d3df681ded",9.333333333333334],[5864,"6800233067edd4c471ae7ceb9e294241e0bfac592657e2436d02a107abaadfd9",9.917710196779964],[15536,"46501a7b3a42a0950afd96dd78e9173d147fbf96108359efd97a072ab86f3b73",9.317957166392093],[12486,"a017a9ea42f3a2c34d79a4e32e317844e6d0b520af20b920aa1022da969907ae",9.917710196779964],[5194,"a858dae8f04f0ff35d3456b2c8d7fd58a786b3af58643e41863fe7bbfa9705de",9.917710196779964],[6958,"adee7804da16ab36c9ff09f82f06481394c16400dcb51a0e795d95b8273339d2",9.917710196779964],[18632,"5945c441992a4350b1e77aa93dd1b9e2d31365268e5d87a9f07e509f5eb57f2d",9.317957166392093],[4816,"9d5cd2bf2209547747543a24de900739d6e81230b430d66ad91f1e6e4f0054e0",10.013531799729364],[17207,"5ebc95c286f222b887fa436c38f553c5d4bf7e44a0eea8ad9859aa9d0eb4a14d",15.609756097560975],[10740,"fc394b3822907623d5ae769d8a2087b92cf3b7379171b963311557be5106bcb9",9.917710196779964],[2498,"7fd445c399e742963f93ebfc785fbe75d4b7e9ee5dcff79f00a28fea93aadbef",9.917710196779964],[16277,"1f5ce761f97ef4ab81c5eddc374342b68df80513e5a049c084f7f7d611f9ad61",28],[16806,"943ba664afbe14c3b84e5c8609dbd38e54bd4a0cd71b416e9421390352be0f56",9.317957166392093],[5564,"c511c156e25e68e5e18f2ca6cb25266745c426585e8127bde920b5c1ea02d8db",9.917710196779964],[6524,"bab0dddba213134e3f3f2364255b18fc489b48361cf2d71cc2532227dd7041d5",9.317957166392093],[14224,"3f976188d14c179e9951c27e5cd1ebc0192818b2c479cecce92afa7fe1d1918f",9.317957166392093],[1917,"1df3eb670d63636bf4d72e0b57cb5847c5581dd0e14c338185aedcdb1ad991f3",9.317957166392093],[15866,"e0e3db25db9f35a130b611e4f99d659a98db7b2bb6781ac2e8310569043ec76b",9.997888067581837],[6564,"1186c62c301a515222110b0558bbc9ca99a2d82fab2f02df23957753377feed4",9.317957166392093],[10831,"53d548f749f976c6e5e93d486f33a1169154ce922912a612d4a28a3a43a91ab9",9.917710196779964],[19226,"0a40fe738b94dfa4715e88601a406df5b3bef0728bf5b488b34e8deaf172bd17",9.647446457990116],[5343,"60c677e334a37acc6af61e77ad695c96a7276b085285ec46a971ea9c22f82fdd",9.917710196779964],[2346,"a0428c153c2c79a2ea1c3185d734ff1900de322ce08bb28e9b5965912a44c3f0",9.317957166392093],[7735,"443c1c960c2cfec6c3cfaa0d82b7f66c60db5ccbc6360f268b0f1b2e50fa43cd",9.917710196779964],[5138,"d26aeb6ad8978b34d4a5a1995e15e2b9256c2f35be34ba9c729e99da9a0e5ede",9.917710196779964],[3910,"e5cc9d5c2a5414da90d5daf7f85297e34aaa68666c6030dc6d2bc7b23b2e49e6",9.917710196779964],[19562,"8cceeee0ca774f9c851f9ba3cc0feb2c54c0cc4ccef88f55f41454f565fb310c",9.317957166392093],[525,"cf5c2721cc1beb579f1eea69802a34497b2a5774d2d23344275171de16537efc",9.647446457990116],[14317,"199cc502c73943a261684ed504242b86ad63cc5cea0e0d01e8d5b3c269873b8d",36.119261713203976],[3573,"d3ca6972e26ae777c034ad6592dd40612ec64afdd70fddb1736e33d58eef78e8",9.317957166392093],[9539,"5c84457e4307660743e6a7c187c9519646efc574f63f66ac08640a4b0fb873c1",9.917710196779964],[12954,"cca48e6b4e6e82cdd7b3d4b053eb30217573707b8264143b47ba92670ba3ddaa",9.917710196779964],[15552,"a91781c21660dc4b5982ab625c785d1fe930c5eb8fdbe288cf1ee23ee976c672",9.317957166392093],[19050,"4834b668dc9632a0df702a28da346c87abc7b65e6073bd6f5612f99bd2a3b01e",9.317957166392093],[6830,"af23263f477ef8c8f4f60b782d897812e9c18b1d03e6dd9128707571469310d3",9.917710196779964],[7347,"f5d4fdaf4beecf7d25dbdbad29177d8824db7e104e8fb584a956beb10713b8cf",9.917710196779964],[16951,"24f04fc6d66fdb9255d9714be2b597ef717a6e597de72536a487d33bd3b12453",9.317957166392093],[19639,"951865d40f855e3aa81ead7d51c9dbb404889306943a22235b75b6ff5f6c3e08",12.05911330049261],[13283,"58ca3dfbf81cb43f641f7bca3a666d4560d0169c849c8d93756591f0b9cbf9a4",9.647446457990116],[18554,"cdc6f77aa2a9021db5d1bcf3ac40e3971643f2c0071af2eafdd87e2ad6765c30",9.317957166392093],[7552,"6843be57129bfd07e4ddc027b2a31f516faf6a5f5031cdafa8bd3555e9647ace",9.917710196779964],[11908,"99834ac691d623af8ee36e36f32f702ea935e30527a02bb22963334558a0f7b1",9.317957166392093],[19234,"2100e5d9ff6431d6b27fe099efa7f58ebe96d13f5f950da5b52abe7b5ac36c17",9.317957166392093],[1786,"81484e6a29a16df882fd06574eddd68a825c5088506315e4a803e2ff2f5e54f4",9.317957166392093],[15219,"79919508d86fa67310986e0a2bdb7024b1465a58facbe5afca28b6ed6439117a",45.79245283018868],[8025,"598cf4731f1a460f1417a026590b943d6ff5ed5feb531c778a5f6474235a66cb",9.317957166392093],[11389,"a2cab0b9591efbef5bf9b227bf068e07ae248e0320f18e917d6b5334b6916cb5",9.917710196779964],[9671,"baf33310bdd06fe440bd6e0e619bb449b91e72374cf3092f450a13b8eb5592c0",9.317957166392093],[18504,"cb36e1d4c3b6335366d1f8a160979844f6e35e87d95a6a7a4236470d3a9d5531",18.106090373280942],[2473,"02a556167ae23991191fbae88014167983e594b2c9705c8aa73c9ad24daa0af0",9.917710196779964],[9032,"f1ce8b2f49bfc713157a28c63fea8518cd16de831b93489aa2b11600abb495c4",9.917710196779964],[8983,"9e6fd2a69487beabb73bfd1c7e9b7355066bdb01433a16ee6043631f16b2eac4",9.917710196779964],[11330,"09ae38a6b77c1c2fec9754125e0b05cf1aa9825ad4c8bce5105ab3c12838c7b5",9.317957166392093],[17197,"dc8a4653c5898fe7271a16a51d7ae15d42fb514a95a058cb7e123e5c66dbcf4d",9.997888067581837],[11191,"8a857fbaa7a2d831ce12755e5275d59392504595423dab4b543220445e73b9b6",9.917710196779964],[10856,"60d1ba6e0ed93ca88dbfaebc219fe8d636c2cbaecc5af9e96eeb0c9ad2f1eeb8",9.317957166392093],[19114,"992fe09b4faaebb4f4837d02e04f93736367df8a76520c856eee3e2e47a8cc1b",9.647446457990116],[3098,"c14049bad742790e8df35de5d043b3dbd4586a1ffd93aad9d75c8b80c611a5eb",9.917710196779964],[10564,"7589c81ac9db1bf2cc38e6704a77cfe702a3cb38ec4380bec90df73b9234d1ba",9.917710196779964],[11784,"7346c83558ba1040ad3deb05acd06925eff0d31f8740c3716f88097e9eedcfb2",9.917710196779964],[14072,"5a99694e249628aacd89b535f91c9d4937d904b289829c52efa4bdd9dc774593",9.317957166392093],[1024,"9055ec6257986f5b482f79efbe1fef71ce3fbc3db0e73bf14887eb0cf36f19f9",9.917710196779964],[9757,"47dec26894330264202b8334527c31194a21e85e00eeaecd9842713563a2f8bf",9.917710196779964],[11831,"5b2daaa8467f2bcd8ddb1e63cbd60ef8d020262872ea672926a0abdde57186b2",9.917710196779964],[7431,"2613110d926035432bc3a12c141332640c7cc4dc31e2cb547628e24a5f922ccf",9.917710196779964],[18800,"689e794a57b4d0fdebb2e446fcf93b076e1f10850d94e8232ae055fbab66e726",9.317957166392093],[7741,"a2a07524f7060c1b146e7c3e79ae0ec1585c0fd88b9c3f52e9cd11be494c37cd",9.317957166392093],[6697,"05e7edba127f2f19ef905134f249d9db09e446f1e92fc73aea265dfbac63fbd3",9.917710196779964],[7784,"94477921d7808f81c336aa0bb8e6a07055a8afc028d0f8ea8088bf0d9edbe9cc",9.917710196779964],[8132,"f6d96b52eb75f9b66384b8a127742527310259a05000dcd4e02e1bc5c6f880ca",9.917710196779964],[12094,"914293578041dc5fd2621172c827cce1a415ddcbebb637f476386ce0e91fbcb0",9.317957166392093],[11665,"f2b84f7812e3abdf3577ac8e6249122b055e4552ae0d9f9a49717ed22fa17db3",9.317957166392093],[3599,"43aaf64f063a978ba462e19c49bb06934a9c343189bdf9c8d381000d9ce637e8",9.317957166392093],[13934,"7328a1b35abedd74c096222d27753f1756e584a327ea19fb98622a0c3abb4b96",22.83553875236295],[7721,"1baa730bad13c227740ac0a739278f06659a5c3f5349bb12cf532a304ec163cd",9.317957166392093],[1943,"8f9b9adb9d57f2cedca818b022b5eb0b6b90e138bd9fdb3237609632482b68f3",9.917710196779964],[15258,"600a37e1943605c97eb6091705fb71904fda6b7f14609dfbc5c889778d7b4079",9.317957166392093],[12719,"03cc535c497f136f68473798a3cf7ab4b4934b067176ee244b40e547d37b79ac",9.917710196779964],[6629,"30b62e3fa1e0770605e9828ddf7164a12308d398ef4cf03dbc0af5d6c81c76d4",9.917710196779964],[8636,"8e99f37912cd1ce35c3341704f2ceddd9e0a7f45b8ca24abedcaa5fd551d32c7",9.917710196779964],[8219,"988dba81bf2577a2bf41d654e4f02bdbe11ea7322182e443697098bade69cfc9",9.917710196779964],[12341,"3c53c920b47031d467e4d0c04cb9180963bc55f683e3acd3b124c15db1deefae",9.317957166392093],[12896,"530b294a28f92db5fec22caa8ba94619bb8fed8178e7f949e5793a223f7853ab",9.917710196779964],[13056,"c6ba7972eaf7bb3e94a43762f384a2493f7dc5fae6e77e7b8d5b47d9990140aa",9.917710196779964],[19221,"62a7250ad0738e04741e24ba5b63af3054a8b53c971bb1bf90f7406e1d43fb17",9.317957166392093],[9348,"89c6b4621bb6d092b165e56ef07198297205ba7c793bcc381ddd6b875e0797c2",25.97195253505933],[9972,"9d38aa7278180fe4494df22835db2e4c0db0ce15fb53705939796ba922a47bbe",9.917710196779964],[1023,"651e941acae3f6f8a737702913d2a1b8adcc27daab7ffa8f943431fc772b1af9",9.917710196779964],[5290,"df5ecfc1dfb8e2e6aa3e749eae96d567787129cd55e273d176c9b1bcc89973dd",9.317957166392093],[9644,"24d9cb0f68396558bd4c827714ce468fbe53b50def4ad56a10d3a6afbc8fbdc0",9.917710196779964],[13017,"90550be2f975f480a4c30c76df5406ebfd189b1141d4061e02178458bb9b79aa",9.917710196779964],[4515,"6da77b30aae0c7a488ce6161ba033ff2289b79c3c8ad2d6ebd9ac0eb647942e2",9.917710196779964],[15837,"b0b23f4a6d7e57e7e1c95385344dc97dd60635c196a58875aa9926ad6f06926c",9.317957166392093],[18059,"3dcac1dc7916ce8ea28c21275216929a7971d4c521cae52673ff609decb1033c",9.317957166392093],[950,"d50342cd6dd735ce377f613c4f9706e7f3c0c372c5fa5fb6d675bccff0137cf9",9.917710196779964],[8986,"79f0bba3f2816254b476571671671f64f496edf49f250a43dfa7ba450590dbc4",9.917710196779964],[16581,"bcbd4d5d4c71fd9a81a5dfdf08ed5dc82bdc186d734ff044ced7dd8247e56d5b",9.317957166392093],[1844,"51ec4eab2b0ae4a3813595a58f867575dd359f968f4a14a5cb1744c3aa37f3f3",10.052724077328646],[3064,"db79e507571384a109823402b8977c082ab0918dc14e47e4e71f8d1934e7e2eb",9.917710196779964],[4026,"be97d7d3b531442074af326128a8c0d214996235fe8ce1c749b14327d0c795e5",9.917710196779964],[17626,"515ee9fbf473f34c625379f153188e53a24927dd7e53bbd74b30175cd528b044",9.317957166392093],[5177,"32d5d482535f01035a626344ae9a25bb38a736c97af3c4e4a8a11ebe22761ede",9.917710196779964],[15373,"88ffe099ea966cc9ff31c2ac7bef7016c4bf031a35f129aa2c644f3706c1e176",9.317957166392093],[6783,"793770f5cbdfec2b4266e3d460212c909ed75040f3c6a8abdbd877b94d4664d3",9.917710196779964],[3984,"5beb25792b4389ebd01912ebb21e4ad1c9eb2bd2c005102db3e23afaa1a4cfe5",9.917710196779964],[19865,"5f5b901fcb60859384d0c9cf1c5fb487481ab31a5a203356d9246cce39b44e00",9.317957166392093],[18451,"6980d7e5f8742c084970eb372827cece462fda42282303aedf74e4ea2cfa9432",28.558533145275035],[5724,"accb8d0646248ec7bb60f783437ef87efad34e7e04d97e94eb0a1082adc1e5da",9.917710196779964],[2655,"b68f501ffbb4333c9826d00137b1fc59e92ff095cc576ce111f9dae855add3ee",9.317957166392093],[1559,"69aa4368e63b48fa7f0e6a7c661498c7d3ae00003a7919b821884259592fc5f5",9.917710196779964],[831,"b2cdb73fab08c228d737ec344fc983ebef00fd2f737a06790efa08ba277c58fa",9.741496598639456],[17162,"4c61b268cbfff5335000530a031a2bae761d3b0f73d815aa7089a0a8000bcf4e",9.317957166392093],[13775,"428521167c8d0a758aa5c34d74b3cccdc2532964d243f83a55efb8923df6e099",9.317957166392093],[14729,"2369e71ce8abe7ea68a889bd5f6482e988e273b5520cd8fc360da92c840d6484",9.317957166392093],[14641,"d8d1c7987006c797d6f4b3ca8b55f2d55f6736319389dcd63643bb7633612186",9.317957166392093],[8456,"38f370219169dc01e59118d3746af5ab7da7248b0ae8f1bbb18c4cec21db4ac8",9.917710196779964],[1185,"c5e0bdac663b3d186fbcf23ae917fcf569d5f9c6a609335c7be7326cd0411cf8",9.317957166392093],[1754,"55b81b58ba6d1603f0f94c1034fae4565fb1b4a61dd3c1417eb824c4e5308ff4",9.317957166392093],[13556,"684bc13cb8b47e278fa1a5c8fbb16f6fa9ce33bb259395e616a2cad664f59f9e",9.317957166392093],[17988,"1f7356fd7ec92db2bf9ab8c1e1127c681afe2636a50811e3ee44484f2f32673d",9.317957166392093],[6335,"f3250bbb2935b53a64731c3180c67fba85e1da0da37218ef124f2c5c0c69c2d6",9.317957166392093],[14781,"e16bd017b692a8179921f0f055d04367ac235b048b40b77c14661e9c75be4483",9.578580565480129],[2794,"2b5125751caba332db4f14d2683302ff53591e41cf589eb3c796507157fcc3ed",39.13588850174216],[3956,"4a262ec501f6838826cff51fd627c62b97c01c6f10fada99698e67a319f3f8e5",9.917710196779964],[2769,"f51effeea3f318ecde2023bcea54375e13ebdabb4c8d53d091fa519cce6ff9ed",9.917710196779964],[19807,"724c8306b9b1f303e17c67cd17393e82fdbe000021c67cef746d7fc906f75302",9.338112305854242],[10859,"e7bdbfb23e23b7a6aaf473a5e51018585d1d7451801a44c7a5e061d0a5a4e6b8",9.917710196779964],[15919,"07be8f95c214ec5976b562a589b0db0b0cb7a2ad7f02109718b2ca666719b66a",9.317957166392093],[4579,"3441e7fea38700c2f232f62f9a9fc79152a1cc504d0f97fd7209c217023cc2e1",9.317957166392093],[14808,"2662894377c7285054fdd9e441d2536b5fb5ee5d8fa8d73495c6cb7208e99882",9.317957166392093],[19721,"811c7bf0a0c924faab391b5a96ac9fdcd2dc4532ce8941664ac01b44b754ef05",9.317957166392093],[13940,"6f425f3b1e83c72293f80bdd197cc18af36d6b0e56eca8dc5a66db8526f43096",40.71504424778761],[18548,"272d7327a6aa00b90d4577dc6f20c74e06691bebcdfc0a781cb4b8cae7477e30",9.317957166392093],[16165,"a12dddc5dd664c1c3c6fbd5d1a2636d21fa3ee8d1b197b60328fdf3c8b93a664",9.317957166392093],[5971,"04e464f2a382dfa7e7809b554f703228bca99db48cbcc4a68defab5a641f4bd9",9.917710196779964],[14689,"77fb7c1b62ad80ac1a900c73dbeec3caddae67cedc8975efae89368e79800c85",9.317957166392093],[9696,"1ecf628ae64257e53c5918a62854dfaf103634b61d2d7da780b9f149fb5c6ec0",9.917710196779964],[16313,"0737cb7c466dfeff552a8b91bd5fe868fdc68287b3602cc61455de9bb99bc360",9.317957166392093],[18622,"774f12870f9294801d66da1e1c5534ea06f8963b94c174bb8ff2f1963d6c222e",9.647446457990116],[1201,"9d5b0002ada5f7fb325c78a4641c204fc15a54948efef8bf8dfcb3b74b4601f8",9.917710196779964],[11397,"b8ba9a3f79a1551057ce7e8ceb07367e2917adb6d799fa377f8d1d352aca5fb5",9.647446457990116],[1412,"951151649399e7c5cd59b900593e34aff4fc072021d4cbdc40e3dae55215bff6",9.917710196779964],[1136,"3b8f44ff5460a0d587e29c931d86f658fd6d334e998671e25b76ce72974761f8",9.917710196779964],[9008,"8657a2d85398d79615dfe09b1b453bf7098b0f6fd04ddf460cfa0c747a9dbfc4",9.917710196779964],[19046,"8988947fea2cb6abdce3553a8afde35f130d62586e24ffe1b6f89a5c637fe31e",26.615384615384617],[3413,"46422f32e1b1c44c964d16068872cd7f2935d69291815084ff9f187b4dfc94e9",9.317957166392093],[9203,"7fc4b1eb4c08d98e3ef3889de6db4bdb36de80c356dce6a1958d50aec3c66ac3",9.917710196779964],[860,"a4ff43a016968457321213adff90de4844b636eecb18d8ec9a72c11bc50029fa",9.317957166392093],[19760,"d6f113a8d75176d6eae6ab59a3f312943a5cace9c0f28975accced3d333a3f04",28.899115044247786],[16578,"5d3825591a554282ff8809815269cabf3938ea1c4455d7034b08ede54058815b",9.317957166392093],[17577,"cae7833d8426b93f6650b71f6ad3e606e94faae126c0e8bbd93d34aa9b68c145",9.570744449281671],[5591,"26cafb19726a350dcdb49af405be11bc4f430a238a490f776f53e6bcb03facdb",9.647446457990116],[10515,"e399759e1bd1ccc028b3c73f43fed9809132d7a9ec89e9020f602b9450c417bb",9.917710196779964],[12605,"7a08e02c1ee23947561debe7bae028f548583011dccdb38a1df8f04e99873aad",9.917710196779964],[17355,"6be0dec310b7e9b39679e219e5382fa6ec45fda629ee9f56b4a2faf05811ce4a",9.317957166392093],[19115,"c367a487f1d883860750344e69c17907bbad63e9ba3800c499c8fbc11463cc1b",10.052724077328646],[16917,"c2f1105a4f566b354a7a959232d39040e2f59e44e26743218029e50d22fbc653",9.317957166392093],[14583,"023b324fd16ed7991de5ca10229abeb38cd81aded61f00349bd89b1e2dd97787",9.317957166392093],[17560,"71d2f4785fe92003fe9d0278f49ee7f816f17bdc1cfd96daa5cf11d624105846",9.38219895287958],[15781,"5d7a027e5068b60dbfe2085b7e2be63796889c57aae56963a6e4ba0e102bae6d",9.317957166392093],[16731,"f3931a6ac750087fd33c4f1059108ce23ffbd75f2af4cbfee3c696c007e7ca57",9.317957166392093],[11147,"56c421347f35779a411d28cf0f9a16b50da315050d815989e5335773b406fbb6",9.917710196779964],[6364,"63318c2ca2efed019d74aab078677b0b77a67ec3a9d896cfffd144e7112791d6",9.917710196779964],[2502,"3cc1b1ee0b1f1bd4d7373ea1bdfd964b853edcbe23ebf6e64512963ae69cd7ef",9.917710196779964],[3801,"96ad8a45af94a8f37e2c41411d52cb549108c7638d2768fbcce7b21a477ef6e6",9.917710196779964],[19033,"08644f04efe429ce5f002b7627c4ed890a192fbc694e51c68e2e6d3b9185781f",37.936395759717314],[17817,"57df372f07e39a9b9c1fa1c950d4c37dba0e4866da29e78ae34451f79a52e740",9.317957166392093],[6690,"203ab70f46031739a529c36dd5332639550ddca22bf0b7e3eb23d53290ee02d4",25.897625329815302],[16157,"bbc727c037dd417a46855be53c9cc1e702e06af840b2f9d8ae45ba73a36ccf64",9.317957166392093],[13769,"0db8a6aff5eadda195d31a8765ad3e6afc9bcbc5d9010dda1a669df730fe019a",9.317957166392093],[12727,"890625c231d95213ef60ffdde260380d0c66c728c03447912d75906dc94b69ac",9.917710196779964],[1078,"b47bf6adf6ccae27f240c75d3052f829aa3caa0fc007c4216ad2fa93714bbbf8",9.917710196779964],[13818,"6f85319d43207f97dae73c08a0dd57a4bfd7338d15531c024977966077471f99",9.317957166392093],[4150,"2cd1a630cd6c69d1f13a93c17472e4f63984e45090aa9fcd4ee5af1a2e4db9e4",9.917710196779964],[15964,"bdde519e4a10e500dac28ad35d6c199cc37ca9aeb1804a323b466410c0eb8769",9.317957166392093],[3330,"d7724f8e16d65c4e4dc4895e76e1d1d07244325909c6f92b480df9c35c982eea",9.317957166392093],[16524,"beadf096f2ba93decae3677618b364a9463a799401720e06fbe217ab946d945c",9.317957166392093],[19012,"f931587b1edf90e633cb7e7b125f49d7a005ef27e376c343782405b7d7340b20",28.097560975609756],[8050,"e5ef13089f1a115af42497354e2e203350f66ed07fe8eafd8283b75fd27828cb",9.917710196779964],[6248,"a7094058424fb1fe435c02cd5c7cfba6c0c9459c80a7df1ef18b45a90f0865d7",9.917710196779964],[5026,"29b3b6c5f3fc7af1ab4bd6bf51cd5ef73d845e97148370add06c70848b6b07df",9.917710196779964],[3300,"9f9dbbce3fb3b21ebe21a0c5e09b793625a7c652f7996441b0531cbc90de66ea",9.317957166392093],[16342,"8e9de33dee264ca9c2a08824e5fd70c0c1dfbf476a9ee29b8b15f4e697cf2f60",9.317957166392093],[14449,"0f2b3b2d0f7f4cee9c33f5f2b27e3c923c8bf709f480bfb51d3b7de9f0414e8a",9.317957166392093],[5011,"31249d0ded9759ee54f2098943347299c70b0291553499e6a6757269443c17df",9.917710196779964],[5720,"e7f57abb41449620ca03f79be51783a0c7edb66389b1b97e49e689d9368de9da",9.317957166392093],[6475,"2b643482679f7ce437312c96db558ade6d2989d748cb36e2ae697c0b9ad3a0d5",9.917710196779964],[18069,"19328fb68a3ee46e480e1b58420b3664d026386532fcf255fa295639eae3b43b",9.317957166392093],[8116,"401fdb0a9e84195b0fe5116712d3b41ee4cfe88e4830b562a5b31ac2b50ea8ca",9.917710196779964],[2592,"6f65c0071714a57840bc4d001d1eab256004d56636206f2f445b96b7742b33ef",9.917710196779964],[13496,"fbb8fc09b4164a03e6e627ada11f36b67b5f67ebdce2ee7fbc52148ec8f0e19f",9.317957166392093],[5370,"5cb69c233e3b4549ed6f3b842defb144d6aedc31fc9ed160eb035d1000cf08dd",9.317957166392093],[10887,"8ca29231703d435d2964a936bd31d30c97b2d3695856b565f0b2dce12966bbb8",9.917710196779964],[16140,"cb11a153117a43f9dad9f3b4a00cd571750e79994ee4d3119565a697e7f33765",9.317957166392093],[11248,"131c5686ad8a63a0a28d2f012a5ed2cfaf021c4cd375ee1117e8d8f0afc85bb6",9.917710196779964],[5263,"fcde135a3869ab803b834475340c3a774f411e711500e73793bd809d506698dd",9.917710196779964],[2342,"0550055786de8129f2edfc05de7cf441f4b53643bad7fa94abb6bc584f51c6f0",9.917710196779964],[7575,"b4242f443efdea56d2082156b3451eaab23c02d724fe543d7d823258dbc955ce",9.317957166392093],[2192,"3635b1f6186742b930672e5a0eaa88802f06ace40dbabc2d5d6dc740a9de9af1",9.917710196779964],[16163,"870753b2a09f0bb70a5622a41cdd8d41ff7de7cf583e87f428c32698a8bec664",36.143540669856456],[3281,"f7617a4424d1759e8f5ee87815ce23c6cb1fdadff6edef37a4acf381e5f083ea",9.317957166392093],[18253,"178c1c61ee388afcd3c60b7749ee6df78d5ef6a57805de8e8ef660de77e4fa36",9.317957166392093],[5337,"08b193eb7914c7c5bc38b14e35e6a9f5f5341f9f328e6f5cb94ec3d7a0bf33dd",9.376589215256466],[19790,"281dfb7b2fe8bade80add2d7026c8d7c84566a6efb06421e624c33c4fccff902",9.647446457990116],[17859,"7f821f1f2837d5d584fbc4b00b22512ae8219d5776ff6143b24f41c2f9550740",9.497392881432782],[7129,"a680f951a7436cb3e8c1af6f4e452b57975cdf6889f5522c3fd4cf1ab9b120d1",9.317957166392093],[1938,"aa17b0b77f8efee4f50d91a2e4dc493dc8a3b7d350ac390c5728f3534d3d70f3",9.917710196779964],[8927,"017071e5a79b8a86b854174679b94851ffe000ebd51d63041f6493eb045e50c5",9.917710196779964],[8395,"58087ac49f2be6a482eb8036a3e1818b6e5d798e5c0eb2fc1f836f75827aa0c8",9.917710196779964],[1656,"e7dd6bab9d153a0f35faa587079acc582a0136e1c4340c1190e0c30f5d1039f5",9.317957166392093],[13266,"9a1b2b83a3b76bb393b605ffaf816ea275c7695b3fb0ae31c83fbec5db1554a5",26.11764705882353],[14733,"e13e2b7e82aa22809c3823fe2bf3d5b52fc97c1ef705ce9718dc4b8bafec3784",9.317957166392093],[4395,"9fb25e212babe9f55fe1d1c8a935715903dac57dc83e0948d40186f156a31de3",9.478527607361963],[11561,"e8d0c6990162f80cecc9aef80f57937bcddc643def6dd3f0633c7e95672a2eb4",9.917710196779964],[11620,"39ea21a5f674def5aad27c041839d12232febe08aefaad5713341d88950ac8b3",9.917710196779964],[6391,"38c027f9cf29bb795d8543139f9ac446787a9e441c20e18e49d1dfaec4af63d6",9.647446457990116],[5356,"3cdd8707e83ed25a890373468467863df8b7594dc31b6956004b3775be041bdd",9.917710196779964],[16103,"c3ea54edad24df67db3cfd117794d7ed74f08875c9e6acb4fb9c74f93a700766",19.2],[14765,"2511afdfca5aa7c8bcf775a548ab71e6ea17ad021bbd991720cb228899d09b83",9.647446457990116],[8060,"d461bcb63bed5cdbf093e76600daf87b4e8eabfdbf03d3452ecfd9ede5870dcb",9.917710196779964],[4147,"c24de1b15faaa6c84eceeb85e3808169d42c941c5d05b66b9e7e682704cac0e4",9.317957166392093],[12862,"c9cbae92648c02cf49d3e07e1f0437328a617cd978033ad7f8a17e06e3f07dab",9.917710196779964],[15985,"9d7b81ac726bb03ab79e3fe03267481225e65b6904e05fe8246c089c3c0dc668",9.317957166392093],[1757,"cda859c835dcbb47a065fd61b707d101b9f7fcff3d85513af8613677b5788cf4",16.17081850533808],[11345,"7d47c401bb71b289b3a5a9820c1e191314f78f1ad2ae49074d03ba23590bb3b5",9.917710196779964],[19678,"b16bae83f4c371cd1be6ba3dd3731ee8ab04a3785cc95307f470afb0ea216707",10],[1778,"c3a7bbe51be1e712969d27bc972700aa6d518e849c390dc5dbd6eb3b403465f4",9.917710196779964],[3881,"bc7c13ac2ec717486eced6fbf01765ed7c707242886437d65bd7a3bf763e7ee6",9.917710196779964],[16465,"9f556bc3b11d374d23bba657b65175973ac631c3fc1ddb5c025669b5c357f35d",9.647446457990116],[16402,"80ad50303fdcb938eb1a54bb6ffdab6b91a028631a1a43a13d6b2a22408e155f",9.317957166392093],[15616,"36fcf2a947b36154ff90bd4e9a3231c410f796d25b5dc05036a8034ffbda1371",9.317957166392093],[5749,"d83356c701289e2795d74fd3a00684165adb78a474312422e4e8c2e74d31c8da",9.917710196779964],[19550,"72090fe8080f24a6ff3ac8f51af10c00bfdc5fb9f66d772bb08f6c2e02479e0c",9.317957166392093],[1792,"43e13a23141b72347d57ec6134b509efaf2fb686091f82385a3ca5f2f2b94af4",9.917710196779964],[257,"e3b1e942f98d9c7e89730396b7931d1cf6bd4d01269dc46510eb71d2719c3cfe",9.917710196779964],[18112,"85609156f5bcdc2b41181896344058f1b187a0b930720ae7c6896695b97ea13a",9.317957166392093],[2275,"93f6580fd4afd4dcc30234475a7c617718a8af6b3aa85d75c664544793e420f1",10.052724077328646],[16167,"d0f8ae1588cd5bda6563b302c680389888ebdf806a18ecc13e0282364ad4a264",10.052724077328646],[18991,"a7ef17d077a697b511cea861832f19fa385ad633b490bbdf579d56ccaab7f320",45.960880195599024],[8174,"06f4f70296ec19acc50cde9b538d5ddb8ff0226f3a1d9765cae943847b4425ca",9.917710196779964],[16139,"8d825e10b3d2174941452161e79bfcd673676bb4208f6e8f7b8860e453253d65",9.317957166392093],[1440,"6f026140b47f5a166fcb3228bcaa2088572e971eb4f0ccb5dc9d6fcee62392f6",9.917710196779964],[4228,"7cc7b4fd4217e7ba641ebab673f79601a88481a07a8f87dee828eda6b4a43be4",9.917710196779964],[13344,"8ab04c633d951e9240efd5918d1cb359cdeb99cf5724d28f96789c54f1669ba3",9.317957166392093],[5338,"3378d04ad9f1141250706b6f92d0873998f7679260652677dc728721787633dd",9.917710196779964],[4154,"7db463440b36cef74839edc6d99b85cf04848d178aee557d07de596d5fc0b1e4",9.917710196779964],[15273,"b8fc444f6abf9bdd45af902ac36ebafbb97e78ce599e3d9f1fe72973c692f378",9.317957166392093],[6254,"be8f9d43974a82faaae79ad9aee2b08ee042cb05226b0987b0d30a00803d62d7",9.917710196779964],[4803,"cda97d84f20e00efe9c89af6bc5d438bbf5850114799e21301fa20d0824860e0",9.317957166392093],[608,"48a6c123305960c6ed6fd2f906873effc2e27ec195c49a8bec8d9d6a87fbe3fb",9.917710196779964],[16006,"60400499ebb74e5dd458af4b7cbaa9599f1227a20e16e42e6a0a7dec0d465968",9.647446457990116],[693,"7e0ab38ca8ef1fad164dfae3f7aa798cdfbcdf168a0453cbadebf7cffe9f47fb",9.917710196779964],[1137,"5c74430b2ead065a9f1734937271f1e8d4eb983fa9a7e8d8f94f55b885e860f8",9.917710196779964],[10271,"bdb192ff13a9ecff50c0497c234adc331e24e5185d08008dd40d24682c7b96bc",9.317957166392093],[15750,"83b1b821f24b08b113bd2c2c06b54f345ae2bd14df55c83f02402df8c304586e",9.317957166392093],[7919,"cd6a40c37ef67f4888efda9ea68da956ecb8efc463fcaec246e6fc134f6a18cc",14.147138964577657],[11881,"6c4a4ceee7899e8c8ebe1518bebd99c96c19b45ceb354c8ebdd3816ccd3829b2",9.917710196779964],[15393,"1eeb60d73685d1d04fd160a2346a1c70a079eafdbc0fcf2dcd68f9c42d817076",9.317957166392093],[9878,"e48ec2a895296090f7a5bb84f1e914ea4bed80c5352a272f47b13009fa3417bf",9.917710196779964],[204,"033c1cf57327ab62a3ad092f00c8e46bd5418e8a7fb9b50a97fe1edcb13e98fe",9.917710196779964],[7879,"e33800b75a95ea8c09c05901f04a2a830a49bf2d0805ac11e98235231e6766cc",9.917710196779964],[10753,"035dde4febab242d1a516282d3bdc326ad6ae1fa67d3d65a842b227047baa4b9",9.917710196779964],[7148,"d4e943f146620d2894005379b15639f1c744b4a317cb67e50536516a9d8d08d1",9.917710196779964],[4157,"ca2590fb98f9ac8af4e7a5d9fbe22f180d518124d129d7f456a042f816cdade4",9.317957166392093],[17236,"12312d3788c7d3bcb936943748f8ebb1c882fcdfacb3a35f43cd480638ec294d",9.317957166392093],[74,"7d3fa2c8c4abcc3af834bffb2b13d661205c3cf866394a08a5b5c9107d9a82ff",9.917710196779964],[8685,"04d2365bf3da77b908feb5298574753df61fc366913374f46e66d024265dc6c6",9.917710196779964],[136,"2e4561b0041c848f085238210f403b56c17799f42677a65f4a695fa4fe0216ff",9.317957166392093],[2089,"265283d67fc3154a9bb48ed19ebc959cbf3c531ebe5da9017be8579156ed4bf2",9.917710196779964],[1625,"c7d62e03f8bf280741c463ef43273c49562e1b0adea55a390363d739a9276ff5",9.917710196779964],[13786,"535ac87912d217a30b55fc04d3e0527009fe90497b00c27e2b3234414e49a999",10.034187455573232],[11149,"f64a643f07012627126edd3d7fc3eb98d9b12098521c9f4f031232842f07f8b6",9.917710196779964],[19662,"0846a22e9d063823669e4605b75a6daf13584b70ac4f58eb73b5f9894619bf07",24.66609735269001],[16111,"d51b83ef20ea4c9b6fd6b94f56d80c71da7d37bd3772e17188c066fd48abbf65",9.317957166392093],[17428,"4fd8e8c0f0c0a2ddc37343fb766be60832a20d5871682e5a47c76cb759e92949",9.647446457990116],[7749,"01da9c3965f45f96696761411f20ed88ab17d0c4b0935f2fdfdf205d3b4c25cd",9.917710196779964],[12676,"007ddd8e371259246c4d0c461385d89c7eb9f36f65320b413138a623514dc0ac",9.917710196779964],[2103,"c803500cb061df9749e2f085b3aa5dc97f38133fab729df4b974354c3b5236f2",9.917710196779964],[3878,"c4a19e4d8b0211cbd8d6c13240f5da4e7eaf65c9ebc256d45140ce9eeb0482e6",9.917710196779964],[14824,"1ab06c3c16e242cf3bbd2386fb73ba7fb847b07867ee66c3d139ce5aa3395782",9.61451247165533],[2823,"849b7492ef0821dd477d6e146e56612784b8109b90595414b63ca306fd6389ed",9.917710196779964],[12751,"58b15b732338532ee0a2be0b6c3753e2e67ea278d031f6e0d670ec7f7c003cac",10.052724077328646],[12323,"9b468ccc17e8f4e4e3c672905f36868932651baf13abb97e71a20a6ad72713af",9.317957166392093],[8438,"8532a78d8f49cb7ca16bebfc2ac45d39c6dd404d06789deab1dcbfc3e87467c8",9.317957166392093],[12945,"7579822c46324c8b7e35ee9ec2400addd7004691da758905d6c25240d2def6aa",9.317957166392093],[7562,"d77f39f0a70105a282009bfa12eec7574b0caf4d834327a4d520cc4092d46ace",9.917710196779964],[7228,"8b8ce1a2bc8a01467416074d86e6fdb80410ccd4ba73d70bd8cf10ae54717ed0",9.917710196779964],[2397,"dd46c128603a4e58d4f861c06e3621a1284a5e8a46d264e86ce8540c3e7982f0",9.317957166392093],[11473,"d61e2e969d9ba4632f22425a62f80df7104d3693c3a4cd3f6eef087beb45b5b4",9.917710196779964],[8133,"ec6200d0a5d8cf36039de4cccb9cb193502513d43c28681652adcec6e0d780ca",9.317957166392093],[11505,"2cc6fcde57ece74ca6aa333f34295c3b2c713b582036f7be6c8d22d01a047ab4",9.917710196779964],[18237,"3fc05a7eda27dadacbb72798107ea0a8f9460df1a4f50d632d6722a73e424237",14.090909090909092],[5868,"feafd67de914d3906276be969d1968a9fff0b66954d3e1eda238214275afded9",9.917710196779964],[550,"f1571059d1e58d7dc53f63d7a39f6fce584cef48d714193cd994509db9d94afc",9.317957166392093],[7263,"43a16b3286c46bdfb29c0b607a817cf4c86d216b6596cd25bce426e717d93dd0",9.917710196779964],[439,"c55b0b07e920bf69a423ff06fcb3b0802ca692cec10c9fb2aa3f20bb047a1efd",9.917710196779964],[8651,"c4428465481e6f40abf7e98969a42165720cceeb6c9ac8956e9a1df9d8740cc7",9.317957166392093],[11388,"1c6f77ec79c95f19380f9cfafe9aeac1a7e52320c28c9a48d8a2835fa3976db5",9.917710196779964],[9822,"365ac94b4ca89d44ab3fb827f678a5b3c7074689389cae55a1c0e5ce9bca7ebf",10.052724077328646],[12310,"2d1ed9212795ec8a35a6e0d92689467a2671f2f1d6f9e16f9bfd0197cd922caf",9.917710196779964],[9182,"59ef54f91963fc352dd5bd3b8410fd1426d3031f31d906bd6bad27097a1f9ac3",9.917710196779964],[5457,"a84a517e734c81e2009a2fe5a4599eb6acada3e90f666a6fc6d3f8c3643573dc",10.052724077328646],[2874,"650e6dbf4dd41eedf1d39d3afc732525b980649efb42cbbae9cbd539190145ed",9.917710196779964],[8011,"5302a5df801fcc69dc323b0c94f1d4d2241575ae159bf38d3e45ee9f62f676cb",9.917710196779964],[16065,"20d3aed522573c41e4b665d2dc447215627c3949ec5085a933235b6c61f90f67",56.19512195121951],[10988,"e98bb090f6d7a6160f09983f7a09e5a02b9d348a613a6631f6247bc4ccc511b8",9.917710196779964],[8402,"60a08a4681ca0dc6a55b6ee4c2e28532400e93858d98573c8098494f8e1a97c8",9.917710196779964],[9599,"e78d1ae7752ac00bfcfd8cd45a45047daafb780f58065e149000d3a36a9506c1",9.917710196779964],[3345,"3da1b80d5089e6d851386bcdf79143bd0b98e2ffdeacce24c5e06f06c7a307ea",9.917710196779964],[11602,"880af74a5dafffc62c29968ef68a133feeeb9918f4e75fbfb44daad46180e5b3",9.917710196779964],[14186,"fe7aa0688dcb28a8d6823cf0defdafe78ad16823fcaf2c52be5dec614309ae90",9.317957166392093],[2208,"a0c48a366694aec445719aa7f2dd407812aa3716cd0d992f1c60aa1640f979f1",9.917710196779964],[14012,"84ed83a4d1466b987bd5934d4af3a2fd1e31ba4474c539533efaa866c93c8e94",27.900178253119428],[4353,"14f3868b195f528c7fad73c1811f0bdd5725bbea5f01e6624861357b9d9664e3",9.317957166392093],[9006,"d0e487db45786b66b17e8b0f89f3ada6f3f5e55e40e4b0b42a7dc319c048c2c4",9.917710196779964],[4196,"904526681b1a92252b6953d9e11c495c32ff760f7577e5b78705b813074471e4",9.917710196779964],[19043,"e3ffd4dbd1e70c1db3369c301d472ca8cf38cb6803c87812202efc6f32e5251f",9.647446457990116],[4191,"c4edb71e484f54cc2f16dca121eb5fd27522612cc0bc134841f89ff705e179e4",9.317957166392093],[18518,"32c2683d2ba7a03b7a420d3804d96fe3611536fd4179ba499de990d0a7941231",9.317957166392093],[15567,"c20b9727dccaec84dafc55e3e3801c5bb1ca413e15654d4fd01d329787e55b72",9.317957166392093],[13269,"6f7d193d60a2240faffda6fc8834ec6e015b1646f12cdfff9b0a1cefd0ae4da5",9.317957166392093],[7150,"6f6b20fd093db571f3295cec945d0ed6916831d75e17fc49396d91d228f604d1",9.917710196779964],[4704,"77cf0ef02189da84cb38dc3db80ad1263a401b21a3b00e095432b3d3a042fbe0",9.917710196779964],[3436,"75324807cfd5e243dfbc85931d07a6cc2dfb40a0fa3f791955cf5ed2d02a73e9",9.917710196779964],[19646,"7f2b04bef8e95a44ce9f737ef521be517a84ce613c45505420a61647de792208",9.317957166392093],[1540,"f2ef19ddaf96c1ef061a151f23d986bc9fd0d332893727a637483cc0e7a1e5f5",9.917710196779964],[8276,"6339763e7194518c9037f7d2bb0b2a36b1f76592582bd5f1c0de5cc9e8227ec9",9.917710196779964],[9371,"531018d081f26e6a2f3d8c74f6ec1448a2fbbe9c97c4cfcf5eff537d974168c2",9.917710196779964],[3018,"f3b31d6d1ff4b1cba0b8260446c5077a5d043afd5056328db491df56fd2325ec",9.317957166392093],[265,"7020be3695ace1f4260b89606ca999b7d40a7811795448f93beddb5472f927fe",9.317957166392093],[11285,"a127d86f5aeab6184ff2643310f2859508c4c57467260f6be0c6a62c0e1d21b6",9.917710196779964],[1544,"1c0622e54b1765e536b4d544e4d49bb1d2bbbb44b3bf452d25c56924dc68e0f5",9.917710196779964],[13360,"ab5e24c9405a9d10829cd38a5241b112bfd50c69fbd38863aa1760fcf4b543a3",9.317957166392093],[8292,"f399b4f74857fde89834ec275353b29141b6fe527d2127289139ac7998915ec9",9.317957166392093],[17978,"544525697a3555faffe1f6689d24ccdddc65288121c9db00452b00ffe0a5923d",9.317957166392093],[998,"1b20ff9963559d320ad593383ed9505531bb85b79949c76dfa0647c1af7340f9",26.115555555555556],[9298,"b7454d12366fbb690a0fd14e13e4a5920f783348c7bf8edd98c4dd7673bdd6c2",9.917710196779964],[18311,"2d66f1596a3bb6ed8a2818d22894907d5027343dcda68e454150cb3682eab635",9.360507246376812],[19319,"064392dc29120096ab200de98223a2b22b5a1d42c5e9b467410fb60bc6395d14",9.317957166392093],[4924,"3bf06e8c2ae7595101b0a53de5241a737f13084bd57b074f9f78469593d8b6df",9.917710196779964],[13915,"370feae118a27ac36c2cc7c1270ea30a6e6cf64d2d6cd59ebb5787fd7df3b396",9.317957166392093],[11745,"023056199b6d5c17955633c4e576ca8e968a77b3be8f89d481f57ca424240ab3",9.317957166392093],[3586,"32be49b1b298a57bf1ee5113ff314801b8176abdd71542e713000e56ace265e8",9.917710196779964],[4985,"f2290e6fc13aa269eb89d173c7560b1ec02e03dd5734db5bbedd38bde99648df",9.917710196779964],[17598,"8337577c6adb602d1e4f077b77200961c9ffe4e21ec3aea6cb74e0f4c09e3945",9.317957166392093],[8028,"b1a9282adae63567b378986360a15f0bf4e43f4c2cab09036fe6dc9c0ce45fcb",9.917710196779964],[13117,"cb0d03d72ebe29eedd3a345c5f47a738b536e2090fe2b391da008f8690f3aca8",9.317957166392093],[19632,"e91215885277973c9ca07b3973198e243e66ad33c000808cf77e02fd732f5f08",18.06896551724138],[17426,"72c61bf6c43daeb118031f046c72e8138597b124938c4c18f54962ec13bd3e49",40.16475972540046],[7765,"f602199b0981231c45d5c033c8c53e08de530bbc3668a7ddc6ff99c9d11e0dcd",9.917710196779964],[19784,"36fe21191d333c88b06d04625cae69fd7c57a067d1644d3d0703398ac2994903",9.317957166392093],[15817,"982a0ce80caec69d5c628b0d3a448fa60ec897492f8456395e42c0456e6f0b6d",40.78004535147392],[13082,"e273071b7542d5fc1bb132d11256152aa136be0a0d6712eca118b1e72994dea9",9.317957166392093],[3731,"b504aeee04a5d74bf02e855340065ffda8eca453774454e24b12e6ca14c666e7",9.917710196779964],[2083,"666571fb2cfe341bfac83e3d14f1723c9a6bdbc63b5c9d1f75eb96d7015759f2",9.917710196779964],[2274,"d7620abcbc32490acaea7ec547fa20c0118c3cad6f81099627093afd48e923f1",9.917710196779964],[10821,"d6775d5926e3af249735f8589abaa82b02a48fb3a037e572d18822c2de9729b9",9.317957166392093],[18080,"5fba41913f4076f95918f255a0bdcea349d205426c29a25309d7568e9177843b",9.317957166392093],[17101,"e1810df101efa11c6f2151a2b91124f0ff5d2f278f50f1fbbe457b303b1af84f",9.647446457990116],[11054,"1e100a6622bab405b3d44afef546f23c338815fb68d02aa0d555fadcf3a7a1b7",9.317957166392093],[264,"02b051a02b696ec44cf946fe4bee16c131f3c758cc627aa0482d3ada617b2dfe",9.917710196779964],[12967,"98b5f3746ea72a8bfd7b559c00d44c7b084a4ed7d90ad58ba43c408933cfc7aa",9.917710196779964],[10829,"fff10d5ab624d8610f3931edeee308c05d9cb24097998f0dda2dd49860351cb9",9.917710196779964],[5984,"3476392cbdfbe58bf495b0abb3c406183715412d30420b1ba9f97e5964da2fd9",9.917710196779964],[3028,"c427b5c6692abc439ff8e40c6753d2d76483a47d2d4ac16be618b51587381cec",9.917710196779964],[16288,"64c3098d74bad02712a36c49eabad185e5aff8d258608139a95bfd044a007861",9.317957166392093],[5542,"dd5debd71c961cc7136a1ebc9b4237b22ab9c68020f9a09160707bc08017f8db",9.917710196779964],[4413,"8bb1601df17af48113fa3c9c77414bd6917a09ea137a3f1a1279bb3b1fa5fae2",9.317957166392093],[19741,"3965aee69a57cb4139964be99b100a9a61024f42495c88941365bdc977ab5505",10.052724077328646],[15600,"7063ecfc7bdace6501806ebc9d6ad2fce76d701a1938428738ec0b0976bc6671",9.647446457990116],[15569,"037ae25fb9e66489845bb29f418b938cd657e4a83c49c040e5076405d23f5272",35.387900355871885],[3052,"5eb5d943f18e1dce4f25ffacc85c48ee62d05e36d96cd09cf7e5e5507433faeb",9.917710196779964],[16178,"839a124c15d5d073a7624294e7c309b8c9362a2e9d4baf2fc5d8318339996b64",28.933014354066987],[17331,"fc40e2a078792a101d1b2663f44bcf8117a82cb270b295612d4f76c9cd2e3f4b",9.317957166392093],[5568,"52f5ba0b9700b2ee097ff99e466baf6864c4bfe5c9c4d97cb9080774e58ed1db",9.917710196779964],[11756,"cacb355564ad255904ad9c9f5c9b7cd278bbe22f328016fba1d23d912cf7f3b2",9.917710196779964],[13371,"d88353a2a01cdeb5c7ef19c6d818700cfa05cb92e813620c27c664bf14d709a3",9.317957166392093],[1542,"e12539b9612dbcc4cdc93f240ee6e687c8e91da52672b5eb7bc435b0ab78e2f5",9.917710196779964],[17591,"3aab37132074564edf17159d7becb81e1725cde572222ac59bc88f898e425845",9.317957166392093],[5432,"58b85399e95100e0e3500df1df36c3cd344885f6364d9d02b6ae85122a8c94dc",9.917710196779964],[10343,"6216bbaeb0522c9d9c7138d19e9f98bf4459ec363189b61c7adcfb6eb09713bc",9.917710196779964],[1628,"99a6a3d840da59c8213dd67458adcee75b7d473062dfa2ebc6ffcc6f4e296cf5",9.917710196779964],[5304,"436754de8aa3cf34123eb6fff8fbfc3bbfb489db12b3a611e5bdcd1054315edd",9.917710196779964],[7378,"79da5e5c19f60f51bf75e8119987a8a38d3d0aa1f7b2c07bcdfb292a23a18ecf",9.917710196779964],[8178,"53b156ec45246b369a8d171c6136c37e8bd4dd394892e1b73e758b320d1e1dca",9.317957166392093],[8212,"d72c62a63653f626c47ec71d87fcd328dac34ea1fc38b29d3c46a1aed795e1c9",9.917710196779964],[9615,"4be55c2a455d6173c985aed8010390c7f3a8dd4779d25423b0012ea6ace2ecc0",9.917710196779964],[2829,"119647c65cecc98cb08d2db99c61d2172e8f728fa1ad22e3b9ec0a6a6f2480ed",9.917710196779964],[4470,"4cec26f9caa7a84b64c045c43cb917bb4074f036f3774da326bd9cf413e89be2",9.917710196779964],[19508,"e0ef1244f672c00061268e505378fd551be59cfd898d5477f7b9b2e97e13030e",9.317957166392093],[7237,"ff9abdde20db9510b36880d337aef702d0876532d47c3ed8962a9f86233e76d0",9.917710196779964],[17894,"6553d05f4ecf3e6bbfe2ac55efeeab418aee107280a0a8113c69cb8110d35c3f",12.23873873873874],[13425,"2cae75f876dc2883da5d20910853f42668c9dec4f2208cfe45c5ce2375fbe7a1",9.317957166392093],[2596,"17b90b2c03952c4c31d7f83230af053b8dc82c05f3941ce61e2630dcc4772eef",9.917710196779964],[3886,"69311c32ee55c216fb94bc2cee4bf717c1bd0c9b8077901944165c81e0ef72e6",9.917710196779964],[17575,"3126303edf48eba5bdc45c5663b644b2d15f38cc75c45acdc4c34a935b00c745",9.317957166392093],[14948,"731455d3215330465cb521b7281dfcaa47cc6abf05c7b9efbf9dda2b3302dd7f",20.07662835249042],[516,"139e480c7a21ee41f60ba453dd4fb1dd38c2d8e6fa44c9a7fea237bae34e95fc",9.917710196779964],[9187,"6d41866b60b38929551f83b4ede950b96529953b874704154a180f1d4c3f94c3",9.917710196779964],[1153,"3521d952122b58b66d80ab85a2aba462d93c6a1caba104703fbdf78124bd47f8",9.917710196779964],[10519,"6bdbc0ea3a025129c7fbda6a47e91450f29b4b71a8f9b6342655c35ec6d514bb",9.317957166392093],[3771,"b56fedc4221abff4d195ba3c363eea9e7cc662cf31f3678cddbe89a7c2a523e7",9.317957166392093],[16856,"9c342bf377119262a5042636375de037573ac473b825f10261524be912032b55",9.317957166392093],[19316,"d5e022b441cc2293075faa96c3d9187253ca2179feb32a531980937cc5357514",9.317957166392093],[4329,"0775bf81079953e6cb9390568e359ab0faf1f585ff2cc41bea100e30501b95e3",9.917710196779964],[166,"fb8082d75e130db5b647e80b1380a2113e4d9ea78d986b55ea83bd9e477de0fe",9.917710196779964],[9015,"954bb3884b78f437d12f746f8203a1966ee07ef3bba94cba58fc46f1422aa8c4",9.917710196779964],[7554,"dc0c00ddeb46c89609dd76e63cc52cb7eb62b81ee5a52c4a183d58068e8977ce",9.917710196779964],[11755,"b82259119d185b047590efffbfdf00af2eb0272e7e6e5d51a3d7381cd7d7f5b2",9.917710196779964],[5404,"7afc9d609a901ff88ee39d4df08c851f22f3af76adf54eb30d80cb94775fcadc",9.917710196779964],[3906,"0ba5c45eed2ce2690d5e17bf199bc2bab3ad19c7501f145fa243a083cc5b53e6",9.917710196779964],[3156,"f095f71af92f83e47fbfa8b2567a5531110671eba3abd2678d520154fc8554eb",9.317957166392093],[7698,"bf9669422d734f23a13ba693bff1fb4de199ca8fa238d727351f3ec8bfa68dcd",9.917710196779964],[5127,"4c76e2841ea1b19fe280dab341b63bac64277002e6d20c05c19c437d3e626ede",9.917710196779964],[8241,"738a91498cfd41a85e20e45ae244bd2f8f7a6006461cd45e5229f026c409b0c9",9.917710196779964],[460,"5b98f911c57d91365447670020b5908bebeb8de26556ae06f18f4226ec88ebfc",9.917710196779964],[1973,"2ff57c6ad5ec4b69c9d31a604009f0a27aedb33d8bedab3b977dc95702fa2df3",9.917710196779964],[11216,"68265a0bc9d6d26e5033f0cbb5394ef301f70e2cb19ee0d9fee565c11cc498b6",9.917710196779964],[11056,"5824538d6d738c30e3b2a0e24c18ec750197e8c85d7e0e5694c7a9ed1f279fb7",9.917710196779964],[7163,"88ec96cbe59be965413c324105abb3dbd2a9db165a5ce9dc1890c7780809efd0",9.917710196779964],[15924,"5e2faf2420287443bc77beef4e904c71f6a38938b322d74123da25d0b619a06a",9.317957166392093],[16388,"1307ad748aa8ffc09e572414dcbeb333a82d959e777a5bd7d80633f039f6495f",9.317957166392093],[7097,"7acbaa2dae5b23da2506decc29e3e17fd497b883237052e52a7fef720eff5dd1",9.917710196779964],[8268,"7e01a0dd54ecee0acea68104272648c8836e6fc09691c2e1138a4a87581f85c9",9.317957166392093],[2546,"4a851f2e19996d58c7adadce9bc9007b1a68532653a2934d67676c35681a8eef",9.917710196779964],[13695,"d93477a892a6fcda44e583b7f9c502eabda9d4d126730714ecdc1cdcfbe5539b",9.317957166392093],[3321,"1746b56cb0c0e9f87af3e06d9bf427456fc79dff550c689fde305ea0aaa23aea",9.917710196779964],[184,"9ad52fe7850bccaedf97788faecc78c61095f78922aee36e551e9455b50ec7fe",9.917710196779964],[13716,"187a40e60b835ad9c67d0f48726f4ea3426a8ddedf497f76f3c016a04699079b",22.31578947368421],[15243,"2655ef8869bb53da29dda68a5fe93a3b3f308d7abfb60a709337abfc1e979379",9.317957166392093],[3223,"f2b68b6b88bf5676b6ab62098f371157af5f43ffeb1359b6a8a7a0c35ea2ecea",9.917710196779964],[6257,"8d2bdab00cf9bca9ef4dc5cac475848e0df088e3ab70ba231bdbd5445b535bd7",9.647446457990116],[18667,"70ab26494f50a901172426356921d63faa3406faf7db9e521b1c4c14be37fb2b",9.317957166392093],[16396,"6400927336d1d324c8dcac4e0e2611817f14fe9174245ff84985465256c6275f",9.317957166392093],[18163,"3a70e9a4d121c37a397f05a12485d75ea86bf31fab6f624cce1c70a9e8991439",9.317957166392093],[7311,"fa7195e46e0fc63db24357323154cb9adb084ce553c01bb29604787fc788fecf",9.917710196779964],[16565,"d30470e7b6c15ece6e73691fc744cc59b543cc4fdb7893ba26857655475ecc5b",10.052724077328646],[17571,"4190c87c0d59aa83cde41abdfb471de74300c92b3b68910382b129c598a9dd45",9.317957166392093],[7047,"5525bbd07fed7c01cba7c27ba386a5449296e8def33dfaffe801634cf028b1d1",9.917710196779964],[4991,"40f4e6ea416989bddc9a1d1502117b3bb9987fcd4cf833563db11bf5a0e53edf",9.917710196779964],[12002,"537b7375a74b39c47d4a0b9ddbb30db5d6ba8b0d859bc77de23a31939c3c4db1",9.917710196779964],[12364,"bfcfd51d920c2c1522ffa45f661c452a6f183b59c72864ff3d7c1eb7e363d5ae",9.917710196779964],[3522,"45bcb94976746bc9aadb8045e5b09b3513094966c6b147ff6882b60a2eddcfe8",9.317957166392093],[675,"b7f18cda12d09df7fa79fff88a8853a4b5b9303025de466ca1efcc6179ed65fb",40.02826855123675],[14563,"5a38b4202c8b913c07a7c0aa285ce583746be86e7195eecf6d575479c9afd387",9.317957166392093],[2024,"90f9545d4b68145666a0cde585130e301143e1892fcf6edfea14398909b0cbf2",9.917710196779964],[343,"34bc5d79eabfe363adfcf0b42030acc5d08729f0349d87d22ca608d42a8bc1fd",9.917710196779964],[6398,"4db5e6442b7f666c5c31da3782f443421f0168f41d617fb47ddcb3ecb83a5bd6",9.317957166392093],[13905,"c0bc074d6a30aab99a339972fb422b073092cb31f046851ee15f7f3c583eeb96",9.317957166392093],[6707,"473a02de6c010f09547ca840eea07177a5af63376b0e867eec76dfc159c9e7d3",9.917710196779964],[8727,"3fe40cc287c863a67fb82b50891e78cbdd4b5baeaf9c89a50e555792473e87c6",9.317957166392093],[6882,"bac809be76abd9d2cf591a1c37c4fc50e319e7039bc3c189e685d023c5dcb8d2",9.917710196779964],[12508,"b3272c4c5e02690296266a26909e5d1ee3078c12e5c640f597ee2f0fdb53ebad",9.917710196779964],[5244,"9486407bbe5387522564b9f099c3defb001d6e755bfbc0d33915d9ffbfe4b7dd",9.917710196779964],[2667,"72d6fa6e0e7b6ca9ca48eeaf07bbb6407f4d2f13f869e1ed55dce806d863b9ee",9.917710196779964],[12665,"604a0d8a3d52c524efd06907f4bca5ac2782e55a11d1f6a41c610d4b1489d3ac",9.317957166392093],[1807,"a0bd6bfa9989d70f32baa3f527126daeadb00e086941217825926c7c1a762ef4",12.252121212121212],[19587,"d50e68fb5df5a7873e9a940d92e27d9e63b68d976e66c5c287f3cb2bcc2da00a",9.317957166392093],[7490,"a1835d5b8915a3b1e300e5d11f6405e8d8c1acc57b5b4675481d88eab89bcbce",9.917710196779964],[11456,"a38c47610ac0846b18cea66371cb172433f1ecd44e3134979b03298dbcfee2b4",9.917710196779964],[9656,"caa5a59db2031d8c18d683691a54454dd2e47d51211f5ded94a5dee6aacfa9c0",9.917710196779964],[11666,"ed610fa7b3174d6d62349485c3ae87448b383a7a9a7726e0abc807a135d77cb3",9.917710196779964],[16629,"9d9718955051c7ef3def7c45fca1186a381fb5e0e0908ce0571f11b1f3982e5a",9.647446457990116],[16512,"e5fd23db6031046f0ef2f37e27b376f95b9773e395ada5a2d9ea63d946f3f05c",9.317957166392093],[9667,"23be6d3d624ec4b305a8b9330c22d53ae9b906f521ee937eb7af64e1ab6397c0",9.917710196779964],[1506,"6b7a3cb133733babd2c115436967a037a707ac06d7d685b606840c9171a911f6",16.035555555555554],[6521,"7aeda2384133759a6f7a9d12d5a9a9ea6c12cb37b106798e3a3b4884790645d5",9.917710196779964],[2923,"e91b5853b467e89f960415f8d01ad55d4d595da7e62a11b2c12e651c824ce8ec",9.917710196779964],[19384,"d7e2ac0b2f62082b8a04e006fbd32af064b1bc7c91e20ec31dcd28200ade8812",9.317957166392093],[18171,"293556e79e638f49c2e305cf5a1857af2c70031b65c8cfd39d9363b1ec8fe938",9.317957166392093],[274,"c81a6e6f01eeac7530b8b20bb4e427be397d673ce7ddbc776e2e894cccbf1efe",9.317957166392093],[18939,"74a205982d1cafc02f3432f07dba0a539db2415f5c6bff23b2b36e3e4d076e22",14.931818181818182],[4153,"89592fdf9604bdd7dcdd69d658f9b8867f3b6aa6c0f0909205a5fa2f2308b5e4",9.917710196779964],[2366,"9cd51837eb4293f5d0aca6d333387bc80edaceb994bd20e1bbd8cb140818abf0",9.917710196779964],[13430,"dba0d22a41293fba441f114c4f84f07325a7b185d8b7c7cd5569b14cf4c0d1a1",9.647446457990116],[14551,"85b67326878a24f9fdc3a61e6658d0ff0ec95bb4e83ca85c4ff95f9197f01e88",33.44127708095781],[19624,"44ca8fe08f807f803d9a68700f39f9e35967dc56adbccbdffe77f1a37d57c308",9.647446457990116],[15844,"bd4163be9768f9e4f4fc0b1febc886fec1c490f500ff23e7ada6090862036a6c",9.317957166392093],[16859,"4cd2f449a88813c69a3ada1d858c597efccb3bcedeb679953dab3e381ff72055",9.317957166392093],[10521,"32806768b074d55a96a12e9ab8fbb328b41a9db923087c21a3ab23ada86113bb",9.917710196779964],[7457,"ccc147c9e6e3f34ddc5460b10197858539ce39e38ddcaecd800187895b0308cf",9.917710196779964],[15431,"03378b53351e2ef86d44e173d79871836c44d686808f4241b27b8558f7539e75",9.317957166392093],[6562,"aff01da64fb3686dcef34c8836d4d5bd4975c94a36d5c5f413bf6c95d177efd4",9.917710196779964],[8369,"012abaadffc8ca422d19f16fe5bd1d06756dfd444aeeb92119668128e0fdd4c8",9.917710196779964],[14864,"a747a0eb716ca82a29199934e86ae422186eda268bc4c2d5a8acc8a666417d81",9.317957166392093],[4325,"7eaa56b26d661ba95bb83bc4509343b4393b4ad4bd451aee54240f63c2f09ce3",9.917710196779964],[1829,"f6fecad5d8ef6ce74e797d41ddc6e68e4f62563083c2671f78b174160b4410f4",9.917710196779964],[14116,"55c8f9bf5b667892500abc6fcb68240ff1ca2db0aca107d660f600a228943592",9.317957166392093],[3083,"ff0f98e133ac8ddf4497fab1617893f69c9707491cf5df090a3733484f8ec2eb",9.917710196779964],[17325,"c80fdbc8c91af94d457fff2f5a339305e66f3ede092c9f449fcb1f92ea96644b",9.317957166392093],[19259,"e573bb97a835591493674a8224786f93acbe2cd77aa0ec363a7e847e15b15a16",9.317957166392093],[15894,"d21fd23976ac31ab54de26e0796eb5c78568f5676abc0441a50a9f7060741a6b",9.317957166392093],[12238,"f14ddfed6f7f4b51d389056db134db8c7aea805a8853a3d6124cd18c2cc2bdaf",9.317957166392093],[10173,"537b845a44314ea83e81c6edf41c3caee38df0ae7ba21ee79e5f306756e13abd",9.917710196779964],[4678,"b7d6e0d5d302201e72386e14207afde60422233655aef7df43a2cb42c4781fe1",9.917710196779964],[14387,"6f58d7067b085ead8cbeddb23d2b7cb6277a14f2862b581ab10a24f47c7f908b",14.95187165775401],[7528,"19905dae14b2b8f213d8ea1ea323fb996bdebf2842a53ffcee9b3b3f38b798ce",9.917710196779964],[1365,"69abb2f2dd1c05571ccd97fab522574a19aa2749747a1e8fdf4882062b66f9f6",9.317957166392093],[3746,"642dec5553480366aec04e97fc97e1a8725f07400bdb9a67b814bc60726146e7",27.486486486486488],[8750,"2586559446ff81fd219c2f2a5fe78a2caf08ceee507895c4b916d064687c5dc6",9.917710196779964],[8583,"0e88c47196c6f1426123742a233becbbdc234385b3a3a2f60426737c7a9587c7",9.317957166392093],[18499,"c2178c32e78d66f3c59f6848f425da242d1b12b7d0e178788b2df4a8b3ca6c31",9.317957166392093],[9440,"600ef4c59f1fa3edbf5b6a8ab6324a3d774d60dee0bf45e2e53474c5bdfb13c2",9.317957166392093],[11314,"62a873c851e1882589cb667bb9efb2fd6a540c31b70c3451a3d0eee52ab2e9b5",9.917710196779964],[2272,"5f8e7ade542baf17aa2b5c8dca7c68007496d6ac4624d3646fa9ca8fba9f24f1",9.917710196779964],[15757,"210b059219056bd70bce2c008cf346e4d7711d7aa68ae334b6e65f02ef9c426e",9.317957166392093],[1512,"286fbebf5c393704cf289c6c29da1faad3a3a46fc7737d2b8f62be8fff860bf6",9.917710196779964],[14849,"d994bd8792203bea26e1d4d29a5183244fbffd6b8e9488cfe6cebae7a10ef881",9.317957166392093],[12993,"6e9559655868ef369fa5370952e18e6d84a2165f3fdad5554e5e5674e84da8aa",9.917710196779964],[16416,"d235c5a85f4e40055c3445e730e99fc74e70f7e35324623e7f8fa4e11211c25e",9.317957166392093],[4999,"4b080c7ee1edda15781c0dd688e7ecccdf5b92395b53a3f9047bff1709ae31df",9.997888067581837],[117,"ec45dc6dc8086aaac67b2a1f244a29c59f9689414d8563f7ee3b58aa358d47ff",9.917710196779964],[10508,"4f10a66e766d66ffb516b5da2b12da4ee1f251e5b05cf3f83f332ba43fbc22bb",9.917710196779964],[11143,"0bd83f8529b6c6224bec40dd68aba569f24527b94384e96e63aec84a9e9e01b7",9.917710196779964],[11404,"522d39c1b7ff252ceb12d15afd75c8da745a3faae2c4934175d04958e66452b5",9.917710196779964],[18965,"f7c3b6c85a00002c3ff9e70288c20e1126fee5a10100f517c9128aaf4f4ba421",35.02880658436214],[14996,"3a1825ccd7500585bdebbc4f96520a086eaf738d327250939ac71c76a574967e",9.317957166392093],[11712,"f63292f222554c5e6df9a28a1a69fafc11e98bd700c146ca0383addc27043bb3",9.917710196779964],[5834,"7283e0e53b0a9a8916ed634bddee8e7cc9fd24777eedcf75a332d0f0bc681fda",9.917710196779964],[2142,"5e70e57036601d000f53c892d6397d4bd76ca8b4bb6a7761815d58815579faf1",9.917710196779964],[9103,"dd642c8537ff24c00c6fb6d65d4f13797de987c74e101b8e3098b53aa9e928c4",9.917710196779964],[13061,"d229b4733bc0041994e07197d4e6033a7cf3b82f6e54d67a12b30c5270ac39aa",9.917710196779964],[10392,"694a9f510f1fee40c9b5ecf1f790f35d7237525cbad95a894ea15e279b85d8bb",9.917710196779964],[9275,"ee9e5b2da68d2d37c05acc9b2f4fc65f044791a7afff08ea52ebe224f604f7c2",9.917710196779964],[13487,"5f9e9cd8887a700cf64fc6da4de532f07144affdcad16457817bf7663d852aa0",9.317957166392093],[2992,"188f3ec6b102707be9b526dc99df0b2af919b78d3779f11caf09d443c9d156ec",9.917710196779964],[2708,"367e7c91f411979f20a893d3f806096bbeb15740ab96e299544d88c8de3866ee",15.92434988179669],[17982,"4e308079be7d7599c810e52036c3f549c1e38ab087a9165561b3b185e8917d3d",9.317957166392093],[8691,"13bc81d17e4b3d1859db2e6771249b3222c0b4bcd8e4326635327a779710bcc6",9.917710196779964],[10627,"df7583a963132aaa7855c0b0f7bb16e2f994f6a59c6cf5356cdb2243246184ba",9.917710196779964],[12681,"ebc7be23c18428725e6d42704c400b463ffb07c91a7d6c266c7caabe68b2b5ac",9.917710196779964],[19615,"289b97f93ebf94da985fb4614ad82a859e537c50619fe716b1584d258b264909",9.317957166392093],[11141,"50746a0eeb0d2761d40f9690e5c463b15ef307b7b661df23d5dd7b72d98503b7",9.917710196779964],[6824,"39a41edc9f2b0d29e5b6741182cd53f1292a344e3f22c0ded47ee056ddde1ad3",9.917710196779964],[8036,"e50804e47bae973a08f4eece12f4b5f02557a934930e47194ad2406c195b56cb",9.917710196779964],[16538,"c706261f25cc793ba10a54a45bf755f31b1263b68b47bb1266aef21aeb7b5a5c",9.317957166392093],[17266,"88512db88131b85c4b206df8e78b5d02a43f7bd3597874d6a048d91dec15d54c",9.317957166392093],[7394,"050327d052d807f4551bb8d67c899b3b9982a527fca3708b8ff975f009ed76cf",9.917710196779964],[13410,"44b1fa69786ae62caf71e9f9ca11d65444c088f252fdb4b1e1bde926f51118a2",15.91459074733096],[252,"e8ac99f0c6a703bf8c6e050e0c21f6bd24d91ec2f9d2ec48bcf8decbb4ab4afe",9.917710196779964],[4997,"1df5e25fef9c5fdbe1d9e4daf318c5ff1c0851fe490a14870641bc5f15b733df",9.917710196779964],[11722,"ef79ac2a4dfae38729ab896980866eea7597336a883e326eb063b62d0b0528b3",9.917710196779964],[11498,"026fb3ea7c8edd1175002f548c39a7ddb4562ff824d32e8da8c384671eb488b4",138.68092691622104],[1380,"ecbd2a9aa11c1014f5bb67cefc22f8d6e5d530f889498707b3100730d126e1f6",9.917710196779964],[15760,"2c4ba354f5055f3d6ac99f8fe363c85d334f73519dd6bca1e30df4c7362d386e",9.317957166392093],[17031,"18ece5a99c19c89056c84982af8ea38c9c04d27d655388c44e4a56edbc155c51",9.317957166392093],[16516,"16e221c91e61a19b9a3a0716121eae31f41d94d5d17f528dc1b27c4ff3aae35c",9.317957166392093],[2423,"72d8cea8f7b47b3c2598c4070a1946c00db14f8aa63aea70759578d0153154f0",9.317957166392093],[5253,"53e0c681bafd85c8bf250d3b681e8a45d1222af779e17bce752e133f0b1db1dd",9.917710196779964],[1798,"94f0ee3b5a418af248c22d4fb9cc59e81cbc578892b27205c063356bcbfd44f4",9.917710196779964],[6024,"768236163d8469d2081d3628982bc706fca7cc1aedc21f8ffd74f50e88f1e9d8",9.917710196779964],[17728,"f2a4701385e99156620fa467645c58d34f3c21681147175933b0fdfb1f99a742",28.097560975609756],[1249,"cb793cd3d605b34512f81fc5d25d6169105e7f692bfdcbbc8b28c4d37c4fb1f7",9.917710196779964],[1939,"031c77e167ad54d342de332cb81b6e748ce97721e27d883c498c1fc98b9e6ef3",9.317957166392093],[6805,"b7548716112e64416832aaa6e0c61844190f69b41c76b5953721824735e339d3",9.917710196779964],[6268,"55e24aae8712588ceb5f825cd86f654262a06c465d68f013a839fc3c3cbe4ad7",9.917710196779964],[4558,"e5c853f0b3d336ec655f365cabcf16b0940ecbbe0fb80c78318463041dc0eae1",9.917710196779964],[15040,"da97b663cc209d8d4d001ec19ecbde21469add6df1170aa66abc2a4b05f9b77d",9.317957166392093],[3356,"6c2dc196be96b194200b218cdfd993f6cdd74af14361208ed39251eabe2bfee9",9.917710196779964],[8905,"d774bfb4e55744ffad616072cc1b7b1b81a1d0143410f706db3b5173fc306dc5",9.917710196779964],[19440,"11c080b43f16c5c14fa06f3d3144370c2c3c3cc23282f64b4b329d992dc02410",9.317957166392093],[19082,"7c74d24a92f6405803eb29856be8ecd1014e5bdc1ca9695944e7076121ab891d",16.968325791855204],[667,"1930119ef0b86b75b8ba36d91584b70aca8516b986c299e0e6555d84a69773fb",9.317957166392093],[11261,"b51a67fbb15b9ee471683182497471e479b6e2cab5a539bee10ffb82022a47b6",9.917710196779964],[2457,"14c54ca99f04f2b8483c9f18fffcdf086f5a1ad50b1ad306d3d280bb773e24f0",10.052724077328646],[5701,"87dd4e6e8671655fa70c68157145e86950293e0c15f0feac168b324f9b3f0adb",9.917710196779964],[14470,"0ce4abf3f516799a4efd1973ea5f36a59c340e598ece4e734e4faff4b620df89",9.637172758800602],[6895,"395ba184dd211ede5c2818d3e9c8dcf89a7af20ac1ee5e0ac3d26e683139a8d2",9.917710196779964],[4451,"b1455876736fe74e8d9ecd748313232c307142a85a382804432f523e921cbce2",9.647446457990116],[10438,"986179fd8b23d25319be52f33a6d5890f84db4c72244a371f3e4f45612348bbb",9.917710196779964],[15404,"2a5bb540319157e12a3f4fa0c0961892f4e5072ebc8f2622e341599b2f9d4276",9.317957166392093],[7828,"c3489927fc2851bc8ee619ac1694cde427786ffdb85e7845d09825c3749f97cc",9.917710196779964],[11053,"d64dcc014aa412722644450623dbc6361252a0008e5880a3bbeb4b26cd79a4b7",9.317957166392093],[2075,"03a9f288f858afcbed3a9187c13b53ebef74b4f8ff734bdd9bd018a183b668f2",9.317957166392093],[15249,"948d9473250dae905d2811a4b90f738f58442ea2ebe4f3945e06ab5d1e637479",9.317957166392093],[5703,"f1b6bca0188e06cbf38f5c999abc7dc4b5a67def8aebb8794c5be83082ee08db",9.917710196779964],[12188,"d92ecb5c7c72abb125c4f78aa209fa8ce319f561c97e476657edd86aebd325b0",9.917710196779964],[9465,"80c8dd752a9427c83a1e5c5d5208c2c6a0d39fa259bf991c24a1fc1dac12f0c1",9.317957166392093],[5943,"7b5c3581b2d4d7ff0bfa908c16a23aa1f10caf39214e756e5b84cdf3d8af6dd9",9.317957166392093],[16145,"7b262fc1dfd84fd6fdb757f883c893de5e4a8fd63823f45f542341c847d01b65",19],[10650,"b736d84916ea5033bcbbf1ba25016d3ca6475f3e80c444e8d46d5620055861ba",9.917710196779964],[3404,"f2e294c04313f3dcd6ee636a2a2ba6d1d4f43f83615c039da62c56c5d93eace9",9.917710196779964],[15842,"40963a08b263561302192c39b31f1ad8ce8c1ad7fb45ff36d2d8a0ea4b467e6c",9.317957166392093],[19863,"a9c2a4f2625a8fafe26e4a6984d997fb9cbe20df47d9ce64196eae7dd5d27000",9.317957166392093],[1451,"7cdd1fbd17c44a2d85e50c0dfb009fd58211de4b122a9da15318183506057ff6",9.917710196779964],[18617,"b5392cca4d4c525d2261db220917d7236ab824a4a372bc80b8966b81436b3d2e",9.317957166392093],[4496,"01cbea7392b63249bb1bdc7db9c61222b02801df04eca69e935e3633dc8a6ce2",9.917710196779964],[17604,"14ccb074c2a870b1373713fa2ec48c0a3f066a08c4042b839a3a3259b3abfd44",10],[9411,"4090406e5a16a798f2c425b97f50a948de7b49450510f6c10b433e9cef4e3cc2",45.02173913043478],[18694,"6e906bae476d7c007db9739ec309934d78ce91523d8948968326d31188e2942a",9.647446457990116],[15303,"c7d039c27ff30d0733d493108772da47687b64c307cd44007c0bb3ad0f905578",9.317957166392093],[5313,"b8e0d19d8702b35181640dc0bd9e8bf61bc53ba98cac2d5685c359c6571e4fdd",9.917710196779964],[19449,"f33bf8cef9cc328df0adcc9f8782535a89ef8859ad3ea52db1e06d117b6ee50f",9.317957166392093],[16907,"8b71c37e56fa0f42cfcb945cb1c45cfcb98bb8589dbde6ff6134cc8b78affe53",9.317957166392093],[8889,"20f86490ab67732d30de8babf00225a5b74e369f44135eca0a9ed6b8fbbf7bc5",9.917710196779964],[6273,"586719e2431336adc0033c0f73cb49d5bff636c39f558ff8423e29703e9844d7",9.917710196779964],[11071,"0b3cd45cce8a83b76d34dda3df9afb7195c8b085a2d765c7c10f297d85bf86b7",9.317957166392093],[3227,"8c0bf350543b76bd3a075108def97c3438373124cab1b5549b8186060eade3ea",9.917710196779964],[19626,"46406270b90c084b2937763eef8e0717bb563e6805191d92fc49fa942a8fa008",37.93594306049822],[9422,"2fa4ae1a5275b13f68a0a55e27de2a410af5806794da1b894e5ab61388702ec2",9.317957166392093],[16305,"c27862bd84dc9b1ffab0bbd460d9a9e6897fa8759ea5fadbb1ba87ae17870461",9.317957166392093],[9463,"cac7ad7891fde188fe7a1bbb1f061e8245d1e30b65a888f833dd6a7ce75bf3c1",9.917710196779964],[14175,"331dd355649847449ed334761a6d01ebf8fd73d14f749e07004f195b6b6be690",9.647446457990116],[16172,"406223d3dd71b0a8888a1acfcbdaae33fe3f5434545e09a25b0ac0fb12ff8664",71.301247771836],[7255,"20434b4bf683150bb1cae5dcd1d1d03205c9acb3f5920b28f6d28835a2fb56d0",9.917710196779964],[3251,"008f533062f027ae66b2a83138b686cfbc19043dbfa5003f3603cfaf9cb4a6ea",9.917710196779964],[4684,"bbf3208dbe114d855f6f94342949796717a95a736f04fb2972268905362a1ae1",9.917710196779964],[5674,"b1615aa2fbbac5289f27042a5fe82817882fcd72f21c74b175177ef216882ddb",9.917710196779964],[4937,"ab805a12fef1177b9ab547406eb05baf5c6e8cc7bc5025ad31a5192f351e97df",9.917710196779964],[2145,"8ca998833f42d0d780be1fd90ecd8fa6ff16f773b7a64c81f4f0527d72a3f2f1",9.917710196779964],[5122,"2cb7c1e37d5032fd96fc6ba2b6e3353030b156067ef98cba337fef06341876de",9.917710196779964],[8719,"b9d230b9eb14d3cfa36328b4e9e2df115efcf0f27865e94b70d6059465d690c6",9.917710196779964],[5147,"28c8399e410fa5ab5245331f5a89dce0bcc111f0bc5dbe00e496740bf44d52de",34.26086956521739],[18360,"085fa05b18fd64a1666e86f732ee26ba2545ad1789058f673afe1e672bfe7f34",9.317957166392093],[15646,"074093136a5027773cff49c6056ff1e34f439d8f89165d6be0cb5a5bc1c77070",9.317957166392093],[3990,"d75c19158b90feee7ee97d889a3e632870a10b6a9f577fe5110624e382ffc6e5",9.917710196779964],[14925,"e5adec09cac7cb501fc18d68802f6a3356285cf8f4cd6ceb6ff5d3daa7b77080",9.317957166392093],[4136,"b62ee60564ae8022649deabdc1eecdc368e625a51df0dda1b9fede7f2a07d2e4",9.917710196779964],[1333,"0c68e97a107f0526a949c6c810b4f1acbc502e6da7880def61fd879834db30f7",9.317957166392093],[319,"f4d43a175d806e4215a9fa562470b11cfd9dc12b3600bb1a4b221bc9a87ae5fd",9.317957166392093],[16992,"3cd8d7e31e48d81e5ed058e05338d94f381c99ae573ef96cd9c1dc6044d23952",9.317957166392093],[8232,"39f539b9938ed4d2f72b77b362f2a39f20c6f56b46521801845073c89a2dbcc9",9.917710196779964],[3872,"71d1918b0bf05a3e2891ead63f8e445fe62802819d624404407e5601ca9e8de6",9.917710196779964],[415,"d39a3e8b40a992f73a3ca3c1d7871416b87ff9745d1795c6dd831c9d19fe45fd",9.917710196779964],[15419,"706b55b665527e9e7b3acc1f1e80b28d4f14f2b3046ef2516af9f69d1c5eed75",9.317957166392093],[6852,"e8eb4917f19305aacd17d96609fbc2d88a13f2fc85c10e976ee74879437df8d2",21.057471264367816],[5130,"c2f99b6ee5e28568fe57529db9856c94e1465f445ad03cc944274019f1946cde",9.917710196779964],[19147,"645e1f657cf8896fdec0cc7939472c3fbea24818feba778c0c28b428dc1c981a",9.317957166392093],[16136,"97e4fb82c8d06cf2a4cd65665e4f5ce0b635720fa2f5b49cc35b17c864b94965",9.317957166392093],[15315,"0133bf6442da90887685b4e9cd6e6190b42da9b8cba434b59599a97a16b80478",9.317957166392093],[13246,"97518da2854f4c151fa1956c850b222dc607a638122c5f8360efd590ab2ceaa5",9.647446457990116],[2206,"5ff2b00f5c3f7df1d181d6151a9ba503a0898cc78894677da90e3b438e607bf1",9.917710196779964],[16588,"aa826fd7b9c045932fb833fddcc19183dafa8d37b0098bd639d05e1c564f3b5b",9.317957166392093],[15764,"f393e383c1123e8d9ee438c61409e9ac816a693af77739632575139c21b9186e",33.721254355400696],[2420,"bbbab8c503ba3508c4111c060bf26e641bb3df2b48f479f5482ed2e75e9f56f0",9.647446457990116],[10002,"4b8b0c55715e2d0492d9a0042ef7496302df5c6b9e2a50113b2fb92153a051be",9.917710196779964],[12763,"3542b9c592bd2c71a558644d83fae80f363f69e5ed1e9af4314f1710d55425ac",9.917710196779964],[10818,"30d7d9c71607aad9a8bcaad542953dd4bf32ed84ab2037912bc87acfbe102eb9",9.917710196779964],[5437,"a3f2c730667c849a4444b0456f772f2845cee3d2753fabef14ea175bb06a8bdc",9.317957166392093],[15996,"aa8f3508737a85485052a2b2939705c98f589f72d7059ebce68745b081f29168",30.16042780748663],[11499,"a6aba40d8dd16df3413bf23db68cb04ed75741a285ff122a2c77588c1aae87b4",9.917710196779964],[213,"85cdacaa5d4104ee031a018f6e5fda738e06569c2fff61b5298144fc68278dfe",9.917710196779964],[17491,"6245641e6c248b16298ed80ccc4fd8e81553a4b232dcc039660f07ea44bacb47",9.317957166392093],[4620,"2ca70aa8524a39b8c0bb9ad38616189b5bf15ea2a9999ac72eef447a0f0e7ce1",9.317957166392093],[3133,"e8e16ff081bb3dbc400d732d37e2285052d57a72f0328f81b8bbcd197c3375eb",9.917710196779964],[2117,"f1608c4a97d46f0b683b769239376a00dc7e41885f8028017a3ccb3ddfc91ff2",9.317957166392093],[9574,"134cc4884af0e51d704a3ebc3a6fb90fc5bd681a2735115c7dc7faa6388c29c1",9.317957166392093],[19731,"1685ff49865b54af10b99ee6ee5995b36d435882e19136c1bef3ff803aeab805",9.317957166392093],[16001,"b94e896ea06fcfd6bb6862cefb9c593072dee330f8aa12daa8b26b0742997968",9.317957166392093],[7345,"408b62776ad76882b2ac71cc70b8127f8831d5daecabdb1d793eee22e30cbbcf",9.917710196779964],[16166,"e17ca8d8f6fd5c83015b08c2a7404fd0aad6414d3d096d6b885d0b673363a664",9.317957166392093],[10120,"4d53f4a93a797d9418cbc0c6340e4b7f37c1d2e93b17e77f89445566d46d91bd",9.917710196779964],[5225,"e20e01ae34a90aeded118f31f4a3b8f240131f55cae8881ae5d1bb76baa4d2dd",9.917710196779964],[14501,"40922146b60caf2e123d3e698c43b7d09b3f6ccb2b3d811d67086ac303ba3e89",9.317957166392093],[15147,"a8182c060db9c4cd845f564d9b9b6e3057367a812cfec8d97cc1dde0a17f957b",9.317957166392093],[13174,"3983a92b14218dfbc6024fa6d889f9633fbf814deb11666f6e849a7af26d82a7",9.317957166392093],[13760,"64586509c037916d6963949c567e7b08d6fa9d5961c23e60e935075a29eb1b9a",10.052724077328646],[13013,"7560b37e703f4dc068007054e770f2e23a7354d3a4e3a228c0b7f0192f0c7faa",9.917710196779964],[4603,"5443cbc90e4710c9808660762c626119ed79e78297e45553055f3d87857f9be1",9.917710196779964],[13462,"84838859150339f6656ea43614d9129340f5266a993d41d21e8e810b4093caa0",9.317957166392093],[6150,"9c51b7fc9cdc565ccfc79fc9aa93e5e2fb1da8b114b7922e993e87b3ab4f25d8",9.917710196779964],[3375,"1c9ae98d91a0e0f16420854c92d28e9a6b83aec5f601bc451d4ac84b4951dfe9",9.917710196779964],[2783,"f0677f28a00760044d358a29f6cb12fcb83406aee64d1665536b17b4b643dced",9.917710196779964],[18475,"0a0e87f7c69f489c5ccd47b4003a83037a035f71921b16e6ed49ab200a7b0032",40.70935960591133],[9688,"c99213ae30c6a9182f163d7e44e18b44aedc1981d1de321ae6f229484a1379c0",9.917710196779964],[12602,"3d8111fbebfffc1dc1ba4a5610728350c0ecb0c8c5eb9f21190d07b6b66a41ad",9.317957166392093],[16669,"9b0d48536e9e1a1e1b787d94165b9cde33651c23ea03e3951a6bfa0749744d59",9.317957166392093],[17655,"e63b00f1257a86de519f6a1f2b851c317f952330a3bf78995084bfeeb9260e44",10.052724077328646],[18255,"1e2470c8bbdecadbb1500a366de7f438e3b2a05706d613d5c7472f571765ea36",10.014471780028943],[16428,"9827bceb88161e7bf1a7544a5185e82182e715a64432c2dc7cec7441aa218b5e",9.317957166392093],[11076,"9ead96e88961718390b6eb154a52618eb3c984172e7ab40b4531f741147c79b7",9.344814676151254],[6676,"a19200008c0242666d4d995e905a9547b862466bb8a232e8138604fc11fa25d4",9.917710196779964],[19774,"1b57ace7e7c81386ae6458f9e1159e21ffba0e9ed9f131e2b6e5c23a21c49e03",9.317957166392093],[17976,"16a5f396edb99a1c3b8ea3d1cd1507e4da527c19ab7c610fe5b2ca0f019f973d",9.317957166392093],[16284,"0cd4a0e46b504b4f7680f7a03168dc9c1bb228c0900f4a0ad1d42ffffa049061",9.317957166392093],[325,"a3b9acd6806e24eb1ff8ca902f668615bda66826e443b967fd1b0d07f56bdafd",9.917710196779964],[18731,"aa1a4386999e5a17fc03015750b4c24cf0aa49aee4147a8f5f85f730a1c85329",16.19964349376114],[570,"a78ae68e78d4bbff67a17aec7c9ebe1490b1213de894350e020f5ee69f9b22fc",9.917710196779964],[14928,"6aaeb843b4b226ca7cc985b5677ed21f1ee097ea361599930b1dbfa0ce765c80",9.317957166392093],[346,"3603656a5cc937857d7b291c4e2f17bfbcf179f8f48bcf9024a42d1a7755befd",9.317957166392093],[8397,"b9805490098cd7335ea9dccb7f42c64336cb0b179b28239a6a785dfc42289cc8",9.917710196779964],[15933,"b4401142bfdcd48ae2062fd12b3ab846f03ec8ede47c5d195655a17958355a6a",20.306595365418893],[669,"0e7d899347b0b832d49a6df1eb7826ac77d524ad625fc33f03273fac97856efb",9.917710196779964],[11884,"721b0cf3fb97cba57574e2c62184bb3f8270b8c7a0e5e783bd8b6a2926111eb2",9.317957166392093],[15939,"f29e7f5ba04fe85592254cbc643b84e1f00c004a45b8d8538745e2160c8f2e6a",9.317957166392093],[4894,"45373891b743ccb59c18d6111bfbc4cbd29b95e175b8de6e39b168762c04e1df",9.917710196779964],[3078,"fa66564069a76568c149b2b00ec2a5b1587d2346059b59657f3e4c8feda5caeb",9.917710196779964],[63,"9becf03b0f453de3a05ad1d602f5b0490d0b8a5722611230e43dc2b052b990ff",9.317957166392093],[15356,"4bb9c2effa7ff2d1361d5d14e4684b33357f80422f28621088b826cf8b914977",9.317957166392093],[18678,"914c9915879dc196e70c8cb9f544537cfd9c1e1c9125d54df028548e6b1f5c2b",9.317957166392093],[16522,"087703ecb47629dfc06dee7e93e851e3d38ebe6477fbdf859cd6c43141f6a05c",28],[14986,"85912dd76f8b98e517e03e253519018d791e90e641fc72c2a020149d3d9ed07e",9.317957166392093],[10377,"eb2dd0cc7920550daedb414b214a1552ab5f0cca6083afdd7344bdccbd16f0bb",9.917710196779964],[6159,"67449c9d8c1a767f739bee996289c9d9433215c40ca2a041ed532e6f265818d8",9.317957166392093],[14998,"760204e6da9e93bb08b109903d284461d49208046964c4f6b34806ebe877917e",9.317957166392093],[19365,"0d60e2c8069309b7276d779fe8a34809e63d66178ffc0c6670d0cdcc86043a13",9.647446457990116],[8630,"9379f83e4e4b81622ed5078b125072def52c3bd25a5ef42a11d1041d439d3dc7",9.917710196779964],[1343,"7bc8c89540b872c5daa68636b3c921ceb28df685321d6013e0bc9d61d97321f7",9.917710196779964],[14648,"acbb60111e69af7c00cc1922b523a00df765073e6cef0c28b69118abf564e985",9.317957166392093],[3857,"5fb9e86429aaebcdb4a1d5b94ced90328ca79e45f4050a7eea92060a749b9fe6",9.917710196779964],[2374,"613f80603807687daead5f6836fbd3cc022b1894275f538c2038c4b61891a0f0",9.917710196779964],[16410,"516ce847eeb2a66b3b5956500af97db4e622ec38a5b80c6b9930734998cbef5e",9.317957166392093],[2386,"b888fc49e80f0f20724658009601b4de7d2f00a1ba01524b46483139486f89f0",9.917710196779964],[14558,"e3c194681c013c462d7b2fc74ddb6fbdc7687dccbab1cdd75f4f329532d9e687",9.317957166392093],[18476,"7052bfa420f9b9939419d627be0809821d44731e50a5188209e8c00bea04fd31",9.317957166392093],[18503,"160eaa77b97f660c76c236df72cea2e2ce1d865cf2ba0cfe790f91c2e7895731",9.317957166392093],[1712,"8e8a0d4761bf2cb79dd7d37685b6030a0f681338f95edc93735f52fed581d6f4",9.917710196779964],[3524,"6d8ba47baa45ec0d1fdde28f4cd85aa08916fd88289c28bffd35c376583acae8",9.317957166392093],[6917,"c6fb079820a50e5db69e78089bbf7b982da2f019c0c611f36350e5327fcb7bd2",9.917710196779964],[1679,"ead88d2353f6eaf3d75443e7eef2d7695081e86e3b1f4ebda5ede8f7754c0af5",9.917710196779964],[2137,"eb81105c972ddefd6edcaebfcd16ed52bce0f74f82a84c7a14af1476d95703f2",30.134529147982065],[12125,"52fbe8fc821b8b50c880bc0b0810f604d0e7fd0f0233afed42d957c230a483b0",9.917710196779964],[5016,"de0865de80cb6bafc6fb68802a32a53f4979ff64d8e5bcc6b61855289cdb10df",9.917710196779964],[19122,"ce49bb65f477fa94d8d55df42a25302cad2323cc887ce644812a7a79917a741b",9.317957166392093],[8705,"8e513009cfd0828eeb48dc58d41860e2b4fb920f6ce4781892f9fb93866cacc6",9.917710196779964],[2588,"f16df073dac27a97a71bb7b9f883c522aaf20dfc4b1bd95f23565394a50b3cef",16.056140350877193],[19305,"900b82379e84a64e34e5cf1fd433cc90dbcd6a35607b3012847cd2704d1acc14",26.036553524804177],[16018,"12a3968a7e958b0a03f1f774e5c77c82cdc32f6107bb170afc10923873891068",9.317957166392093],[18675,"8d5b3292ebbdad0433043d015ff615fef47f4c6b870624df0612cc694632902b",10.052724077328646],[8021,"de397f9328826885b2cb3414ae4cf71eeb226cd2bc8076fd1b9d941b5e216bcb",9.917710196779964],[142,"457b91ec7c9c22f131f6234963cbc0b8523afae91278aa5f224c455d4f7d0aff",9.917710196779964],[11306,"ced93fbc33eb727c1483facf23ebe43667492144b64037e94330e536d25cf9b5",9.317957166392093],[13012,"ab061f6fb8eb639a4e5593685f635f05dbe95974d52a4cf8a1ddb9c8388880aa",9.917710196779964],[11986,"cd89a03e82a3502a8481947159cbb264d71e594b1520d1d4afdeb591c16c67b1",9.917710196779964],[470,"70e42393df05a11ca53925f8161c3aba3b639ea4c72f56eccc1f0dbbd9f9d7fc",9.917710196779964],[7970,"d79b2e46467e57cd1e4b49f53ab9839c43313e496be73bc6c35d3bd6c2d9bbcb",9.917710196779964],[10370,"580715ede048c3a1097d2a3bcfff89bc00a001e8ce714e9f19283c2abc09f4bb",9.917710196779964],[11548,"dd8b0a3ef73dbe3d749cfd8b50ce4890922ee9eda2565cea4f2e6b8f81de3fb4",9.917710196779964],[9113,"e59e05e3c3e4c1e796ed866163f3dbc891dfc0fb315400826b2c0fc11d560fc4",9.917710196779964],[9139,"ad36c985d1549fdfc72de06c025a71c0feb4ec52e186ee840b8b208325d0e0c3",9.317957166392093],[12115,"ee2250efed7d9b2f79ff3bd82dd17b3e11e0dc74f21cd6e7bf99f5c03608a6b0",9.317957166392093],[17776,"9f3f370260d253b506621148fdee8c5e21bd40f123383c3da2d4b7fa5191ca41",9.317957166392093],[15656,"28364995cb030c366bed921be55824e0fe291915706fde4c4851ce0b81573570",9.317957166392093],[7447,"57d2848499e399ef328cef079399ff6e78136a71730bd03323445252efaf1acf",9.917710196779964],[10204,"6a5794d87b167ba15f3ba94c9964dbdf982ec818d73edc18b6a8d32d9b32f8bc",9.917710196779964],[15330,"0de5537766ce950e85453ce7a2d855a094d6f7bb8c12a902ff076a03df69c377",10.030959752321982],[12875,"4b2bc088532718899ddcbc6789973af1759273ebff706deb78cc73ec60b96bab",9.424083769633508],[6045,"0b52ca99c74664a42b38682dd8ad624a9ede150d936072010c923e3aaf2ccad8",9.917710196779964],[7178,"dbcf1a30f31218dc748a50d41c056e4df3df61204cacf7b11f4aa182a260d7d0",9.917710196779964],[7950,"1c778de59faf4abb2297e14d968aab48726fe481909474e860ae1584105ddfcb",9.917710196779964],[16406,"a8b62cac825bddd25447b9be13a2773837344621f83f5a5f08419f0be808025f",9.317957166392093],[1010,"669fa62f1607c7c059dfa4f21304bcc4a41e9b8a5757e05e41829f0015f724f9",9.917710196779964],[11180,"aaf6524124401cbd72476c073d341401f2cad71915b56b354e6a680ab037d1b6",9.917710196779964],[2237,"7c4836a6472e88ba60065c85255f6a8dc487871658ba8fec815b1a3cc09a50f1",9.917710196779964],[11758,"689bf37a9d13a816653cc8a401ce31be7d67d9216cae5ba3f885d41977f4f0b2",9.917710196779964],[14708,"37d902e1cd39c99c26b3b1f9d58a120f1bbbad18d07e0a7149417668f879bc84",29.93211488250653],[7545,"4519b9198861b9601423db6cdcb940156be65de9c8845d017b23a79129668dce",9.317957166392093],[6995,"1e27697a9cf88778ff2b0854e27352f8d536452c473e73b727af9d507a7809d2",9.917710196779964],[10822,"cf26a0c0b2d24066d908fd9c94d960d29c7b4052f5805d47f09a82e12a7227b9",9.917710196779964],[16258,"fa36920df56d570f3efe609658fdd78c92fd61f4b80e6edcace62e9329452e62",10.052724077328646],[19614,"f4770c1fb7da9e1e91cd310cf5b8f2617bf9854aee38657360a6f288ffa26209",9.317957166392093],[11174,"c54f1393a0262b9e9e8015dd23d18796d61ce396249ee3a86b801b379651d9b6",27.185354691075514],[5284,"302a91f51e4fe99cc8a6ac4dbee553df5ca4930eb051d0055d5e60c356997fdd",9.917710196779964],[17208,"961cbc54c3fad07ec347be7f9682f3e918e4fd1a7d4f354b7a69a339b539a04d",10.033508207818581],[15557,"966b44691d606e1147fb3a75c6ed61649feac24f7c7a13692dab1bce35b3ab72",9.868312757201647],[19,"fd20b3f3df736f05163671a3dbee68a3393f22643c3d58c5cf54098f5d62e4ff",9.917710196779964],[16607,"99248cfbadc4edb50e1ad263a2fa22d08617bac0d01b50ae7d1e73365081ab5a",9.317957166392093],[9647,"1a131a1222e6f82d7aa099ad91de57f4fe22b447c28dfa625abf32348994bbc0",33.78407079646018],[5915,"6d3c6e3aca6794aa5678baaf8c1c2ddddca4493dccfda881beab450dfb7e98d9",9.917710196779964],[17806,"cd81d7cb54d4ec3ff2d1b6cdfb8bdd696b88fb2406e8c288acea326a37e72941",451.7711670480549],[18485,"ddc8b878347c525b7c7ea2f5525df6975e5d5c0ea7f58b3c20164dadd392b431",9.317957166392093],[18271,"3a359cec4fbe39bd29514bc462f951591f847097fa3efd387495bf3a6a836b36",9.317957166392093],[3204,"4b4fb918e23acdf02df22d096db3570bb87819a20911313be8a5e5bfcbc605eb",9.917710196779964],[2436,"cb642de9b0e9f44d7bad6ac6b1dac195a94b5c0cbd2b77fb101397ac523f3ef0",9.917710196779964],[11545,"684e0129b6b105b46f9a890ca60ce3bea72ef5b732f74c2a386246419bdd44b4",9.917710196779964],[1726,"daf06b95933249590a2827151823a5a0488264457e3133ad9c67750c9be6c0f4",9.917710196779964],[3353,"d209e72034aee5c1809ad59388c101f03079c626f3df5d9a6860cfa8dc3001ea",9.317957166392093],[2490,"b76e7bab4e406b0e5a1176c0f6c652a58fb740c8e7613610b7b717666b14eaef",9.917710196779964],[9156,"57cb8cf72b1955c1aff85c296129976797a60b74bcefd1f8d8a5ef6218e2c7c3",9.917710196779964],[2533,"3590a316817dda074db688785fc7a82bda9829500b31ccfb11acfc27eddc9aef",9.917710196779964],[8588,"80a7d66f4d49992133ac443d4369b4605f0cbdaadd5e408100394a8ffa7f7fc7",9.647446457990116],[9394,"677179eb3521e944c905852060b38b5a989a8df2a9dc0abe45faaa12143c4fc2",9.317957166392093],[17794,"510fdc3f6ba74c2e91dd5496c51bd3deecfce2e090bf8f4dbd4031444bd06b41",10.052724077328646],[3258,"c0de1383bf512aea511c94a006edcc5e27573e8f2b3e944c0969165c4ce9a0ea",9.917710196779964],[16715,"b204622a9f15fa88ac3ea073e8b29795a4be6255a0f84f35192f7d8135303858",9.317957166392093],[16067,"164628d683af2860cc862c4f1d662674c59e84794e14159cb860c0771b7ffa66",9.647446457990116],[6155,"e0385d00c36dab536c53548f2ffbfe6103583499460bb6aee2c8664d3f2e1ed8",9.917710196779964],[15090,"e2f73c5c0935e2a5a96aa7e5fd515049fdacb2111cb13c7626f2e43f3f27e37c",9.317957166392093],[7588,"6b8550cda5eec45db625bf26289906edf1ee29ce998a4e49093eadb2f77c42ce",9.917710196779964],[3448,"10f15535fac8c5eeb28b2f672a83b7173c6458a1968a7181ccbeb767812a64e9",9.317957166392093],[6654,"738964b6ef972a18621268326d2a3343d0844007e2691587696fce0b188549d4",9.317957166392093],[18450,"4f43f91a3c9b91300c0608043f9fc9374fef7db5d9f84c7783f64b4ff2bea732",9.317957166392093],[9163,"5a6e21856fcbab3d0463d5c71b27cd6344c73211bff4f931feb0d01febebbec3",9.917710196779964],[16456,"e6dce996c5d5e3858287fcc4ed0aac368f09d613d3eb200d3d2a6ec33bb51b5e",9.317957166392093],[11276,"1ab6b41c099e26ac4abd44ab11161c5406d7ce23c0b0c7ed5172c57c877c31b6",9.917710196779964],[16078,"db340a8b97d21ea08ba1c71df56f8ed49221b6c6ed2ef16b7add4d84ef8eb766",9.317957166392093],[13142,"68c6e5849e0677d9e3d3553ae3a0aeaef4b3a5985334d0364a020e9f68b418a8",9.317957166392093],[16108,"c28e6abb37325b81eb6ccba8e7ab32f83075f6a58376baf7beadc77d943ed365",9.317957166392093],[19867,"2ca5f60ab0186f199d3c3856db55a3ed8914fb82b64d9f3c1ff9ec93729d4700",9.317957166392093],[12687,"ffdfb78e45f402a0a54d783f46008cf6368401f98d0fcfeba47a4e36495ba8ac",9.917710196779964],[15664,"60afd7d7715ab86b8c5b8fe394265d60da646d35f78888f572b855c241ad1a70",9.317957166392093],[5865,"0f12ca04be968ab54f2d9fcf7c42990c10073c37d2955c904940ac1fcaa5dfd9",9.917710196779964],[12971,"8d91787c793fc35f5932b133d29d24e983d0052f443a70fc0a5c75e11df0c0aa",9.317957166392093],[15270,"041fa97fbfe4fa3377acc2b6c3e2cd9bd188171cdcd10dc73bb4c6bcd35dff78",17.077062556663645],[19283,"8c501b53573b1fd3105f4caad97547c5b4dba481ffe3f930ed8c7ea9a8ec5615",25.356890459363957],[3992,"cfc9d9b0b2748d68596386a938c8f2a036fcc2dca94c8a38c68aacdc5018c4e5",9.917710196779964],[18013,"f1d5694c532ffda80ceb17adb3ea64faced503104659abe2feac590cdb1dfb3c",10.0090661831369],[14406,"360c6956b21eb53e980131cb22c555da05d1b8a5934e5d637072730ebba82f8b",37.937282229965156],[7966,"5307165c18895f447acb6344c3cd078bc4175c4aff1928ae7a889055c3d2c9cb",9.917710196779964],[3552,"89269d3155ba25052801e7cc4bbfb9aede65f7282dae9fa915665149bc1f92e8",9.917710196779964],[6994,"6e63ab95aa88133a2eedce7ccb0a11b45cec64e7a904d50842496f7293660bd2",9.917710196779964],[4855,"72d1ae1b4f5be253f436c144cae861ae9ef82905a2157cc38526ad0508671be0",9.917710196779964],[10798,"b07e16c03998211b5a5df70e1dec38190a5c652ee1d8f4192ea66b92212a4db9",9.317957166392093],[8551,"55e364550ec7cbff8ae51df2507c54f8f95958c2fdd1678049e191b2abb9b8c7",9.917710196779964],[17340,"f1748848e90289b1116a2906cb1d0a957725dba38baa04bfa6b56c24dfad1e4b",9.317957166392093],[5527,"61263a1aac6c157580c25e0218ef8c3e517672398bb06e6eada2917288db0edc",9.917710196779964],[3148,"9514dd974d273135e51b40584812d8bbcf0ec179c6c471382f034fb8a4155ceb",9.917710196779964],[2810,"800c9dec613eff4899ddb293f95075d35e970a707d0adb3d07e32c331c4198ed",9.917710196779964],[14730,"130d530afc290cd67a54f851dda9b45a4f4fea70164d48c121b7dd0f90525384",9.317957166392093],[8309,"df2bbd210d3f500a38595a9fca1b7f9cf39de49277b0ece7c9c8a468e92442c9",9.917710196779964],[8898,"b40be1de618618f0da9b31cdd1faa8b6bad0d0fdece122b063cf108a720b75c5",9.917710196779964],[19387,"8e26e33d1798130a906a09bbf8070c6d54fda41450fb7b1d5e285650653a4e12",9.317957166392093],[13848,"ef623ecf9850510417f7d7445d2b84f8e6fc08259e92717749129efe29777098",9.317957166392093],[11405,"36b3dc53a8553efaa979736c61edf5880d376365b12b75ec24911d96ffaf50b5",9.917710196779964],[1363,"cc5a8ebaec19e796bf4ed944e2426298e2f437a6cc818e40dc65a019a571faf6",9.917710196779964],[6910,"4cf97fd16fdbfef149c2bef522cc360cb75aed735dd8ce80095cdc0331dc87d2",27.658536585365855],[15114,"8c746a9120c464adca83f17bca2d67f2da5e853c661c0e2261b7296f58eb5a7c",9.317957166392093],[9927,"63efb6ae4d31bdbc51627296979f2d0efd4d885eee996a1438340d616a72cabe",9.317957166392093],[14047,"a3ca1a0f2b59a60b4da0d2e0dbe2bae32fcfe98b56e67525a28d660ee1b9bc93",9.317957166392093],[1081,"a7e33b3b50d56402a56ac35f48b143d719ca8c86f2d102dd982d552e2fa8b2f8",9.917710196779964],[2034,"430ab7dff7840705cc59ec2d5b23ec8372f91e9775947e2e9583e9039727bff2",9.917710196779964],[18803,"d45f519957b7e5ae4849c3a47b663a2d2afdd595b281b7669c445b504d2ed726",9.317957166392093],[18557,"c560ac61fbe14aa376fba307ae10e873f2cfed0f08c6a6d812517700db484330",9.317957166392093],[17643,"5705da4c4432566ce6632a3cacdd8b671ea669024b78faece3a2ba7872985644",9.647446457990116],[10449,"6b264de2ad5cf634ce676dea329f8743c820ef271048ec94eb40f101af856bbb",9.917710196779964],[10677,"d9d094adc718d5e94e15ed327f21ec16fb3114f0ca839885a9924787295132ba",9.917710196779964],[4648,"20b43f3dfa3377cd2d9fc9c962d53888b289e344b11fc681190ae600449955e1",9.917710196779964],[284,"ddc60e8f2e837951d9ecadb498ffdcf438b87728a2097bda1b3763ae2a160efe",9.317957166392093],[814,"087afbd779d0377368dcc04f31940af1a040ade9ba5cae1b3f568de1af3072fa",9.917710196779964],[13739,"46e7587533743d379f34ad3eef0157b1022f21e3465de0b5ab2719152b08b49a",9.317957166392093],[18205,"e688ce515ff270ab457733762e70cdac3eb592950d94a76d76ab4cf29335e637",9.317957166392093],[15869,"7c625fb2d7a1757e1d541b34773757bc53ffe7f46dbaa6b4e1a2d2edcd3bbb6b",9.317957166392093],[2468,"8e9a867165f75483e7b5e186488048d691675ebe6ffbb5de09a3c610424311f0",9.917710196779964],[9356,"a4795ad28b8c0a40010f02e406c4cf9610b1e8b884d3f121f96fc3a8388c91c2",9.917710196779964],[19010,"2e9705a693f65d443dcd336a2fd87267054c58e9c5eee5515e31d98000362b20",9.317957166392093],[8617,"4151b3b955163095d118eb4bcbee7309bcc98345e271de6ce3c80026e7e04dc7",9.917710196779964],[16590,"67bee763fe32b1c18e41f984ceee29385b11fdd68deb04c74571551739e41d5b",9.317957166392093],[5669,"9b9e75ef14229a7296942b973cde411b72531a293d282c4ee940492b8a0b36db",9.647446457990116],[9637,"0e2064a006097b983fd872413e80de70e8b5323746caeb255f1f3bc8004fcbc0",9.317957166392093],[13994,"79309e1df951ab97f6ee2dd140f1ab4a7a9272f54a4077d29be81f52ae2d1995",9.317957166392093],[19681,"daf79e2c299ae3ada1c23fec2cc878df5d1bc1a38bbacfda75d841b1986a5707",41.35472370766488],[26,"eac0b4d41f68a33f98d03d16e78759cb785ae6e8dbe6b1ba05108c3b6a73deff",9.917710196779964],[11625,"2b3b1363a532cd376999f8b5a4e7258593cfa53c0209138ec27e7aaad3cfbcb3",9.917710196779964],[17144,"92ff48749ebe1dcb3f3b9230efaf4fbbac12a9889d3d90d727cde891b1d32e4f",9.317957166392093],[12438,"de8b48c2dc9c614e7acf840feb21b1146c5085074b847f552d9378d4bacc59ae",9.917710196779964],[18999,"cf9212ed0a7c78d709984ba8aa48eae6ddfdbb331c4feba700b2d512ad0a8820",9.317957166392093],[4650,"47a2740f7d7c29910b892bd89063fbeaf8a2e2bcf7e504468dd7b98b53594ae1",9.917710196779964],[4600,"71a39fe86e42da7188089e0791cb8aeb6b2f37f132204a26a0d4c331f61ca0e1",9.917710196779964],[5986,"ebdd9f9e8c6e3eb99ce082c5828dedeca09f2fff78d00ebd49984fbb21e82cd9",9.317957166392093],[14564,"e0cc95f59dd0a209b64c0fa63e9aff382d337745d9fac374bca516d43dcfd187",9.317957166392093],[18138,"720ab91650a5151639cdf2906d4ab0175edaa359556230e24d4925448a0ff239",9.424083769633508],[7975,"21b6211b11615dd6ad133ce663ec026abc6e37a443df4e131a5503f90ea1b0cb",28],[15697,"381760c342bc3c6d88a792e633a340143c642c0900254626a070f3c913b98c6f",9.317957166392093],[17324,"d6f12691386220d2a8ff123c7d7cc101ff07ef2d2689933c1fb0be6a7b75654b",9.317957166392093],[9925,"e0fbb3a889eefd77e1eea369890bb25c8accc1b1779aae3e088c897e8410d0be",9.917710196779964],[15227,"94a5874c2ee1b4ed04c99bd570b18b9e42097877a9c85b5412beb059f36ff579",9.317957166392093],[8427,"62d8100b581b2c904dcb34c47cd146771f4404caa7bd438af2e2d6c2ff6673c8",9.317957166392093],[17307,"b4516056783f2b0f37edf0bfe4d297eba86f570fdabbecc7ab637460ce6cd04b",9.317957166392093],[12462,"b95666106d17fd870bd84b9ae3cd62bbf0d4b46728b29b724c4a68e852f83bae",9.917710196779964],[6867,"944288dd28c354a8812184742b63f025fc3007bde4b47eb74ac310ef4ef9d3d2",9.917710196779964],[2196,"ce52ecf4a1e537d22a30ebbdf37f40c066020337a0c64327a0fb692142e991f1",9.917710196779964],[2018,"8f9f8b22edd0c747b73db6442e0986a82f1797ec9b12bb3c6a054fd45da1def2",9.917710196779964],[1850,"4aa1cb9336265285aafdb79a4be3accba88a7d6e278f705f34c9b31bdb72eef3",9.917710196779964],[18144,"dbb0ea4b3193c83ffdf3370f70a7aecf7c965caf9bbf0581b4e259755f40cf39",9.317957166392093],[2157,"e806c2a2561dce76921938ca48abccb16b527d3880d08edb7265064ac61adbf1",9.647446457990116],[17305,"595d59b9a302f0c10f37abc0b3a9dbb25b748be2196b387c2814039d62bae14b",9.317957166392093],[17505,"7059a5a3c27b8e4427f530e2eb854fb40d7f13e19116e92fa8c4927d919d5c47",16.475972540045767],[8452,"0eae2d76e672336f1f066438f203d046f01721e15a3568db9e15c134e0264fc8",9.917710196779964],[14596,"22ac1180342a384303d40d5e06840bf22f5d8a1388e0248f6e243141cd482e87",9.317957166392093],[16764,"a9e2393f4bf649c4674bf5f9061acef02ee0f3cadd6698cbff57d7399a352157",25],[9222,"d3c1c5f3f37244c227d0efee95676db11c4187c44264ec0b64a7fc7d683756c3",9.917710196779964],[6188,"429b8d93d3d7ce0573febd078d4cf4ee47027e86ab12ed21db23274ed586dbd7",9.317957166392093],[12415,"af56208532dec7364e5cb3bcee80b39d022e21e022a70a92132633dec71e7fae",9.917710196779964],[17995,"55a3c59c49de808ec767350c904a4a2ee34bf431b434f594b2b5f5feb4e24f3d",9.317957166392093],[8346,"21afb05a577d357712444cd0a489d9aa8e8124492319e4888269d67edb2307c9",9.317957166392093],[10819,"218b31767e9e7f43d4ee31c99b4f21e99bcc1b7734b24c3d91267fb6f7912cb9",9.917710196779964],[1206,"2d0c2e6772e8173795296b25d876be60096d973ecbc771638d05237665def9f7",9.917710196779964],[17842,"254ebfc233ea7a5b8da05106f9c84482872bf2dd32b1d884c46cdd5f5c136740",9.986861079955135],[3582,"fec407269fc980cda1afc007ed556adb78eb14b44d2b1ea61346847e9d5b6ee8",9.917710196779964],[17545,"f0d2faf0872ec07fccbf222e790630af30207da332e4ab4d29f183b066a59646",9.317957166392093],[17044,"dadea1805ce8b81b7bb48ddcd3a415336bc6163e83e16b0b47be1fac590a2a51",9.647446457990116],[15360,"5ee6843bafd4e6a64152bee12d21260e1e603b181a1f7897684079d67bde3877",9.317957166392093],[3708,"c26bd247affa93b45671fca65b7c0286457efe53e048329dcedb640c8e6888e7",9.917710196779964],[3382,"79568ee390011d7d2bb5378ddbd9e01b4f146bd366a6baaba0a98d043e0ed2e9",9.917710196779964],[5913,"09b15adc3b309fc557654c9e36a98beb0196bcb434d1a20d2662aaa99acb99d9",9.917710196779964],[16228,"29f7faf0ba0add6b386f31a10893e7b014b69f205451c38e7c1975b37f501463",9.317957166392093],[4472,"9ed4250a4d3574172a90f92aea6791d5359c13bbac083730d1fbd32d98d297e2",9.917710196779964],[13226,"a55145732ddd46c217946b58206a154205832be1ccc345b6bf576b19d2d45fa6",24.072948328267476],[9748,"a516918e070d2497ddec5e9324c729de981983cd9ad69251d8acdcf1af2a04c0",9.917710196779964],[12250,"d7ff35661b2cfc4d5e46f1025945a1875d9bfa867a81db1f43234e1c1120b1af",9.917710196779964],[14457,"d38cb451c788f1c75e070a26d6bfc97448573a0680ed927ba4102c781880188a",15.942959001782532],[19641,"85fa397d821093d9d5ddaf8cf3ec8a134994abda1fbdfaed9a300395474b3108",26.13903743315508],[6125,"8d14bc97e845c910bdc45ba567941f190b3c8ac2a922f3ddc022562fbdef49d8",9.917710196779964],[16711,"05de5eb263d4c1e619184be9c06f4dd6399f66ea3ee6253ee79eec2f29604e58",9.317957166392093],[9933,"0b46e107560fec6bfc53aef4f8586271191153990d52ea42e091b3802614c3be",9.917710196779964],[11906,"9f45110415ea0af705f2fdf70ec4727e34d531b3391ea81e2802c51b6520fbb1",9.917710196779964],[6660,"1e7493e52c72fce26ecab812ffcf783cf2e9810bed1a3082d05285f371b93fd4",9.917710196779964],[5205,"b4a2707d877c000f7497ca4e060ed0e33d4c79fce6556b059cd6c40f6105f6dd",9.917710196779964],[1336,"c285f4ec2ac28487aaa807e8f1304139ea363952f2b88bf7769c58c898012af7",9.917710196779964],[15459,"5c621a07f7fc35a851edcf31b075e50935bb0486b2eba051a8e7293fe1550075",9.317957166392093],[14635,"eb53e71cc528b2616ea202c8a9db9be5781ceda27bb8bddef2debb3260674786",9.317957166392093],[17892,"5c0dc3edfbb76f8f27649593f515d595c0bbae33183d56f463e30a8c02526d3f",9.317957166392093],[14144,"b17572b5d100e09ae0f0a9aa71689be80f9f50f15310f7a997bd7d07d1b9a891",9.317957166392093],[5328,"e84f7671ffe586137536d7c1f8e6ff3e292c8962dce50237297f83c6ef7643dd",9.317957166392093],[16317,"5d2b1fd19e748cb7cf59d27ac722ebdba3be0ea966a050b85ba648c21bd8a360",10.052724077328646],[3213,"a1e2e1aed3b59339f86fbc2fc93918e02f22377a6a7bd2cb4dba42e56622f8ea",9.317957166392093],[10993,"a0223ed4f38ce195c5608c55690c139cd2eac22f51024fa7e135315c168407b8",26.928759894459102],[815,"c1c18a1b9c5471f8c020f36256877cec13706e8730184f6d5959024d82d471fa",9.917710196779964],[9469,"ebd01235b1eb58246acbf960a8f733b1920d8ccd0bdaa64bc6779b86ef3ae9c1",9.917710196779964],[11982,"22bbb6210f707f2bf61d08e95abad2c9d62a98b74f18ca435e3af3430e686db1",9.917710196779964],[505,"1c51ca0d6a249b0eb8b2fcb21f302946b759b9e5eb3ba32ac4c523759184a5fc",9.917710196779964],[13752,"6a4ef61654215a7fecc8f4e2b0629df5186407f5fc3ef54f626b408febf1669a",9.317957166392093],[10428,"b3608ece29e433b3052c2f4207ade840f631209bb1c2b900cfd78bb96d7fa0bb",9.344947735191637],[9940,"650a9874b65714e10d4e1fbf7bd75ba926f5f73ecb46a0bfa25a141ab79eb4be",9.917710196779964],[13511,"b648e2a7da4335debd2e18618a2c3d681e6ea1b0a6d7cc699b8d1067cd3b8f9f",9.317957166392093],[14038,"fce5cb0697475591fa7390b7890f07bb34fa202b52bf782a40cf163f5c5ed993",9.317957166392093],[8598,"2bae66e6076190f622bd670a5c5fdef873d9c2b2215563ab09f1f144127874c7",17.089005235602095],[17186,"b6fc8e2b51240a96cadf5849ef8de2629d2b447eecd65c32db3e54828092114e",9.317957166392093],[11622,"8441b059dd75eedfd81e6e02734058363f36ff8e489ace609ef5f00b6182c2b3",9.917710196779964],[894,"51c3ca03456766d22eb1aab2f3a556eaa08df5f723646c371c6256913e18f5f9",9.917710196779964],[6586,"191ed07e4b1b13534ed5e25db7181aaa49ef47ed7e14011bbd8434d62c13bbd4",9.917710196779964],[17002,"1db26b339717b7f17672a80fb15654ff9f4c5d638ee16d369c57d59bb062f451",9.317957166392093],[9585,"065d3c9a7e73993b0831257c5eec62e13d3b58acf80d6c188ce14e3d3b4917c1",9.917710196779964],[9981,"48ed91c97ffa61e283ae4ed74a298210ac8c403a7d2c937b1502d88ebb0470be",9.917710196779964],[1304,"ad615b067c2755c8852a771bc291c5b1be1d3e90b4ab7997a2a0c7fc346f5bf7",9.917710196779964],[13415,"cf7f5e0160f8d050e461c5948c201a4bba10258b225fd5ab29f2ee1fb3910ba2",9.317957166392093],[18152,"b8e8432ecd5ee0c623e9851b9a02ab56d6bbc7c1da2357022d46f0dd28a35239",9.317957166392093],[4597,"4c4b9fc718b5377b3caf411e3594b8d26228149bd814f1d6eedca2cf0ff0a2e1",9.917710196779964],[15111,"2030ee722a7241e62804c3aaf830b127c29fd299f1ae9c23ac99b650c573617c",256.5445026178011],[17147,"f4ce2fcb63f465a1fc81c80e5716319186b5cf20ee3b69ef4c3688ef7cea234f",9.317957166392093],[904,"fe31c266b3a4dce07e1eeedba709879a9455e99e395578fed11eab584ea4d1f9",9.317957166392093],[1282,"3df03fac2cc67632b8d8044df5a6e5174627249129cfbb929877b380dd947cf7",9.917710196779964],[4832,"254ed0ac263cac7a6cd3d2efee6f733a61d07219354a74bd910a660009e53be0",9.917710196779964],[16701,"94091b9e2097351f9d387ff950be023418d9c31fb011f5186ed182df67f77658",9.491990846681922],[5615,"c1b3ce3c28ae4b34c12db1c419e51eea711b9572cf4a268fcbe88bdc580493db",9.917710196779964],[9530,"e1fa2b3b9ddc599a3608cb3424cd1ae05885b7867b7c6de9a2b08be1be397fc1",9.917710196779964],[859,"3470d90ff0c1637e1ee14a1d720393aef9d744ecbbaa6bd5add42d5db9fc29fa",9.917710196779964],[14735,"9df7b14df28dd464b93c3ae28881de5edce89214a9d221ba786e38a55c602d84",9.317957166392093],[8291,"666b72ad8fd4c592bd1929139bb295b3461a4c4f8ef2de57aa28682d43aa5fc9",9.647446457990116],[3011,"0c51eff729fd9786090a7693279187946cba39b688bc3d28e24f3ed46e1035ec",9.917710196779964],[19262,"af091b7b88cff361e277954dfd0ec1cd4ba1409a2a6d7dd0d242c816ee093a16",9.675862068965516],[3373,"ba455c14306d433fb8074e3540c40162361269207b318ca4de13a2564766e0e9",9.917710196779964],[11450,"da0e06b1c396f21f7f348e3630a58f7cf65349ed8d5b7037adb7126f51f8f2b4",9.317957166392093],[10039,"9137f54554bf68e7850d7e4a5ac7055065c4200310c7db4fe9b68937612618be",9.917710196779964],[13103,"45feffebd4f80185f20a9b739c8647b801add6dc044456318d194ce6512a25a9",38.72],[14187,"7d5cd89d5a06b5e55566edacc72e3ed572b17cf099985666c2b85a44fdb8ad90",26.291115311909262],[4720,"793640f7340424976544b64509bac1a171d3c25e0370ff56ed2394b6a04febe0",9.917710196779964],[7574,"bd222aaa1c6b42d21935c23bce4a9ca31737c6e06799b7e4143a6019355157ce",9.917710196779964],[6592,"624e0da3de2252f42e1bb33f897aa8115fc474e037584d95f04f0cd1b404b4d4",9.917710196779964],[18874,"901fb77ac18590fda2910547e68035770e0f2487f36249fc51a675ae58494724",9.317957166392093],[4890,"4984ec7683dbc0365851304746e914092899a71a17b634291db261022804e5df",9.917710196779964],[15178,"74fc822e9f9b7b97dd62ccdc02eda0a72445647ae1c93c05797c3d1caae8fe7a",37.014925373134325],[18487,"535f1f20c15f297af9c4f87834a10f388a36b43ecc6253e4157484116b4eaf31",25],[12095,"af04b3688f9706fe2180cfde299da60fe1c0a85f8c14165ca54662272a8bbab0",9.317957166392093],[16093,"63bf7d74dff80ba4e1f61a71fdfd73733700386a24b93782f6ac727690e95b66",9.317957166392093],[18400,"132b2a2d91a15db52b13cfb81e852bf5379f5eda5f2be6912f501280600f6f33",9.317957166392093],[10526,"ebe3249f6182c51255717af3ab36875122a587c180f3262ff6471166ba4902bb",9.317957166392093],[13237,"7bc93d23f289d817b86f176a8a5ece880806e8b0198d337f966785258f0525a6",9.317957166392093],[11097,"124fc171bec5e4ad9b3bcbd56fe282a382ec80207bc308dde04b5e040b2f45b7",9.317957166392093],[16740,"9b819eb2b88b21199d7b259425d5640287b9e045fde1f5378fcbbbe88e369857",9.647446457990116],[15105,"f602405d62d81d1c74a96895d66138de480fcb052c63c5c92a5e744667f17a7c",41.35472370766488],[11630,"4003163e56d94af01d560f3d94efb447c2ac8bc217a1906997a3526f7ce2b7b3",9.917710196779964],[14976,"b62f615a918965a3552902b575c0b2a627e08b0e0dd71f4ab9d185df5b7b197f",14.188948306595366],[12359,"df35b5c501637dd073bedfb20bc099aa9ddcd6c7d1fb0f50a6bebcf96e61dfae",9.917710196779964],[15607,"cefe72661f2d51ebc8fa04b104c3cd7d3e08af7328f83d5251dab5285b304671",9.317957166392093],[13260,"c5f2b5f54a6adadae51a96eb1ae08f6cf1c2aa45ce569c14e5f888cac8ea7aa5",9.317957166392093],[4055,"2a7dd569ede155409363b68dd428616a5936005d18df01cb02ff0af8667264e5",9.917710196779964],[300,"243316de468586885389486dcf8acc988309bd340b3b73a809f43858e93df2fd",9.917710196779964],[14606,"ec715465fe4aad57e841d154bc24bb0ed1e6394aa9221bb8a7a6ef0dda3cfd86",9.317957166392093],[2884,"45f4926c13d66bc8b7bb91ff41b702cf2d8b8218007b1db05c2018d2e6fa39ed",9.917710196779964],[10121,"8a79478430c84943e2410b363fc8f05e0839d960cbd7a5c97883d4b4793191bd",9.917710196779964],[981,"cbea13c775905d9f6ed4f7faf1844803baeee84f666df2114ad733d00f5551f9",9.917710196779964],[10784,"4c06151602e6b1d26a4fc5c5c51a233216485e14793503717eef145a63b568b9",9.917710196779964],[15172,"a30771bb9422b8ed8fa837e5fa40bb927a20046fecf4612c6c8557dd57ab0b7b",9.317957166392093],[5953,"f72333590e2541d4a95d68a15a52aa0b4e4b4c4a9f7ed43b90fa1aa4c28665d9",9.917710196779964],[10270,"019b955bf606efc79f22f7743c7612b28d600f17ab832d82ccb082667d4b97bc",9.317957166392093],[15254,"9e862a81d00d087baadd1f6c502a39365edea63210cc61439fbeeed3d8315a79",9.317957166392093],[10842,"3f231fd1d5dd57bc4fe101729c7f0c90ee63c0d09a8d4793a59fbf5599fa09b9",9.917710196779964],[8867,"393413f1149640ab83bd8cc949061f6a7f0fd9f13dbd8bdf0f529a938397a3c5",9.317957166392093],[17456,"ca337eb8b90798a484182ec2559d761b3b0cb8ab58d8b5138a257cac1367a348",10.052724077328646],[14562,"b0eb01c7eb8cc1d3b88720c8bb0db83c58b2061cd9090a4d590854532a18d787",28.124444444444446],[9398,"4dae4b6f97ef42cd19f9652c4bedc05f7a3786b4e6c7b1fb70c6f9f33aee47c2",9.917710196779964],[1195,"ef8eff69d7d8bf1923afc92cd1349806c7e8af2d91750ed13ec7e09d5d3e08f8",9.917710196779964],[9544,"153ffbc6bb245db592e67af41a378ca43cfa05ec78b1ec7ac93b0e8d63f46dc1",9.917710196779964],[11915,"abe8837b57d46bb076619075b462c0b88baef4e359aff624f62c0c8cea5ee7b1",9.917710196779964],[11500,"808ba7759529fe4c8e051fd229f57ba03182208aed738a9636fd0dcccef084b4",9.917710196779964],[7293,"9c4f843399d25e2e279a1a25f748830742fb6edd5d8f0f850f89cb0c881a1ed0",9.917710196779964],[13008,"04529b92a7f1cd63091e114a82f04b2324f38a25aadcabee6e3744ca97d488aa",9.917710196779964],[12544,"b17e4be4977ad079533f3371b6a4078a51abe1f11da57513b23ff29f4fb8a8ad",9.917710196779964],[17535,"eed4c6826f5980b8a2ecbb7c89b3daaf41afd06a20c1aa7bdc5db0ae5422db46",9.317957166392093],[6826,"9db4a451edaf7b99e40751d1d750ca1ec1d2098718a8229562bb6149d75515d3",9.917710196779964],[3793,"053cf7dc3ea853876f0919d5a18070691d687c12c8603a593ba5da77bc44ffe6",9.317957166392093],[11847,"15195238fdff8e0f474cb6469be4fa2cae69c304b9a757eafa43d71923d96bb2",9.917710196779964],[9760,"50897b04831f4313daa9f1b3bdc429d4e8c4072872399890e223123329eff3bf",9.917710196779964],[5993,"17bb9d5c04e4b4baf08659bff8f5fc3995870d0ddc4bb797e00cfd3cb6771fd9",9.917710196779964],[1009,"66813f495a575bb3d0918f28093cc31a48876511aafb87cd07c845341ab026f9",9.917710196779964],[4092,"c8edfe2db05a751de4d42dabb3c451612416a64e6c520e1c5eeff703f2f01fe5",9.917710196779964],[4701,"ca6504a0f93a0f5dc5beb4c7cbb0702c27c3919ae275f30981980da9df72fee0",9.917710196779964],[12377,"d4be8e332e83895759d79f913aaab19b10230a91f509ebdd0c200aba1c48c7ae",9.647446457990116],[16768,"7ea6d0a64b9ab5fb19db6d6dde069a612bf0a0b6e3c23ae67e420d797d861057",9.317957166392093],[19689,"03beca5cc04891afa0fd1e75c2dc8fcf0ed3b5941de43bfac45b3f5079ad1d07",22.196428571428573],[16627,"36f2e7fd07cfdcaa87d07b4cfffee0278d7d16786927a10ea78d6b32178d445a",9.317957166392093],[3177,"9906f0de63b8b1d85202c651dc8ba55404636a3dff54d4c18e6aeaade6412aeb",9.917710196779964],[15132,"2e46259bb2a343826b835e617ec75f9e2af650663176ebb94516552269140e7c",9.317957166392093],[8972,"bd2df9f999c8f32107b8e81c5ca715e84badd520dfbc44ce90435ebc28bdfec4",9.917710196779964],[16404,"85e38456d5fa48e188c8d605cd473be9affcec0065326d2ebc04fe8797cb075f",27.800711743772244],[4234,"80fed791ae60a4bb869e79ac8949ddc71f910da9d0ac7918d1a1eb2fc5ce31e4",9.917710196779964],[161,"125ef251bd87b362cdbd7b03ed51fab7a30f60b2e8fd2c53ce33a09aa1ccedfe",9.917710196779964],[10084,"5c1fbf788be9418030aadef09c0ce5d1c8126c5e4798603b11d554fd44d0cebd",9.917710196779964],[16394,"536b936dcce3db60009dcbf88bc4416a614305ee0338596a7b7081f21f572a5f",9.317957166392093],[2786,"dbcfc0aa82ee95f3f604926962a1dce13f0079c5761c88e9ce5e3df1a4b2d8ed",9.317957166392093],[8131,"c560bb856ab43dd7dfe7f8de5e8e746cc4c0c7c4eba30b8485c95486724f86ca",9.317957166392093],[15740,"66dfcd57b4d14aafbce3fb27df7b53d27689119ad98719542be301014eb5936e",9.317957166392093],[11821,"4341efc934972f3d230958b53d93151813d16f3b3cf4a2ffe28ed121d94991b2",9.317957166392093],[8320,"81c1b2f07964371b9b172b50c45dea5eb5397bd72b992f786dc2d671f46037c9",9.917710196779964],[4149,"f33f9dfc53b5914086f2465a16434767cb71b2524046f24aedc5bb5cb0b6bce4",9.917710196779964],[14234,"a8b19839d451ecccdcce2628a76a15a0113fb3a6b3a8a168849a35fb3060618f",9.317957166392093],[18041,"abe74bde42d9e7a6dc40c58a1f1a3fdb89ace3367d28c0dfa39553658083723c",9.317957166392093],[12518,"9b95de07c39b62de9afe28ba19f4e51552259467e26edc990b99e138842ad8ad",9.917710196779964],[14383,"a6040cd4ba462f5fdf5a91c10dc938480c7fba02ae5db9770f5a51beda5eb08b",9.317957166392093],[19735,"3c8080615bb028402a611fcffed0bf5896a47569a3e0481622cd1c6662779405",9.317957166392093],[3417,"d10d096e3daf09d4fa41e6b5620193d18fd7db2a064d204290d8551b38c78be9",9.917710196779964],[9724,"d8f0228c079265018c36968de67f50da04955611ae2185756bb8fc8e142430c0",23.958115183246072],[5403,"366f810d2409f3acb14100f6fd8046408e9b452135438230bcd4d9bdc70accdc",9.917710196779964],[12685,"12012ea165ce4e7347db97da412cb85c0ac9d5d0e32eee1da8dce8cea027abac",9.317957166392093],[15401,"4a1457d094568611e1398091303b2861f41f6ae94a4bb8466f594cd7a0664776",9.317957166392093],[14424,"3717ba6ae5c5591ef995ace53c5b4bf29ee7f0f23b5c829e6ed5d9e67d7acc8a",9.317957166392093],[14680,"496544618de2c5b5cef20840ed0991fd3bea227578974ba622bbdac4bf803d85",9.317957166392093],[4664,"f8a41ea58cd224268a0e594fb28d6ccc18049d9c736e5dfc562bb7e41e9537e1",9.917710196779964],[7580,"7d036a952595773fbfb5d8c42a008a00cf84b53e4de97f6a610d8eaec17d4bce",9.917710196779964],[2615,"fe1b061e0bc073d13fd4582515ad9199a844f047c0af2505832ac3ed70ac10ef",9.917710196779964],[17442,"28f7f0c9c070dd74091bded6a67988a795cc17304307814675497f826a9fd848",9.317957166392093],[14185,"dbbebc2a8e5493b9255fb1e077eff73ca2e543f1880da82f1c0e363d7c0bb590",9.317957166392093],[10123,"2c57304c2b8c6aa60f9d9be63a894423e5a25a64d4c239d40e46cfb960e08cbd",9.917710196779964],[1635,"15c7c16f1ef11a5bc8fd3fd21b4e9dceee4314fc639218bb4d1746d50abc65f5",18.130434782608695],[12205,"74cf584ca74ca05460a7d7e3c35643eed17eddd75532f9b65141bf11bb350ab0",9.917710196779964],[15584,"dd99fadac74d6e57fad040860bc76d29f8e6fbee8745ef1a10ca93a3e29db871",9.317957166392093],[10734,"0db316d9319972944d6df0e8a877cfee5df3d172503d400aaa4d7f4dc800c5b9",9.917710196779964],[7141,"916365d4f2687505116543e87ae22d002e5254b65adfcf2c8cf08971e97e14d1",9.917710196779964],[13522,"59c49cabbe23dda149ff3601e2da31abc34a3f9feafa450932c7071e34835c9f",9.317957166392093],[2968,"d270107979ed62ebedd19f8ee99d5a24072f6bf2a28d6ae30e03a09b8a6982ec",9.917710196779964],[15414,"7cca64a40c4de0942ac763c21343973917e9eea079b151818ff564c1de4d0076",9.317957166392093],[7100,"860c213a772c721afa6e82b384875ea6103f34edc8cb4d404da9436282d659d1",9.917710196779964],[3494,"78b59a19919e43625025c4c6519004b5418fad4710fdc9e04526040628bb04e9",9.917710196779964],[1064,"3f142b8237d818aa400d7808464545682e4a0e2d1bef5ad76345b4976306d6f8",9.647446457990116],[4176,"2b651e0948ff03800aa08b80d13a8d26cddb6271828a116d852d69214e0898e4",9.917710196779964],[16299,"f17440a5587ba7a736f224fa3e821c9cf449092fd9756b3837dcdca639922261",9.317957166392093],[13078,"841be0117a01dd8435860788f13df6751da598ecadf24ae7212f69c3ba8deda9",9.317957166392093],[8374,"da672dafac0feef2dd3b3b7597d347bcb7b3f58db1b0a1a31ee7222693fbcdc8",9.317957166392093],[4250,"49432842a11b8c52d5653f9fef2d6eade9bf152914ac2e1b3e6ebec5ec7e1de4",9.917710196779964],[4898,"4db4b565a9525221bbddec2d10452b758c36e983a7b38dbad33a085fbdc5dfdf",9.917710196779964],[10570,"79e5d3cca91047c670efb93522beae36073a6a88b4eb1a4e346b6833694dc7ba",9.917710196779964],[12484,"70b04d4e18cdd285f90717f80d800a92e8c56f9e4d484a538bbba7cfe21409ae",9.917710196779964],[2244,"c8d9cbc885ae64e245224882d2c8d891312206e87b3fda9a1efd3b346b9e47f1",9.917710196779964],[17024,"e9cd55797acd1cacdd7b7182a86685c396f5f4ac57fb0668320507e7c2f26e51",9.317957166392093],[4113,"48144110db733853acd0e62fb671884b9adc9a45ff31c1ad2c7c661c2f73f4e4",9.917710196779964],[3117,"310baf01277cf635ba1cb81eb7af5f9b545adb43c4c688feff86cb8022e18beb",19.228318584070795],[15447,"8c2ee04b51363c7367b8063043eb7bef2356ae9e692cfd719ad26d113bdc2b75",9.317957166392093],[13376,"bcbdd6a5495b7dee8b94c92dc3681bf76dce92ca3837ecd3633c8b786f48e9a2",9.317957166392093],[6205,"4b224884f9172dbcd1a218649fae7d2ec0b60955f40245d85769adab6c76b8d7",9.317957166392093],[13108,"8d9a7ea2ef9e7c8c945abc27c46420b4de264d398e24471f69278e3cf20aeaa8",9.647446457990116],[4152,"e527eccf558772feb71007f32da7735bd08120c804417e6eb8437d8a43fbb6e4",10.052724077328646],[18621,"5abf969a19af2fbefe31188f55fa4a362eb6f623f5d7b0bf19f8ddf94ce1242e",9.317957166392093],[17276,"581e9fc96d29e4b82b0ed5d0d91453b1f909d5b520bb9f82bdb3bcec6cc5b14c",9.317957166392093],[1320,"f5621a6bc27679c9e713cebf95fab40e198ca3aa3d607cd3523be7d242b549f7",9.317957166392093],[5735,"d37c51e3f80689421321bf1524bbbf8b519e5fb04c44fd5a059425cee788dada",9.917710196779964],[7429,"54512c1f64cac1230b59149c1e5d1ffda17fa9b5877420757c7013b85c8d30cf",9.917710196779964],[3969,"1db261adac980cb1dc44b2dc1d07e2dc09378df2e6cdc3273af402895494ebe5",9.917710196779964],[1058,"9a6ae4b788bc02a8e3b9766e99944b9a42a77a6bf61cc7033835bc90b0c9def8",9.917710196779964],[8279,"03cde9befb5139860605213e66ef5d144352cb07e4f47e54b8ab6eb056b57ac9",9.917710196779964],[53,"dc604f30cfedfa395a5499d303cfb34695d97efa85bdfe4f5e4b2b1e0c0f9fff",9.917710196779964],[3406,"066c85cd80b5ad6b757377401091c1c0a73b568f2ba2dae92100e9b10cc6a9e9",9.917710196779964],[8286,"7af3b384870eff61277b2bf2d758efd5000b0150f9fc8d6925342df1093b67c9",9.917710196779964],[1331,"cd4219ee92787b516a5a339a17e6ae87bd8a171c45d4c5bdf8e4b0e3ff9739f7",9.317957166392093],[18092,"c4ecdd5e6b1822bb705a351f5d4a67572309a5fee8d73c6b1c1575368bcb173b",9.506082725060827],[4917,"99ce5a1a789bb4a22e93d522ca1e8cd3fa67e0b95e4f709d95ef77d0f6e5c2df",19.033462486791123],[15458,"a72e6706c2958c39b6d5718b4e16cb24e8930853d123aa2d100b37b4b2b10875",28.110847189231986],[12528,"fff0f90d00062f2bdeefbe6c9ce9396d73c1940fd68ce01806d9a2dc057abdad",9.917710196779964],[3380,"62a0b6458aa4b0fd7d68d1e2fde2bc245408aa40ebff112a244260f43a79d4e9",9.917710196779964],[4120,"0de6a295a1062f0ed7b3168e36763c12724307452d36faad373ddb11cddaeee4",18.130434782608695],[5054,"3140558364f1623999ede711dd91134628bdc69475f3777efe73e5749debd7de",9.917710196779964],[2233,"4ad39263d7e8020be4d1258d06ba803c4fdd24d8f6d7ba320392d3d9b94d52f1",9.917710196779964],[6074,"e3801c37e98fdf6b13f728f972192dc39f315d8216228caaedff31d5d1e594d8",9.317957166392093],[16422,"46aba2c68f2ffba825653e662cec8f3666ef0d342c13eca2555651665034a75e",9.647446457990116],[16262,"36795167fdd7fd5fb9d588d923e8444f5f0e802d77de9a14a3057ba5ca921d62",9.647446457990116],[13534,"e83ebc31c7b52e4f340e0ee70cbf4bf952a0d6feb45bc21d88b1fd68cbed179f",9.317957166392093],[17965,"3e835f8742a49591011bbf0097e60371dbcdf37b25966d400034feb5b391d93d",9.317957166392093],[10603,"0c3806e067e81fdd1bae1e498e99d1f044dd6af6a42a85ab29af13996869a0ba",9.917710196779964],[842,"32253416852960cf261857c69b56323f9c2607535f7cc08bf51fc4dbbb9348fa",9.917710196779964],[8487,"707ff92e8181fbd5844091cec07127b416ff4a0e30fa99864f79f91530e417c8",9.917710196779964],[238,"f092660af44e9fe40ee5d9dd717720865a0b46ccd0a5201e56c5af9417a362fe",9.917710196779964],[17149,"9a295102e54564c8f84c76c7246f0d43d8b0ab3db4e1cb036eb218790ea1214f",9.647446457990116],[7733,"587d26300264b3286d8d5d3ab939bf866582b2f89a961aa6a16c5ffd37f846cd",9.917710196779964],[4586,"2d1f19dcd3791a3a79ea210a4ce58027e13bea9502240224db9e011100ceb3e1",9.917710196779964],[14022,"4a11339190cd8c7854f45f17018b94cc7b37c924063e795eac0f700369123e94",9.693363844393593],[19495,"0be41149861d29c266c36e674908ef0c9b0fa6cda86a8805de96caff4225840e",9.317957166392093],[15901,"e3fa485f7489f2e71cce244c29d754bf7f28a4bd63dd86ff43adb0f529b9046b",9.317957166392093],[5966,"fbc1a9ed866ecd8b906d39b71a89c3c6d29eadb44af337f512e341d847db50d9",9.917710196779964],[809,"7058bd2fdbf4d57e96a68ddef474e9e4335439cca3a73420a8f3b6a480737ffa",9.917710196779964],[12230,"f2b98e0fc81c351a7b974183154e40b8b6bc74bb2986907405f246ad5bf2cfaf",9.917710196779964],[16002,"24e1db661c0735d96e1c9c604517998597c52b7cfe82ac8b3c54e467d1b37068",9.317957166392093]] \ No newline at end of file diff --git a/backend/src/api/about.routes.ts b/backend/src/api/about.routes.ts new file mode 100644 index 0000000000..5e7d3b70e3 --- /dev/null +++ b/backend/src/api/about.routes.ts @@ -0,0 +1,87 @@ +import { Application } from "express"; +import config from "../config"; +import axios from "axios"; +import logger from "../logger"; + +class AboutRoutes { + public initRoutes(app: Application) { + app + .get(config.MEMPOOL.API_URL_PREFIX + 'donations', async (req, res) => { + try { + const response = await axios.get(`${config.EXTERNAL_DATA_SERVER.MEMPOOL_API}/donations`, { responseType: 'stream', timeout: 10000 }); + response.data.pipe(res); + } catch (e) { + res.status(500).end(); + } + }) + .get(config.MEMPOOL.API_URL_PREFIX + 'donations/images/:id', async (req, res) => { + try { + const response = await axios.get(`${config.EXTERNAL_DATA_SERVER.MEMPOOL_API}/donations/images/${req.params.id}`, { + responseType: 'stream', timeout: 10000 + }); + response.data.pipe(res); + } catch (e) { + res.status(500).end(); + } + }) + .get(config.MEMPOOL.API_URL_PREFIX + 'contributors', async (req, res) => { + try { + const response = await axios.get(`${config.EXTERNAL_DATA_SERVER.MEMPOOL_API}/contributors`, { responseType: 'stream', timeout: 10000 }); + response.data.pipe(res); + } catch (e) { + res.status(500).end(); + } + }) + .get(config.MEMPOOL.API_URL_PREFIX + 'contributors/images/:id', async (req, res) => { + try { + const response = await axios.get(`${config.EXTERNAL_DATA_SERVER.MEMPOOL_API}/contributors/images/${req.params.id}`, { + responseType: 'stream', timeout: 10000 + }); + response.data.pipe(res); + } catch (e) { + res.status(500).end(); + } + }) + .get(config.MEMPOOL.API_URL_PREFIX + 'translators', async (req, res) => { + try { + const response = await axios.get(`${config.EXTERNAL_DATA_SERVER.MEMPOOL_API}/translators`, { responseType: 'stream', timeout: 10000 }); + response.data.pipe(res); + } catch (e) { + res.status(500).end(); + } + }) + .get(config.MEMPOOL.API_URL_PREFIX + 'translators/images/:id', async (req, res) => { + try { + const response = await axios.get(`${config.EXTERNAL_DATA_SERVER.MEMPOOL_API}/translators/images/${req.params.id}`, { + responseType: 'stream', timeout: 10000 + }); + response.data.pipe(res); + } catch (e) { + res.status(500).end(); + } + }) + .get(config.MEMPOOL.API_URL_PREFIX + 'services/sponsors', async (req, res) => { + const url = `${config.MEMPOOL_SERVICES.API}/${req.originalUrl.replace('/api/v1/services/', '')}`; + try { + const response = await axios.get(url, { responseType: 'stream', timeout: 10000 }); + response.data.pipe(res); + } catch (e) { + logger.err(`Unable to fetch sponsors from ${url}. ${e}`, 'About Page'); + res.status(500).end(); + } + }) + .get(config.MEMPOOL.API_URL_PREFIX + 'services/account/images/:username', async (req, res) => { + const url = `${config.MEMPOOL_SERVICES.API}/${req.originalUrl.replace('/api/v1/services/', '')}`; + try { + const response = await axios.get(url, { responseType: 'stream', timeout: 10000 }); + response.data.pipe(res); + } catch (e) { + logger.err(`Unable to fetch sponsor profile image from ${url}. ${e}`, 'About Page'); + res.status(500).end(); + } + }) + ; + } +} + +export default new AboutRoutes(); \ No newline at end of file diff --git a/backend/src/api/acceleration/acceleration.routes.ts b/backend/src/api/acceleration/acceleration.routes.ts new file mode 100644 index 0000000000..082d533307 --- /dev/null +++ b/backend/src/api/acceleration/acceleration.routes.ts @@ -0,0 +1,84 @@ +import { Application, Request, Response } from 'express'; +import config from '../../config'; +import axios from 'axios'; +import logger from '../../logger'; +import mempool from '../mempool'; +import AccelerationRepository from '../../repositories/AccelerationRepository'; + +class AccelerationRoutes { + private tag = 'Accelerator'; + + public initRoutes(app: Application): void { + app + .get(config.MEMPOOL.API_URL_PREFIX + 'services/accelerator/accelerations', this.$getAcceleratorAccelerations.bind(this)) + .get(config.MEMPOOL.API_URL_PREFIX + 'services/accelerator/accelerations/history', this.$getAcceleratorAccelerationsHistory.bind(this)) + .get(config.MEMPOOL.API_URL_PREFIX + 'services/accelerator/accelerations/history/aggregated', this.$getAcceleratorAccelerationsHistoryAggregated.bind(this)) + .get(config.MEMPOOL.API_URL_PREFIX + 'services/accelerator/accelerations/stats', this.$getAcceleratorAccelerationsStats.bind(this)) + .post(config.MEMPOOL.API_URL_PREFIX + 'services/accelerator/estimate', this.$getAcceleratorEstimate.bind(this)) + ; + } + + private async $getAcceleratorAccelerations(req: Request, res: Response): Promise { + const accelerations = mempool.getAccelerations(); + res.status(200).send(Object.values(accelerations)); + } + + private async $getAcceleratorAccelerationsHistory(req: Request, res: Response): Promise { + const history = await AccelerationRepository.$getAccelerationInfo(null, req.query.blockHeight ? parseInt(req.query.blockHeight as string, 10) : null); + res.status(200).send(history.map(accel => ({ + txid: accel.txid, + added: accel.added, + status: 'completed', + effectiveFee: accel.effective_fee, + effectiveVsize: accel.effective_vsize, + boostRate: accel.boost_rate, + boostCost: accel.boost_cost, + blockHeight: accel.height, + pools: [accel.pool], + }))); + } + + private async $getAcceleratorAccelerationsHistoryAggregated(req: Request, res: Response): Promise { + const url = `${config.MEMPOOL_SERVICES.API}/${req.originalUrl.replace('/api/v1/services/', '')}`; + try { + const response = await axios.get(url, { responseType: 'stream', timeout: 10000 }); + for (const key in response.headers) { + res.setHeader(key, response.headers[key]); + } + response.data.pipe(res); + } catch (e) { + logger.err(`Unable to get aggregated acceleration history from ${url} in $getAcceleratorAccelerationsHistoryAggregated(), ${e}`, this.tag); + res.status(500).end(); + } + } + + private async $getAcceleratorAccelerationsStats(req: Request, res: Response): Promise { + const url = `${config.MEMPOOL_SERVICES.API}/${req.originalUrl.replace('/api/v1/services/', '')}`; + try { + const response = await axios.get(url, { responseType: 'stream', timeout: 10000 }); + for (const key in response.headers) { + res.setHeader(key, response.headers[key]); + } + response.data.pipe(res); + } catch (e) { + logger.err(`Unable to get acceleration stats from ${url} in $getAcceleratorAccelerationsStats(), ${e}`, this.tag); + res.status(500).end(); + } + } + + private async $getAcceleratorEstimate(req: Request, res: Response): Promise { + const url = `${config.MEMPOOL_SERVICES.API}/${req.originalUrl.replace('/api/v1/services/', '')}`; + try { + const response = await axios.post(url, req.body, { responseType: 'stream', timeout: 10000 }); + for (const key in response.headers) { + res.setHeader(key, response.headers[key]); + } + response.data.pipe(res); + } catch (e) { + logger.err(`Unable to get acceleration estimate from ${url} in $getAcceleratorEstimate(), ${e}`, this.tag); + res.status(500).end(); + } + } +} + +export default new AccelerationRoutes(); \ No newline at end of file diff --git a/backend/src/api/acceleration/acceleration.ts b/backend/src/api/acceleration/acceleration.ts new file mode 100644 index 0000000000..f26805ff20 --- /dev/null +++ b/backend/src/api/acceleration/acceleration.ts @@ -0,0 +1,244 @@ +import logger from '../../logger'; +import { MempoolTransactionExtended } from '../../mempool.interfaces'; +import { GraphTx, getSameBlockRelatives, initializeRelatives, makeBlockTemplate, mempoolComparator, removeAncestors, setAncestorScores } from '../mini-miner'; + +const BLOCK_WEIGHT_UNITS = 4_000_000; +const MAX_RELATIVE_GRAPH_SIZE = 200; +const BID_BOOST_WINDOW = 40_000; +const BID_BOOST_MIN_OFFSET = 10_000; +const BID_BOOST_MAX_OFFSET = 400_000; + +export type Acceleration = { + txid: string; + max_bid: number; +}; + +interface TxSummary { + txid: string; // txid of the current transaction + effectiveVsize: number; // Total vsize of the dependency tree + effectiveFee: number; // Total fee of the dependency tree in sats + ancestorCount: number; // Number of ancestors +} + +export interface AccelerationInfo { + txSummary: TxSummary; + targetFeeRate: number; // target fee rate (recommended next block fee, or median fee for mined block) + nextBlockFee: number; // fee in sats required to be in the next block (using recommended next block fee, or median fee for mined block) + cost: number; // additional cost to accelerate ((cost + txSummary.effectiveFee) / txSummary.effectiveVsize) >= targetFeeRate +} + +class AccelerationCosts { + /** + * Takes a list of accelerations and verbose block data + * Returns the "fair" boost rate to charge accelerations + * + * @param accelerationsx + * @param verboseBlock + */ + public calculateBoostRate(accelerations: Acceleration[], blockTxs: MempoolTransactionExtended[]): number { + // Run GBT ourselves to calculate accurate effective fee rates + // the list of transactions comes from a mined block, so we already know everything fits within consensus limits + const template = makeBlockTemplate(blockTxs, accelerations, 1, Infinity, Infinity); + + // initialize working maps for fast tx lookups + const accMap = {}; + const txMap = {}; + for (const acceleration of accelerations) { + accMap[acceleration.txid] = acceleration; + } + for (const tx of template) { + txMap[tx.txid] = tx; + } + + // Identify and exclude accelerated and otherwise prioritized transactions + const excludeMap = {}; + let totalWeight = 0; + let minAcceleratedPackage = Infinity; + let lastEffectiveRate = 0; + // Iterate over the mined template from bottom to top. + // Transactions should appear in ascending order of mining priority. + for (const blockTx of [...blockTxs].reverse()) { + const txid = blockTx.txid; + const tx = txMap[txid]; + totalWeight += tx.weight; + const isAccelerated = accMap[txid] != null; + // If a cluster has a in-band effective fee rate than the previous cluster, + // it must have been prioritized out-of-band (in order to have a higher mining priority) + // so exclude from the analysis. + const isPrioritized = tx.effectiveFeePerVsize < lastEffectiveRate; + if (isPrioritized || isAccelerated) { + let packageWeight = 0; + // exclude this whole CPFP cluster + for (const clusterTxid of tx.cluster) { + packageWeight += txMap[clusterTxid].weight; + if (!excludeMap[clusterTxid]) { + excludeMap[clusterTxid] = true; + } + } + // keep track of the smallest accelerated CPFP cluster for later + if (isAccelerated) { + minAcceleratedPackage = Math.min(minAcceleratedPackage, packageWeight); + } + } + if (!isPrioritized) { + if (!isAccelerated) { + lastEffectiveRate = tx.effectiveFeePerVsize; + } + } + } + + // The Bid Boost Rate is calculated by disregarding the bottom X weight units of the block, + // where X is the larger of BID_BOOST_MIN_OFFSET or the smallest accelerated package weight (the "offset"), + // then taking the average fee rate of the following BID_BOOST_WINDOW weight units + // (ignoring accelerated transactions and their ancestors). + // + // Transactions within the offset might pay less than the fair rate due to bin-packing effects + // But the average rate paid by the next chunk of non-accelerated transactions provides a good + // upper bound on the "next best rate" of alternatives to including the accelerated transactions + // (since, if there were any better options, they would have been included instead) + const spareWeight = BLOCK_WEIGHT_UNITS - totalWeight; + const windowOffset = Math.min(Math.max(minAcceleratedPackage, BID_BOOST_MIN_OFFSET, spareWeight), BID_BOOST_MAX_OFFSET); + const leftBound = windowOffset; + const rightBound = windowOffset + BID_BOOST_WINDOW; + let totalFeeInWindow = 0; + let totalWeightInWindow = Math.max(0, spareWeight - leftBound); + let txIndex = blockTxs.length - 1; + for (let offset = spareWeight; offset < BLOCK_WEIGHT_UNITS && txIndex >= 0; txIndex--) { + const txid = blockTxs[txIndex].txid; + const tx = txMap[txid]; + if (excludeMap[txid]) { + // skip prioritized transactions and their ancestors + continue; + } + + const left = offset; + const right = offset + tx.weight; + offset += tx.weight; + if (right < leftBound) { + // not within window yet + continue; + } + if (left > rightBound) { + // past window + break; + } + // count fees for weight units within the window + const overlapLeft = Math.max(leftBound, left); + const overlapRight = Math.min(rightBound, right); + const overlapUnits = overlapRight - overlapLeft; + totalFeeInWindow += (tx.effectiveFeePerVsize * (overlapUnits / 4)); + totalWeightInWindow += overlapUnits; + } + + if (totalWeightInWindow < BID_BOOST_WINDOW) { + // not enough un-prioritized transactions to calculate a fair rate + // just charge everyone their max bids + return Infinity; + } + // Divide the total fee by the size of the BID_BOOST_WINDOW in vbytes + const averageRate = totalFeeInWindow / (BID_BOOST_WINDOW / 4); + return averageRate; + } + + + /** + * Takes an accelerated mined txid and a target rate + * Returns the total vsize, fees and acceleration cost (in sats) of the tx and all same-block ancestors + * + * @param txid + * @param medianFeeRate + */ + public getAccelerationInfo(tx: MempoolTransactionExtended, targetFeeRate: number, transactions: MempoolTransactionExtended[]): AccelerationInfo { + // Get same-block transaction ancestors + const allRelatives = getSameBlockRelatives(tx, transactions); + const relativesMap = initializeRelatives(allRelatives); + const rootTx = relativesMap.get(tx.txid) as GraphTx; + + // Calculate cost to boost + return this.calculateAccelerationAncestors(rootTx, relativesMap, targetFeeRate); + } + + /** + * Given a root transaction, a list of in-mempool ancestors, and a target fee rate, + * Calculate the minimum set of transactions to fee-bump, their total vsize + fees + * + * @param tx + * @param ancestors + */ + private calculateAccelerationAncestors(tx: GraphTx, relatives: Map, targetFeeRate: number): AccelerationInfo { + // add root tx to the ancestor map + relatives.set(tx.txid, tx); + + // Check for high-sigop transactions (not supported) + relatives.forEach(entry => { + if (entry.vsize > Math.ceil(entry.weight / 4)) { + throw new Error(`high_sigop_tx`); + } + }); + + // Initialize individual & ancestor fee rates + relatives.forEach(entry => setAncestorScores(entry)); + + // Sort by descending ancestor score + let sortedRelatives = Array.from(relatives.values()).sort(mempoolComparator); + + let includedInCluster: Map | null = null; + + // While highest score >= targetFeeRate + let maxIterations = MAX_RELATIVE_GRAPH_SIZE; + while (sortedRelatives.length && sortedRelatives[0].score && sortedRelatives[0].score >= targetFeeRate && maxIterations > 0) { + maxIterations--; + // Grab the highest scoring entry + const best = sortedRelatives.shift(); + if (best) { + const cluster = new Map(best.ancestors?.entries() || []); + if (best.ancestors.has(tx.txid)) { + includedInCluster = cluster; + } + cluster.set(best.txid, best); + // Remove this cluster (it already pays over the target rate, so doesn't need to be boosted) + // and update scores, ancestor totals and dependencies for the survivors + removeAncestors(cluster, relatives); + + // re-sort + sortedRelatives = Array.from(relatives.values()).sort(mempoolComparator); + } + } + + // sanity check for infinite loops / too many ancestors (should never happen) + if (maxIterations <= 0) { + logger.warn(`acceleration dependency calculation failed: calculateAccelerationAncestors loop exceeded ${MAX_RELATIVE_GRAPH_SIZE} iterations, unable to proceed`); + throw new Error('invalid_tx_dependencies'); + } + + let totalFee = tx.fees.ancestor; + + // transaction is already CPFP-d above the target rate by some descendant + if (includedInCluster) { + let clusterSize = 0; + let clusterFee = 0; + includedInCluster.forEach(entry => { + clusterSize += entry.vsize; + clusterFee += entry.fees.base; + }); + const clusterRate = clusterFee / clusterSize; + totalFee = Math.ceil(tx.ancestorsize * clusterRate); + } + + // Whatever remains in the accelerated tx's dependencies needs to be boosted to the targetFeeRate + // Cost = (totalVsize * targetFeeRate) - totalFee + return { + txSummary: { + txid: tx.txid, + effectiveVsize: tx.ancestorsize, + effectiveFee: totalFee, + ancestorCount: tx.ancestorcount, + }, + cost: Math.max(0, Math.ceil(tx.ancestorsize * targetFeeRate) - totalFee), + targetFeeRate, + nextBlockFee: Math.ceil(tx.ancestorsize * targetFeeRate), + }; + } +} + +export default new AccelerationCosts; \ No newline at end of file diff --git a/backend/src/api/audit.ts b/backend/src/api/audit.ts new file mode 100644 index 0000000000..4d05870e80 --- /dev/null +++ b/backend/src/api/audit.ts @@ -0,0 +1,181 @@ +import config from '../config'; +import logger from '../logger'; +import { MempoolTransactionExtended, MempoolBlockWithTransactions } from '../mempool.interfaces'; +import rbfCache from './rbf-cache'; + +const PROPAGATION_MARGIN = 180; // in seconds, time since a transaction is first seen after which it is assumed to have propagated to all miners + +class Audit { + auditBlock(transactions: MempoolTransactionExtended[], projectedBlocks: MempoolBlockWithTransactions[], mempool: { [txId: string]: MempoolTransactionExtended }, useAccelerations: boolean = false) + : { censored: string[], added: string[], prioritized: string[], fresh: string[], sigop: string[], fullrbf: string[], accelerated: string[], score: number, similarity: number } { + if (!projectedBlocks?.[0]?.transactionIds || !mempool) { + return { censored: [], added: [], prioritized: [], fresh: [], sigop: [], fullrbf: [], accelerated: [], score: 1, similarity: 1 }; + } + + const matches: string[] = []; // present in both mined block and template + const added: string[] = []; // present in mined block, not in template + const prioritized: string[] = [] // present in the mined block, not in the template, but further down in the mempool + const fresh: string[] = []; // missing, but firstSeen or lastBoosted within PROPAGATION_MARGIN + const rbf: string[] = []; // either missing or present, and either part of a full-rbf replacement, or a conflict with the mined block + const accelerated: string[] = []; // prioritized by the mempool accelerator + const isCensored = {}; // missing, without excuse + const isDisplaced = {}; + let displacedWeight = 0; + let matchedWeight = 0; + let projectedWeight = 0; + + const inBlock = {}; + const inTemplate = {}; + + const now = Math.round((Date.now() / 1000)); + for (const tx of transactions) { + inBlock[tx.txid] = tx; + if (mempool[tx.txid] && mempool[tx.txid].acceleration) { + accelerated.push(tx.txid); + } + } + // coinbase is always expected + if (transactions[0]) { + inTemplate[transactions[0].txid] = true; + } + // look for transactions that were expected in the template, but missing from the mined block + for (const txid of projectedBlocks[0].transactionIds) { + if (!inBlock[txid]) { + // allow missing transactions which either belong to a full rbf tree, or conflict with any transaction in the mined block + if (rbfCache.has(txid) && (rbfCache.isFullRbf(txid) || rbfCache.anyInSameTree(txid, (tx) => inBlock[tx.txid]))) { + rbf.push(txid); + } else if (mempool[txid]?.firstSeen != null && (now - (mempool[txid]?.firstSeen || 0)) <= PROPAGATION_MARGIN) { + // tx is recent, may have reached the miner too late for inclusion + fresh.push(txid); + } else if (mempool[txid]?.lastBoosted != null && (now - (mempool[txid]?.lastBoosted || 0)) <= PROPAGATION_MARGIN) { + // tx was recently cpfp'd, miner may not have the latest effective rate + fresh.push(txid); + } else { + isCensored[txid] = true; + } + displacedWeight += mempool[txid]?.weight || 0; + } else { + matchedWeight += mempool[txid]?.weight || 0; + } + projectedWeight += mempool[txid]?.weight || 0; + inTemplate[txid] = true; + } + + if (transactions[0]) { + displacedWeight += (4000 - transactions[0].weight); + projectedWeight += transactions[0].weight; + matchedWeight += transactions[0].weight; + } + + // we can expect an honest miner to include 'displaced' transactions in place of recent arrivals and censored txs + // these displaced transactions should occupy the first N weight units of the next projected block + let displacedWeightRemaining = displacedWeight + 4000; + let index = 0; + let lastFeeRate = Infinity; + let failures = 0; + let blockIndex = 1; + while (projectedBlocks[blockIndex] && failures < 500) { + const txid = projectedBlocks[blockIndex].transactionIds[index]; + const tx = mempool[txid]; + if (tx) { + const fits = (tx.weight - displacedWeightRemaining) < 4000; + // 0.005 margin of error for any remaining vsize rounding issues + const feeMatches = tx.effectiveFeePerVsize >= (lastFeeRate - 0.005); + if (fits || feeMatches) { + isDisplaced[txid] = true; + if (fits) { + // (tx.effectiveFeePerVsize * tx.vsize) / Math.ceil(tx.vsize) attempts to correct for vsize rounding in the simple non-CPFP case + lastFeeRate = Math.min(lastFeeRate, (tx.effectiveFeePerVsize * tx.vsize) / Math.ceil(tx.vsize)); + } + if (tx.firstSeen == null || (now - (tx?.firstSeen || 0)) > PROPAGATION_MARGIN) { + displacedWeightRemaining -= tx.weight; + } + failures = 0; + } else { + failures++; + } + } else { + logger.warn('projected transaction missing from mempool cache'); + } + index++; + if (index >= projectedBlocks[blockIndex].transactionIds.length) { + index = 0; + blockIndex++; + } + } + + // mark unexpected transactions in the mined block as 'added' + let overflowWeight = 0; + let totalWeight = 0; + for (const tx of transactions) { + if (inTemplate[tx.txid]) { + matches.push(tx.txid); + } else { + if (rbfCache.has(tx.txid)) { + rbf.push(tx.txid); + } else if (!isDisplaced[tx.txid]) { + if (mempool[tx.txid]) { + prioritized.push(tx.txid); + } else { + added.push(tx.txid); + } + } + overflowWeight += tx.weight; + } + totalWeight += tx.weight; + } + + // transactions missing from near the end of our template are probably not being censored + let overflowWeightRemaining = overflowWeight - (config.MEMPOOL.BLOCK_WEIGHT_UNITS - totalWeight); + let maxOverflowRate = 0; + let rateThreshold = 0; + index = projectedBlocks[0].transactionIds.length - 1; + while (index >= 0) { + const txid = projectedBlocks[0].transactionIds[index]; + const tx = mempool[txid]; + if (tx) { + if (overflowWeightRemaining > 0) { + if (isCensored[txid]) { + delete isCensored[txid]; + } + if (tx.effectiveFeePerVsize > maxOverflowRate) { + maxOverflowRate = tx.effectiveFeePerVsize; + rateThreshold = (Math.ceil(maxOverflowRate * 100) / 100) + 0.005; + } + } else if (tx.effectiveFeePerVsize <= rateThreshold) { // tolerance of 0.01 sat/vb + rounding + if (isCensored[txid]) { + delete isCensored[txid]; + } + } + overflowWeightRemaining -= (mempool[txid]?.weight || 0); + } else { + logger.warn('projected transaction missing from mempool cache'); + } + index--; + } + + const numCensored = Object.keys(isCensored).length; + const numMatches = matches.length - 1; // adjust for coinbase tx + let score = 0; + if (numMatches <= 0 && numCensored <= 0) { + score = 1; + } else if (numMatches > 0) { + score = (numMatches / (numMatches + numCensored)); + } + const similarity = projectedWeight ? matchedWeight / projectedWeight : 1; + + return { + censored: Object.keys(isCensored), + added, + prioritized, + fresh, + sigop: [], + fullrbf: rbf, + accelerated, + score, + similarity, + }; + } +} + +export default new Audit(); \ No newline at end of file diff --git a/backend/src/api/backend-info.ts b/backend/src/api/backend-info.ts index 8f028bac8b..d4500a837b 100644 --- a/backend/src/api/backend-info.ts +++ b/backend/src/api/backend-info.ts @@ -1,28 +1,40 @@ -import * as fs from 'fs'; -import * as os from 'os'; +import fs from 'fs'; +import path from 'path'; +import os from 'os'; +import { IBackendInfo } from '../mempool.interfaces'; +import config from '../config'; class BackendInfo { - gitCommitHash = ''; - hostname = ''; + private backendInfo: IBackendInfo; constructor() { - this.setLatestCommitHash(); - this.hostname = os.hostname(); + // This file is created by ./fetch-version.ts during building + const versionFile = path.join(__dirname, 'version.json'); + let versionInfo; + if (fs.existsSync(versionFile)) { + versionInfo = JSON.parse(fs.readFileSync(versionFile).toString()); + } else { + // Use dummy values if `versionFile` doesn't exist (e.g., during testing) + versionInfo = { + version: '?', + gitCommit: '?' + }; + } + this.backendInfo = { + hostname: os.hostname(), + version: versionInfo.version, + gitCommit: versionInfo.gitCommit, + lightning: config.LIGHTNING.ENABLED, + backend: config.MEMPOOL.BACKEND, + }; } - public getBackendInfo() { - return { - 'hostname': this.hostname, - 'git-commit': this.gitCommitHash, - }; + public getBackendInfo(): IBackendInfo { + return this.backendInfo; } - private setLatestCommitHash(): void { - try { - this.gitCommitHash = fs.readFileSync('../.git/refs/heads/master').toString().trim(); - } catch (e) { - console.log('Could not load git commit info, skipping.'); - } + public getShortCommitHash(): string { + return this.backendInfo.gitCommit.slice(0, 7); } } diff --git a/backend/src/api/bisq.ts b/backend/src/api/bisq.ts deleted file mode 100644 index e5f9e11c48..0000000000 --- a/backend/src/api/bisq.ts +++ /dev/null @@ -1,228 +0,0 @@ -const config = require('../../mempool-config.json'); -import * as fs from 'fs'; -import * as request from 'request'; -import { BisqBlocks, BisqBlock, BisqTransaction, BisqStats, BisqTrade } from '../interfaces'; -import { Common } from './common'; - -class Bisq { - private latestBlockHeight = 0; - private blocks: BisqBlock[] = []; - private transactions: BisqTransaction[] = []; - private transactionIndex: { [txId: string]: BisqTransaction } = {}; - private blockIndex: { [hash: string]: BisqBlock } = {}; - private addressIndex: { [address: string]: BisqTransaction[] } = {}; - private stats: BisqStats = { - minted: 0, - burnt: 0, - addresses: 0, - unspent_txos: 0, - spent_txos: 0, - }; - private price: number = 0; - private priceUpdateCallbackFunction: ((price: number) => void) | undefined; - private subdirectoryWatcher: fs.FSWatcher | undefined; - - constructor() {} - - startBisqService(): void { - this.loadBisqDumpFile(); - setInterval(this.updatePrice.bind(this), 1000 * 60 * 60); - this.updatePrice(); - this.startTopLevelDirectoryWatcher(); - this.restartSubDirectoryWatcher(); - } - - getTransaction(txId: string): BisqTransaction | undefined { - return this.transactionIndex[txId]; - } - - getTransactions(start: number, length: number): [BisqTransaction[], number] { - return [this.transactions.slice(start, length + start), this.transactions.length]; - } - - getBlock(hash: string): BisqBlock | undefined { - return this.blockIndex[hash]; - } - - getAddress(hash: string): BisqTransaction[] { - return this.addressIndex[hash]; - } - - getBlocks(start: number, length: number): [BisqBlock[], number] { - return [this.blocks.slice(start, length + start), this.blocks.length]; - } - - getStats(): BisqStats { - return this.stats; - } - - setPriceCallbackFunction(fn: (price: number) => void) { - this.priceUpdateCallbackFunction = fn; - } - - getLatestBlockHeight(): number { - return this.latestBlockHeight; - } - - private startTopLevelDirectoryWatcher() { - let fsWait: NodeJS.Timeout | null = null; - fs.watch(config.BSQ_BLOCKS_DATA_PATH, () => { - if (fsWait) { - clearTimeout(fsWait); - } - fsWait = setTimeout(() => { - console.log(`Change detected in the top level Bisq data folder. Resetting inner watcher.`); - this.restartSubDirectoryWatcher(); - }, 15000); - }); - } - - private restartSubDirectoryWatcher() { - if (this.subdirectoryWatcher) { - this.subdirectoryWatcher.close(); - } - - let fsWait: NodeJS.Timeout | null = null; - this.subdirectoryWatcher = fs.watch(config.BSQ_BLOCKS_DATA_PATH + '/all', () => { - if (fsWait) { - clearTimeout(fsWait); - } - fsWait = setTimeout(() => { - console.log(`Change detected in the Bisq data folder.`); - this.loadBisqDumpFile(); - }, 2000); - }); - } - - private updatePrice() { - request('https://markets.bisq.network/api/trades/?market=bsq_btc', { json: true }, (err, res, trades: BisqTrade[]) => { - if (err) { return console.log(err); } - - const prices: number[] = []; - trades.forEach((trade) => { - prices.push(parseFloat(trade.price) * 100000000); - }); - prices.sort((a, b) => a - b); - this.price = Common.median(prices); - if (this.priceUpdateCallbackFunction) { - this.priceUpdateCallbackFunction(this.price); - } - }); - } - - private async loadBisqDumpFile(): Promise { - try { - const data = await this.loadData(); - await this.loadBisqBlocksDump(data); - this.buildIndex(); - this.calculateStats(); - } catch (e) { - console.log('loadBisqDumpFile() error.', e.message); - } - } - - private buildIndex() { - const start = new Date().getTime(); - this.transactions = []; - this.transactionIndex = {}; - this.addressIndex = {}; - - this.blocks.forEach((block) => { - /* Build block index */ - if (!this.blockIndex[block.hash]) { - this.blockIndex[block.hash] = block; - } - - /* Build transactions index */ - block.txs.forEach((tx) => { - this.transactions.push(tx); - this.transactionIndex[tx.id] = tx; - }); - }); - - /* Build address index */ - this.transactions.forEach((tx) => { - tx.inputs.forEach((input) => { - if (!this.addressIndex[input.address]) { - this.addressIndex[input.address] = []; - } - if (this.addressIndex[input.address].indexOf(tx) === -1) { - this.addressIndex[input.address].push(tx); - } - }); - tx.outputs.forEach((output) => { - if (!this.addressIndex[output.address]) { - this.addressIndex[output.address] = []; - } - if (this.addressIndex[output.address].indexOf(tx) === -1) { - this.addressIndex[output.address].push(tx); - } - }); - }); - - const time = new Date().getTime() - start; - console.log('Bisq data index rebuilt in ' + time + ' ms'); - } - - private calculateStats() { - let minted = 0; - let burned = 0; - let unspent = 0; - let spent = 0; - - this.transactions.forEach((tx) => { - tx.outputs.forEach((output) => { - if (output.opReturn) { - return; - } - if (output.txOutputType === 'GENESIS_OUTPUT' || output.txOutputType === 'ISSUANCE_CANDIDATE_OUTPUT' && output.isVerified) { - minted += output.bsqAmount; - } - if (output.isUnspent) { - unspent++; - } else { - spent++; - } - }); - burned += tx['burntFee']; - }); - - this.stats = { - addresses: Object.keys(this.addressIndex).length, - minted: minted, - burnt: burned, - spent_txos: spent, - unspent_txos: unspent, - }; - } - - private async loadBisqBlocksDump(cacheData: string): Promise { - const start = new Date().getTime(); - if (cacheData && cacheData.length !== 0) { - console.log('Loading Bisq data from dump...'); - const data: BisqBlocks = JSON.parse(cacheData); - if (data.blocks && data.blocks.length !== this.blocks.length) { - this.blocks = data.blocks.filter((block) => block.txs.length > 0); - this.blocks.reverse(); - this.latestBlockHeight = data.chainHeight; - const time = new Date().getTime() - start; - console.log('Bisq dump loaded in ' + time + ' ms'); - } else { - throw new Error(`Bisq dump didn't contain any blocks`); - } - } - } - - private loadData(): Promise { - return new Promise((resolve, reject) => { - fs.readFile(config.BSQ_BLOCKS_DATA_PATH + '/all/blocks.json', 'utf8', (err, data) => { - if (err) { - reject(err); - } - resolve(data); - }); - }); - } -} - -export default new Bisq(); diff --git a/backend/src/api/bitcoin/bitcoin-api-abstract-factory.ts b/backend/src/api/bitcoin/bitcoin-api-abstract-factory.ts new file mode 100644 index 0000000000..a08f432380 --- /dev/null +++ b/backend/src/api/bitcoin/bitcoin-api-abstract-factory.ts @@ -0,0 +1,55 @@ +import { IBitcoinApi, TestMempoolAcceptResult } from './bitcoin-api.interface'; +import { IEsploraApi } from './esplora-api.interface'; + +export interface AbstractBitcoinApi { + $getRawMempool(): Promise; + $getRawTransaction(txId: string, skipConversion?: boolean, addPrevout?: boolean, lazyPrevouts?: boolean): Promise; + $getRawTransactions(txids: string[]): Promise; + $getMempoolTransactions(txids: string[]): Promise; + $getAllMempoolTransactions(lastTxid?: string, max_txs?: number); + $getTransactionHex(txId: string): Promise; + $getBlockHeightTip(): Promise; + $getBlockHashTip(): Promise; + $getTxIdsForBlock(hash: string): Promise; + $getTxsForBlock(hash: string): Promise; + $getBlockHash(height: number): Promise; + $getBlockHeader(hash: string): Promise; + $getBlock(hash: string): Promise; + $getRawBlock(hash: string): Promise; + $getAddress(address: string): Promise; + $getAddressTransactions(address: string, lastSeenTxId: string): Promise; + $getAddressPrefix(prefix: string): string[]; + $getScriptHash(scripthash: string): Promise; + $getScriptHashTransactions(address: string, lastSeenTxId: string): Promise; + $sendRawTransaction(rawTransaction: string): Promise; + $testMempoolAccept(rawTransactions: string[], maxfeerate?: number): Promise; + $getOutspend(txId: string, vout: number): Promise; + $getOutspends(txId: string): Promise; + $getBatchedOutspends(txId: string[]): Promise; + $getBatchedOutspendsInternal(txId: string[]): Promise; + $getOutSpendsByOutpoint(outpoints: { txid: string, vout: number }[]): Promise; + $getCoinbaseTx(blockhash: string): Promise; + + startHealthChecks(): void; + getHealthStatus(): HealthCheckHost[]; +} +export interface BitcoinRpcCredentials { + host: string; + port: number; + user: string; + pass: string; + timeout: number; + cookie?: string; +} + +export interface HealthCheckHost { + host: string; + active: boolean; + rtt: number; + latestHeight: number; + socket: boolean; + outOfSync: boolean; + unreachable: boolean; + checked: boolean; + lastChecked: number; +} diff --git a/backend/src/api/bitcoin/bitcoin-api-factory.ts b/backend/src/api/bitcoin/bitcoin-api-factory.ts new file mode 100644 index 0000000000..24916b97b0 --- /dev/null +++ b/backend/src/api/bitcoin/bitcoin-api-factory.ts @@ -0,0 +1,22 @@ +import config from '../../config'; +import { AbstractBitcoinApi } from './bitcoin-api-abstract-factory'; +import EsploraApi from './esplora-api'; +import BitcoinApi from './bitcoin-api'; +import ElectrumApi from './electrum-api'; +import bitcoinClient from './bitcoin-client'; + +function bitcoinApiFactory(): AbstractBitcoinApi { + switch (config.MEMPOOL.BACKEND) { + case 'esplora': + return new EsploraApi(); + case 'electrum': + return new ElectrumApi(bitcoinClient); + case 'none': + default: + return new BitcoinApi(bitcoinClient); + } +} + +export const bitcoinCoreApi = new BitcoinApi(bitcoinClient); + +export default bitcoinApiFactory(); diff --git a/backend/src/api/bitcoin/bitcoin-api.interface.ts b/backend/src/api/bitcoin/bitcoin-api.interface.ts new file mode 100644 index 0000000000..6e8583f6fd --- /dev/null +++ b/backend/src/api/bitcoin/bitcoin-api.interface.ts @@ -0,0 +1,220 @@ +export namespace IBitcoinApi { + export interface MempoolInfo { + loaded: boolean; // (boolean) True if the mempool is fully loaded + size: number; // (numeric) Current tx count + bytes: number; // (numeric) Sum of all virtual transaction sizes as defined in BIP 141. + usage: number; // (numeric) Total memory usage for the mempool + total_fee: number; // (numeric) Total fees of transactions in the mempool + maxmempool: number; // (numeric) Maximum memory usage for the mempool + mempoolminfee: number; // (numeric) Minimum fee rate in BTC/kB for tx to be accepted. + minrelaytxfee: number; // (numeric) Current minimum relay fee for transactions + } + + export interface RawMempool { [txId: string]: MempoolEntry; } + + export interface MempoolEntry { + vsize: number; // (numeric) virtual transaction size as defined in BIP 141. + weight: number; // (numeric) transaction weight as defined in BIP 141. + time: number; // (numeric) local time transaction entered pool in seconds since 1 Jan 1970 GMT + height: number; // (numeric) block height when transaction entered pool + descendantcount: number; // (numeric) number of in-mempool descendant transactions (including this one) + descendantsize: number; // (numeric) virtual transaction size of in-mempool descendants (including this one) + ancestorcount: number; // (numeric) number of in-mempool ancestor transactions (including this one) + ancestorsize: number; // (numeric) virtual transaction size of in-mempool ancestors (including this one) + wtxid: string; // (string) hash of serialized transactionumber; including witness data + fees: { + base: number; // (numeric) transaction fee in BTC + modified: number; // (numeric) transaction fee with fee deltas used for mining priority in BTC + ancestor: number; // (numeric) modified fees (see above) of in-mempool ancestors (including this one) in BTC + descendant: number; // (numeric) modified fees (see above) of in-mempool descendants (including this one) in BTC + }; + depends: string[]; // (string) parent transaction id + spentby: string[]; // (array) unconfirmed transactions spending outputs from this transaction + 'bip125-replaceable': boolean; // (boolean) Whether this transaction could be replaced due to BIP125 (replace-by-fee) + } + + export interface Block { + hash: string; // (string) the block hash (same as provided) + confirmations: number; // (numeric) The number of confirmations, or -1 if the block is not on the main chain + size: number; // (numeric) The block size + strippedsize: number; // (numeric) The block size excluding witness data + weight: number; // (numeric) The block weight as defined in BIP 141 + height: number; // (numeric) The block height or index + version: number; // (numeric) The block version + versionHex: string; // (string) The block version formatted in hexadecimal + merkleroot: string; // (string) The merkle root + tx: Transaction[]; + time: number; // (numeric) The block time expressed in UNIX epoch time + mediantime: number; // (numeric) The median block time expressed in UNIX epoch time + nonce: number; // (numeric) The nonce + bits: string; // (string) The bits + difficulty: number; // (numeric) The difficulty + chainwork: string; // (string) Expected number of hashes required to produce the chain up to this block (in hex) + nTx: number; // (numeric) The number of transactions in the block + previousblockhash: string; // (string) The hash of the previous block + nextblockhash: string; // (string) The hash of the next block + } + + export interface Transaction { + in_active_chain: boolean; // (boolean) Whether specified block is in the active chain or not + hex: string; // (string) The serialized, hex-encoded data for 'txid' + txid: string; // (string) The transaction id (same as provided) + hash: string; // (string) The transaction hash (differs from txid for witness transactions) + size: number; // (numeric) The serialized transaction size + vsize: number; // (numeric) The virtual transaction size (differs from size for witness transactions) + weight: number; // (numeric) The transaction's weight (between vsize*4-3 and vsize*4) + version: number; // (numeric) The version + locktime: number; // (numeric) The lock time + vin: Vin[]; + vout: Vout[]; + blockhash: string; // (string) the block hash + confirmations: number; // (numeric) The confirmations + blocktime: number; // (numeric) The block time expressed in UNIX epoch time + time: number; // (numeric) Same as blocktime + } + + export interface VerboseBlock extends Block { + tx: VerboseTransaction[]; // The transactions in the format of the getrawtransaction RPC. Different from verbosity = 1 "tx" result + } + + export interface VerboseTransaction extends Transaction { + fee?: number; // (numeric) The transaction fee in BTC, omitted if block undo data is not available + } + + export interface Vin { + txid?: string; // (string) The transaction id + vout?: number; // (string) + scriptSig?: { // (json object) The script + asm: string; // (string) asm + hex: string; // (string) hex + }; + sequence: number; // (numeric) The script sequence number + txinwitness?: string[]; // (string) hex-encoded witness data + coinbase?: string; + is_pegin?: boolean; // (boolean) Elements peg-in + } + + export interface Vout { + value: number; // (numeric) The value in BTC + n: number; // (numeric) index + asset?: string; // (string) Elements asset id + scriptPubKey: { // (json object) + asm: string; // (string) the asm + hex: string; // (string) the hex + reqSigs?: number; // (numeric) The required sigs + type: string; // (string) The type, eg 'pubkeyhash' + address?: string; // (string) bitcoin address + addresses?: string[]; // (string) bitcoin addresses + pegout_chain?: string; // (string) Elements peg-out chain + pegout_address?: string; // (string) Elements peg-out address + pegout_addresses?: string[]; // (string) Elements peg-out addresses + }; + } + + export interface AddressInformation { + isvalid: boolean; // (boolean) If the address is valid or not. If not, this is the only property returned. + isvalid_parent?: boolean; // (boolean) Elements only + address: string; // (string) The bitcoin address validated + scriptPubKey: string; // (string) The hex-encoded scriptPubKey generated by the address + isscript: boolean; // (boolean) If the key is a script + iswitness: boolean; // (boolean) If the address is a witness + witness_version?: number; // (numeric, optional) The version number of the witness program + witness_program: string; // (string, optional) The hex value of the witness program + confidential_key?: string; // (string) Elements only + unconfidential?: string; // (string) Elements only + } + + export interface ChainTips { + height: number; // (numeric) height of the chain tip + hash: string; // (string) block hash of the tip + branchlen: number; // (numeric) zero for main chain, otherwise length of branch connecting the tip to the main chain + status: 'invalid' | 'headers-only' | 'valid-headers' | 'valid-fork' | 'active'; + } + + export interface BlockchainInfo { + chain: number; // (string) current network name as defined in BIP70 (main, test, regtest) + blocks: number; // (numeric) the current number of blocks processed in the server + headers: number; // (numeric) the current number of headers we have validated + bestblockhash: string, // (string) the hash of the currently best block + difficulty: number; // (numeric) the current difficulty + mediantime: number; // (numeric) median time for the current best block + verificationprogress: number; // (numeric) estimate of verification progress [0..1] + initialblockdownload: boolean; // (bool) (debug information) estimate of whether this node is in Initial Block Download mode. + chainwork: string // (string) total amount of work in active chain, in hexadecimal + size_on_disk: number; // (numeric) the estimated size of the block and undo files on disk + pruned: number; // (boolean) if the blocks are subject to pruning + pruneheight: number; // (numeric) lowest-height complete block stored (only present if pruning is enabled) + automatic_pruning: number; // (boolean) whether automatic pruning is enabled (only present if pruning is enabled) + prune_target_size: number; // (numeric) the target size used by pruning (only present if automatic pruning is enabled) + softforks: SoftFork[]; // (array) status of softforks in progress + bip9_softforks: { [name: string]: Bip9SoftForks[] } // (object) status of BIP9 softforks in progress + warnings: string; // (string) any network and blockchain warnings. + } + + interface SoftFork { + id: string; // (string) name of softfork + version: number; // (numeric) block version + reject: { // (object) progress toward rejecting pre-softfork blocks + status: boolean; // (boolean) true if threshold reached + }, + } + interface Bip9SoftForks { + status: number; // (string) one of defined, started, locked_in, active, failed + bit: number; // (numeric) the bit (0-28) in the block version field used to signal this softfork (only for started status) + startTime: number; // (numeric) the minimum median time past of a block at which the bit gains its meaning + timeout: number; // (numeric) the median time past of a block at which the deployment is considered failed if not yet locked in + since: number; // (numeric) height of the first block to which the status applies + statistics: { // (object) numeric statistics about BIP9 signalling for a softfork (only for started status) + period: number; // (numeric) the length in blocks of the BIP9 signalling period + threshold: number; // (numeric) the number of blocks with the version bit set required to activate the feature + elapsed: number; // (numeric) the number of blocks elapsed since the beginning of the current period + count: number; // (numeric) the number of blocks with the version bit set in the current period + possible: boolean; // (boolean) returns false if there are not enough blocks left in this period to pass activation threshold + } + } + + export interface BlockStats { + "avgfee": number; + "avgfeerate": number; + "avgtxsize": number; + "blockhash": string; + "feerate_percentiles": [number, number, number, number, number]; + "height": number; + "ins": number; + "maxfee": number; + "maxfeerate": number; + "maxtxsize": number; + "medianfee": number; + "mediantime": number; + "mediantxsize": number; + "minfee": number; + "minfeerate": number; + "mintxsize": number; + "outs": number; + "subsidy": number; + "swtotal_size": number; + "swtotal_weight": number; + "swtxs": number; + "time": number; + "total_out": number; + "total_size": number; + "total_weight": number; + "totalfee": number; + "txs": number; + "utxo_increase": number; + "utxo_size_inc": number; + } +} + +export interface TestMempoolAcceptResult { + txid: string, + wtxid: string, + allowed?: boolean, + vsize?: number, + fees?: { + base: number, + "effective-feerate": number, + "effective-includes": string[], + }, + ['reject-reason']?: string, +} diff --git a/backend/src/api/bitcoin/bitcoin-api.ts b/backend/src/api/bitcoin/bitcoin-api.ts new file mode 100644 index 0000000000..3e1fe21084 --- /dev/null +++ b/backend/src/api/bitcoin/bitcoin-api.ts @@ -0,0 +1,418 @@ +import * as bitcoinjs from 'bitcoinjs-lib'; +import { AbstractBitcoinApi, HealthCheckHost } from './bitcoin-api-abstract-factory'; +import { IBitcoinApi, TestMempoolAcceptResult } from './bitcoin-api.interface'; +import { IEsploraApi } from './esplora-api.interface'; +import blocks from '../blocks'; +import mempool from '../mempool'; +import { TransactionExtended } from '../../mempool.interfaces'; +import transactionUtils from '../transaction-utils'; + +class BitcoinApi implements AbstractBitcoinApi { + private rawMempoolCache: IBitcoinApi.RawMempool | null = null; + protected bitcoindClient: any; + + constructor(bitcoinClient: any) { + this.bitcoindClient = bitcoinClient; + } + + static convertBlock(block: IBitcoinApi.Block): IEsploraApi.Block { + return { + id: block.hash, + height: block.height, + version: block.version, + timestamp: block.time, + bits: parseInt(block.bits, 16), + nonce: block.nonce, + difficulty: block.difficulty, + merkle_root: block.merkleroot, + tx_count: block.nTx, + size: block.size, + weight: block.weight, + previousblockhash: block.previousblockhash, + mediantime: block.mediantime, + stale: block.confirmations === -1, + }; + } + + + $getRawTransaction(txId: string, skipConversion = false, addPrevout = false, lazyPrevouts = false): Promise { + // If the transaction is in the mempool we already converted and fetched the fee. Only prevouts are missing + const txInMempool = mempool.getMempool()[txId]; + if (txInMempool && addPrevout) { + return this.$addPrevouts(txInMempool); + } + + return this.bitcoindClient.getRawTransaction(txId, true) + .then((transaction: IBitcoinApi.Transaction) => { + if (skipConversion) { + transaction.vout.forEach((vout) => { + vout.value = Math.round(vout.value * 100000000); + }); + return transaction; + } + return this.$convertTransaction(transaction, addPrevout, lazyPrevouts); + }) + .catch((e: Error) => { + if (e.message.startsWith('The genesis block coinbase')) { + return this.$returnCoinbaseTransaction(); + } + throw e; + }); + } + + async $getRawTransactions(txids: string[]): Promise { + const txs: IEsploraApi.Transaction[] = []; + for (const txid of txids) { + try { + const tx = await this.$getRawTransaction(txid, false, true); + txs.push(tx); + } catch (err) { + // skip failures + } + } + return txs; + } + + $getMempoolTransactions(txids: string[]): Promise { + throw new Error('Method getMempoolTransactions not supported by the Bitcoin RPC API.'); + } + + $getAllMempoolTransactions(lastTxid?: string, max_txs?: number): Promise { + throw new Error('Method getAllMempoolTransactions not supported by the Bitcoin RPC API.'); + + } + + async $getTransactionHex(txId: string): Promise { + const txInMempool = mempool.getMempool()[txId]; + if (txInMempool && txInMempool.hex) { + return txInMempool.hex; + } + + return this.bitcoindClient.getRawTransaction(txId, true) + .then((transaction: IBitcoinApi.Transaction) => { + return transaction.hex; + }); + } + + $getBlockHeightTip(): Promise { + return this.bitcoindClient.getBlockCount(); + } + + $getBlockHashTip(): Promise { + return this.bitcoindClient.getBestBlockHash(); + } + + $getTxIdsForBlock(hash: string): Promise { + return this.bitcoindClient.getBlock(hash, 1) + .then((rpcBlock: IBitcoinApi.Block) => rpcBlock.tx); + } + + async $getTxsForBlock(hash: string): Promise { + const verboseBlock: IBitcoinApi.VerboseBlock = await this.bitcoindClient.getBlock(hash, 2); + const transactions: IEsploraApi.Transaction[] = []; + for (const tx of verboseBlock.tx) { + const converted = await this.$convertTransaction(tx, true); + transactions.push(converted); + } + return transactions; + } + + $getRawBlock(hash: string): Promise { + return this.bitcoindClient.getBlock(hash, 0) + .then((raw: string) => Buffer.from(raw, "hex")); + } + + $getBlockHash(height: number): Promise { + return this.bitcoindClient.getBlockHash(height); + } + + $getBlockHeader(hash: string): Promise { + return this.bitcoindClient.getBlockHeader(hash, false); + } + + async $getBlock(hash: string): Promise { + const foundBlock = blocks.getBlocks().find((block) => block.id === hash); + if (foundBlock) { + return foundBlock; + } + + return this.bitcoindClient.getBlock(hash) + .then((block: IBitcoinApi.Block) => BitcoinApi.convertBlock(block)); + } + + $getAddress(address: string): Promise { + throw new Error('Method getAddress not supported by the Bitcoin RPC API.'); + } + + $getAddressTransactions(address: string, lastSeenTxId: string): Promise { + throw new Error('Method getAddressTransactions not supported by the Bitcoin RPC API.'); + } + + $getScriptHash(scripthash: string): Promise { + throw new Error('Method getScriptHash not supported by the Bitcoin RPC API.'); + } + + $getScriptHashTransactions(scripthash: string, lastSeenTxId: string): Promise { + throw new Error('Method getScriptHashTransactions not supported by the Bitcoin RPC API.'); + } + + $getRawMempool(): Promise { + return this.bitcoindClient.getRawMemPool(); + } + + $getAddressPrefix(prefix: string): string[] { + const found: { [address: string]: string } = {}; + const mp = mempool.getMempool(); + for (const tx in mp) { + for (const vout of mp[tx].vout) { + if (vout.scriptpubkey_address?.indexOf(prefix) === 0) { + found[vout.scriptpubkey_address] = ''; + if (Object.keys(found).length >= 10) { + return Object.keys(found); + } + } + } + for (const vin of mp[tx].vin) { + if (vin.prevout?.scriptpubkey_address?.indexOf(prefix) === 0) { + found[vin.prevout?.scriptpubkey_address] = ''; + if (Object.keys(found).length >= 10) { + return Object.keys(found); + } + } + } + } + return Object.keys(found); + } + + $sendRawTransaction(rawTransaction: string): Promise { + return this.bitcoindClient.sendRawTransaction(rawTransaction); + } + + async $testMempoolAccept(rawTransactions: string[], maxfeerate?: number): Promise { + if (rawTransactions.length) { + return this.bitcoindClient.testMempoolAccept(rawTransactions, maxfeerate ?? undefined); + } else { + return []; + } + } + + async $getOutspend(txId: string, vout: number): Promise { + const txOut = await this.bitcoindClient.getTxOut(txId, vout, false); + return { + spent: txOut === null, + status: { + confirmed: true, + } + }; + } + + async $getOutspends(txId: string): Promise { + const outSpends: IEsploraApi.Outspend[] = []; + const tx = await this.$getRawTransaction(txId, true, false); + for (let i = 0; i < tx.vout.length; i++) { + if (tx.status && tx.status.block_height === 0) { + outSpends.push({ + spent: false + }); + } else { + const txOut = await this.bitcoindClient.getTxOut(txId, i); + outSpends.push({ + spent: txOut === null, + }); + } + } + return outSpends; + } + + async $getBatchedOutspends(txId: string[]): Promise { + const outspends: IEsploraApi.Outspend[][] = []; + for (const tx of txId) { + const outspend = await this.$getOutspends(tx); + outspends.push(outspend); + } + return outspends; + } + + async $getBatchedOutspendsInternal(txId: string[]): Promise { + return this.$getBatchedOutspends(txId); + } + + async $getOutSpendsByOutpoint(outpoints: { txid: string, vout: number }[]): Promise { + const outspends: IEsploraApi.Outspend[] = []; + for (const outpoint of outpoints) { + const outspend = await this.$getOutspend(outpoint.txid, outpoint.vout); + outspends.push(outspend); + } + return outspends; + } + + async $getCoinbaseTx(blockhash: string): Promise { + const txids = await this.$getTxIdsForBlock(blockhash); + return this.$getRawTransaction(txids[0]); + } + + $getEstimatedHashrate(blockHeight: number): Promise { + // 120 is the default block span in Core + return this.bitcoindClient.getNetworkHashPs(120, blockHeight); + } + + protected async $convertTransaction(transaction: IBitcoinApi.Transaction, addPrevout: boolean, lazyPrevouts = false): Promise { + let esploraTransaction: IEsploraApi.Transaction = { + txid: transaction.txid, + version: transaction.version, + locktime: transaction.locktime, + size: transaction.size, + weight: transaction.weight, + fee: 0, + vin: [], + vout: [], + status: { confirmed: false }, + }; + + esploraTransaction.vout = transaction.vout.map((vout) => { + return { + value: Math.round(vout.value * 100000000), + scriptpubkey: vout.scriptPubKey.hex, + scriptpubkey_address: vout.scriptPubKey && vout.scriptPubKey.address ? vout.scriptPubKey.address + : vout.scriptPubKey.addresses ? vout.scriptPubKey.addresses[0] : '', + scriptpubkey_asm: vout.scriptPubKey.asm ? transactionUtils.convertScriptSigAsm(vout.scriptPubKey.hex) : '', + scriptpubkey_type: this.translateScriptPubKeyType(vout.scriptPubKey.type), + }; + }); + + esploraTransaction.vin = transaction.vin.map((vin) => { + return { + is_coinbase: !!vin.coinbase, + prevout: null, + scriptsig: vin.scriptSig && vin.scriptSig.hex || vin.coinbase || '', + scriptsig_asm: vin.scriptSig && transactionUtils.convertScriptSigAsm(vin.scriptSig.hex) || '', + sequence: vin.sequence, + txid: vin.txid || '', + vout: vin.vout || 0, + witness: vin.txinwitness || [], + inner_redeemscript_asm: '', + inner_witnessscript_asm: '', + }; + }); + + if (transaction.confirmations) { + esploraTransaction.status = { + confirmed: true, + block_height: blocks.getCurrentBlockHeight() - transaction.confirmations + 1, + block_hash: transaction.blockhash, + block_time: transaction.blocktime, + }; + } + + if (addPrevout) { + esploraTransaction = await this.$calculateFeeFromInputs(esploraTransaction, false, lazyPrevouts); + } else if (!transaction.confirmations) { + esploraTransaction = await this.$appendMempoolFeeData(esploraTransaction); + } + + return esploraTransaction; + } + + private translateScriptPubKeyType(outputType: string): string { + const map = { + 'pubkey': 'p2pk', + 'pubkeyhash': 'p2pkh', + 'scripthash': 'p2sh', + 'witness_v0_keyhash': 'v0_p2wpkh', + 'witness_v0_scripthash': 'v0_p2wsh', + 'witness_v1_taproot': 'v1_p2tr', + 'nonstandard': 'nonstandard', + 'multisig': 'multisig', + 'nulldata': 'op_return' + }; + + if (map[outputType]) { + return map[outputType]; + } else { + return 'unknown'; + } + } + + private async $appendMempoolFeeData(transaction: IEsploraApi.Transaction): Promise { + if (transaction.fee) { + return transaction; + } + let mempoolEntry: IBitcoinApi.MempoolEntry; + if (!mempool.isInSync() && !this.rawMempoolCache) { + this.rawMempoolCache = await this.$getRawMempoolVerbose(); + } + if (this.rawMempoolCache && this.rawMempoolCache[transaction.txid]) { + mempoolEntry = this.rawMempoolCache[transaction.txid]; + } else { + mempoolEntry = await this.$getMempoolEntry(transaction.txid); + } + transaction.fee = Math.round(mempoolEntry.fees.base * 100000000); + return transaction; + } + + protected async $addPrevouts(transaction: TransactionExtended): Promise { + for (const vin of transaction.vin) { + if (vin.prevout) { + continue; + } + const innerTx = await this.$getRawTransaction(vin.txid, false, false); + vin.prevout = innerTx.vout[vin.vout]; + transactionUtils.addInnerScriptsToVin(vin); + } + return transaction; + } + + protected $returnCoinbaseTransaction(): Promise { + return this.bitcoindClient.getBlockHash(0).then((hash: string) => + this.bitcoindClient.getBlock(hash, 2) + .then((block: IBitcoinApi.Block) => { + return this.$convertTransaction(Object.assign(block.tx[0], { + confirmations: blocks.getCurrentBlockHeight() + 1, + blocktime: block.time }), false); + }) + ); + } + + private $getMempoolEntry(txid: string): Promise { + return this.bitcoindClient.getMempoolEntry(txid); + } + + private $getRawMempoolVerbose(): Promise { + return this.bitcoindClient.getRawMemPool(true); + } + + + private async $calculateFeeFromInputs(transaction: IEsploraApi.Transaction, addPrevout: boolean, lazyPrevouts: boolean): Promise { + if (transaction.vin[0].is_coinbase) { + transaction.fee = 0; + return transaction; + } + let totalIn = 0; + + for (let i = 0; i < transaction.vin.length; i++) { + if (lazyPrevouts && i > 12) { + transaction.vin[i].lazy = true; + continue; + } + const innerTx = await this.$getRawTransaction(transaction.vin[i].txid, false, false); + transaction.vin[i].prevout = innerTx.vout[transaction.vin[i].vout]; + transactionUtils.addInnerScriptsToVin(transaction.vin[i]); + totalIn += innerTx.vout[transaction.vin[i].vout].value; + } + if (lazyPrevouts && transaction.vin.length > 12) { + transaction.fee = -1; + } else { + const totalOut = transaction.vout.reduce((p, output) => p + output.value, 0); + transaction.fee = parseFloat((totalIn - totalOut).toFixed(8)); + } + return transaction; + } + + public startHealthChecks(): void {}; + + public getHealthStatus() { + return []; + } +} + +export default BitcoinApi; diff --git a/backend/src/api/bitcoin/bitcoin-client.ts b/backend/src/api/bitcoin/bitcoin-client.ts new file mode 100644 index 0000000000..e8b30a8885 --- /dev/null +++ b/backend/src/api/bitcoin/bitcoin-client.ts @@ -0,0 +1,14 @@ +import config from '../../config'; +const bitcoin = require('../../rpc-api/index'); +import { BitcoinRpcCredentials } from './bitcoin-api-abstract-factory'; + +const nodeRpcCredentials: BitcoinRpcCredentials = { + host: config.CORE_RPC.HOST, + port: config.CORE_RPC.PORT, + user: config.CORE_RPC.USERNAME, + pass: config.CORE_RPC.PASSWORD, + timeout: config.CORE_RPC.TIMEOUT, + cookie: config.CORE_RPC.COOKIE ? config.CORE_RPC.COOKIE_PATH : undefined, +}; + +export default new bitcoin.Client(nodeRpcCredentials); diff --git a/backend/src/api/bitcoin/bitcoin-core.routes.ts b/backend/src/api/bitcoin/bitcoin-core.routes.ts new file mode 100644 index 0000000000..7933dc17b1 --- /dev/null +++ b/backend/src/api/bitcoin/bitcoin-core.routes.ts @@ -0,0 +1,249 @@ +import { Application, NextFunction, Request, Response } from 'express'; +import logger from '../../logger'; +import bitcoinClient from './bitcoin-client'; + +/** + * Define a set of routes used by the accelerator server + * Those routes are not designed to be public + */ +class BitcoinBackendRoutes { + private static tag = 'BitcoinBackendRoutes'; + + public initRoutes(app: Application) { + app + .get('/api/internal/bitcoin-core/' + 'get-mempool-entry', this.disableCache, this.$getMempoolEntry) + .post('/api/internal/bitcoin-core/' + 'decode-raw-transaction', this.disableCache, this.$decodeRawTransaction) + .get('/api/internal/bitcoin-core/' + 'get-raw-transaction', this.disableCache, this.$getRawTransaction) + .post('/api/internal/bitcoin-core/' + 'send-raw-transaction', this.disableCache, this.$sendRawTransaction) + .post('/api/internal/bitcoin-core/' + 'test-mempool-accept', this.disableCache, this.$testMempoolAccept) + .get('/api/internal/bitcoin-core/' + 'get-mempool-ancestors', this.disableCache, this.$getMempoolAncestors) + .get('/api/internal/bitcoin-core/' + 'get-block', this.disableCache, this.$getBlock) + .get('/api/internal/bitcoin-core/' + 'get-block-hash', this.disableCache, this.$getBlockHash) + .get('/api/internal/bitcoin-core/' + 'get-block-count', this.disableCache, this.$getBlockCount) + ; + } + + /** + * Disable caching for bitcoin core routes + * + * @param req + * @param res + * @param next + */ + private disableCache(req: Request, res: Response, next: NextFunction): void { + res.setHeader('Pragma', 'no-cache'); + res.setHeader('Cache-control', 'private, no-store, no-cache, must-revalidate, proxy-revalidate, max-age=0'); + res.setHeader('expires', -1); + next(); + } + + /** + * Exeption handler to return proper details to the accelerator server + * + * @param e + * @param fnName + * @param res + */ + private static handleException(e: any, fnName: string, res: Response): void { + if (typeof(e.code) === 'number') { + res.status(400).send(JSON.stringify(e, ['code', 'message'])); + } else { + const err = `exception in ${fnName}. ${e}. Details: ${JSON.stringify(e, ['code', 'message'])}`; + logger.err(err, BitcoinBackendRoutes.tag); + res.status(500).send(err); + } + } + + private async $getMempoolEntry(req: Request, res: Response): Promise { + const txid = req.query.txid; + try { + if (typeof(txid) !== 'string' || txid.length !== 64) { + res.status(400).send(`invalid param txid ${txid}. must be a string of 64 char`); + return; + } + const mempoolEntry = await bitcoinClient.getMempoolEntry(txid); + if (!mempoolEntry) { + res.status(404).send(`no mempool entry found for txid ${txid}`); + return; + } + res.status(200).send(mempoolEntry); + } catch (e: any) { + BitcoinBackendRoutes.handleException(e, 'getMempoolEntry', res); + } + } + + private async $decodeRawTransaction(req: Request, res: Response): Promise { + const rawTx = req.body.rawTx; + try { + if (typeof(rawTx) !== 'string') { + res.status(400).send(`invalid param rawTx ${rawTx}. must be a string`); + return; + } + const decodedTx = await bitcoinClient.decodeRawTransaction(rawTx); + if (!decodedTx) { + res.status(400).send(`unable to decode rawTx ${rawTx}`); + return; + } + res.status(200).send(decodedTx); + } catch (e: any) { + BitcoinBackendRoutes.handleException(e, 'decodeRawTransaction', res); + } + } + + private async $getRawTransaction(req: Request, res: Response): Promise { + const txid = req.query.txid; + const verbose = req.query.verbose; + try { + if (typeof(txid) !== 'string' || txid.length !== 64) { + res.status(400).send(`invalid param txid ${txid}. must be a string of 64 char`); + return; + } + if (typeof(verbose) !== 'string') { + res.status(400).send(`invalid param verbose ${verbose}. must be a string representing an integer`); + return; + } + const verboseNumber = parseInt(verbose, 10); + if (typeof(verboseNumber) !== 'number') { + res.status(400).send(`invalid param verbose ${verbose}. must be a valid integer`); + return; + } + + const decodedTx = await bitcoinClient.getRawTransaction(txid, verboseNumber); + if (!decodedTx) { + res.status(400).send(`unable to get raw transaction for txid ${txid}`); + return; + } + res.status(200).send(decodedTx); + } catch (e: any) { + BitcoinBackendRoutes.handleException(e, 'decodeRawTransaction', res); + } + } + + private async $sendRawTransaction(req: Request, res: Response): Promise { + const rawTx = req.body.rawTx; + try { + if (typeof(rawTx) !== 'string') { + res.status(400).send(`invalid param rawTx ${rawTx}. must be a string`); + return; + } + const txHex = await bitcoinClient.sendRawTransaction(rawTx); + if (!txHex) { + res.status(400).send(`unable to send rawTx ${rawTx}`); + return; + } + res.status(200).send(txHex); + } catch (e: any) { + BitcoinBackendRoutes.handleException(e, 'sendRawTransaction', res); + } + } + + private async $testMempoolAccept(req: Request, res: Response): Promise { + const rawTxs = req.body.rawTxs; + try { + if (typeof(rawTxs) !== 'object') { + res.status(400).send(`invalid param rawTxs ${JSON.stringify(rawTxs)}. must be an array of string`); + return; + } + const txHex = await bitcoinClient.testMempoolAccept(rawTxs); + if (typeof(txHex) !== 'object' || txHex.length === 0) { + res.status(400).send(`testmempoolaccept failed for raw txs ${JSON.stringify(rawTxs)}, got an empty result`); + return; + } + res.status(200).send(txHex); + } catch (e: any) { + BitcoinBackendRoutes.handleException(e, 'testMempoolAccept', res); + } + } + + private async $getMempoolAncestors(req: Request, res: Response): Promise { + const txid = req.query.txid; + const verbose = req.query.verbose; + try { + if (typeof(txid) !== 'string' || txid.length !== 64) { + res.status(400).send(`invalid param txid ${txid}. must be a string of 64 char`); + return; + } + if (typeof(verbose) !== 'string' || (verbose !== 'true' && verbose !== 'false')) { + res.status(400).send(`invalid param verbose ${verbose}. must be a string ('true' | 'false')`); + return; + } + + const ancestors = await bitcoinClient.getMempoolAncestors(txid, verbose === 'true' ? true : false); + if (!ancestors) { + res.status(400).send(`unable to get mempool ancestors for txid ${txid}`); + return; + } + res.status(200).send(ancestors); + } catch (e: any) { + BitcoinBackendRoutes.handleException(e, 'getMempoolAncestors', res); + } + } + + private async $getBlock(req: Request, res: Response): Promise { + const blockHash = req.query.hash; + const verbosity = req.query.verbosity; + try { + if (typeof(blockHash) !== 'string' || blockHash.length !== 64) { + res.status(400).send(`invalid param blockHash ${blockHash}. must be a string of 64 char`); + return; + } + if (typeof(verbosity) !== 'string') { + res.status(400).send(`invalid param verbosity ${verbosity}. must be a string representing an integer`); + return; + } + const verbosityNumber = parseInt(verbosity, 10); + if (typeof(verbosityNumber) !== 'number') { + res.status(400).send(`invalid param verbosity ${verbosity}. must be a valid integer`); + return; + } + + const block = await bitcoinClient.getBlock(blockHash, verbosityNumber); + if (!block) { + res.status(400).send(`unable to get block for block hash ${blockHash}`); + return; + } + res.status(200).send(block); + } catch (e: any) { + BitcoinBackendRoutes.handleException(e, 'getBlock', res); + } + } + + private async $getBlockHash(req: Request, res: Response): Promise { + const blockHeight = req.query.height; + try { + if (typeof(blockHeight) !== 'string') { + res.status(400).send(`invalid param blockHeight ${blockHeight}, must be a string representing an integer`); + return; + } + const blockHeightNumber = parseInt(blockHeight, 10); + if (typeof(blockHeightNumber) !== 'number') { + res.status(400).send(`invalid param blockHeight ${blockHeight}. must be a valid integer`); + return; + } + + const block = await bitcoinClient.getBlockHash(blockHeightNumber); + if (!block) { + res.status(400).send(`unable to get block hash for block height ${blockHeightNumber}`); + return; + } + res.status(200).send(block); + } catch (e: any) { + BitcoinBackendRoutes.handleException(e, 'getBlockHash', res); + } + } + + private async $getBlockCount(req: Request, res: Response): Promise { + try { + const count = await bitcoinClient.getBlockCount(); + if (!count) { + res.status(400).send(`unable to get block count`); + return; + } + res.status(200).send(`${count}`); + } catch (e: any) { + BitcoinBackendRoutes.handleException(e, 'getBlockCount', res); + } + } +} + +export default new BitcoinBackendRoutes \ No newline at end of file diff --git a/backend/src/api/bitcoin/bitcoin-second-client.ts b/backend/src/api/bitcoin/bitcoin-second-client.ts new file mode 100644 index 0000000000..6ae9cefb0b --- /dev/null +++ b/backend/src/api/bitcoin/bitcoin-second-client.ts @@ -0,0 +1,14 @@ +import config from '../../config'; +const bitcoin = require('../../rpc-api/index'); +import { BitcoinRpcCredentials } from './bitcoin-api-abstract-factory'; + +const nodeRpcCredentials: BitcoinRpcCredentials = { + host: config.SECOND_CORE_RPC.HOST, + port: config.SECOND_CORE_RPC.PORT, + user: config.SECOND_CORE_RPC.USERNAME, + pass: config.SECOND_CORE_RPC.PASSWORD, + timeout: config.SECOND_CORE_RPC.TIMEOUT, + cookie: config.SECOND_CORE_RPC.COOKIE ? config.SECOND_CORE_RPC.COOKIE_PATH : undefined, +}; + +export default new bitcoin.Client(nodeRpcCredentials); diff --git a/backend/src/api/bitcoin/bitcoin.routes.ts b/backend/src/api/bitcoin/bitcoin.routes.ts new file mode 100644 index 0000000000..a65af3f190 --- /dev/null +++ b/backend/src/api/bitcoin/bitcoin.routes.ts @@ -0,0 +1,786 @@ +import { Application, Request, Response } from 'express'; +import axios from 'axios'; +import * as bitcoinjs from 'bitcoinjs-lib'; +import config from '../../config'; +import websocketHandler from '../websocket-handler'; +import mempool from '../mempool'; +import feeApi from '../fee-api'; +import mempoolBlocks from '../mempool-blocks'; +import bitcoinApi from './bitcoin-api-factory'; +import { Common } from '../common'; +import backendInfo from '../backend-info'; +import transactionUtils from '../transaction-utils'; +import { IEsploraApi } from './esplora-api.interface'; +import loadingIndicators from '../loading-indicators'; +import { TransactionExtended } from '../../mempool.interfaces'; +import logger from '../../logger'; +import blocks from '../blocks'; +import bitcoinClient from './bitcoin-client'; +import difficultyAdjustment from '../difficulty-adjustment'; +import transactionRepository from '../../repositories/TransactionRepository'; +import rbfCache from '../rbf-cache'; +import { calculateMempoolTxCpfp } from '../cpfp'; + +class BitcoinRoutes { + public initRoutes(app: Application) { + app + .get(config.MEMPOOL.API_URL_PREFIX + 'transaction-times', this.getTransactionTimes) + .get(config.MEMPOOL.API_URL_PREFIX + 'cpfp/:txId', this.$getCpfpInfo) + .get(config.MEMPOOL.API_URL_PREFIX + 'difficulty-adjustment', this.getDifficultyChange) + .get(config.MEMPOOL.API_URL_PREFIX + 'fees/recommended', this.getRecommendedFees) + .get(config.MEMPOOL.API_URL_PREFIX + 'fees/mempool-blocks', this.getMempoolBlocks) + .get(config.MEMPOOL.API_URL_PREFIX + 'backend-info', this.getBackendInfo) + .get(config.MEMPOOL.API_URL_PREFIX + 'init-data', this.getInitData) + .get(config.MEMPOOL.API_URL_PREFIX + 'validate-address/:address', this.validateAddress) + .get(config.MEMPOOL.API_URL_PREFIX + 'tx/:txId/rbf', this.getRbfHistory) + .get(config.MEMPOOL.API_URL_PREFIX + 'tx/:txId/cached', this.getCachedTx) + .get(config.MEMPOOL.API_URL_PREFIX + 'replacements', this.getRbfReplacements) + .get(config.MEMPOOL.API_URL_PREFIX + 'fullrbf/replacements', this.getFullRbfReplacements) + .post(config.MEMPOOL.API_URL_PREFIX + 'tx/push', this.$postTransactionForm) + .get(config.MEMPOOL.API_URL_PREFIX + 'blocks', this.getBlocks.bind(this)) + .get(config.MEMPOOL.API_URL_PREFIX + 'blocks/:height', this.getBlocks.bind(this)) + .get(config.MEMPOOL.API_URL_PREFIX + 'block/:hash', this.getBlock) + .get(config.MEMPOOL.API_URL_PREFIX + 'block/:hash/summary', this.getStrippedBlockTransactions) + .get(config.MEMPOOL.API_URL_PREFIX + 'block/:hash/audit-summary', this.getBlockAuditSummary) + .get(config.MEMPOOL.API_URL_PREFIX + 'block/:hash/tx/:txid/audit', this.$getBlockTxAuditSummary) + .get(config.MEMPOOL.API_URL_PREFIX + 'blocks/tip/height', this.getBlockTipHeight) + .post(config.MEMPOOL.API_URL_PREFIX + 'psbt/addparents', this.postPsbtCompletion) + .get(config.MEMPOOL.API_URL_PREFIX + 'blocks-bulk/:from', this.getBlocksByBulk.bind(this)) + .get(config.MEMPOOL.API_URL_PREFIX + 'blocks-bulk/:from/:to', this.getBlocksByBulk.bind(this)) + ; + + if (config.MEMPOOL.BACKEND !== 'esplora') { + app + .get(config.MEMPOOL.API_URL_PREFIX + 'mempool', this.getMempool) + .get(config.MEMPOOL.API_URL_PREFIX + 'mempool/txids', this.getMempoolTxIds) + .get(config.MEMPOOL.API_URL_PREFIX + 'mempool/recent', this.getRecentMempoolTransactions) + .get(config.MEMPOOL.API_URL_PREFIX + 'tx/:txId', this.getTransaction) + .post(config.MEMPOOL.API_URL_PREFIX + 'tx', this.$postTransaction) + .post(config.MEMPOOL.API_URL_PREFIX + 'txs/test', this.$testTransactions) + .get(config.MEMPOOL.API_URL_PREFIX + 'tx/:txId/hex', this.getRawTransaction) + .get(config.MEMPOOL.API_URL_PREFIX + 'tx/:txId/status', this.getTransactionStatus) + .get(config.MEMPOOL.API_URL_PREFIX + 'tx/:txId/outspends', this.getTransactionOutspends) + .get(config.MEMPOOL.API_URL_PREFIX + 'txs/outspends', this.$getBatchedOutspends) + .get(config.MEMPOOL.API_URL_PREFIX + 'block/:hash/header', this.getBlockHeader) + .get(config.MEMPOOL.API_URL_PREFIX + 'blocks/tip/hash', this.getBlockTipHash) + .get(config.MEMPOOL.API_URL_PREFIX + 'block/:hash/raw', this.getRawBlock) + .get(config.MEMPOOL.API_URL_PREFIX + 'block/:hash/txids', this.getTxIdsForBlock) + .get(config.MEMPOOL.API_URL_PREFIX + 'block/:hash/txs', this.getBlockTransactions) + .get(config.MEMPOOL.API_URL_PREFIX + 'block/:hash/txs/:index', this.getBlockTransactions) + .get(config.MEMPOOL.API_URL_PREFIX + 'block-height/:height', this.getBlockHeight) + .get(config.MEMPOOL.API_URL_PREFIX + 'address/:address', this.getAddress) + .get(config.MEMPOOL.API_URL_PREFIX + 'address/:address/txs', this.getAddressTransactions) + .get(config.MEMPOOL.API_URL_PREFIX + 'address/:address/txs/summary', this.getAddressTransactionSummary) + .get(config.MEMPOOL.API_URL_PREFIX + 'scripthash/:scripthash', this.getScriptHash) + .get(config.MEMPOOL.API_URL_PREFIX + 'scripthash/:scripthash/txs', this.getScriptHashTransactions) + .get(config.MEMPOOL.API_URL_PREFIX + 'scripthash/:scripthash/txs/summary', this.getScriptHashTransactionSummary) + .get(config.MEMPOOL.API_URL_PREFIX + 'address-prefix/:prefix', this.getAddressPrefix) + ; + } + } + + + private getInitData(req: Request, res: Response) { + try { + const result = websocketHandler.getSerializedInitData(); + res.set('Content-Type', 'application/json'); + res.send(result); + } catch (e) { + res.status(500).send(e instanceof Error ? e.message : e); + } + } + + private getRecommendedFees(req: Request, res: Response) { + if (!mempool.isInSync()) { + res.statusCode = 503; + res.send('Service Unavailable'); + return; + } + const result = feeApi.getRecommendedFee(); + res.json(result); + } + + private getMempoolBlocks(req: Request, res: Response) { + try { + const result = mempoolBlocks.getMempoolBlocks(); + res.json(result); + } catch (e) { + res.status(500).send(e instanceof Error ? e.message : e); + } + } + + private getTransactionTimes(req: Request, res: Response) { + if (!Array.isArray(req.query.txId)) { + res.status(500).send('Not an array'); + return; + } + const txIds: string[] = []; + for (const _txId in req.query.txId) { + if (typeof req.query.txId[_txId] === 'string') { + txIds.push(req.query.txId[_txId].toString()); + } + } + + const times = mempool.getFirstSeenForTransactions(txIds); + res.json(times); + } + + private async $getBatchedOutspends(req: Request, res: Response): Promise { + const txids_csv = req.query.txids; + if (!txids_csv || typeof txids_csv !== 'string') { + res.status(500).send('Invalid txids format'); + return; + } + const txids = txids_csv.split(','); + if (txids.length > 50) { + res.status(400).send('Too many txids requested'); + return; + } + + try { + const batchedOutspends = await bitcoinApi.$getBatchedOutspends(txids); + res.json(batchedOutspends); + } catch (e) { + res.status(500).send(e instanceof Error ? e.message : e); + } + } + + private async $getCpfpInfo(req: Request, res: Response) { + if (!/^[a-fA-F0-9]{64}$/.test(req.params.txId)) { + res.status(501).send(`Invalid transaction ID.`); + return; + } + + const tx = mempool.getMempool()[req.params.txId]; + if (tx) { + if (tx?.cpfpChecked) { + res.json({ + ancestors: tx.ancestors, + bestDescendant: tx.bestDescendant || null, + descendants: tx.descendants || null, + effectiveFeePerVsize: tx.effectiveFeePerVsize || null, + sigops: tx.sigops, + fee: tx.fee, + adjustedVsize: tx.adjustedVsize, + acceleration: tx.acceleration, + acceleratedBy: tx.acceleratedBy || undefined, + acceleratedAt: tx.acceleratedAt || undefined, + }); + return; + } + + const cpfpInfo = calculateMempoolTxCpfp(tx, mempool.getMempool()); + + res.json(cpfpInfo); + return; + } else { + let cpfpInfo; + if (config.DATABASE.ENABLED) { + try { + cpfpInfo = await transactionRepository.$getCpfpInfo(req.params.txId); + } catch (e) { + res.status(500).send('failed to get CPFP info'); + return; + } + } + if (cpfpInfo) { + res.json(cpfpInfo); + return; + } else { + res.json({ + ancestors: [] + }); + return; + } + } + } + + private getBackendInfo(req: Request, res: Response) { + res.json(backendInfo.getBackendInfo()); + } + + private async getTransaction(req: Request, res: Response) { + try { + const transaction = await transactionUtils.$getTransactionExtended(req.params.txId, true, false, false, true); + res.json(transaction); + } catch (e) { + let statusCode = 500; + if (e instanceof Error && e instanceof Error && e.message && e.message.indexOf('No such mempool or blockchain transaction') > -1) { + statusCode = 404; + } + res.status(statusCode).send(e instanceof Error ? e.message : e); + } + } + + private async getRawTransaction(req: Request, res: Response) { + try { + const transaction: IEsploraApi.Transaction = await bitcoinApi.$getRawTransaction(req.params.txId, true); + res.setHeader('content-type', 'text/plain'); + res.send(transaction.hex); + } catch (e) { + let statusCode = 500; + if (e instanceof Error && e.message && e.message.indexOf('No such mempool or blockchain transaction') > -1) { + statusCode = 404; + } + res.status(statusCode).send(e instanceof Error ? e.message : e); + } + } + + /** + * Takes the PSBT as text/plain body, parses it, and adds the full + * parent transaction to each input that doesn't already have it. + * This is used for BTCPayServer / Trezor users which need access to + * the full parent transaction even with segwit inputs. + * It will respond with a text/plain PSBT in the same format (hex|base64). + */ + private async postPsbtCompletion(req: Request, res: Response): Promise { + res.setHeader('content-type', 'text/plain'); + const notFoundError = `Couldn't get transaction hex for parent of input`; + try { + let psbt: bitcoinjs.Psbt; + let format: 'hex' | 'base64'; + let isModified = false; + try { + psbt = bitcoinjs.Psbt.fromBase64(req.body); + format = 'base64'; + } catch (e1) { + try { + psbt = bitcoinjs.Psbt.fromHex(req.body); + format = 'hex'; + } catch (e2) { + throw new Error(`Unable to parse PSBT`); + } + } + for (const [index, input] of psbt.data.inputs.entries()) { + if (!input.nonWitnessUtxo) { + // Buffer.from ensures it won't be modified in place by reverse() + const txid = Buffer.from(psbt.txInputs[index].hash) + .reverse() + .toString('hex'); + + let transactionHex: string; + // If missing transaction, return 404 status error + try { + transactionHex = await bitcoinApi.$getTransactionHex(txid); + if (!transactionHex) { + throw new Error(''); + } + } catch (err) { + throw new Error(`${notFoundError} #${index} @ ${txid}`); + } + + psbt.updateInput(index, { + nonWitnessUtxo: Buffer.from(transactionHex, 'hex'), + }); + if (!isModified) { + isModified = true; + } + } + } + if (isModified) { + res.send(format === 'hex' ? psbt.toHex() : psbt.toBase64()); + } else { + // Not modified + // 422 Unprocessable Entity + // https://developer.mozilla.org/en-US/docs/Web/HTTP/Status/422 + res.status(422).send(`Psbt had no missing nonWitnessUtxos.`); + } + } catch (e: any) { + if (e instanceof Error && new RegExp(notFoundError).test(e.message)) { + res.status(404).send(e.message); + } else { + res.status(500).send(e instanceof Error ? e.message : e); + } + } + } + + private async getTransactionStatus(req: Request, res: Response) { + try { + const transaction = await transactionUtils.$getTransactionExtended(req.params.txId, true); + res.json(transaction.status); + } catch (e) { + let statusCode = 500; + if (e instanceof Error && e.message && e.message.indexOf('No such mempool or blockchain transaction') > -1) { + statusCode = 404; + } + res.status(statusCode).send(e instanceof Error ? e.message : e); + } + } + + private async getStrippedBlockTransactions(req: Request, res: Response) { + try { + const transactions = await blocks.$getStrippedBlockTransactions(req.params.hash); + res.setHeader('Expires', new Date(Date.now() + 1000 * 3600 * 24 * 30).toUTCString()); + res.json(transactions); + } catch (e) { + res.status(500).send(e instanceof Error ? e.message : e); + } + } + + private async getBlock(req: Request, res: Response) { + try { + const block = await blocks.$getBlock(req.params.hash); + + const blockAge = new Date().getTime() / 1000 - block.timestamp; + const day = 24 * 3600; + let cacheDuration; + if (blockAge > 365 * day) { + cacheDuration = 30 * day; + } else if (blockAge > 30 * day) { + cacheDuration = 10 * day; + } else { + cacheDuration = 600 + } + + res.setHeader('Expires', new Date(Date.now() + 1000 * cacheDuration).toUTCString()); + res.json(block); + } catch (e) { + res.status(500).send(e instanceof Error ? e.message : e); + } + } + + private async getBlockHeader(req: Request, res: Response) { + try { + const blockHeader = await bitcoinApi.$getBlockHeader(req.params.hash); + res.setHeader('content-type', 'text/plain'); + res.send(blockHeader); + } catch (e) { + res.status(500).send(e instanceof Error ? e.message : e); + } + } + + private async getBlockAuditSummary(req: Request, res: Response) { + try { + const auditSummary = await blocks.$getBlockAuditSummary(req.params.hash); + if (auditSummary) { + res.setHeader('Expires', new Date(Date.now() + 1000 * 3600 * 24 * 30).toUTCString()); + res.json(auditSummary); + } else { + return res.status(404).send(`audit not available`); + } + } catch (e) { + res.status(500).send(e instanceof Error ? e.message : e); + } + } + + private async $getBlockTxAuditSummary(req: Request, res: Response) { + try { + const auditSummary = await blocks.$getBlockTxAuditSummary(req.params.hash, req.params.txid); + if (auditSummary) { + res.setHeader('Expires', new Date(Date.now() + 1000 * 3600 * 24 * 30).toUTCString()); + res.json(auditSummary); + } else { + return res.status(404).send(`transaction audit not available`); + } + } catch (e) { + res.status(500).send(e instanceof Error ? e.message : e); + } + } + + private async getBlocks(req: Request, res: Response) { + try { + if (['mainnet', 'testnet', 'signet'].includes(config.MEMPOOL.NETWORK)) { // Bitcoin + const height = req.params.height === undefined ? undefined : parseInt(req.params.height, 10); + res.setHeader('Expires', new Date(Date.now() + 1000 * 60).toUTCString()); + res.json(await blocks.$getBlocks(height, 15)); + } else { // Liquid + return await this.getLegacyBlocks(req, res); + } + } catch (e) { + res.status(500).send(e instanceof Error ? e.message : e); + } + } + + private async getBlocksByBulk(req: Request, res: Response) { + try { + if (['mainnet', 'testnet', 'signet'].includes(config.MEMPOOL.NETWORK) === false) { // Liquid - Not implemented + return res.status(404).send(`This API is only available for Bitcoin networks`); + } + if (config.MEMPOOL.MAX_BLOCKS_BULK_QUERY <= 0) { + return res.status(404).send(`This API is disabled. Set config.MEMPOOL.MAX_BLOCKS_BULK_QUERY to a positive number to enable it.`); + } + if (!Common.indexingEnabled()) { + return res.status(404).send(`Indexing is required for this API`); + } + + const from = parseInt(req.params.from, 10); + if (!req.params.from || from < 0) { + return res.status(400).send(`Parameter 'from' must be a block height (integer)`); + } + const to = req.params.to === undefined ? await bitcoinApi.$getBlockHeightTip() : parseInt(req.params.to, 10); + if (to < 0) { + return res.status(400).send(`Parameter 'to' must be a block height (integer)`); + } + if (from > to) { + return res.status(400).send(`Parameter 'to' must be a higher block height than 'from'`); + } + if ((to - from + 1) > config.MEMPOOL.MAX_BLOCKS_BULK_QUERY) { + return res.status(400).send(`You can only query ${config.MEMPOOL.MAX_BLOCKS_BULK_QUERY} blocks at once.`); + } + + res.setHeader('Expires', new Date(Date.now() + 1000 * 60).toUTCString()); + res.json(await blocks.$getBlocksBetweenHeight(from, to)); + + } catch (e) { + res.status(500).send(e instanceof Error ? e.message : e); + } + } + + private async getLegacyBlocks(req: Request, res: Response) { + try { + const returnBlocks: IEsploraApi.Block[] = []; + const tip = blocks.getCurrentBlockHeight(); + const fromHeight = Math.min(parseInt(req.params.height, 10) || tip, tip); + + // Check if block height exist in local cache to skip the hash lookup + const blockByHeight = blocks.getBlocks().find((b) => b.height === fromHeight); + let startFromHash: string | null = null; + if (blockByHeight) { + startFromHash = blockByHeight.id; + } else { + startFromHash = await bitcoinApi.$getBlockHash(fromHeight); + } + + let nextHash = startFromHash; + for (let i = 0; i < 15 && nextHash; i++) { + const localBlock = blocks.getBlocks().find((b) => b.id === nextHash); + if (localBlock) { + returnBlocks.push(localBlock); + nextHash = localBlock.previousblockhash; + } else { + const block = await bitcoinApi.$getBlock(nextHash); + returnBlocks.push(block); + nextHash = block.previousblockhash; + } + } + + res.setHeader('Expires', new Date(Date.now() + 1000 * 60).toUTCString()); + res.json(returnBlocks); + } catch (e) { + res.status(500).send(e instanceof Error ? e.message : e); + } + } + + private async getBlockTransactions(req: Request, res: Response) { + try { + loadingIndicators.setProgress('blocktxs-' + req.params.hash, 0); + + const txIds = await bitcoinApi.$getTxIdsForBlock(req.params.hash); + const transactions: TransactionExtended[] = []; + const startingIndex = Math.max(0, parseInt(req.params.index || '0', 10)); + + const endIndex = Math.min(startingIndex + 10, txIds.length); + for (let i = startingIndex; i < endIndex; i++) { + try { + const transaction = await transactionUtils.$getTransactionExtended(txIds[i], true, true); + transactions.push(transaction); + loadingIndicators.setProgress('blocktxs-' + req.params.hash, (i - startingIndex + 1) / (endIndex - startingIndex) * 100); + } catch (e) { + logger.debug('getBlockTransactions error: ' + (e instanceof Error ? e.message : e)); + } + } + res.json(transactions); + } catch (e) { + loadingIndicators.setProgress('blocktxs-' + req.params.hash, 100); + res.status(500).send(e instanceof Error ? e.message : e); + } + } + + private async getBlockHeight(req: Request, res: Response) { + try { + const blockHash = await bitcoinApi.$getBlockHash(parseInt(req.params.height, 10)); + res.send(blockHash); + } catch (e) { + res.status(500).send(e instanceof Error ? e.message : e); + } + } + + private async getAddress(req: Request, res: Response) { + if (config.MEMPOOL.BACKEND === 'none') { + res.status(405).send('Address lookups cannot be used with bitcoind as backend.'); + return; + } + + try { + const addressData = await bitcoinApi.$getAddress(req.params.address); + res.json(addressData); + } catch (e) { + if (e instanceof Error && e.message && (e.message.indexOf('too long') > 0 || e.message.indexOf('confirmed status') > 0)) { + return res.status(413).send(e instanceof Error ? e.message : e); + } + res.status(500).send(e instanceof Error ? e.message : e); + } + } + + private async getAddressTransactions(req: Request, res: Response): Promise { + if (config.MEMPOOL.BACKEND === 'none') { + res.status(405).send('Address lookups cannot be used with bitcoind as backend.'); + return; + } + + try { + let lastTxId: string = ''; + if (req.query.after_txid && typeof req.query.after_txid === 'string') { + lastTxId = req.query.after_txid; + } + const transactions = await bitcoinApi.$getAddressTransactions(req.params.address, lastTxId); + res.json(transactions); + } catch (e) { + if (e instanceof Error && e.message && (e.message.indexOf('too long') > 0 || e.message.indexOf('confirmed status') > 0)) { + res.status(413).send(e instanceof Error ? e.message : e); + return; + } + res.status(500).send(e instanceof Error ? e.message : e); + } + } + + private async getAddressTransactionSummary(req: Request, res: Response): Promise { + if (config.MEMPOOL.BACKEND !== 'esplora') { + res.status(405).send('Address summary lookups require mempool/electrs backend.'); + return; + } + } + + private async getScriptHash(req: Request, res: Response) { + if (config.MEMPOOL.BACKEND === 'none') { + res.status(405).send('Address lookups cannot be used with bitcoind as backend.'); + return; + } + + try { + // electrum expects scripthashes in little-endian + const electrumScripthash = req.params.scripthash.match(/../g)?.reverse().join('') ?? ''; + const addressData = await bitcoinApi.$getScriptHash(electrumScripthash); + res.json(addressData); + } catch (e) { + if (e instanceof Error && e.message && (e.message.indexOf('too long') > 0 || e.message.indexOf('confirmed status') > 0)) { + return res.status(413).send(e instanceof Error ? e.message : e); + } + res.status(500).send(e instanceof Error ? e.message : e); + } + } + + private async getScriptHashTransactions(req: Request, res: Response): Promise { + if (config.MEMPOOL.BACKEND === 'none') { + res.status(405).send('Address lookups cannot be used with bitcoind as backend.'); + return; + } + + try { + // electrum expects scripthashes in little-endian + const electrumScripthash = req.params.scripthash.match(/../g)?.reverse().join('') ?? ''; + let lastTxId: string = ''; + if (req.query.after_txid && typeof req.query.after_txid === 'string') { + lastTxId = req.query.after_txid; + } + const transactions = await bitcoinApi.$getScriptHashTransactions(electrumScripthash, lastTxId); + res.json(transactions); + } catch (e) { + if (e instanceof Error && e.message && (e.message.indexOf('too long') > 0 || e.message.indexOf('confirmed status') > 0)) { + res.status(413).send(e instanceof Error ? e.message : e); + return; + } + res.status(500).send(e instanceof Error ? e.message : e); + } + } + + private async getScriptHashTransactionSummary(req: Request, res: Response): Promise { + if (config.MEMPOOL.BACKEND !== 'esplora') { + res.status(405).send('Scripthash summary lookups require mempool/electrs backend.'); + return; + } + } + + private async getAddressPrefix(req: Request, res: Response) { + try { + const blockHash = await bitcoinApi.$getAddressPrefix(req.params.prefix); + res.send(blockHash); + } catch (e) { + res.status(500).send(e instanceof Error ? e.message : e); + } + } + + private async getRecentMempoolTransactions(req: Request, res: Response) { + const latestTransactions = Object.entries(mempool.getMempool()) + .sort((a, b) => (b[1].firstSeen || 0) - (a[1].firstSeen || 0)) + .slice(0, 10).map((tx) => Common.stripTransaction(tx[1])); + + res.json(latestTransactions); + } + + private async getMempool(req: Request, res: Response) { + const info = mempool.getMempoolInfo(); + res.json({ + count: info.size, + vsize: info.bytes, + total_fee: info.total_fee * 1e8, + fee_histogram: [] + }); + } + + private async getMempoolTxIds(req: Request, res: Response) { + try { + const rawMempool = await bitcoinApi.$getRawMempool(); + res.send(rawMempool); + } catch (e) { + res.status(500).send(e instanceof Error ? e.message : e); + } + } + + private getBlockTipHeight(req: Request, res: Response) { + try { + const result = blocks.getCurrentBlockHeight(); + if (!result) { + return res.status(503).send(`Service Temporarily Unavailable`); + } + res.setHeader('content-type', 'text/plain'); + res.send(result.toString()); + } catch (e) { + res.status(500).send(e instanceof Error ? e.message : e); + } + } + + private async getBlockTipHash(req: Request, res: Response) { + try { + const result = await bitcoinApi.$getBlockHashTip(); + res.setHeader('content-type', 'text/plain'); + res.send(result); + } catch (e) { + res.status(500).send(e instanceof Error ? e.message : e); + } + } + + private async getRawBlock(req: Request, res: Response) { + try { + const result = await bitcoinApi.$getRawBlock(req.params.hash); + res.setHeader('content-type', 'application/octet-stream'); + res.send(result); + } catch (e) { + res.status(500).send(e instanceof Error ? e.message : e); + } + } + + private async getTxIdsForBlock(req: Request, res: Response) { + try { + const result = await bitcoinApi.$getTxIdsForBlock(req.params.hash); + res.json(result); + } catch (e) { + res.status(500).send(e instanceof Error ? e.message : e); + } + } + + private async validateAddress(req: Request, res: Response) { + try { + const result = await bitcoinClient.validateAddress(req.params.address); + res.json(result); + } catch (e) { + res.status(500).send(e instanceof Error ? e.message : e); + } + } + + private async getRbfHistory(req: Request, res: Response) { + try { + const replacements = rbfCache.getRbfTree(req.params.txId) || null; + const replaces = rbfCache.getReplaces(req.params.txId) || null; + res.json({ + replacements, + replaces + }); + } catch (e) { + res.status(500).send(e instanceof Error ? e.message : e); + } + } + + private async getRbfReplacements(req: Request, res: Response) { + try { + const result = rbfCache.getRbfTrees(false); + res.json(result); + } catch (e) { + res.status(500).send(e instanceof Error ? e.message : e); + } + } + + private async getFullRbfReplacements(req: Request, res: Response) { + try { + const result = rbfCache.getRbfTrees(true); + res.json(result); + } catch (e) { + res.status(500).send(e instanceof Error ? e.message : e); + } + } + + private async getCachedTx(req: Request, res: Response) { + try { + const result = rbfCache.getTx(req.params.txId); + if (result) { + res.json(result); + } else { + res.status(204).send(); + } + } catch (e) { + res.status(500).send(e instanceof Error ? e.message : e); + } + } + + private async getTransactionOutspends(req: Request, res: Response) { + try { + const result = await bitcoinApi.$getOutspends(req.params.txId); + res.json(result); + } catch (e) { + res.status(500).send(e instanceof Error ? e.message : e); + } + } + + private getDifficultyChange(req: Request, res: Response) { + try { + const da = difficultyAdjustment.getDifficultyAdjustment(); + if (da) { + res.json(da); + } else { + res.status(503).send(`Service Temporarily Unavailable`); + } + } catch (e) { + res.status(500).send(e instanceof Error ? e.message : e); + } + } + + private async $postTransaction(req: Request, res: Response) { + res.setHeader('content-type', 'text/plain'); + try { + const rawTx = Common.getTransactionFromRequest(req, false); + const txIdResult = await bitcoinApi.$sendRawTransaction(rawTx); + res.send(txIdResult); + } catch (e: any) { + res.status(400).send(e.message && e.code ? 'sendrawtransaction RPC error: ' + JSON.stringify({ code: e.code, message: e.message }) + : (e.message || 'Error')); + } + } + + private async $postTransactionForm(req: Request, res: Response) { + res.setHeader('content-type', 'text/plain'); + try { + const txHex = Common.getTransactionFromRequest(req, true); + const txIdResult = await bitcoinClient.sendRawTransaction(txHex); + res.send(txIdResult); + } catch (e: any) { + res.status(400).send(e.message && e.code ? 'sendrawtransaction RPC error: ' + JSON.stringify({ code: e.code, message: e.message }) + : (e.message || 'Error')); + } + } + + private async $testTransactions(req: Request, res: Response) { + try { + const rawTxs = Common.getTransactionsFromRequest(req); + const maxfeerate = parseFloat(req.query.maxfeerate as string); + const result = await bitcoinApi.$testMempoolAccept(rawTxs, maxfeerate); + res.send(result); + } catch (e: any) { + res.setHeader('content-type', 'text/plain'); + res.status(400).send(e.message && e.code ? 'testmempoolaccept RPC error: ' + JSON.stringify({ code: e.code, message: e.message }) + : (e.message || 'Error')); + } + } + +} + +export default new BitcoinRoutes(); diff --git a/backend/src/api/bitcoin/electrs-api.ts b/backend/src/api/bitcoin/electrs-api.ts deleted file mode 100644 index 87ae5cc7cf..0000000000 --- a/backend/src/api/bitcoin/electrs-api.ts +++ /dev/null @@ -1,146 +0,0 @@ -const config = require('../../../mempool-config.json'); -import { Transaction, Block, MempoolInfo } from '../../interfaces'; -import * as request from 'request'; - -class ElectrsApi { - - constructor() { - } - - getMempoolInfo(): Promise { - return new Promise((resolve, reject) => { - request(config.ELECTRS_API_URL + '/mempool', { json: true, timeout: 10000 }, (err, res, response) => { - if (err) { - reject(err); - } else if (res.statusCode !== 200) { - reject(response); - } else { - if (typeof response.count !== 'number') { - reject('Empty data'); - return; - } - resolve({ - size: response.count, - bytes: response.vsize, - }); - } - }); - }); - } - - getRawMempool(): Promise { - return new Promise((resolve, reject) => { - request(config.ELECTRS_API_URL + '/mempool/txids', { json: true, timeout: 10000, forever: true }, (err, res, response) => { - if (err) { - reject(err); - } else if (res.statusCode !== 200) { - reject(response); - } else { - if (response.constructor === Array) { - resolve(response); - } else { - reject('returned invalid data'); - } - } - }); - }); - } - - getRawTransaction(txId: string): Promise { - return new Promise((resolve, reject) => { - request(config.ELECTRS_API_URL + '/tx/' + txId, { json: true, timeout: 10000, forever: true }, (err, res, response) => { - if (err) { - reject(err); - } else if (res.statusCode !== 200) { - reject(response); - } else { - if (response.constructor === Object) { - resolve(response); - } else { - reject('returned invalid data'); - } - } - }); - }); - } - - getBlockHeightTip(): Promise { - return new Promise((resolve, reject) => { - request(config.ELECTRS_API_URL + '/blocks/tip/height', { json: true, timeout: 10000 }, (err, res, response) => { - if (err) { - reject(err); - } else if (res.statusCode !== 200) { - reject(response); - } else { - resolve(response); - } - }); - }); - } - - getTxIdsForBlock(hash: string): Promise { - return new Promise((resolve, reject) => { - request(config.ELECTRS_API_URL + '/block/' + hash + '/txids', { json: true, timeout: 10000 }, (err, res, response) => { - if (err) { - reject(err); - } else if (res.statusCode !== 200) { - reject(response); - } else { - if (response.constructor === Array) { - resolve(response); - } else { - reject('returned invalid data'); - } - } - }); - }); - } - - getBlockHash(height: number): Promise { - return new Promise((resolve, reject) => { - request(config.ELECTRS_API_URL + '/block-height/' + height, { json: true, timeout: 10000 }, (err, res, response) => { - if (err) { - reject(err); - } else if (res.statusCode !== 200) { - reject(response); - } else { - resolve(response); - } - }); - }); - } - - getBlocksFromHeight(height: number): Promise { - return new Promise((resolve, reject) => { - request(config.ELECTRS_API_URL + '/blocks/' + height, { json: true, timeout: 10000 }, (err, res, response) => { - if (err) { - reject(err); - } else if (res.statusCode !== 200) { - reject(response); - } else { - resolve(response); - } - }); - }); - } - - getBlock(hash: string): Promise { - return new Promise((resolve, reject) => { - request(config.ELECTRS_API_URL + '/block/' + hash, { json: true, timeout: 10000 }, (err, res, response) => { - if (err) { - reject(err); - } else if (res.statusCode !== 200) { - reject(response); - } else { - if (response.constructor === Object) { - resolve(response); - } else { - reject('getBlock returned invalid data'); - } - } - }); - }); - } -} - -export default new ElectrsApi(); diff --git a/backend/src/api/bitcoin/electrum-api.interface.ts b/backend/src/api/bitcoin/electrum-api.interface.ts new file mode 100644 index 0000000000..633de3cbcd --- /dev/null +++ b/backend/src/api/bitcoin/electrum-api.interface.ts @@ -0,0 +1,12 @@ +export namespace IElectrumApi { + export interface ScriptHashBalance { + confirmed: number; + unconfirmed: number; + } + + export interface ScriptHashHistory { + height: number; + tx_hash: string; + fee?: number; + } +} diff --git a/backend/src/api/bitcoin/electrum-api.ts b/backend/src/api/bitcoin/electrum-api.ts new file mode 100644 index 0000000000..07c58dbc9a --- /dev/null +++ b/backend/src/api/bitcoin/electrum-api.ts @@ -0,0 +1,223 @@ +import config from '../../config'; +import Client from '@mempool/electrum-client'; +import { AbstractBitcoinApi } from './bitcoin-api-abstract-factory'; +import { IEsploraApi } from './esplora-api.interface'; +import { IElectrumApi } from './electrum-api.interface'; +import BitcoinApi from './bitcoin-api'; +import logger from '../../logger'; +import crypto from "crypto-js"; +import loadingIndicators from '../loading-indicators'; +import memoryCache from '../memory-cache'; + +class BitcoindElectrsApi extends BitcoinApi implements AbstractBitcoinApi { + private electrumClient: any; + + constructor(bitcoinClient: any) { + super(bitcoinClient); + + const electrumConfig = { client: 'mempool-v2', version: '1.4' }; + const electrumPersistencePolicy = { retryPeriod: 1000, maxRetry: Number.MAX_SAFE_INTEGER, callback: null }; + + const electrumCallbacks = { + onConnect: (client, versionInfo) => { logger.info(`Connected to Electrum Server at ${config.ELECTRUM.HOST}:${config.ELECTRUM.PORT} (${JSON.stringify(versionInfo)})`); }, + onClose: (client) => { logger.info(`Disconnected from Electrum Server at ${config.ELECTRUM.HOST}:${config.ELECTRUM.PORT}`); }, + onError: (err) => { logger.err(`Electrum error: ${JSON.stringify(err)}`); }, + onLog: (str) => { logger.debug(str); }, + }; + + this.electrumClient = new Client( + config.ELECTRUM.PORT, + config.ELECTRUM.HOST, + config.ELECTRUM.TLS_ENABLED ? 'tls' : 'tcp', + null, + electrumCallbacks + ); + + this.electrumClient.initElectrum(electrumConfig, electrumPersistencePolicy) + .then(() => { }) + .catch((err) => { + logger.err(`Error connecting to Electrum Server at ${config.ELECTRUM.HOST}:${config.ELECTRUM.PORT}`); + }); + } + + async $getAddress(address: string): Promise { + const addressInfo = await this.bitcoindClient.validateAddress(address); + if (!addressInfo || !addressInfo.isvalid) { + return ({ + 'address': address, + 'chain_stats': { + 'funded_txo_count': 0, + 'funded_txo_sum': 0, + 'spent_txo_count': 0, + 'spent_txo_sum': 0, + 'tx_count': 0 + }, + 'mempool_stats': { + 'funded_txo_count': 0, + 'funded_txo_sum': 0, + 'spent_txo_count': 0, + 'spent_txo_sum': 0, + 'tx_count': 0 + } + }); + } + + try { + const balance = await this.$getScriptHashBalance(addressInfo.scriptPubKey); + const history = await this.$getScriptHashHistory(addressInfo.scriptPubKey); + + const unconfirmed = history.filter((h) => h.fee).length; + + return { + 'address': addressInfo.address, + 'chain_stats': { + 'funded_txo_count': 0, + 'funded_txo_sum': balance.confirmed ? balance.confirmed : 0, + 'spent_txo_count': 0, + 'spent_txo_sum': balance.confirmed < 0 ? balance.confirmed : 0, + 'tx_count': history.length - unconfirmed, + }, + 'mempool_stats': { + 'funded_txo_count': 0, + 'funded_txo_sum': balance.unconfirmed > 0 ? balance.unconfirmed : 0, + 'spent_txo_count': 0, + 'spent_txo_sum': balance.unconfirmed < 0 ? -balance.unconfirmed : 0, + 'tx_count': unconfirmed, + }, + 'electrum': true, + }; + } catch (e: any) { + throw new Error(typeof e === 'string' ? e : e && e.message || e); + } + } + + async $getAddressTransactions(address: string, lastSeenTxId: string): Promise { + const addressInfo = await this.bitcoindClient.validateAddress(address); + if (!addressInfo || !addressInfo.isvalid) { + return []; + } + + try { + loadingIndicators.setProgress('address-' + address, 0); + + const transactions: IEsploraApi.Transaction[] = []; + const history = await this.$getScriptHashHistory(addressInfo.scriptPubKey); + history.sort((a, b) => (b.height || 9999999) - (a.height || 9999999)); + + let startingIndex = 0; + if (lastSeenTxId) { + const pos = history.findIndex((historicalTx) => historicalTx.tx_hash === lastSeenTxId); + if (pos) { + startingIndex = pos + 1; + } + } + const endIndex = Math.min(startingIndex + 10, history.length); + + for (let i = startingIndex; i < endIndex; i++) { + const tx = await this.$getRawTransaction(history[i].tx_hash, false, true); + transactions.push(tx); + loadingIndicators.setProgress('address-' + address, (i + 1) / endIndex * 100); + } + + return transactions; + } catch (e: any) { + loadingIndicators.setProgress('address-' + address, 100); + throw new Error(typeof e === 'string' ? e : e && e.message || e); + } + } + + async $getScriptHash(scripthash: string): Promise { + try { + const balance = await this.electrumClient.blockchainScripthash_getBalance(scripthash); + let history = memoryCache.get('Scripthash_getHistory', scripthash); + if (!history) { + history = await this.electrumClient.blockchainScripthash_getHistory(scripthash); + memoryCache.set('Scripthash_getHistory', scripthash, history, 2); + } + + const unconfirmed = history ? history.filter((h) => h.fee).length : 0; + + return { + 'scripthash': scripthash, + 'chain_stats': { + 'funded_txo_count': 0, + 'funded_txo_sum': balance.confirmed ? balance.confirmed : 0, + 'spent_txo_count': 0, + 'spent_txo_sum': balance.confirmed < 0 ? balance.confirmed : 0, + 'tx_count': (history?.length || 0) - unconfirmed, + }, + 'mempool_stats': { + 'funded_txo_count': 0, + 'funded_txo_sum': balance.unconfirmed > 0 ? balance.unconfirmed : 0, + 'spent_txo_count': 0, + 'spent_txo_sum': balance.unconfirmed < 0 ? -balance.unconfirmed : 0, + 'tx_count': unconfirmed, + }, + 'electrum': true, + }; + } catch (e: any) { + throw new Error(typeof e === 'string' ? e : e && e.message || e); + } + } + + async $getScriptHashTransactions(scripthash: string, lastSeenTxId?: string): Promise { + try { + loadingIndicators.setProgress('address-' + scripthash, 0); + + const transactions: IEsploraApi.Transaction[] = []; + let history = memoryCache.get('Scripthash_getHistory', scripthash); + if (!history) { + history = await this.electrumClient.blockchainScripthash_getHistory(scripthash); + memoryCache.set('Scripthash_getHistory', scripthash, history, 2); + } + if (!history) { + throw new Error('failed to get scripthash history'); + } + history.sort((a, b) => (b.height || 9999999) - (a.height || 9999999)); + + let startingIndex = 0; + if (lastSeenTxId) { + const pos = history.findIndex((historicalTx) => historicalTx.tx_hash === lastSeenTxId); + if (pos) { + startingIndex = pos + 1; + } + } + const endIndex = Math.min(startingIndex + 10, history.length); + + for (let i = startingIndex; i < endIndex; i++) { + const tx = await this.$getRawTransaction(history[i].tx_hash, false, true); + transactions.push(tx); + loadingIndicators.setProgress('address-' + scripthash, (i + 1) / endIndex * 100); + } + + return transactions; + } catch (e: any) { + loadingIndicators.setProgress('address-' + scripthash, 100); + throw new Error(typeof e === 'string' ? e : e && e.message || e); + } + } + + private $getScriptHashBalance(scriptHash: string): Promise { + return this.electrumClient.blockchainScripthash_getBalance(this.encodeScriptHash(scriptHash)); + } + + private $getScriptHashHistory(scriptHash: string): Promise { + const fromCache = memoryCache.get('Scripthash_getHistory', scriptHash); + if (fromCache) { + return Promise.resolve(fromCache); + } + return this.electrumClient.blockchainScripthash_getHistory(this.encodeScriptHash(scriptHash)) + .then((history) => { + memoryCache.set('Scripthash_getHistory', scriptHash, history, 2); + return history; + }); + } + + private encodeScriptHash(scriptPubKey: string): string { + const addrScripthash = crypto.enc.Hex.stringify(crypto.SHA256(crypto.enc.Hex.parse(scriptPubKey))); + return addrScripthash!.match(/.{2}/g)!.reverse().join(''); + } + +} + +export default BitcoindElectrsApi; diff --git a/backend/src/api/bitcoin/esplora-api.interface.ts b/backend/src/api/bitcoin/esplora-api.interface.ts new file mode 100644 index 0000000000..6e6860a417 --- /dev/null +++ b/backend/src/api/bitcoin/esplora-api.interface.ts @@ -0,0 +1,182 @@ +export namespace IEsploraApi { + export interface Transaction { + txid: string; + version: number; + locktime: number; + size: number; + weight: number; + fee: number; + sigops?: number; + vin: Vin[]; + vout: Vout[]; + status: Status; + hex?: string; + } + + export interface Recent { + txid: string; + fee: number; + vsize: number; + value: number; + } + + export interface Vin { + txid: string; + vout: number; + is_coinbase: boolean; + scriptsig: string; + scriptsig_asm: string; + inner_redeemscript_asm: string; + inner_witnessscript_asm: string; + sequence: any; + witness: string[]; + prevout: Vout | null; + // Elements + is_pegin?: boolean; + issuance?: Issuance; + // Custom + lazy?: boolean; + } + + interface Issuance { + asset_id: string; + is_reissuance: string; + asset_blinding_nonce: string; + asset_entropy: string; + contract_hash: string; + assetamount?: number; + assetamountcommitment?: string; + tokenamount?: number; + tokenamountcommitment?: string; + } + + export interface Vout { + scriptpubkey: string; + scriptpubkey_asm: string; + scriptpubkey_type: string; + scriptpubkey_address?: string; + value: number; + // Elements + valuecommitment?: number; + asset?: string; + pegout?: Pegout; + } + + interface Pegout { + genesis_hash: string; + scriptpubkey: string; + scriptpubkey_asm: string; + scriptpubkey_address: string; + } + + export interface Status { + confirmed: boolean; + block_height?: number; + block_hash?: string; + block_time?: number; + } + + export interface Block { + id: string; + height: number; + version: number; + timestamp: number; + bits: number; + nonce: number; + difficulty: number; + merkle_root: string; + tx_count: number; + size: number; + weight: number; + previousblockhash: string; + mediantime: number; + stale: boolean; + } + + export interface Address { + address: string; + chain_stats: ChainStats; + mempool_stats: MempoolStats; + electrum?: boolean; + } + + export interface ScriptHash { + scripthash: string; + chain_stats: ChainStats; + mempool_stats: MempoolStats; + electrum?: boolean; + } + + export interface ChainStats { + funded_txo_count: number; + funded_txo_sum: number; + spent_txo_count: number; + spent_txo_sum: number; + tx_count: number; + } + + export interface MempoolStats { + funded_txo_count: number; + funded_txo_sum: number; + spent_txo_count: number; + spent_txo_sum: number; + tx_count: number; + } + + export interface Outspend { + spent: boolean; + txid?: string; + vin?: number; + status?: Status; + } + + export interface Asset { + asset_id: string; + issuance_txin: IssuanceTxin; + issuance_prevout: IssuancePrevout; + reissuance_token: string; + contract_hash: string; + status: Status; + chain_stats: AssetStats; + mempool_stats: AssetStats; + } + + export interface AssetExtended extends Asset { + name: string; + ticker: string; + precision: number; + entity: Entity; + version: number; + issuer_pubkey: string; + } + + export interface Entity { + domain: string; + } + + interface IssuanceTxin { + txid: string; + vin: number; + } + + interface IssuancePrevout { + txid: string; + vout: number; + } + + interface AssetStats { + tx_count: number; + issuance_count: number; + issued_amount: number; + burned_amount: number; + has_blinded_issuances: boolean; + reissuance_tokens: number; + burned_reissuance_tokens: number; + peg_in_count: number; + peg_in_amount: number; + peg_out_count: number; + peg_out_amount: number; + burn_count: number; + } + +} diff --git a/backend/src/api/bitcoin/esplora-api.ts b/backend/src/api/bitcoin/esplora-api.ts new file mode 100644 index 0000000000..b4ae35da9f --- /dev/null +++ b/backend/src/api/bitcoin/esplora-api.ts @@ -0,0 +1,383 @@ +import config from '../../config'; +import axios, { AxiosResponse, isAxiosError } from 'axios'; +import http from 'http'; +import { AbstractBitcoinApi, HealthCheckHost } from './bitcoin-api-abstract-factory'; +import { IEsploraApi } from './esplora-api.interface'; +import logger from '../../logger'; +import { Common } from '../common'; +import { TestMempoolAcceptResult } from './bitcoin-api.interface'; + +interface FailoverHost { + host: string, + rtts: number[], + rtt: number, + timedOut?: boolean, + failures: number, + latestHeight?: number, + socket?: boolean, + outOfSync?: boolean, + unreachable?: boolean, + preferred?: boolean, + checked: boolean, + lastChecked?: number, +} + +class FailoverRouter { + activeHost: FailoverHost; + fallbackHost: FailoverHost; + maxSlippage: number = config.ESPLORA.MAX_BEHIND_TIP ?? 2; + maxHeight: number = 0; + hosts: FailoverHost[]; + multihost: boolean; + pollInterval: number = 60000; + pollTimer: NodeJS.Timeout | null = null; + pollConnection = axios.create(); + requestConnection = axios.create({ + httpAgent: new http.Agent({ keepAlive: true }) + }); + + constructor() { + // setup list of hosts + this.hosts = (config.ESPLORA.FALLBACK || []).map(domain => { + return { + host: domain, + checked: false, + rtts: [], + rtt: Infinity, + failures: 0, + }; + }); + this.activeHost = { + host: config.ESPLORA.UNIX_SOCKET_PATH || config.ESPLORA.REST_API_URL, + rtts: [], + rtt: 0, + failures: 0, + socket: !!config.ESPLORA.UNIX_SOCKET_PATH, + preferred: true, + checked: false, + }; + this.fallbackHost = this.activeHost; + this.hosts.unshift(this.activeHost); + this.multihost = this.hosts.length > 1; + } + + public startHealthChecks(): void { + // use axios interceptors to measure request rtt + this.pollConnection.interceptors.request.use((config) => { + config['meta'] = { startTime: Date.now() }; + return config; + }); + this.pollConnection.interceptors.response.use((response) => { + response.config['meta'].rtt = Date.now() - response.config['meta'].startTime; + return response; + }); + + if (this.multihost) { + this.pollHosts(); + } + } + + // start polling hosts to measure availability & rtt + private async pollHosts(): Promise { + if (this.pollTimer) { + clearTimeout(this.pollTimer); + } + + const start = Date.now(); + + // update rtts & sync status + for (const host of this.hosts) { + try { + const result = await (host.socket + ? this.pollConnection.get('/blocks/tip/height', { socketPath: host.host, timeout: config.ESPLORA.FALLBACK_TIMEOUT }) + : this.pollConnection.get(host.host + '/blocks/tip/height', { timeout: config.ESPLORA.FALLBACK_TIMEOUT }) + ); + if (result) { + const height = result.data; + host.latestHeight = height; + this.maxHeight = Math.max(height || 0, ...this.hosts.map(h => (!(h.unreachable || h.timedOut || h.outOfSync) ? h.latestHeight || 0 : 0))); + const rtt = result.config['meta'].rtt; + host.rtts.unshift(rtt); + host.rtts.slice(0, 5); + host.rtt = host.rtts.reduce((acc, l) => acc + l, 0) / host.rtts.length; + if (height == null || isNaN(height) || (this.maxHeight - height > this.maxSlippage)) { + host.outOfSync = true; + } else { + host.outOfSync = false; + } + host.unreachable = false; + } else { + host.outOfSync = true; + host.unreachable = true; + host.rtts = []; + host.rtt = Infinity; + } + host.timedOut = false; + } catch (e) { + host.outOfSync = true; + host.unreachable = true; + host.rtts = []; + host.rtt = Infinity; + if (isAxiosError(e) && (e.code === 'ECONNABORTED' || e.code === 'ETIMEDOUT')) { + host.timedOut = true; + } else { + host.timedOut = false; + } + } + host.checked = true; + host.lastChecked = Date.now(); + + const rankOrder = this.sortHosts(); + // switch if the current host is out of sync or significantly slower than the next best alternative + if (this.activeHost.outOfSync || this.activeHost.unreachable || (this.activeHost !== rankOrder[0] && rankOrder[0].preferred) || (!this.activeHost.preferred && this.activeHost.rtt > (rankOrder[0].rtt * 2) + 50)) { + if (this.activeHost.unreachable) { + logger.warn(`🚨🚨🚨 Unable to reach ${this.activeHost.host}, failing over to next best alternative 🚨🚨🚨`); + } else if (this.activeHost.outOfSync) { + logger.warn(`🚨🚨🚨 ${this.activeHost.host} has fallen behind, failing over to next best alternative 🚨🚨🚨`); + } else { + logger.debug(`🛠️ ${this.activeHost.host} is no longer the best esplora host 🛠️`); + } + this.electHost(); + } + await Common.sleep$(50); + } + + const rankOrder = this.updateFallback(); + logger.debug(`Tomahawk ranking:\n${rankOrder.map((host, index) => this.formatRanking(index, host, this.activeHost, this.maxHeight)).join('\n')}`); + + const elapsed = Date.now() - start; + + this.pollTimer = setTimeout(() => { this.pollHosts(); }, Math.max(1, this.pollInterval - elapsed)); + } + + private formatRanking(index: number, host: FailoverHost, active: FailoverHost, maxHeight: number): string { + const heightStatus = !host.checked ? '⏳' : (host.outOfSync ? '🚫' : (host.latestHeight && host.latestHeight < maxHeight ? '🟧' : '✅')); + return `${host === active ? '⭐️' : ' '} ${host.rtt < Infinity ? Math.round(host.rtt).toString().padStart(5, ' ') + 'ms' : (host.timedOut ? ' ⌛️💥 ' : ' - ')} ${!host.checked ? '⏳' : (host.unreachable ? '🔥' : '✅')} | block: ${host.latestHeight || '??????'} ${heightStatus} | ${host.host} ${host === active ? '⭐️' : ' '}`; + } + + private updateFallback(): FailoverHost[] { + const rankOrder = this.sortHosts(); + if (rankOrder.length > 1 && rankOrder[0] === this.activeHost) { + this.fallbackHost = rankOrder[1]; + } else { + this.fallbackHost = rankOrder[0]; + } + return rankOrder; + } + + // sort hosts by connection quality, and update default fallback + public sortHosts(): FailoverHost[] { + // sort by connection quality + return this.hosts.slice().sort((a, b) => { + if ((a.unreachable || a.outOfSync) === (b.unreachable || b.outOfSync)) { + if (a.preferred === b.preferred) { + // lower rtt is best + return a.rtt - b.rtt; + } else { // unless we have a preferred host + return a.preferred ? -1 : 1; + } + } else { // or the host is out of sync + return (a.unreachable || a.outOfSync) ? 1 : -1; + } + }); + } + + // depose the active host and choose the next best replacement + private electHost(): void { + this.activeHost.failures = 0; + const rankOrder = this.sortHosts(); + this.activeHost = rankOrder[0]; + logger.warn(`Switching esplora host to ${this.activeHost.host}`); + } + + private addFailure(host: FailoverHost): FailoverHost { + host.failures++; + if (host.failures > 5 && this.multihost) { + logger.warn(`🚨🚨🚨 Too many esplora failures on ${this.activeHost.host}, falling back to next best alternative 🚨🚨🚨`); + this.activeHost.unreachable = true; + this.electHost(); + return this.activeHost; + } else { + return this.fallbackHost; + } + } + + private async $query(method: 'get'| 'post', path, data: any, responseType = 'json', host = this.activeHost, retry: boolean = true): Promise { + let axiosConfig; + let url; + if (host.socket) { + axiosConfig = { socketPath: host.host, timeout: config.ESPLORA.REQUEST_TIMEOUT, responseType }; + url = path; + } else { + axiosConfig = { timeout: config.ESPLORA.REQUEST_TIMEOUT, responseType }; + url = host.host + path; + } + if (data?.params) { + axiosConfig.params = data.params; + } + return (method === 'post' + ? this.requestConnection.post(url, data, axiosConfig) + : this.requestConnection.get(url, axiosConfig) + ).then((response) => { host.failures = Math.max(0, host.failures - 1); return response.data; }) + .catch((e) => { + let fallbackHost = this.fallbackHost; + if (e?.response?.status !== 404) { + logger.warn(`esplora request failed ${e?.response?.status} ${host.host}${path}`); + logger.warn(e instanceof Error ? e.message : e); + fallbackHost = this.addFailure(host); + } + if (retry && e?.code === 'ECONNREFUSED' && this.multihost) { + // Retry immediately + return this.$query(method, path, data, responseType, fallbackHost, false); + } else { + throw e; + } + }); + } + + public async $get(path, responseType = 'json', params: any = null): Promise { + return this.$query('get', path, params ? { params } : null, responseType); + } + + public async $post(path, data: any, responseType = 'json'): Promise { + return this.$query('post', path, data, responseType); + } +} + +class ElectrsApi implements AbstractBitcoinApi { + private failoverRouter = new FailoverRouter(); + + $getRawMempool(): Promise { + return this.failoverRouter.$get('/mempool/txids'); + } + + $getRawTransaction(txId: string): Promise { + return this.failoverRouter.$get('/tx/' + txId); + } + + async $getRawTransactions(txids: string[]): Promise { + return this.failoverRouter.$post('/internal/txs', txids, 'json'); + } + + async $getMempoolTransactions(txids: string[]): Promise { + return this.failoverRouter.$post('/internal/mempool/txs', txids, 'json'); + } + + async $getAllMempoolTransactions(lastSeenTxid?: string, max_txs?: number): Promise { + return this.failoverRouter.$get('/internal/mempool/txs' + (lastSeenTxid ? '/' + lastSeenTxid : ''), 'json', max_txs ? { max_txs } : null); + } + + $getTransactionHex(txId: string): Promise { + return this.failoverRouter.$get('/tx/' + txId + '/hex'); + } + + $getBlockHeightTip(): Promise { + return this.failoverRouter.$get('/blocks/tip/height'); + } + + $getBlockHashTip(): Promise { + return this.failoverRouter.$get('/blocks/tip/hash'); + } + + $getTxIdsForBlock(hash: string): Promise { + return this.failoverRouter.$get('/block/' + hash + '/txids'); + } + + $getTxsForBlock(hash: string): Promise { + return this.failoverRouter.$get('/internal/block/' + hash + '/txs'); + } + + $getBlockHash(height: number): Promise { + return this.failoverRouter.$get('/block-height/' + height); + } + + $getBlockHeader(hash: string): Promise { + return this.failoverRouter.$get('/block/' + hash + '/header'); + } + + $getBlock(hash: string): Promise { + return this.failoverRouter.$get('/block/' + hash); + } + + $getRawBlock(hash: string): Promise { + return this.failoverRouter.$get('/block/' + hash + '/raw', 'arraybuffer') + .then((response) => { return Buffer.from(response.data); }); + } + + $getAddress(address: string): Promise { + throw new Error('Method getAddress not implemented.'); + } + + $getAddressTransactions(address: string, txId?: string): Promise { + throw new Error('Method getAddressTransactions not implemented.'); + } + + $getScriptHash(scripthash: string): Promise { + throw new Error('Method getScriptHash not implemented.'); + } + + $getScriptHashTransactions(scripthash: string, txId?: string): Promise { + throw new Error('Method getScriptHashTransactions not implemented.'); + } + + $getAddressPrefix(prefix: string): string[] { + throw new Error('Method not implemented.'); + } + + $sendRawTransaction(rawTransaction: string): Promise { + throw new Error('Method not implemented.'); + } + + $testMempoolAccept(rawTransactions: string[], maxfeerate?: number): Promise { + throw new Error('Method not implemented.'); + } + + $getOutspend(txId: string, vout: number): Promise { + return this.failoverRouter.$get('/tx/' + txId + '/outspend/' + vout); + } + + $getOutspends(txId: string): Promise { + return this.failoverRouter.$get('/tx/' + txId + '/outspends'); + } + + async $getBatchedOutspends(txids: string[]): Promise { + throw new Error('Method not implemented.'); + } + + async $getBatchedOutspendsInternal(txids: string[]): Promise { + return this.failoverRouter.$post('/internal/txs/outspends/by-txid', txids, 'json'); + } + + async $getOutSpendsByOutpoint(outpoints: { txid: string, vout: number }[]): Promise { + return this.failoverRouter.$post('/internal/txs/outspends/by-outpoint', outpoints.map(out => `${out.txid}:${out.vout}`), 'json'); + } + + async $getCoinbaseTx(blockhash: string): Promise { + const txid = await this.failoverRouter.$get(`/block/${blockhash}/txid/0`); + return this.failoverRouter.$get('/tx/' + txid); + } + + public startHealthChecks(): void { + this.failoverRouter.startHealthChecks(); + } + + public getHealthStatus(): HealthCheckHost[] { + if (config.MEMPOOL.OFFICIAL) { + return this.failoverRouter.sortHosts().map(host => ({ + host: host.host, + active: host === this.failoverRouter.activeHost, + rtt: host.rtt, + latestHeight: host.latestHeight || 0, + socket: !!host.socket, + outOfSync: !!host.outOfSync, + unreachable: !!host.unreachable, + checked: !!host.checked, + lastChecked: host.lastChecked || 0, + })); + } else { + return []; + } + } +} + +export default ElectrsApi; diff --git a/backend/src/api/blocks.ts b/backend/src/api/blocks.ts index 8f67c0a1a5..762c81ff7c 100644 --- a/backend/src/api/blocks.ts +++ b/backend/src/api/blocks.ts @@ -1,105 +1,1441 @@ -const config = require('../../mempool-config.json'); -import bitcoinApi from './bitcoin/electrs-api'; +import config from '../config'; +import bitcoinApi, { bitcoinCoreApi } from './bitcoin/bitcoin-api-factory'; +import logger from '../logger'; import memPool from './mempool'; -import { Block, TransactionExtended, TransactionMinerInfo } from '../interfaces'; +import { BlockExtended, BlockExtension, BlockSummary, PoolTag, TransactionExtended, TransactionMinerInfo, CpfpSummary, MempoolTransactionExtended, TransactionClassified, BlockAudit, TransactionAudit } from '../mempool.interfaces'; import { Common } from './common'; +import diskCache from './disk-cache'; +import transactionUtils from './transaction-utils'; +import bitcoinClient from './bitcoin/bitcoin-client'; +import { IBitcoinApi } from './bitcoin/bitcoin-api.interface'; +import { IEsploraApi } from './bitcoin/esplora-api.interface'; +import poolsRepository from '../repositories/PoolsRepository'; +import blocksRepository from '../repositories/BlocksRepository'; +import loadingIndicators from './loading-indicators'; +import BitcoinApi from './bitcoin/bitcoin-api'; +import BlocksRepository from '../repositories/BlocksRepository'; +import HashratesRepository from '../repositories/HashratesRepository'; +import indexer from '../indexer'; +import poolsParser from './pools-parser'; +import BlocksSummariesRepository from '../repositories/BlocksSummariesRepository'; +import BlocksAuditsRepository from '../repositories/BlocksAuditsRepository'; +import cpfpRepository from '../repositories/CpfpRepository'; +import mining from './mining/mining'; +import DifficultyAdjustmentsRepository from '../repositories/DifficultyAdjustmentsRepository'; +import PricesRepository from '../repositories/PricesRepository'; +import priceUpdater from '../tasks/price-updater'; +import chainTips from './chain-tips'; +import websocketHandler from './websocket-handler'; +import redisCache from './redis-cache'; +import rbfCache from './rbf-cache'; +import { calcBitsDifference } from './difficulty-adjustment'; +import AccelerationRepository from '../repositories/AccelerationRepository'; +import { calculateFastBlockCpfp, calculateGoodBlockCpfp } from './cpfp'; +import mempool from './mempool'; +import CpfpRepository from '../repositories/CpfpRepository'; class Blocks { - private blocks: Block[] = []; + private blocks: BlockExtended[] = []; + private blockSummaries: BlockSummary[] = []; private currentBlockHeight = 0; - private newBlockCallback: ((block: Block, txIds: string[], transactions: TransactionExtended[]) => void) | undefined; + private currentBits = 0; + private lastDifficultyAdjustmentTime = 0; + private previousDifficultyRetarget = 0; + private quarterEpochBlockTime: number | null = null; + private newBlockCallbacks: ((block: BlockExtended, txIds: string[], transactions: TransactionExtended[]) => void)[] = []; + private newAsyncBlockCallbacks: ((block: BlockExtended, txIds: string[], transactions: MempoolTransactionExtended[]) => Promise)[] = []; + private classifyingBlocks: boolean = false; + + private mainLoopTimeout: number = 120000; constructor() { } - public getBlocks(): Block[] { + public getBlocks(): BlockExtended[] { return this.blocks; } - public setBlocks(blocks: Block[]) { + public setBlocks(blocks: BlockExtended[]) { this.blocks = blocks; } - public setNewBlockCallback(fn: (block: Block, txIds: string[], transactions: TransactionExtended[]) => void) { - this.newBlockCallback = fn; + public getBlockSummaries(): BlockSummary[] { + return this.blockSummaries; } - public async updateBlocks() { - try { - const blockHeightTip = await bitcoinApi.getBlockHeightTip(); + public setBlockSummaries(blockSummaries: BlockSummary[]) { + this.blockSummaries = blockSummaries; + } + + public setNewBlockCallback(fn: (block: BlockExtended, txIds: string[], transactions: TransactionExtended[]) => void) { + this.newBlockCallbacks.push(fn); + } + + public setNewAsyncBlockCallback(fn: (block: BlockExtended, txIds: string[], transactions: MempoolTransactionExtended[]) => Promise) { + this.newAsyncBlockCallbacks.push(fn); + } + + /** + * Return the list of transaction for a block + * @param blockHash + * @param blockHeight + * @param onlyCoinbase - Set to true if you only need the coinbase transaction + * @param txIds - optional ordered list of transaction ids if already known + * @param quiet - don't print non-essential logs + * @param addMempoolData - calculate sigops etc + * @returns Promise + */ + private async $getTransactionsExtended( + blockHash: string, + blockHeight: number, + blockTime: number, + onlyCoinbase: boolean, + txIds: string[] | null = null, + quiet: boolean = false, + addMempoolData: boolean = false, + ): Promise { + const isEsplora = config.MEMPOOL.BACKEND === 'esplora'; + const transactionMap: { [txid: string]: TransactionExtended } = {}; + + if (!txIds) { + txIds = await bitcoinApi.$getTxIdsForBlock(blockHash); + } + + const mempool = memPool.getMempool(); + let foundInMempool = 0; + let totalFound = 0; + + // Copy existing transactions from the mempool + if (!onlyCoinbase) { + for (const txid of txIds) { + if (mempool[txid]) { + mempool[txid].status = { + confirmed: true, + block_height: blockHeight, + block_hash: blockHash, + block_time: blockTime, + }; + transactionMap[txid] = mempool[txid]; + foundInMempool++; + totalFound++; + } + } + } + + if (onlyCoinbase) { + try { + const coinbase = await transactionUtils.$getTransactionExtendedRetry(txIds[0], false, false, false, addMempoolData); + if (coinbase && coinbase.vin[0].is_coinbase) { + return [coinbase]; + } else { + const msg = `Expected a coinbase tx, but the backend API returned something else`; + logger.err(msg); + throw new Error(msg); + } + } catch (e) { + const msg = `Cannot fetch coinbase tx ${txIds[0]}. Reason: ` + (e instanceof Error ? e.message : e); + logger.err(msg); + throw new Error(msg); + } + } + + // Fetch remaining txs in bulk + if (isEsplora && (txIds.length - totalFound > 500)) { + try { + const rawTransactions = await bitcoinApi.$getTxsForBlock(blockHash); + for (const tx of rawTransactions) { + if (!transactionMap[tx.txid]) { + transactionMap[tx.txid] = addMempoolData ? transactionUtils.extendMempoolTransaction(tx) : transactionUtils.extendTransaction(tx); + totalFound++; + } + } + } catch (e) { + logger.err(`Cannot fetch bulk txs for block ${blockHash}. Reason: ` + (e instanceof Error ? e.message : e)); + } + } + + // Fetch remaining txs individually + for (const txid of txIds.filter(txid => !transactionMap[txid])) { + if (!quiet && (totalFound % (Math.round((txIds.length) / 10)) === 0 || totalFound + 1 === txIds.length)) { // Avoid log spam + logger.debug(`Indexing tx ${totalFound + 1} of ${txIds.length} in block #${blockHeight}`); + } + try { + const tx = await transactionUtils.$getTransactionExtendedRetry(txid, false, false, false, addMempoolData); + transactionMap[txid] = tx; + totalFound++; + } catch (e) { + const msg = `Cannot fetch tx ${txid}. Reason: ` + (e instanceof Error ? e.message : e); + logger.err(msg); + throw new Error(msg); + } + } + + if (!quiet) { + logger.debug(`${foundInMempool} of ${txIds.length} found in mempool. ${totalFound - foundInMempool} fetched through backend service.`); + } + + // Require the first transaction to be a coinbase + const coinbase = transactionMap[txIds[0]]; + if (!coinbase || !coinbase.vin[0].is_coinbase) { + const msg = `Expected first tx in a block to be a coinbase, but found something else`; + logger.err(msg); + throw new Error(msg); + } + + // Require all transactions to be present + // (we should have thrown an error already if a tx request failed) + if (txIds.some(txid => !transactionMap[txid])) { + const msg = `Failed to fetch ${txIds.length - totalFound} transactions from block`; + logger.err(msg); + throw new Error(msg); + } + + // Return list of transactions, preserving block order + return txIds.map(txid => transactionMap[txid]); + } + + /** + * Return a block summary (list of stripped transactions) + * @param block + * @returns BlockSummary + */ + public summarizeBlock(block: IBitcoinApi.VerboseBlock): BlockSummary { + if (Common.isLiquid()) { + block = this.convertLiquidFees(block); + } + const stripped = block.tx.map((tx: IBitcoinApi.VerboseTransaction) => { + return { + txid: tx.txid, + vsize: tx.weight / 4, + fee: tx.fee ? Math.round(tx.fee * 100000000) : 0, + value: Math.round(tx.vout.reduce((acc, vout) => acc + (vout.value ? vout.value : 0), 0) * 100000000), + flags: 0, + }; + }); + + return { + id: block.hash, + transactions: stripped + }; + } - if (this.blocks.length === 0) { - this.currentBlockHeight = blockHeightTip - config.INITIAL_BLOCK_AMOUNT; + public summarizeBlockTransactions(hash: string, transactions: TransactionExtended[]): BlockSummary { + return { + id: hash, + transactions: Common.classifyTransactions(transactions), + }; + } + + private convertLiquidFees(block: IBitcoinApi.VerboseBlock): IBitcoinApi.VerboseBlock { + block.tx.forEach(tx => { + if (!isFinite(Number(tx.fee))) { + tx.fee = Object.values(tx.fee || {}).reduce((total, output) => total + output, 0); + } + }); + return block; + } + + /** + * Return a block with additional data (reward, coinbase, fees...) + * @param block + * @param transactions + * @returns BlockExtended + */ + private async $getBlockExtended(block: IEsploraApi.Block, transactions: TransactionExtended[]): Promise { + const coinbaseTx = transactionUtils.stripCoinbaseTransaction(transactions[0]); + + const blk: Partial = Object.assign({}, block); + const extras: Partial = {}; + + extras.reward = transactions[0].vout.reduce((acc, curr) => acc + curr.value, 0); + extras.coinbaseRaw = coinbaseTx.vin[0].scriptsig; + extras.orphans = chainTips.getOrphanedBlocksAtHeight(blk.height); + + if (block.height === 0) { + extras.medianFee = 0; // 50th percentiles + extras.feeRange = [0, 0, 0, 0, 0, 0, 0]; + extras.totalFees = 0; + extras.avgFee = 0; + extras.avgFeeRate = 0; + extras.utxoSetChange = 0; + extras.avgTxSize = 0; + extras.totalInputs = 0; + extras.totalOutputs = 1; + extras.totalOutputAmt = 0; + extras.segwitTotalTxs = 0; + extras.segwitTotalSize = 0; + extras.segwitTotalWeight = 0; + } else { + const stats: IBitcoinApi.BlockStats = await bitcoinClient.getBlockStats(block.id); + let feeStats = { + medianFee: stats.feerate_percentiles[2], // 50th percentiles + feeRange: [stats.minfeerate, stats.feerate_percentiles, stats.maxfeerate].flat(), + }; + if (transactions?.length > 1) { + feeStats = Common.calcEffectiveFeeStatistics(transactions); + } + extras.medianFee = feeStats.medianFee; + extras.feeRange = feeStats.feeRange; + extras.totalFees = stats.totalfee; + extras.avgFee = stats.avgfee; + extras.avgFeeRate = stats.avgfeerate; + extras.utxoSetChange = stats.utxo_increase; + extras.avgTxSize = Math.round(stats.total_size / stats.txs * 100) * 0.01; + extras.totalInputs = stats.ins; + extras.totalOutputs = stats.outs; + extras.totalOutputAmt = stats.total_out; + extras.segwitTotalTxs = stats.swtxs; + extras.segwitTotalSize = stats.swtotal_size; + extras.segwitTotalWeight = stats.swtotal_weight; + } + + if (Common.blocksSummariesIndexingEnabled()) { + extras.feePercentiles = await BlocksSummariesRepository.$getFeePercentilesByBlockId(block.id); + if (extras.feePercentiles !== null) { + extras.medianFeeAmt = extras.feePercentiles[3]; + } + } + + extras.virtualSize = block.weight / 4.0; + if (coinbaseTx?.vout.length > 0) { + extras.coinbaseAddress = coinbaseTx.vout[0].scriptpubkey_address ?? null; + extras.coinbaseAddresses = [...new Set(coinbaseTx.vout.map(v => v.scriptpubkey_address).filter(a => a) as string[])]; + extras.coinbaseSignature = coinbaseTx.vout[0].scriptpubkey_asm ?? null; + extras.coinbaseSignatureAscii = transactionUtils.hex2ascii(coinbaseTx.vin[0].scriptsig) ?? null; + } else { + extras.coinbaseAddress = null; + extras.coinbaseAddresses = null; + extras.coinbaseSignature = null; + extras.coinbaseSignatureAscii = null; + } + + const header = await bitcoinClient.getBlockHeader(block.id, false); + extras.header = header; + + const coinStatsIndex = indexer.isCoreIndexReady('coinstatsindex'); + if (coinStatsIndex !== null && coinStatsIndex.best_block_height >= block.height) { + const txoutset = await bitcoinClient.getTxoutSetinfo('none', block.height); + extras.utxoSetSize = txoutset.txouts, + extras.totalInputAmt = Math.round(txoutset.block_info.prevout_spent * 100000000); + } else { + extras.utxoSetSize = null; + extras.totalInputAmt = null; + } + + if (['mainnet', 'testnet', 'signet'].includes(config.MEMPOOL.NETWORK)) { + let pool: PoolTag; + if (coinbaseTx !== undefined) { + pool = await this.$findBlockMiner(coinbaseTx); + } else { + if (config.DATABASE.ENABLED === true) { + pool = await poolsRepository.$getUnknownPool(); + } else { + pool = poolsParser.unknownPool; + } + } + + if (!pool) { // We should never have this situation in practise + logger.warn(`Cannot assign pool to block ${blk.height} and 'unknown' pool does not exist. ` + + `Check your "pools" table entries`); } else { - this.currentBlockHeight = this.blocks[this.blocks.length - 1].height; + extras.pool = { + id: pool.uniqueId, + name: pool.name, + slug: pool.slug, + }; + } + + extras.matchRate = null; + extras.expectedFees = null; + extras.expectedWeight = null; + if (config.MEMPOOL.AUDIT) { + const auditScore = await BlocksAuditsRepository.$getBlockAuditScore(block.id); + if (auditScore != null) { + extras.matchRate = auditScore.matchRate; + extras.expectedFees = auditScore.expectedFees; + extras.expectedWeight = auditScore.expectedWeight; + } } + } + + blk.extras = extras; + return blk; + } + + /** + * Try to find which miner found the block + * @param txMinerInfo + * @returns + */ + private async $findBlockMiner(txMinerInfo: TransactionMinerInfo | undefined): Promise { + if (txMinerInfo === undefined || txMinerInfo.vout.length < 1) { + if (config.DATABASE.ENABLED === true) { + return await poolsRepository.$getUnknownPool(); + } else { + return poolsParser.unknownPool; + } + } + + const addresses = txMinerInfo.vout.map((vout) => vout.scriptpubkey_address).filter(address => address) as string[]; + + let pools: PoolTag[] = []; + if (config.DATABASE.ENABLED === true) { + pools = await poolsRepository.$getPools(); + } else { + pools = poolsParser.miningPools; + } + + const pool = poolsParser.matchBlockMiner(txMinerInfo.vin[0].scriptsig, addresses || [], pools); + if (pool) { + return pool; + } + + if (config.DATABASE.ENABLED === true) { + return await poolsRepository.$getUnknownPool(); + } else { + return poolsParser.unknownPool; + } + } - if (blockHeightTip - this.currentBlockHeight > config.INITIAL_BLOCK_AMOUNT * 2) { - console.log(`${blockHeightTip - this.currentBlockHeight} blocks since tip. Fast forwarding to the ${config.INITIAL_BLOCK_AMOUNT} recent blocks`); - this.currentBlockHeight = blockHeightTip - config.INITIAL_BLOCK_AMOUNT; + /** + * [INDEXING] Index all blocks summaries for the block txs visualization + */ + public async $generateBlocksSummariesDatabase(): Promise { + if (Common.blocksSummariesIndexingEnabled() === false) { + return; + } + + try { + // Get all indexed block hash + const indexedBlocks = await blocksRepository.$getIndexedBlocks(); + const indexedBlockSummariesHashesArray = await BlocksSummariesRepository.$getIndexedSummariesId(); + + const indexedBlockSummariesHashes = {}; // Use a map for faster seek during the indexing loop + for (const hash of indexedBlockSummariesHashesArray) { + indexedBlockSummariesHashes[hash] = true; } - while (this.currentBlockHeight < blockHeightTip) { - if (this.currentBlockHeight === 0) { - this.currentBlockHeight = blockHeightTip; + // Logging + let newlyIndexed = 0; + let totalIndexed = indexedBlockSummariesHashesArray.length; + let indexedThisRun = 0; + let timer = Date.now() / 1000; + const startedAt = Date.now() / 1000; + + for (const block of indexedBlocks) { + if (indexedBlockSummariesHashes[block.hash] === true) { + continue; + } + + // Logging + const elapsedSeconds = (Date.now() / 1000) - timer; + if (elapsedSeconds > 5) { + const runningFor = (Date.now() / 1000) - startedAt; + const blockPerSeconds = indexedThisRun / elapsedSeconds; + const progress = Math.round(totalIndexed / indexedBlocks.length * 10000) / 100; + logger.debug(`Indexing block summary for #${block.height} | ~${blockPerSeconds.toFixed(2)} blocks/sec | total: ${totalIndexed}/${indexedBlocks.length} (${progress}%) | elapsed: ${runningFor.toFixed(2)} seconds`, logger.tags.mining); + timer = Date.now() / 1000; + indexedThisRun = 0; + } + + + if (config.MEMPOOL.BACKEND === 'esplora') { + const txs = (await bitcoinApi.$getTxsForBlock(block.hash)).map(tx => transactionUtils.extendTransaction(tx)); + const cpfpSummary = await this.$indexCPFP(block.hash, block.height, txs); + if (cpfpSummary) { + await this.$getStrippedBlockTransactions(block.hash, true, true, cpfpSummary, block.height); // This will index the block summary + } } else { - this.currentBlockHeight++; - console.log(`New block found (#${this.currentBlockHeight})!`); + await this.$getStrippedBlockTransactions(block.hash, true, true); // This will index the block summary } - const blockHash = await bitcoinApi.getBlockHash(this.currentBlockHeight); - const block = await bitcoinApi.getBlock(blockHash); - const txIds = await bitcoinApi.getTxIdsForBlock(blockHash); + // Logging + indexedThisRun++; + totalIndexed++; + newlyIndexed++; + } + if (newlyIndexed > 0) { + logger.notice(`Blocks summaries indexing completed: indexed ${newlyIndexed} blocks`, logger.tags.mining); + } else { + logger.debug(`Blocks summaries indexing completed: indexed ${newlyIndexed} blocks`, logger.tags.mining); + } + } catch (e) { + logger.err(`Blocks summaries indexing failed. Trying again in 10 seconds. Reason: ${(e instanceof Error ? e.message : e)}`, logger.tags.mining); + throw e; + } + } + + /** + * [INDEXING] Index transaction CPFP data for all blocks + */ + public async $generateCPFPDatabase(): Promise { + if (Common.cpfpIndexingEnabled() === false) { + return; + } + + try { + // Get all indexed block hash + const unindexedBlockHeights = await blocksRepository.$getCPFPUnindexedBlocks(); + + if (!unindexedBlockHeights?.length) { + return; + } + + logger.info(`Indexing cpfp data for ${unindexedBlockHeights.length} blocks`); + + // Logging + let count = 0; + let countThisRun = 0; + let timer = Date.now() / 1000; + const startedAt = Date.now() / 1000; + for (const height of unindexedBlockHeights) { + // Logging + const hash = await bitcoinApi.$getBlockHash(height); + const elapsedSeconds = (Date.now() / 1000) - timer; + if (elapsedSeconds > 5) { + const runningFor = (Date.now() / 1000) - startedAt; + const blockPerSeconds = countThisRun / elapsedSeconds; + const progress = Math.round(count / unindexedBlockHeights.length * 10000) / 100; + logger.debug(`Indexing cpfp clusters for #${height} | ~${blockPerSeconds.toFixed(2)} blocks/sec | total: ${count}/${unindexedBlockHeights.length} (${progress}%) | elapsed: ${runningFor.toFixed(2)} seconds`); + timer = Date.now() / 1000; + countThisRun = 0; + } + + await this.$indexCPFP(hash, height); // Calculate and save CPFP data for transactions in this block + + // Logging + count++; + countThisRun++; + } + logger.notice(`CPFP indexing completed: indexed ${count} blocks`); + } catch (e) { + logger.err(`CPFP indexing failed. Trying again in 10 seconds. Reason: ${(e instanceof Error ? e.message : e)}`); + throw e; + } + } + + /** + * [INDEXING] Index expected fees & weight for all audited blocks + */ + public async $generateAuditStats(): Promise { + const blockIds = await BlocksAuditsRepository.$getBlocksWithoutSummaries(); + if (!blockIds?.length) { + return; + } + let timer = Date.now(); + let indexedThisRun = 0; + let indexedTotal = 0; + logger.debug(`Indexing ${blockIds.length} block audit details`); + for (const hash of blockIds) { + const summary = await BlocksSummariesRepository.$getTemplate(hash); + let totalFees = 0; + let totalWeight = 0; + for (const tx of summary?.transactions || []) { + totalFees += tx.fee; + totalWeight += (tx.vsize * 4); + } + await BlocksAuditsRepository.$setSummary(hash, totalFees, totalWeight); + const cachedBlock = this.blocks.find(block => block.id === hash); + if (cachedBlock) { + cachedBlock.extras.expectedFees = totalFees; + cachedBlock.extras.expectedWeight = totalWeight; + } + + indexedThisRun++; + indexedTotal++; + const elapsedSeconds = (Date.now() - timer) / 1000; + if (elapsedSeconds > 5) { + const blockPerSeconds = indexedThisRun / elapsedSeconds; + logger.debug(`Indexed ${indexedTotal} / ${blockIds.length} block audit details (${blockPerSeconds.toFixed(1)}/s)`); + timer = Date.now(); + indexedThisRun = 0; + } + } + logger.debug(`Indexing block audit details completed`); + } + + /** + * [INDEXING] Index transaction classification flags for Goggles + */ + public async $classifyBlocks(): Promise { + if (this.classifyingBlocks) { + return; + } + this.classifyingBlocks = true; + + // classification requires an esplora backend + if (!Common.gogglesIndexingEnabled() || config.MEMPOOL.BACKEND !== 'esplora') { + return; + } + + const blockchainInfo = await bitcoinClient.getBlockchainInfo(); + const currentBlockHeight = blockchainInfo.blocks; + + const targetSummaryVersion: number = 1; + const targetTemplateVersion: number = 1; + + const unclassifiedBlocksList = await BlocksSummariesRepository.$getSummariesBelowVersion(targetSummaryVersion); + const unclassifiedTemplatesList = await BlocksSummariesRepository.$getTemplatesBelowVersion(targetTemplateVersion); + + // nothing to do + if (!unclassifiedBlocksList?.length && !unclassifiedTemplatesList?.length) { + return; + } + + let timer = Date.now(); + let indexedThisRun = 0; + let indexedTotal = 0; + + const minHeight = Math.min( + unclassifiedBlocksList[unclassifiedBlocksList.length - 1]?.height ?? Infinity, + unclassifiedTemplatesList[unclassifiedTemplatesList.length - 1]?.height ?? Infinity, + ); + const numToIndex = Math.max( + unclassifiedBlocksList.length, + unclassifiedTemplatesList.length, + ); + + const unclassifiedBlocks = {}; + const unclassifiedTemplates = {}; + for (const block of unclassifiedBlocksList) { + unclassifiedBlocks[block.height] = block.id; + } + for (const template of unclassifiedTemplatesList) { + unclassifiedTemplates[template.height] = template.id; + } + + logger.debug(`Classifying blocks and templates from #${currentBlockHeight} to #${minHeight}`, logger.tags.goggles); + + for (let height = currentBlockHeight; height >= 0; height--) { + try { + let txs: MempoolTransactionExtended[] | null = null; + if (unclassifiedBlocks[height]) { + const blockHash = unclassifiedBlocks[height]; + // fetch transactions + txs = (await bitcoinApi.$getTxsForBlock(blockHash)).map(tx => transactionUtils.extendMempoolTransaction(tx)) || []; + // add CPFP + const cpfpSummary = calculateGoodBlockCpfp(height, txs, []); + // classify + const { transactions: classifiedTxs } = this.summarizeBlockTransactions(blockHash, cpfpSummary.transactions); + await BlocksSummariesRepository.$saveTransactions(height, blockHash, classifiedTxs, 2); + if (unclassifiedBlocks[height].version < 2 && targetSummaryVersion === 2) { + const cpfpClusters = await CpfpRepository.$getClustersAt(height); + if (!cpfpRepository.compareClusters(cpfpClusters, cpfpSummary.clusters)) { + // CPFP clusters changed - update the compact_cpfp tables + await CpfpRepository.$deleteClustersAt(height); + await this.$saveCpfp(blockHash, height, cpfpSummary); + } + } + await Common.sleep$(250); + } + if (unclassifiedTemplates[height]) { + // classify template + const blockHash = unclassifiedTemplates[height]; + const template = await BlocksSummariesRepository.$getTemplate(blockHash); + const alreadyClassified = template?.transactions?.reduce((classified, tx) => (classified || tx.flags > 0), false); + let classifiedTemplate = template?.transactions || []; + if (!alreadyClassified) { + const templateTxs: (TransactionExtended | TransactionClassified)[] = []; + const blockTxMap: { [txid: string]: TransactionExtended } = {}; + for (const tx of (txs || [])) { + blockTxMap[tx.txid] = tx; + } + for (const templateTx of (template?.transactions || [])) { + let tx: TransactionExtended | null = blockTxMap[templateTx.txid]; + if (!tx) { + try { + tx = await transactionUtils.$getTransactionExtended(templateTx.txid, false, true, false); + } catch (e) { + // transaction probably not found + } + } + templateTxs.push(tx || templateTx); + } + const cpfpSummary = calculateGoodBlockCpfp(height, templateTxs?.filter(tx => tx['effectiveFeePerVsize'] != null) as MempoolTransactionExtended[], []); + // classify + const { transactions: classifiedTxs } = this.summarizeBlockTransactions(blockHash, cpfpSummary.transactions); + const classifiedTxMap: { [txid: string]: TransactionClassified } = {}; + for (const tx of classifiedTxs) { + classifiedTxMap[tx.txid] = tx; + } + classifiedTemplate = classifiedTemplate.map(tx => { + if (classifiedTxMap[tx.txid]) { + tx.flags = classifiedTxMap[tx.txid].flags || 0; + } + return tx; + }); + } + await BlocksSummariesRepository.$saveTemplate({ height, template: { id: blockHash, transactions: classifiedTemplate }, version: 1 }); + await Common.sleep$(250); + } + } catch (e) { + logger.warn(`Failed to classify template or block summary at ${height}`, logger.tags.goggles); + } + + // timing & logging + if (unclassifiedBlocks[height] || unclassifiedTemplates[height]) { + indexedThisRun++; + indexedTotal++; + } + const elapsedSeconds = (Date.now() - timer) / 1000; + if (elapsedSeconds > 5) { + const perSecond = indexedThisRun / elapsedSeconds; + logger.debug(`Classified #${height}: ${indexedTotal} / ${numToIndex} blocks (${perSecond.toFixed(1)}/s)`); + timer = Date.now(); + indexedThisRun = 0; + } + } + + this.classifyingBlocks = false; + } + + /** + * [INDEXING] Index missing coinbase addresses for all blocks + */ + public async $indexCoinbaseAddresses(): Promise { + try { + // Get all indexed block hash + const unindexedBlocks = await blocksRepository.$getBlocksWithoutCoinbaseAddresses(); + + if (!unindexedBlocks?.length) { + return; + } + + logger.info(`Indexing missing coinbase addresses for ${unindexedBlocks.length} blocks`); + + // Logging + let count = 0; + let countThisRun = 0; + let timer = Date.now() / 1000; + const startedAt = Date.now() / 1000; + for (const { height, hash } of unindexedBlocks) { + // Logging + const elapsedSeconds = (Date.now() / 1000) - timer; + if (elapsedSeconds > 5) { + const runningFor = (Date.now() / 1000) - startedAt; + const blockPerSeconds = countThisRun / elapsedSeconds; + const progress = Math.round(count / unindexedBlocks.length * 10000) / 100; + logger.debug(`Indexing coinbase addresses for #${height} | ~${blockPerSeconds.toFixed(2)} blocks/sec | total: ${count}/${unindexedBlocks.length} (${progress}%) | elapsed: ${runningFor.toFixed(2)} seconds`); + timer = Date.now() / 1000; + countThisRun = 0; + } + + const coinbaseTx = await bitcoinApi.$getCoinbaseTx(hash); + const addresses = new Set(coinbaseTx.vout.map(v => v.scriptpubkey_address).filter(a => a) as string[]); + await blocksRepository.$saveCoinbaseAddresses(hash, [...addresses]); + + // Logging + count++; + countThisRun++; + } + logger.notice(`coinbase addresses indexing completed: indexed ${count} blocks`); + } catch (e) { + logger.err(`coinbase addresses indexing failed. Trying again in 10 seconds. Reason: ${(e instanceof Error ? e.message : e)}`); + throw e; + } + } + + /** + * [INDEXING] Index all blocks metadata for the mining dashboard + */ + public async $generateBlockDatabase(): Promise { + try { + const blockchainInfo = await bitcoinClient.getBlockchainInfo(); + let currentBlockHeight = blockchainInfo.blocks; + + let indexingBlockAmount = Math.min(config.MEMPOOL.INDEXING_BLOCKS_AMOUNT, blockchainInfo.blocks); + if (indexingBlockAmount <= -1) { + indexingBlockAmount = currentBlockHeight + 1; + } - const mempool = memPool.getMempool(); - let found = 0; - let notFound = 0; + const lastBlockToIndex = Math.max(0, currentBlockHeight - indexingBlockAmount + 1); - const transactions: TransactionExtended[] = []; + logger.debug(`Indexing blocks from #${currentBlockHeight} to #${lastBlockToIndex}`, logger.tags.mining); + loadingIndicators.setProgress('block-indexing', 0); - for (let i = 0; i < txIds.length; i++) { - if (mempool[txIds[i]]) { - transactions.push(mempool[txIds[i]]); - found++; + const chunkSize = 10000; + let totalIndexed = await blocksRepository.$blockCountBetweenHeight(currentBlockHeight, lastBlockToIndex); + let indexedThisRun = 0; + let newlyIndexed = 0; + const startedAt = Date.now() / 1000; + let timer = Date.now() / 1000; + + while (currentBlockHeight >= lastBlockToIndex) { + const endBlock = Math.max(0, lastBlockToIndex, currentBlockHeight - chunkSize + 1); + + const missingBlockHeights: number[] = await blocksRepository.$getMissingBlocksBetweenHeights( + currentBlockHeight, endBlock); + if (missingBlockHeights.length <= 0) { + currentBlockHeight -= chunkSize; + continue; + } + + logger.info(`Indexing ${missingBlockHeights.length} blocks from #${currentBlockHeight} to #${endBlock}`, logger.tags.mining); + + for (const blockHeight of missingBlockHeights) { + if (blockHeight < lastBlockToIndex) { + break; + } + ++indexedThisRun; + ++totalIndexed; + const elapsedSeconds = (Date.now() / 1000) - timer; + if (elapsedSeconds > 5 || blockHeight === lastBlockToIndex) { + const runningFor = (Date.now() / 1000) - startedAt; + const blockPerSeconds = indexedThisRun / elapsedSeconds; + const progress = Math.round(totalIndexed / indexingBlockAmount * 10000) / 100; + logger.debug(`Indexing block #${blockHeight} | ~${blockPerSeconds.toFixed(2)} blocks/sec | total: ${totalIndexed}/${indexingBlockAmount} (${progress.toFixed(2)}%) | elapsed: ${runningFor.toFixed(2)} seconds`, logger.tags.mining); + timer = Date.now() / 1000; + indexedThisRun = 0; + loadingIndicators.setProgress('block-indexing', progress, false); + } + const blockHash = await bitcoinApi.$getBlockHash(blockHeight); + const block: IEsploraApi.Block = await bitcoinApi.$getBlock(blockHash); + const transactions = await this.$getTransactionsExtended(blockHash, block.height, block.timestamp, true, null, true); + const blockExtended = await this.$getBlockExtended(block, transactions); + + newlyIndexed++; + await blocksRepository.$saveBlockInDatabase(blockExtended); + } + + currentBlockHeight -= chunkSize; + } + if (newlyIndexed > 0) { + logger.notice(`Block indexing completed: indexed ${newlyIndexed} blocks`, logger.tags.mining); + } else { + logger.debug(`Block indexing completed: indexed ${newlyIndexed} blocks`, logger.tags.mining); + } + loadingIndicators.setProgress('block-indexing', 100); + } catch (e) { + logger.err('Block indexing failed. Trying again in 10 seconds. Reason: ' + (e instanceof Error ? e.message : e), logger.tags.mining); + loadingIndicators.setProgress('block-indexing', 100); + throw e; + } + + return await BlocksRepository.$validateChain(); + } + + public async $updateBlocks(): Promise { + // warn if this run stalls the main loop for more than 2 minutes + const timer = this.startTimer(); + + diskCache.lock(); + + let fastForwarded = false; + let handledBlocks = 0; + const blockHeightTip = await bitcoinCoreApi.$getBlockHeightTip(); + this.updateTimerProgress(timer, 'got block height tip'); + + if (this.blocks.length === 0) { + this.currentBlockHeight = Math.max(blockHeightTip - config.MEMPOOL.INITIAL_BLOCKS_AMOUNT, -1); + } else { + this.currentBlockHeight = this.blocks[this.blocks.length - 1].height; + } + if (this.currentBlockHeight >= 503) { + try { + const quarterEpochBlockHash = await bitcoinApi.$getBlockHash(this.currentBlockHeight - 503); + const quarterEpochBlock = await bitcoinApi.$getBlock(quarterEpochBlockHash); + this.quarterEpochBlockTime = quarterEpochBlock?.timestamp; + } catch (e) { + this.quarterEpochBlockTime = null; + logger.warn('failed to update last epoch block time: ' + (e instanceof Error ? e.message : e)); + } + } + + if (blockHeightTip - this.currentBlockHeight > config.MEMPOOL.INITIAL_BLOCKS_AMOUNT * 2) { + logger.info(`${blockHeightTip - this.currentBlockHeight} blocks since tip. Fast forwarding to the ${config.MEMPOOL.INITIAL_BLOCKS_AMOUNT} recent blocks`); + this.currentBlockHeight = blockHeightTip - config.MEMPOOL.INITIAL_BLOCKS_AMOUNT; + fastForwarded = true; + logger.info(`Re-indexing skipped blocks and corresponding hashrates data`); + indexer.reindex(); // Make sure to index the skipped blocks #1619 + } + + if (!this.lastDifficultyAdjustmentTime) { + const blockchainInfo = await bitcoinClient.getBlockchainInfo(); + this.updateTimerProgress(timer, 'got blockchain info for initial difficulty adjustment'); + if (blockchainInfo.blocks === blockchainInfo.headers) { + const heightDiff = blockHeightTip % 2016; + const blockHash = await bitcoinApi.$getBlockHash(blockHeightTip - heightDiff); + this.updateTimerProgress(timer, 'got block hash for initial difficulty adjustment'); + const block: IEsploraApi.Block = await bitcoinApi.$getBlock(blockHash); + this.updateTimerProgress(timer, 'got block for initial difficulty adjustment'); + this.lastDifficultyAdjustmentTime = block.timestamp; + this.currentBits = block.bits; + + if (blockHeightTip >= 2016) { + const previousPeriodBlockHash = await bitcoinApi.$getBlockHash(blockHeightTip - heightDiff - 2016); + this.updateTimerProgress(timer, 'got previous block hash for initial difficulty adjustment'); + const previousPeriodBlock: IEsploraApi.Block = await bitcoinApi.$getBlock(previousPeriodBlockHash); + this.updateTimerProgress(timer, 'got previous block for initial difficulty adjustment'); + if (['liquid', 'liquidtestnet'].includes(config.MEMPOOL.NETWORK)) { + this.previousDifficultyRetarget = NaN; } else { - console.log(`Fetching block tx ${i} of ${txIds.length}`); - const tx = await memPool.getTransactionExtended(txIds[i]); - if (tx) { - transactions.push(tx); + this.previousDifficultyRetarget = calcBitsDifference(previousPeriodBlock.bits, block.bits); + } + logger.debug(`Initial difficulty adjustment data set.`); + } + } else { + logger.debug(`Blockchain headers (${blockchainInfo.headers}) and blocks (${blockchainInfo.blocks}) not in sync. Waiting...`); + } + } + + while (this.currentBlockHeight < blockHeightTip) { + if (this.currentBlockHeight === 0) { + this.currentBlockHeight = blockHeightTip; + } else { + this.currentBlockHeight++; + logger.debug(`New block found (#${this.currentBlockHeight})!`); + // skip updating the orphan block cache if we've fallen behind the chain tip + if (this.currentBlockHeight >= blockHeightTip - 2) { + this.updateTimerProgress(timer, `getting orphaned blocks for ${this.currentBlockHeight}`); + await chainTips.updateOrphanedBlocks(); + } + } + + this.updateTimerProgress(timer, `getting block data for ${this.currentBlockHeight}`); + const blockHash = await bitcoinCoreApi.$getBlockHash(this.currentBlockHeight); + const verboseBlock = await bitcoinClient.getBlock(blockHash, 2); + const block = BitcoinApi.convertBlock(verboseBlock); + const txIds: string[] = verboseBlock.tx.map(tx => tx.txid); + const transactions = await this.$getTransactionsExtended(blockHash, block.height, block.timestamp, false, txIds, false, true) as MempoolTransactionExtended[]; + + // fill in missing transaction fee data from verboseBlock + for (let i = 0; i < transactions.length; i++) { + if (!transactions[i].fee && transactions[i].txid === verboseBlock.tx[i].txid) { + transactions[i].fee = (verboseBlock.tx[i].fee * 100_000_000) || 0; + } + } + + const cpfpSummary: CpfpSummary = calculateGoodBlockCpfp(block.height, transactions, Object.values(mempool.getAccelerations()).map(a => ({ txid: a.txid, max_bid: a.feeDelta }))); + const blockExtended: BlockExtended = await this.$getBlockExtended(block, cpfpSummary.transactions); + const blockSummary: BlockSummary = this.summarizeBlockTransactions(block.id, cpfpSummary.transactions); + this.updateTimerProgress(timer, `got block data for ${this.currentBlockHeight}`); + + if (Common.indexingEnabled()) { + if (!fastForwarded) { + const lastBlock = await blocksRepository.$getBlockByHeight(blockExtended.height - 1); + this.updateTimerProgress(timer, `got block by height for ${this.currentBlockHeight}`); + if (lastBlock !== null && blockExtended.previousblockhash !== lastBlock.id) { + logger.warn(`Chain divergence detected at block ${lastBlock.height}, re-indexing most recent data`, logger.tags.mining); + // We assume there won't be a reorg with more than 10 block depth + this.updateTimerProgress(timer, `rolling back diverged chain from ${this.currentBlockHeight}`); + await BlocksRepository.$deleteBlocksFrom(lastBlock.height - 10); + await HashratesRepository.$deleteLastEntries(); + await cpfpRepository.$deleteClustersFrom(lastBlock.height - 10); + await AccelerationRepository.$deleteAccelerationsFrom(lastBlock.height - 10); + this.blocks = this.blocks.slice(0, -10); + this.updateTimerProgress(timer, `rolled back chain divergence from ${this.currentBlockHeight}`); + for (let i = 10; i >= 0; --i) { + const newBlock = await this.$indexBlock(lastBlock.height - i); + this.blocks.push(newBlock); + this.updateTimerProgress(timer, `reindexed block`); + let cpfpSummary; + if (config.MEMPOOL.CPFP_INDEXING) { + cpfpSummary = await this.$indexCPFP(newBlock.id, lastBlock.height - i); + this.updateTimerProgress(timer, `reindexed block cpfp`); + } + await this.$getStrippedBlockTransactions(newBlock.id, true, true, cpfpSummary, newBlock.height); + this.updateTimerProgress(timer, `reindexed block summary`); } - notFound++; + await mining.$indexDifficultyAdjustments(); + await DifficultyAdjustmentsRepository.$deleteLastAdjustment(); + this.updateTimerProgress(timer, `reindexed difficulty adjustments`); + logger.info(`Re-indexed 10 blocks and summaries. Also re-indexed the last difficulty adjustments. Will re-index latest hashrates in a few seconds.`, logger.tags.mining); + indexer.reindex(); + + websocketHandler.handleReorg(); } } - console.log(`${found} of ${txIds.length} found in mempool. ${notFound} not found.`); + await blocksRepository.$saveBlockInDatabase(blockExtended); + this.updateTimerProgress(timer, `saved ${this.currentBlockHeight} to database`); - block.reward = transactions[0].vout.reduce((acc, curr) => acc + curr.value, 0); - block.coinbaseTx = this.stripCoinbaseTransaction(transactions[0]); - transactions.sort((a, b) => b.feePerVsize - a.feePerVsize); - block.medianFee = transactions.length > 1 ? Common.median(transactions.map((tx) => tx.feePerVsize)) : 0; - block.feeRange = transactions.length > 1 ? Common.getFeesInRange(transactions, 8, 1) : [0, 0]; + if (!fastForwarded) { + let lastestPriceId; + try { + lastestPriceId = await PricesRepository.$getLatestPriceId(); + this.updateTimerProgress(timer, `got latest price id ${this.currentBlockHeight}`); + } catch (e) { + logger.debug('failed to fetch latest price id from db: ' + (e instanceof Error ? e.message : e)); + } + if (priceUpdater.historyInserted === true && lastestPriceId !== null) { + await blocksRepository.$saveBlockPrices([{ + height: blockExtended.height, + priceId: lastestPriceId, + }]); + this.updateTimerProgress(timer, `saved prices for ${this.currentBlockHeight}`); + } else { + logger.debug(`Cannot save block price for ${blockExtended.height} because the price updater hasnt completed yet. Trying again in 10 seconds.`, logger.tags.mining); + indexer.scheduleSingleTask('blocksPrices', 10000); + } - this.blocks.push(block); - if (this.blocks.length > config.KEEP_BLOCK_AMOUNT) { - this.blocks.shift(); + // Save blocks summary for visualization if it's enabled + if (Common.blocksSummariesIndexingEnabled() === true) { + await this.$getStrippedBlockTransactions(blockExtended.id, true, false, cpfpSummary, blockExtended.height); + this.updateTimerProgress(timer, `saved block summary for ${this.currentBlockHeight}`); + } + if (config.MEMPOOL.CPFP_INDEXING) { + this.$saveCpfp(blockExtended.id, this.currentBlockHeight, cpfpSummary); + this.updateTimerProgress(timer, `saved cpfp for ${this.currentBlockHeight}`); + } } + } - if (this.newBlockCallback) { - this.newBlockCallback(block, txIds, transactions); + // start async callbacks + this.updateTimerProgress(timer, `starting async callbacks for ${this.currentBlockHeight}`); + const callbackPromises = this.newAsyncBlockCallbacks.map((cb) => cb(blockExtended, txIds, transactions)); + + if (block.height % 2016 === 0) { + if (Common.indexingEnabled()) { + let adjustment; + if (['liquid', 'liquidtestnet'].includes(config.MEMPOOL.NETWORK)) { + adjustment = NaN; + } else { + adjustment = Math.round( + // calcBitsDifference returns +- percentage, +100 returns to positive, /100 returns to ratio. + // Instead of actually doing /100, just reduce the multiplier. + (calcBitsDifference(this.currentBits, block.bits) + 100) * 10000 + ) / 1000000; // Remove float point noise + } + + await DifficultyAdjustmentsRepository.$saveAdjustments({ + time: block.timestamp, + height: block.height, + difficulty: block.difficulty, + adjustment, + }); + this.updateTimerProgress(timer, `saved difficulty adjustment for ${this.currentBlockHeight}`); } + + if (['liquid', 'liquidtestnet'].includes(config.MEMPOOL.NETWORK)) { + this.previousDifficultyRetarget = NaN; + } else { + this.previousDifficultyRetarget = calcBitsDifference(this.currentBits, block.bits); + } + this.lastDifficultyAdjustmentTime = block.timestamp; + this.currentBits = block.bits; + } + + // wait for pending async callbacks to finish + this.updateTimerProgress(timer, `waiting for async callbacks to complete for ${this.currentBlockHeight}`); + await Promise.all(callbackPromises); + this.updateTimerProgress(timer, `async callbacks completed for ${this.currentBlockHeight}`); + + this.blocks.push(blockExtended); + if (this.blocks.length > config.MEMPOOL.INITIAL_BLOCKS_AMOUNT * 4) { + this.blocks = this.blocks.slice(-config.MEMPOOL.INITIAL_BLOCKS_AMOUNT * 4); + } + blockSummary.transactions.forEach(tx => { + delete tx.acc; + }); + this.blockSummaries.push(blockSummary); + if (this.blockSummaries.length > config.MEMPOOL.INITIAL_BLOCKS_AMOUNT * 4) { + this.blockSummaries = this.blockSummaries.slice(-config.MEMPOOL.INITIAL_BLOCKS_AMOUNT * 4); + } + + if (this.newBlockCallbacks.length) { + this.newBlockCallbacks.forEach((cb) => cb(blockExtended, txIds, transactions)); + } + if (config.MEMPOOL.CACHE_ENABLED && !memPool.hasPriority() && (block.height % config.MEMPOOL.DISK_CACHE_BLOCK_INTERVAL === 0)) { + diskCache.$saveCacheToDisk(); + } + + // Update Redis cache + if (config.REDIS.ENABLED) { + await redisCache.$updateBlocks(this.blocks); + await redisCache.$updateBlockSummaries(this.blockSummaries); + await redisCache.$removeTransactions(txIds); + await rbfCache.updateCache(); } - } catch (err) { - console.log('updateBlocks error', err); + handledBlocks++; } + + diskCache.unlock(); + + this.clearTimer(timer); + + return handledBlocks; } - private stripCoinbaseTransaction(tx: TransactionExtended): TransactionMinerInfo { - return { - vin: [{ - scriptsig: tx.vin[0].scriptsig - }], - vout: tx.vout.map((vout) => ({ scriptpubkey_address: vout.scriptpubkey_address, value: vout.value })) + private startTimer() { + const state: any = { + start: Date.now(), + progress: 'begin $updateBlocks', + timer: null, }; + state.timer = setTimeout(() => { + logger.err(`$updateBlocks stalled at "${state.progress}"`); + }, this.mainLoopTimeout); + return state; + } + + private updateTimerProgress(state, msg): void { + state.progress = msg; + } + + private clearTimer(state): void { + if (state.timer) { + clearTimeout(state.timer); + } + } + + /** + * Index a block if it's missing from the database. Returns the block after indexing + */ + public async $indexBlock(height: number): Promise { + if (Common.indexingEnabled()) { + const dbBlock = await blocksRepository.$getBlockByHeight(height); + if (dbBlock !== null) { + return dbBlock; + } + } + + const blockHash = await bitcoinApi.$getBlockHash(height); + const block: IEsploraApi.Block = await bitcoinApi.$getBlock(blockHash); + const transactions = await this.$getTransactionsExtended(blockHash, block.height, block.timestamp, true); + const blockExtended = await this.$getBlockExtended(block, transactions); + + if (Common.indexingEnabled()) { + await blocksRepository.$saveBlockInDatabase(blockExtended); + } + + return blockExtended; + } + + public async $indexStaleBlock(hash: string): Promise { + const block: IEsploraApi.Block = await bitcoinApi.$getBlock(hash); + const transactions = await this.$getTransactionsExtended(hash, block.height, block.timestamp, true); + const blockExtended = await this.$getBlockExtended(block, transactions); + + blockExtended.canonical = await bitcoinApi.$getBlockHash(block.height); + + return blockExtended; + } + + /** + * Get one block by its hash + */ + public async $getBlock(hash: string): Promise { + // Check the memory cache + const blockByHash = this.getBlocks().find((b) => b.id === hash); + if (blockByHash) { + return blockByHash; + } + + // Not Bitcoin network, return the block as it from the bitcoin backend + if (['mainnet', 'testnet', 'signet'].includes(config.MEMPOOL.NETWORK) === false) { + return await bitcoinCoreApi.$getBlock(hash); + } + + // Bitcoin network, add our custom data on top + const block: IEsploraApi.Block = await bitcoinApi.$getBlock(hash); + if (block.stale) { + return await this.$indexStaleBlock(hash); + } else { + return await this.$indexBlock(block.height); + } + } + + public async $getStrippedBlockTransactions(hash: string, skipMemoryCache = false, + skipDBLookup = false, cpfpSummary?: CpfpSummary, blockHeight?: number): Promise + { + if (skipMemoryCache === false) { + // Check the memory cache + const cachedSummary = this.getBlockSummaries().find((b) => b.id === hash); + if (cachedSummary?.transactions?.length) { + return cachedSummary.transactions; + } + } + + // Check if it's indexed in db + if (skipDBLookup === false && Common.blocksSummariesIndexingEnabled() === true) { + const indexedSummary = await BlocksSummariesRepository.$getByBlockId(hash); + if (indexedSummary !== undefined && indexedSummary?.transactions?.length) { + return indexedSummary.transactions; + } + } + + let height = blockHeight; + let summary: BlockSummary; + let summaryVersion = 0; + if (cpfpSummary && !Common.isLiquid()) { + summary = { + id: hash, + transactions: cpfpSummary.transactions.map(tx => { + let flags: number = 0; + try { + flags = Common.getTransactionFlags(tx); + } catch (e) { + logger.warn('Failed to classify transaction: ' + (e instanceof Error ? e.message : e)); + } + return { + txid: tx.txid, + time: tx.firstSeen, + fee: tx.fee || 0, + vsize: tx.vsize, + value: Math.round(tx.vout.reduce((acc, vout) => acc + (vout.value ? vout.value : 0), 0)), + rate: tx.effectiveFeePerVsize, + flags: flags, + }; + }), + }; + summaryVersion = 1; + } else { + if (config.MEMPOOL.BACKEND === 'esplora') { + const txs = (await bitcoinApi.$getTxsForBlock(hash)).map(tx => transactionUtils.extendTransaction(tx)); + summary = this.summarizeBlockTransactions(hash, txs); + summaryVersion = 1; + } else { + // Call Core RPC + const block = await bitcoinClient.getBlock(hash, 2); + summary = this.summarizeBlock(block); + height = block.height; + } + } + if (height == null) { + const block = await bitcoinApi.$getBlock(hash); + height = block.height; + } + + // Index the response if needed + if (Common.blocksSummariesIndexingEnabled() === true) { + await BlocksSummariesRepository.$saveTransactions(height, hash, summary.transactions, summaryVersion); + } + + return summary.transactions; + } + + /** + * Get 15 blocks + * + * Internally this function uses two methods to get the blocks, and + * the method is automatically selected: + * - Using previous block hash links + * - Using block height + * + * @param fromHeight + * @param limit + * @returns + */ + public async $getBlocks(fromHeight?: number, limit: number = 15): Promise { + let currentHeight = fromHeight !== undefined ? fromHeight : this.currentBlockHeight; + if (currentHeight > this.currentBlockHeight) { + limit -= currentHeight - this.currentBlockHeight; + currentHeight = this.currentBlockHeight; + } + const returnBlocks: BlockExtended[] = []; + + if (currentHeight < 0) { + return returnBlocks; + } + + for (let i = 0; i < limit && currentHeight >= 0; i++) { + let block = this.getBlocks().find((b) => b.height === currentHeight); + if (block) { + // Using the memory cache (find by height) + returnBlocks.push(block); + } else { + // Using indexing (find by height, index on the fly, save in database) + block = await this.$indexBlock(currentHeight); + returnBlocks.push(block); + } + currentHeight--; + } + + return returnBlocks; + } + + /** + * Used for bulk block data query + * + * @param fromHeight + * @param toHeight + */ + public async $getBlocksBetweenHeight(fromHeight: number, toHeight: number): Promise { + if (!Common.indexingEnabled()) { + return []; + } + + const blocks: any[] = []; + + while (fromHeight <= toHeight) { + let block: BlockExtended | null = await blocksRepository.$getBlockByHeight(fromHeight); + if (!block) { + await this.$indexBlock(fromHeight); + block = await blocksRepository.$getBlockByHeight(fromHeight); + if (!block) { + continue; + } + } + + // Cleanup fields before sending the response + const cleanBlock: any = { + height: block.height ?? null, + hash: block.id ?? null, + timestamp: block.timestamp ?? null, + median_timestamp: block.mediantime ?? null, + previous_block_hash: block.previousblockhash ?? null, + difficulty: block.difficulty ?? null, + header: block.extras.header ?? null, + version: block.version ?? null, + bits: block.bits ?? null, + nonce: block.nonce ?? null, + size: block.size ?? null, + weight: block.weight ?? null, + tx_count: block.tx_count ?? null, + merkle_root: block.merkle_root ?? null, + reward: block.extras.reward ?? null, + total_fee_amt: block.extras.totalFees ?? null, + avg_fee_amt: block.extras.avgFee ?? null, + median_fee_amt: block.extras.medianFeeAmt ?? null, + fee_amt_percentiles: block.extras.feePercentiles ?? null, + avg_fee_rate: block.extras.avgFeeRate ?? null, + median_fee_rate: block.extras.medianFee ?? null, + fee_rate_percentiles: block.extras.feeRange ?? null, + total_inputs: block.extras.totalInputs ?? null, + total_input_amt: block.extras.totalInputAmt ?? null, + total_outputs: block.extras.totalOutputs ?? null, + total_output_amt: block.extras.totalOutputAmt ?? null, + segwit_total_txs: block.extras.segwitTotalTxs ?? null, + segwit_total_size: block.extras.segwitTotalSize ?? null, + segwit_total_weight: block.extras.segwitTotalWeight ?? null, + avg_tx_size: block.extras.avgTxSize ?? null, + utxoset_change: block.extras.utxoSetChange ?? null, + utxoset_size: block.extras.utxoSetSize ?? null, + coinbase_raw: block.extras.coinbaseRaw ?? null, + coinbase_address: block.extras.coinbaseAddress ?? null, + coinbase_addresses: block.extras.coinbaseAddresses ?? null, + coinbase_signature: block.extras.coinbaseSignature ?? null, + coinbase_signature_ascii: block.extras.coinbaseSignatureAscii ?? null, + pool_slug: block.extras.pool.slug ?? null, + pool_id: block.extras.pool.id ?? null, + }; + + if (Common.blocksSummariesIndexingEnabled() && cleanBlock.fee_amt_percentiles === null) { + cleanBlock.fee_amt_percentiles = await BlocksSummariesRepository.$getFeePercentilesByBlockId(cleanBlock.hash); + if (cleanBlock.fee_amt_percentiles === null) { + + let summary; + let summaryVersion = 0; + if (config.MEMPOOL.BACKEND === 'esplora') { + const txs = (await bitcoinApi.$getTxsForBlock(cleanBlock.hash)).map(tx => transactionUtils.extendTransaction(tx)); + summary = this.summarizeBlockTransactions(cleanBlock.hash, txs); + summaryVersion = 1; + } else { + // Call Core RPC + const block = await bitcoinClient.getBlock(cleanBlock.hash, 2); + summary = this.summarizeBlock(block); + } + + await BlocksSummariesRepository.$saveTransactions(cleanBlock.height, cleanBlock.hash, summary.transactions, summaryVersion); + cleanBlock.fee_amt_percentiles = await BlocksSummariesRepository.$getFeePercentilesByBlockId(cleanBlock.hash); + } + if (cleanBlock.fee_amt_percentiles !== null) { + cleanBlock.median_fee_amt = cleanBlock.fee_amt_percentiles[3]; + await blocksRepository.$updateFeeAmounts(cleanBlock.hash, cleanBlock.fee_amt_percentiles, cleanBlock.median_fee_amt); + } + } + + cleanBlock.fee_amt_percentiles = { + 'min': cleanBlock.fee_amt_percentiles[0], + 'perc_10': cleanBlock.fee_amt_percentiles[1], + 'perc_25': cleanBlock.fee_amt_percentiles[2], + 'perc_50': cleanBlock.fee_amt_percentiles[3], + 'perc_75': cleanBlock.fee_amt_percentiles[4], + 'perc_90': cleanBlock.fee_amt_percentiles[5], + 'max': cleanBlock.fee_amt_percentiles[6], + }; + cleanBlock.fee_rate_percentiles = { + 'min': cleanBlock.fee_rate_percentiles[0], + 'perc_10': cleanBlock.fee_rate_percentiles[1], + 'perc_25': cleanBlock.fee_rate_percentiles[2], + 'perc_50': cleanBlock.fee_rate_percentiles[3], + 'perc_75': cleanBlock.fee_rate_percentiles[4], + 'perc_90': cleanBlock.fee_rate_percentiles[5], + 'max': cleanBlock.fee_rate_percentiles[6], + }; + + // Re-org can happen after indexing so we need to always get the + // latest state from core + cleanBlock.orphans = chainTips.getOrphanedBlocksAtHeight(cleanBlock.height); + + blocks.push(cleanBlock); + fromHeight++; + } + + return blocks; + } + + public async $getBlockAuditSummary(hash: string): Promise { + if (['mainnet', 'testnet', 'signet'].includes(config.MEMPOOL.NETWORK)) { + return BlocksAuditsRepository.$getBlockAudit(hash); + } else { + return null; + } + } + + public async $getBlockTxAuditSummary(hash: string, txid: string): Promise { + if (['mainnet', 'testnet', 'signet'].includes(config.MEMPOOL.NETWORK)) { + return BlocksAuditsRepository.$getBlockTxAudit(hash, txid); + } else { + return null; + } + } + + public getLastDifficultyAdjustmentTime(): number { + return this.lastDifficultyAdjustmentTime; + } + + public getPreviousDifficultyRetarget(): number { + return this.previousDifficultyRetarget; + } + + public getQuarterEpochBlockTime(): number | null { + return this.quarterEpochBlockTime; + } + + public getCurrentBlockHeight(): number { + return this.currentBlockHeight; + } + + public async $indexCPFP(hash: string, height: number, txs?: TransactionExtended[]): Promise { + let transactions = txs; + if (!transactions) { + if (config.MEMPOOL.BACKEND === 'esplora') { + transactions = (await bitcoinApi.$getTxsForBlock(hash)).map(tx => transactionUtils.extendTransaction(tx)); + } + if (!transactions) { + const block = await bitcoinClient.getBlock(hash, 2); + transactions = block.tx.map(tx => { + tx.fee *= 100_000_000; + return tx; + }); + } + } + + if (transactions?.length != null) { + const summary = calculateFastBlockCpfp(height, transactions as TransactionExtended[]); + + await this.$saveCpfp(hash, height, summary); + + const effectiveFeeStats = Common.calcEffectiveFeeStatistics(summary.transactions); + await blocksRepository.$saveEffectiveFeeStats(hash, effectiveFeeStats); + + return summary; + } else { + logger.err(`Cannot index CPFP for block ${height} - missing transaction data`); + return null; + } + } + + public async $saveCpfp(hash: string, height: number, cpfpSummary: CpfpSummary): Promise { + try { + const result = await cpfpRepository.$batchSaveClusters(cpfpSummary.clusters); + if (!result) { + await cpfpRepository.$insertProgressMarker(height); + } + } catch (e) { + // not a fatal error, we'll try again next time the indexer runs + } } } diff --git a/backend/src/api/chain-tips.ts b/backend/src/api/chain-tips.ts new file mode 100644 index 0000000000..b7fd05ad8f --- /dev/null +++ b/backend/src/api/chain-tips.ts @@ -0,0 +1,91 @@ +import logger from '../logger'; +import bitcoinClient from './bitcoin/bitcoin-client'; + +export interface ChainTip { + height: number; + hash: string; + branchlen: number; + status: 'invalid' | 'active' | 'valid-fork' | 'valid-headers' | 'headers-only'; +}; + +export interface OrphanedBlock { + height: number; + hash: string; + status: 'valid-fork' | 'valid-headers' | 'headers-only'; + prevhash: string; +} + +class ChainTips { + private chainTips: ChainTip[] = []; + private orphanedBlocks: { [hash: string]: OrphanedBlock } = {}; + private blockCache: { [hash: string]: OrphanedBlock } = {}; + private orphansByHeight: { [height: number]: OrphanedBlock[] } = {}; + + public async updateOrphanedBlocks(): Promise { + try { + this.chainTips = await bitcoinClient.getChainTips(); + + const start = Date.now(); + const breakAt = start + 10000; + let newOrphans = 0; + this.orphanedBlocks = {}; + + for (const chain of this.chainTips) { + if (chain.status === 'valid-fork' || chain.status === 'valid-headers') { + const orphans: OrphanedBlock[] = []; + let hash = chain.hash; + do { + let orphan = this.blockCache[hash]; + if (!orphan) { + const block = await bitcoinClient.getBlock(hash); + if (block && block.confirmations === -1) { + newOrphans++; + orphan = { + height: block.height, + hash: block.hash, + status: chain.status, + prevhash: block.previousblockhash, + }; + this.blockCache[hash] = orphan; + } + } + if (orphan) { + orphans.push(orphan); + } + hash = orphan?.prevhash; + } while (hash && (Date.now() < breakAt)); + for (const orphan of orphans) { + this.orphanedBlocks[orphan.hash] = orphan; + } + } + if (Date.now() >= breakAt) { + logger.debug(`Breaking orphaned blocks updater after 10s, will continue next block`); + break; + } + } + + this.orphansByHeight = {}; + const allOrphans = Object.values(this.orphanedBlocks); + for (const orphan of allOrphans) { + if (!this.orphansByHeight[orphan.height]) { + this.orphansByHeight[orphan.height] = []; + } + this.orphansByHeight[orphan.height].push(orphan); + } + + logger.debug(`Updated orphaned blocks cache. Fetched ${newOrphans} new orphaned blocks. Total ${allOrphans.length}`); + } catch (e) { + logger.err(`Cannot get fetch orphaned blocks. Reason: ${e instanceof Error ? e.message : e}`); + } + } + + public getOrphanedBlocksAtHeight(height: number | undefined): OrphanedBlock[] { + if (height === undefined) { + return []; + } + + return this.orphansByHeight[height] || []; + } +} + +export default new ChainTips(); \ No newline at end of file diff --git a/backend/src/api/common.ts b/backend/src/api/common.ts index c3e0f1a42b..cba39a5119 100644 --- a/backend/src/api/common.ts +++ b/backend/src/api/common.ts @@ -1,6 +1,40 @@ -import { TransactionExtended } from '../interfaces'; +import * as bitcoinjs from 'bitcoinjs-lib'; +import { Request } from 'express'; +import { CpfpInfo, CpfpSummary, CpfpCluster, EffectiveFeeStats, MempoolBlockWithTransactions, TransactionExtended, MempoolTransactionExtended, TransactionStripped, WorkingEffectiveFeeStats, TransactionClassified, TransactionFlags } from '../mempool.interfaces'; +import config from '../config'; +import { NodeSocket } from '../repositories/NodesSocketsRepository'; +import { isIP } from 'net'; +import transactionUtils from './transaction-utils'; +import { isPoint } from '../utils/secp256k1'; +import logger from '../logger'; +import { getVarIntLength, opcodes, parseMultisigScript } from '../utils/bitcoin-script'; + +// Bitcoin Core default policy settings +const TX_MAX_STANDARD_VERSION = 2; +const MAX_STANDARD_TX_WEIGHT = 400_000; +const MAX_BLOCK_SIGOPS_COST = 80_000; +const MAX_STANDARD_TX_SIGOPS_COST = (MAX_BLOCK_SIGOPS_COST / 5); +const MIN_STANDARD_TX_NONWITNESS_SIZE = 65; +const MAX_P2SH_SIGOPS = 15; +const MAX_STANDARD_P2WSH_STACK_ITEMS = 100; +const MAX_STANDARD_P2WSH_STACK_ITEM_SIZE = 80; +const MAX_STANDARD_TAPSCRIPT_STACK_ITEM_SIZE = 80; +const MAX_STANDARD_P2WSH_SCRIPT_SIZE = 3600; +const MAX_STANDARD_SCRIPTSIG_SIZE = 1650; +const DUST_RELAY_TX_FEE = 3; +const MAX_OP_RETURN_RELAY = 83; +const DEFAULT_PERMIT_BAREMULTISIG = true; export class Common { + static nativeAssetId = config.MEMPOOL.NETWORK === 'liquidtestnet' ? + '144c654344aa716d6f3abcc1ca90e5641e4e2a7f633bc09fe3baf64585819a49' + : '6f0279e9ed041c3d710a9f57d0c02928416460c4b722ae3457a11eec381c526d'; + static _isLiquid = config.MEMPOOL.NETWORK === 'liquid' || config.MEMPOOL.NETWORK === 'liquidtestnet'; + + static isLiquid(): boolean { + return this._isLiquid; + } + static median(numbers: number[]) { let medianNr = 0; const numsLen = numbers.length; @@ -12,39 +46,1073 @@ export class Common { return medianNr; } - static getFeesInRange(transactions: TransactionExtended[], rangeLength: number, lastindex = 0) { - const arr = [transactions[transactions.length - 1].feePerVsize]; + static percentile(numbers: number[], percentile: number) { + if (percentile === 50) { + return this.median(numbers); + } + const index = Math.ceil(numbers.length * (100 - percentile) * 1e-2); + if (index < 0 || index > numbers.length - 1) { + return 0; + } + return numbers[index]; + } + + static getFeesInRange(transactions: TransactionExtended[], rangeLength: number) { + const filtered: TransactionExtended[] = []; + let lastValidRate = Infinity; + // filter out anomalous fee rates to ensure monotonic range + for (const tx of transactions) { + if (tx.effectiveFeePerVsize <= lastValidRate) { + filtered.push(tx); + lastValidRate = tx.effectiveFeePerVsize; + } + } + const arr = [filtered[filtered.length - 1].effectiveFeePerVsize]; const chunk = 1 / (rangeLength - 1); let itemsToAdd = rangeLength - 2; while (itemsToAdd > 0) { - arr.push(transactions[Math.floor(transactions.length * chunk * itemsToAdd)].feePerVsize); + arr.push(filtered[Math.floor(filtered.length * chunk * itemsToAdd)].effectiveFeePerVsize); itemsToAdd--; } - arr.push(transactions[lastindex].feePerVsize); + arr.push(filtered[0].effectiveFeePerVsize); return arr; } - static findRbfTransactions(added: TransactionExtended[], deleted: TransactionExtended[]): { [txid: string]: TransactionExtended } { - const matches: { [txid: string]: TransactionExtended } = {}; - deleted - // The replaced tx must have at least one input with nSequence < maxint-1 (That’s the opt-in) - .filter((tx) => tx.vin.some((vin) => vin.sequence < 0xfffffffe)) - .forEach((deletedTx) => { - const foundMatches = added.find((addedTx) => { + static findRbfTransactions(added: MempoolTransactionExtended[], deleted: MempoolTransactionExtended[], forceScalable = false): { [txid: string]: MempoolTransactionExtended[] } { + const matches: { [txid: string]: MempoolTransactionExtended[] } = {}; + + // For small N, a naive nested loop is extremely fast, but it doesn't scale + if (added.length < 1000 && deleted.length < 50 && !forceScalable) { + added.forEach((addedTx) => { + const foundMatches = deleted.filter((deletedTx) => { // The new tx must, absolutely speaking, pay at least as much fee as the replaced tx. return addedTx.fee > deletedTx.fee // The new transaction must pay more fee per kB than the replaced tx. - && addedTx.feePerVsize > deletedTx.feePerVsize + && addedTx.adjustedFeePerVsize > deletedTx.adjustedFeePerVsize // Spends one or more of the same inputs && deletedTx.vin.some((deletedVin) => - addedTx.vin.some((vin) => vin.txid === deletedVin.txid)); + addedTx.vin.some((vin) => vin.txid === deletedVin.txid && vin.vout === deletedVin.vout)); }); - if (foundMatches) { - matches[deletedTx.txid] = foundMatches; + if (foundMatches?.length) { + matches[addedTx.txid] = [...new Set(foundMatches)]; } }); + } else { + // for large N, build a lookup table of prevouts we can check in ~constant time + const deletedSpendMap: { [txid: string]: { [vout: number]: MempoolTransactionExtended } } = {}; + for (const tx of deleted) { + for (const vin of tx.vin) { + if (!deletedSpendMap[vin.txid]) { + deletedSpendMap[vin.txid] = {}; + } + deletedSpendMap[vin.txid][vin.vout] = tx; + } + } + + for (const addedTx of added) { + const foundMatches = new Set(); + for (const vin of addedTx.vin) { + const deletedTx = deletedSpendMap[vin.txid]?.[vin.vout]; + if (deletedTx && deletedTx.txid !== addedTx.txid + // The new tx must, absolutely speaking, pay at least as much fee as the replaced tx. + && addedTx.fee > deletedTx.fee + // The new transaction must pay more fee per kB than the replaced tx. + && addedTx.adjustedFeePerVsize > deletedTx.adjustedFeePerVsize + ) { + foundMatches.add(deletedTx); + } + if (foundMatches.size) { + matches[addedTx.txid] = [...foundMatches]; + } + } + } + } + return matches; } + + static findMinedRbfTransactions(minedTransactions: TransactionExtended[], spendMap: Map): { [txid: string]: { replaced: MempoolTransactionExtended[], replacedBy: TransactionExtended }} { + const matches: { [txid: string]: { replaced: MempoolTransactionExtended[], replacedBy: TransactionExtended }} = {}; + for (const tx of minedTransactions) { + const replaced: Set = new Set(); + for (let i = 0; i < tx.vin.length; i++) { + const vin = tx.vin[i]; + const match = spendMap.get(`${vin.txid}:${vin.vout}`); + if (match && match.txid !== tx.txid) { + replaced.add(match); + // remove this tx from the spendMap + // prevents the same tx being replaced more than once + for (const replacedVin of match.vin) { + const key = `${replacedVin.txid}:${replacedVin.vout}`; + spendMap.delete(key); + } + } + const key = `${vin.txid}:${vin.vout}`; + spendMap.delete(key); + } + if (replaced.size) { + matches[tx.txid] = { replaced: Array.from(replaced), replacedBy: tx }; + } + } + return matches; + } + + static setSchnorrSighashFlags(flags: bigint, witness: string[]): bigint { + // no witness items + if (!witness?.length) { + return flags; + } + const hasAnnex = witness.length > 1 && witness[witness.length - 1].startsWith('50'); + if (witness?.length === (hasAnnex ? 2 : 1)) { + // keypath spend, signature is the only witness item + if (witness[0].length === 130) { + flags |= this.setSighashFlags(flags, witness[0]); + } else { + flags |= TransactionFlags.sighash_default; + } + } else { + // scriptpath spend, all items except for the script, control block and annex could be signatures + for (let i = 0; i < witness.length - (hasAnnex ? 3 : 2); i++) { + // handle probable signatures + if (witness[i].length === 130) { + flags |= this.setSighashFlags(flags, witness[i]); + } else if (witness[i].length === 128) { + flags |= TransactionFlags.sighash_default; + } + } + } + return flags; + } + + static isDERSig(w: string): boolean { + // heuristic to detect probable DER signatures + return (w.length >= 18 + && w.startsWith('30') // minimum DER signature length is 8 bytes + sighash flag (see https://mempool.space/testnet/tx/c6c232a36395fa338da458b86ff1327395a9afc28c5d2daa4273e410089fd433) + && ['01', '02', '03', '81', '82', '83'].includes(w.slice(-2)) // signature must end with a valid sighash flag + && (w.length === (2 * parseInt(w.slice(2, 4), 16)) + 6) // second byte encodes the combined length of the R and S components + ); + } + + /** + * Validates most standardness rules + * + * returns true early if any standardness rule is violated, otherwise false + * (except for non-mandatory-script-verify-flag and p2sh script evaluation rules which are *not* enforced) + */ + static isNonStandard(tx: TransactionExtended): boolean { + // version + if (tx.version > TX_MAX_STANDARD_VERSION) { + return true; + } + + // tx-size + if (tx.weight > MAX_STANDARD_TX_WEIGHT) { + return true; + } + + // tx-size-small + if (this.getNonWitnessSize(tx) < MIN_STANDARD_TX_NONWITNESS_SIZE) { + return true; + } + + // bad-txns-too-many-sigops + if (tx.sigops && tx.sigops > MAX_STANDARD_TX_SIGOPS_COST) { + return true; + } + + // input validation + for (const vin of tx.vin) { + if (vin.is_coinbase) { + // standardness rules don't apply to coinbase transactions + return false; + } + // scriptsig-size + if ((vin.scriptsig.length / 2) > MAX_STANDARD_SCRIPTSIG_SIZE) { + return true; + } + // scriptsig-not-pushonly + if (vin.scriptsig_asm) { + for (const op of vin.scriptsig_asm.split(' ')) { + if (opcodes[op] && opcodes[op] > opcodes['OP_16']) { + return true; + } + } + } + // bad-txns-nonstandard-inputs + if (vin.prevout?.scriptpubkey_type === 'p2sh') { + // TODO: evaluate script (https://github.com/bitcoin/bitcoin/blob/1ac627c485a43e50a9a49baddce186ee3ad4daad/src/policy/policy.cpp#L177) + // countScriptSigops returns the witness-scaled sigops, so divide by 4 before comparison with MAX_P2SH_SIGOPS + const sigops = (transactionUtils.countScriptSigops(vin.inner_redeemscript_asm) / 4); + if (sigops > MAX_P2SH_SIGOPS) { + return true; + } + } else if (['unknown', 'provably_unspendable', 'empty'].includes(vin.prevout?.scriptpubkey_type || '')) { + return true; + } + // TODO: bad-witness-nonstandard + } + + // output validation + let opreturnCount = 0; + for (const vout of tx.vout) { + // scriptpubkey + if (['nonstandard', 'provably_unspendable', 'empty'].includes(vout.scriptpubkey_type)) { + // (non-standard output type) + return true; + } else if (vout.scriptpubkey_type === 'unknown') { + // undefined segwit version/length combinations are actually standard in outputs + // https://github.com/bitcoin/bitcoin/blob/2c79abc7ad4850e9e3ba32a04c530155cda7f980/src/script/interpreter.cpp#L1950-L1951 + if (vout.scriptpubkey.startsWith('00') || !this.isWitnessProgram(vout.scriptpubkey)) { + return true; + } + } else if (vout.scriptpubkey_type === 'multisig') { + if (!DEFAULT_PERMIT_BAREMULTISIG) { + // bare-multisig + return true; + } + const mOfN = parseMultisigScript(vout.scriptpubkey_asm); + if (!mOfN || mOfN.n < 1 || mOfN.n > 3 || mOfN.m < 1 || mOfN.m > mOfN.n) { + // (non-standard bare multisig threshold) + return true; + } + } else if (vout.scriptpubkey_type === 'op_return') { + opreturnCount++; + if ((vout.scriptpubkey.length / 2) > MAX_OP_RETURN_RELAY) { + // over default datacarrier limit + return true; + } + } + // dust + // (we could probably hardcode this for the different output types...) + if (vout.scriptpubkey_type !== 'op_return') { + let dustSize = (vout.scriptpubkey.length / 2); + // add varint length overhead + dustSize += getVarIntLength(dustSize); + // add value size + dustSize += 8; + if (Common.isWitnessProgram(vout.scriptpubkey)) { + dustSize += 67; + } else { + dustSize += 148; + } + if (vout.value < (dustSize * DUST_RELAY_TX_FEE)) { + // under minimum output size + return true; + } + } + } + + // multi-op-return + if (opreturnCount > 1) { + return true; + } + + // TODO: non-mandatory-script-verify-flag + + return false; + } + + // A witness program is any valid scriptpubkey that consists of a 1-byte push opcode + // followed by a data push between 2 and 40 bytes. + // https://github.com/bitcoin/bitcoin/blob/2c79abc7ad4850e9e3ba32a04c530155cda7f980/src/script/script.cpp#L224-L240 + static isWitnessProgram(scriptpubkey: string): false | { version: number, program: string } { + if (scriptpubkey.length < 8 || scriptpubkey.length > 84) { + return false; + } + const version = parseInt(scriptpubkey.slice(0,2), 16); + if (version !== 0 && version < 0x51 || version > 0x60) { + return false; + } + const push = parseInt(scriptpubkey.slice(2,4), 16); + if (push + 2 === (scriptpubkey.length / 2)) { + return { + version: version ? version - 0x50 : 0, + program: scriptpubkey.slice(4), + }; + } + return false; + } + + static getNonWitnessSize(tx: TransactionExtended): number { + let weight = tx.weight; + let hasWitness = false; + for (const vin of tx.vin) { + if (vin.witness?.length) { + hasWitness = true; + // witness count + weight -= getVarIntLength(vin.witness.length); + for (const witness of vin.witness) { + // witness item size + content + weight -= getVarIntLength(witness.length / 2) + (witness.length / 2); + } + } + } + if (hasWitness) { + // marker & segwit flag + weight -= 2; + } + return Math.ceil(weight / 4); + } + + static setSegwitSighashFlags(flags: bigint, witness: string[]): bigint { + for (const w of witness) { + if (this.isDERSig(w)) { + flags |= this.setSighashFlags(flags, w); + } + } + return flags; + } + + static setLegacySighashFlags(flags: bigint, scriptsig_asm: string): bigint { + for (const item of scriptsig_asm.split(' ')) { + // skip op_codes + if (item.startsWith('OP_')) { + continue; + } + // check pushed data + if (this.isDERSig(item)) { + flags |= this.setSighashFlags(flags, item); + } + } + return flags; + } + + static setSighashFlags(flags: bigint, signature: string): bigint { + switch(signature.slice(-2)) { + case '01': return flags | TransactionFlags.sighash_all; + case '02': return flags | TransactionFlags.sighash_none; + case '03': return flags | TransactionFlags.sighash_single; + case '81': return flags | TransactionFlags.sighash_all | TransactionFlags.sighash_acp; + case '82': return flags | TransactionFlags.sighash_none | TransactionFlags.sighash_acp; + case '83': return flags | TransactionFlags.sighash_single | TransactionFlags.sighash_acp; + default: return flags | TransactionFlags.sighash_default; // taproot only + } + } + + static isBurnKey(pubkey: string): boolean { + return [ + '022222222222222222222222222222222222222222222222222222222222222222', + '033333333333333333333333333333333333333333333333333333333333333333', + '020202020202020202020202020202020202020202020202020202020202020202', + '030303030303030303030303030303030303030303030303030303030303030303', + ].includes(pubkey); + } + + static isInscription(vin, flags): bigint { + // in taproot, if the last witness item begins with 0x50, it's an annex + const hasAnnex = vin.witness?.[vin.witness.length - 1].startsWith('50'); + // script spends have more than one witness item, not counting the annex (if present) + if (vin.witness.length > (hasAnnex ? 2 : 1)) { + // the script itself is the second-to-last witness item, not counting the annex + const asm = vin.inner_witnessscript_asm || transactionUtils.convertScriptSigAsm(vin.witness[vin.witness.length - (hasAnnex ? 3 : 2)]); + // inscriptions smuggle data within an 'OP_0 OP_IF ... OP_ENDIF' envelope + if (asm?.includes('OP_0 OP_IF')) { + flags |= TransactionFlags.inscription; + } + } + return flags; + } + + static getTransactionFlags(tx: TransactionExtended): number { + let flags = tx.flags ? BigInt(tx.flags) : 0n; + + // Update variable flags (CPFP, RBF) + flags &= ~TransactionFlags.cpfp_child; + if (tx.ancestors?.length) { + flags |= TransactionFlags.cpfp_child; + } + flags &= ~TransactionFlags.cpfp_parent; + if (tx.descendants?.length) { + flags |= TransactionFlags.cpfp_parent; + } + flags &= ~TransactionFlags.replacement; + if (tx.replacement) { + flags |= TransactionFlags.replacement; + } + + // Already processed static flags, no need to do it again + if (tx.flags) { + return Number(flags); + } + + // Process static flags + if (tx.version === 1) { + flags |= TransactionFlags.v1; + } else if (tx.version === 2) { + flags |= TransactionFlags.v2; + } else if (tx.version === 3) { + flags |= TransactionFlags.v3; + } + const reusedInputAddresses: { [address: string ]: number } = {}; + const reusedOutputAddresses: { [address: string ]: number } = {}; + const inValues = {}; + const outValues = {}; + let rbf = false; + for (const vin of tx.vin) { + if (vin.sequence < 0xfffffffe) { + rbf = true; + } + if (vin.prevout?.scriptpubkey_type) { + switch (vin.prevout?.scriptpubkey_type) { + case 'p2pk': flags |= TransactionFlags.p2pk; break; + case 'multisig': flags |= TransactionFlags.p2ms; break; + case 'p2pkh': flags |= TransactionFlags.p2pkh; break; + case 'p2sh': flags |= TransactionFlags.p2sh; break; + case 'v0_p2wpkh': flags |= TransactionFlags.p2wpkh; break; + case 'v0_p2wsh': flags |= TransactionFlags.p2wsh; break; + case 'v1_p2tr': { + flags |= TransactionFlags.p2tr; + if (vin.witness?.length) { + flags = Common.isInscription(vin, flags); + } + } break; + } + } else { + // no prevouts, optimistically check witness-bearing inputs + if (vin.witness?.length >= 2) { + try { + flags = Common.isInscription(vin, flags); + } catch { + // witness script parsing will fail if this isn't really a taproot output + } + } + } + + // sighash flags + if (vin.prevout?.scriptpubkey_type === 'v1_p2tr') { + flags |= this.setSchnorrSighashFlags(flags, vin.witness); + } else if (vin.witness) { + flags |= this.setSegwitSighashFlags(flags, vin.witness); + } else if (vin.scriptsig?.length) { + flags |= this.setLegacySighashFlags(flags, vin.scriptsig_asm || transactionUtils.convertScriptSigAsm(vin.scriptsig)); + } + + if (vin.prevout?.scriptpubkey_address) { + reusedInputAddresses[vin.prevout?.scriptpubkey_address] = (reusedInputAddresses[vin.prevout?.scriptpubkey_address] || 0) + 1; + } + inValues[vin.prevout?.value || Math.random()] = (inValues[vin.prevout?.value || Math.random()] || 0) + 1; + } + if (rbf) { + flags |= TransactionFlags.rbf; + } else { + flags |= TransactionFlags.no_rbf; + } + let hasFakePubkey = false; + let P2WSHCount = 0; + let olgaSize = 0; + for (const vout of tx.vout) { + switch (vout.scriptpubkey_type) { + case 'p2pk': { + flags |= TransactionFlags.p2pk; + // detect fake pubkey (i.e. not a valid DER point on the secp256k1 curve) + hasFakePubkey = hasFakePubkey || !isPoint(vout.scriptpubkey?.slice(2, -2)); + } break; + case 'multisig': { + flags |= TransactionFlags.p2ms; + // detect fake pubkeys (i.e. not valid DER points on the secp256k1 curve) + const asm = vout.scriptpubkey_asm || transactionUtils.convertScriptSigAsm(vout.scriptpubkey); + for (const key of (asm?.split(' ') || [])) { + if (!hasFakePubkey && !key.startsWith('OP_')) { + hasFakePubkey = hasFakePubkey || this.isBurnKey(key) || !isPoint(key); + } + } + } break; + case 'p2pkh': flags |= TransactionFlags.p2pkh; break; + case 'p2sh': flags |= TransactionFlags.p2sh; break; + case 'v0_p2wpkh': flags |= TransactionFlags.p2wpkh; break; + case 'v0_p2wsh': flags |= TransactionFlags.p2wsh; break; + case 'v1_p2tr': flags |= TransactionFlags.p2tr; break; + case 'op_return': flags |= TransactionFlags.op_return; break; + } + if (vout.scriptpubkey_address) { + reusedOutputAddresses[vout.scriptpubkey_address] = (reusedOutputAddresses[vout.scriptpubkey_address] || 0) + 1; + } + if (vout.scriptpubkey_type === 'v0_p2wsh') { + if (!P2WSHCount) { + olgaSize = parseInt(vout.scriptpubkey.slice(4, 8), 16); + } + P2WSHCount++; + if (P2WSHCount === Math.ceil((olgaSize + 2) / 32)) { + const nullBytes = (P2WSHCount * 32) - olgaSize - 2; + if (vout.scriptpubkey.endsWith(''.padEnd(nullBytes * 2, '0'))) { + flags |= TransactionFlags.fake_scripthash; + } + } + } else { + P2WSHCount = 0; + } + outValues[vout.value || Math.random()] = (outValues[vout.value || Math.random()] || 0) + 1; + } + if (hasFakePubkey) { + flags |= TransactionFlags.fake_pubkey; + } + + // fast but bad heuristic to detect possible coinjoins + // (at least 5 inputs and 5 outputs, less than half of which are unique amounts, with no address reuse) + const addressReuse = Object.keys(reusedOutputAddresses).reduce((acc, key) => Math.max(acc, (reusedInputAddresses[key] || 0) + (reusedOutputAddresses[key] || 0)), 0) > 1; + if (!addressReuse && tx.vin.length >= 5 && tx.vout.length >= 5 && (Object.keys(inValues).length + Object.keys(outValues).length) <= (tx.vin.length + tx.vout.length) / 2 ) { + flags |= TransactionFlags.coinjoin; + } + // more than 5:1 input:output ratio + if (tx.vin.length / tx.vout.length >= 5) { + flags |= TransactionFlags.consolidation; + } + // less than 1:5 input:output ratio + if (tx.vin.length / tx.vout.length <= 0.2) { + flags |= TransactionFlags.batch_payout; + } + + if (this.isNonStandard(tx)) { + flags |= TransactionFlags.nonstandard; + } + + return Number(flags); + } + + static classifyTransaction(tx: TransactionExtended): TransactionClassified { + let flags = 0; + try { + flags = Common.getTransactionFlags(tx); + } catch (e) { + logger.warn('Failed to add classification flags to transaction: ' + (e instanceof Error ? e.message : e)); + } + tx.flags = flags; + return { + ...Common.stripTransaction(tx), + flags, + }; + } + + static classifyTransactions(txs: TransactionExtended[]): TransactionClassified[] { + return txs.map(Common.classifyTransaction); + } + + static stripTransaction(tx: TransactionExtended): TransactionStripped { + return { + txid: tx.txid, + fee: tx.fee || 0, + vsize: tx.weight / 4, + value: tx.vout.reduce((acc, vout) => acc + (vout.value ? vout.value : 0), 0), + acc: tx.acceleration || undefined, + rate: tx.effectiveFeePerVsize, + time: tx.firstSeen || undefined, + }; + } + + static stripTransactions(txs: TransactionExtended[]): TransactionStripped[] { + return txs.map(Common.stripTransaction); + } + + static sleep$(ms: number): Promise { + return new Promise((resolve) => { + setTimeout(() => { + resolve(); + }, ms); + }); + } + + static shuffleArray(array: any[]) { + for (let i = array.length - 1; i > 0; i--) { + const j = Math.floor(Math.random() * (i + 1)); + [array[i], array[j]] = [array[j], array[i]]; + } + } + + // calculates the ratio of matched transactions to projected transactions by weight + static getSimilarity(projectedBlock: MempoolBlockWithTransactions, transactions: TransactionExtended[]): number { + let matchedWeight = 0; + let projectedWeight = 0; + const inBlock = {}; + + for (const tx of transactions) { + inBlock[tx.txid] = tx; + } + + // look for transactions that were expected in the template, but missing from the mined block + for (const tx of projectedBlock.transactions) { + if (inBlock[tx.txid]) { + matchedWeight += tx.vsize * 4; + } + projectedWeight += tx.vsize * 4; + } + + projectedWeight += transactions[0].weight; + matchedWeight += transactions[0].weight; + + return projectedWeight ? matchedWeight / projectedWeight : 1; + } + + static getSqlInterval(interval: string | null): string | null { + switch (interval) { + case '24h': return '1 DAY'; + case '3d': return '3 DAY'; + case '1w': return '1 WEEK'; + case '1m': return '1 MONTH'; + case '3m': return '3 MONTH'; + case '6m': return '6 MONTH'; + case '1y': return '1 YEAR'; + case '2y': return '2 YEAR'; + case '3y': return '3 YEAR'; + case '4y': return '4 YEAR'; + default: return null; + } + } + + static indexingEnabled(): boolean { + return ( + ['mainnet', 'testnet', 'signet'].includes(config.MEMPOOL.NETWORK) && + config.DATABASE.ENABLED === true && + config.MEMPOOL.INDEXING_BLOCKS_AMOUNT !== 0 + ); + } + + static blocksSummariesIndexingEnabled(): boolean { + return ( + Common.indexingEnabled() && + config.MEMPOOL.BLOCKS_SUMMARIES_INDEXING === true + ); + } + + static gogglesIndexingEnabled(): boolean { + return ( + Common.blocksSummariesIndexingEnabled() && + config.MEMPOOL.GOGGLES_INDEXING === true + ); + } + + static cpfpIndexingEnabled(): boolean { + return ( + Common.indexingEnabled() && + config.MEMPOOL.CPFP_INDEXING === true + ); + } + + static setDateMidnight(date: Date): void { + date.setUTCHours(0); + date.setUTCMinutes(0); + date.setUTCSeconds(0); + date.setUTCMilliseconds(0); + } + + static channelShortIdToIntegerId(channelId: string): string { + if (channelId.indexOf('x') === -1) { // Already an integer id + return channelId; + } + if (channelId.indexOf('/') !== -1) { // Topology import + channelId = channelId.slice(0, -2); + } + const s = channelId.split('x').map(part => BigInt(part)); + return ((s[0] << 40n) | (s[1] << 16n) | s[2]).toString(); + } + + /** Decodes a channel id returned by lnd as uint64 to a short channel id */ + static channelIntegerIdToShortId(id: string): string { + if (id.indexOf('/') !== -1) { + id = id.slice(0, -2); + } + + if (id.indexOf('x') !== -1) { // Already a short id + return id; + } + + const n = BigInt(id); + return [ + n >> 40n, // nth block + (n >> 16n) & 0xffffffn, // nth tx of the block + n & 0xffffn // nth output of the tx + ].join('x'); + } + + static utcDateToMysql(date?: number | null): string | null { + if (date === null) { + return null; + } + const d = new Date((date || 0) * 1000); + return d.toISOString().split('T')[0] + ' ' + d.toTimeString().split(' ')[0]; + } + + static findSocketNetwork(addr: string): {network: string | null, url: string} { + let network: string | null = null; + let url: string = addr; + + if (config.LIGHTNING.BACKEND === 'cln') { + url = addr.split('://')[1]; + } + + if (!url) { + return { + network: null, + url: addr, + }; + } + + if (addr.indexOf('onion') !== -1) { + if (url.split('.')[0].length >= 56) { + network = 'torv3'; + } else { + network = 'torv2'; + } + } else if (addr.indexOf('i2p') !== -1) { + network = 'i2p'; + } else if (addr.indexOf('ipv4') !== -1 || (config.LIGHTNING.BACKEND === 'lnd' && isIP(url.split(':')[0]) === 4)) { + const ipv = isIP(url.split(':')[0]); + if (ipv === 4) { + network = 'ipv4'; + } else { + return { + network: null, + url: addr, + }; + } + } else if (addr.indexOf('ipv6') !== -1 || (config.LIGHTNING.BACKEND === 'lnd' && url.indexOf(']:'))) { + url = url.split('[')[1].split(']')[0]; + const ipv = isIP(url); + if (ipv === 6) { + const parts = addr.split(':'); + network = 'ipv6'; + url = `[${url}]:${parts[parts.length - 1]}`; + } else { + return { + network: null, + url: addr, + }; + } + } else { + return { + network: null, + url: addr, + }; + } + + return { + network: network, + url: url, + }; + } + + static formatSocket(publicKey: string, socket: {network: string, addr: string}): NodeSocket { + if (config.LIGHTNING.BACKEND === 'cln') { + return { + publicKey: publicKey, + network: socket.network, + addr: socket.addr, + }; + } else /* if (config.LIGHTNING.BACKEND === 'lnd') */ { + const formatted = this.findSocketNetwork(socket.addr); + return { + publicKey: publicKey, + network: formatted.network, + addr: formatted.url, + }; + } + } + + static calcEffectiveFeeStatistics(transactions: { weight: number, fee: number, effectiveFeePerVsize?: number, txid: string, acceleration?: boolean }[]): EffectiveFeeStats { + const sortedTxs = transactions.map(tx => { return { txid: tx.txid, weight: tx.weight, rate: tx.effectiveFeePerVsize || ((tx.fee || 0) / (tx.weight / 4)) }; }).sort((a, b) => a.rate - b.rate); + + let weightCount = 0; + let medianFee = 0; + let medianWeight = 0; + + // calculate the "medianFee" as the average fee rate of the middle 0.25% weight units of transactions + const halfWidth = config.MEMPOOL.BLOCK_WEIGHT_UNITS / 800; + const leftBound = Math.floor((config.MEMPOOL.BLOCK_WEIGHT_UNITS / 2) - halfWidth); + const rightBound = Math.ceil((config.MEMPOOL.BLOCK_WEIGHT_UNITS / 2) + halfWidth); + for (let i = 0; i < sortedTxs.length && weightCount < rightBound; i++) { + const left = weightCount; + const right = weightCount + sortedTxs[i].weight; + if (right > leftBound) { + const weight = Math.min(right, rightBound) - Math.max(left, leftBound); + medianFee += (sortedTxs[i].rate * (weight / 4) ); + medianWeight += weight; + } + weightCount += sortedTxs[i].weight; + } + const medianFeeRate = medianWeight ? (medianFee / (medianWeight / 4)) : 0; + + // minimum effective fee heuristic: + // lowest of + // a) the 1st percentile of effective fee rates + // b) the minimum effective fee rate in the last 2% of transactions (in block order) + const minFee = Math.min( + Common.getNthPercentile(1, sortedTxs).rate, + transactions.slice(-transactions.length / 50).reduce((min, tx) => { return Math.min(min, tx.effectiveFeePerVsize || ((tx.fee || 0) / (tx.weight / 4))); }, Infinity) + ); + + // maximum effective fee heuristic: + // highest of + // a) the 99th percentile of effective fee rates + // b) the maximum effective fee rate in the first 2% of transactions (in block order) + const maxFee = Math.max( + Common.getNthPercentile(99, sortedTxs).rate, + transactions.slice(0, transactions.length / 50).reduce((max, tx) => { return Math.max(max, tx.effectiveFeePerVsize || ((tx.fee || 0) / (tx.weight / 4))); }, 0) + ); + + return { + medianFee: medianFeeRate, + feeRange: [ + minFee, + [10,25,50,75,90].map(n => Common.getNthPercentile(n, sortedTxs).rate), + maxFee, + ].flat(), + }; + } + + static getNthPercentile(n: number, sortedDistribution: any[]): any { + return sortedDistribution[Math.floor((sortedDistribution.length - 1) * (n / 100))]; + } + + static getTransactionFromRequest(req: Request, form: boolean): string { + let rawTx: any = typeof req.body === 'object' && form + ? Object.values(req.body)[0] as any + : req.body; + if (typeof rawTx !== 'string') { + throw Object.assign(new Error('Non-string request body'), { code: -1 }); + } + + // Support both upper and lower case hex + // Support both txHash= Form and direct API POST + const reg = form ? /^txHash=((?:[a-fA-F0-9]{2})+)$/ : /^((?:[a-fA-F0-9]{2})+)$/; + const matches = reg.exec(rawTx); + if (!matches || !matches[1]) { + throw Object.assign(new Error('Non-hex request body'), { code: -2 }); + } + + // Guaranteed to be a hex string of multiple of 2 + // Guaranteed to be lower case + // Guaranteed to pass validation (see function below) + return this.validateTransactionHex(matches[1].toLowerCase()); + } + + static getTransactionsFromRequest(req: Request, limit: number = 25): string[] { + if (!Array.isArray(req.body) || req.body.some(hex => typeof hex !== 'string')) { + throw Object.assign(new Error('Invalid request body (should be an array of hexadecimal strings)'), { code: -1 }); + } + + if (limit && req.body.length > limit) { + throw Object.assign(new Error('Exceeded maximum of 25 transactions'), { code: -1 }); + } + + const txs = req.body; + + return txs.map(rawTx => { + // Support both upper and lower case hex + // Support both txHash= Form and direct API POST + const reg = /^((?:[a-fA-F0-9]{2})+)$/; + const matches = reg.exec(rawTx); + if (!matches || !matches[1]) { + throw Object.assign(new Error('Invalid hex string'), { code: -2 }); + } + + // Guaranteed to be a hex string of multiple of 2 + // Guaranteed to be lower case + // Guaranteed to pass validation (see function below) + return this.validateTransactionHex(matches[1].toLowerCase()); + }); + } + + private static validateTransactionHex(txhex: string): string { + // Do not mutate txhex + + // We assume txhex to be valid hex (output of getTransactionFromRequest above) + + // Check 1: Valid transaction parse + let tx: bitcoinjs.Transaction; + try { + tx = bitcoinjs.Transaction.fromHex(txhex); + } catch(e) { + throw Object.assign(new Error('Invalid transaction (could not parse)'), { code: -4 }); + } + + // Check 2: Simple size check + if (tx.weight() > config.MEMPOOL.MAX_PUSH_TX_SIZE_WEIGHT) { + throw Object.assign(new Error(`Transaction too large (max ${config.MEMPOOL.MAX_PUSH_TX_SIZE_WEIGHT} weight units)`), { code: -3 }); + } + + // Check 3: Check unreachable script in taproot (if not allowed) + if (!config.MEMPOOL.ALLOW_UNREACHABLE) { + tx.ins.forEach(input => { + const witness = input.witness; + // See BIP 341: Script validation rules + const hasAnnex = witness.length >= 2 && + witness[witness.length - 1][0] === 0x50; + const scriptSpendMinLength = hasAnnex ? 3 : 2; + const maybeScriptSpend = witness.length >= scriptSpendMinLength; + + if (maybeScriptSpend) { + const controlBlock = witness[witness.length - scriptSpendMinLength + 1]; + if (controlBlock.length === 0 || !this.isValidLeafVersion(controlBlock[0])) { + // Skip this input, it's not taproot + return; + } + // Definitely taproot. Get script + const script = witness[witness.length - scriptSpendMinLength]; + const decompiled = bitcoinjs.script.decompile(script); + if (!decompiled || decompiled.length < 2) { + // Skip this input + return; + } + // Iterate up to second last (will look ahead 1 item) + for (let i = 0; i < decompiled.length - 1; i++) { + const first = decompiled[i]; + const second = decompiled[i + 1]; + if ( + first === bitcoinjs.opcodes.OP_FALSE && + second === bitcoinjs.opcodes.OP_IF + ) { + throw Object.assign(new Error('Unreachable taproot scripts not allowed'), { code: -5 }); + } + } + } + }) + } + + // Pass through the input string untouched + return txhex; + } + + private static isValidLeafVersion(leafVersion: number): boolean { + // See Note 7 in BIP341 + // https://github.com/bitcoin/bips/blob/66a1a8151021913047934ebab3f8883f2f8ca75b/bip-0341.mediawiki#cite_note-7 + // "What constraints are there on the leaf version?" + + // Must be an integer between 0 and 255 + // Since we're parsing a byte + if (Math.floor(leafVersion) !== leafVersion || leafVersion < 0 || leafVersion > 255) { + return false; + } + // "the leaf version cannot be odd" + if ((leafVersion & 0x01) === 1) { + return false; + } + // "The values that comply to this rule are + // the 32 even values between 0xc0 and 0xfe + if (leafVersion >= 0xc0 && leafVersion <= 0xfe) { + return true; + } + // and also 0x66, 0x7e, 0x80, 0x84, 0x96, 0x98, 0xba, 0xbc, 0xbe." + if ([0x66, 0x7e, 0x80, 0x84, 0x96, 0x98, 0xba, 0xbc, 0xbe].includes(leafVersion)) { + return true; + } + // Otherwise, invalid + return false; + } +} + +/** + * Class to calculate average fee rates of a list of transactions + * at certain weight percentiles, in a single pass + * + * init with: + * maxWeight - the total weight to measure percentiles relative to (e.g. 4MW for a single block) + * percentileBandWidth - how many weight units to average over for each percentile (as a % of maxWeight) + * percentiles - an array of weight percentiles to compute, in % + * + * then call .processNext(tx) for each transaction, in descending order + * + * retrieve the final results with .getFeeStats() + */ +export class OnlineFeeStatsCalculator { + private maxWeight: number; + private percentiles = [10,25,50,75,90]; + + private bandWidthPercent = 2; + private bandWidth: number = 0; + private bandIndex = 0; + private leftBound = 0; + private rightBound = 0; + private inBand = false; + private totalBandFee = 0; + private totalBandWeight = 0; + private minBandRate = Infinity; + private maxBandRate = 0; + + private feeRange: { avg: number, min: number, max: number }[] = []; + private totalWeight: number = 0; + + constructor (maxWeight: number, percentileBandWidth?: number, percentiles?: number[]) { + this.maxWeight = maxWeight; + if (percentiles && percentiles.length) { + this.percentiles = percentiles; + } + if (percentileBandWidth != null) { + this.bandWidthPercent = percentileBandWidth; + } + this.bandWidth = this.maxWeight * (this.bandWidthPercent / 100); + // add min/max percentiles aligned to the ends of the range + this.percentiles.unshift(this.bandWidthPercent / 2); + this.percentiles.push(100 - (this.bandWidthPercent / 2)); + this.setNextBounds(); + } + + processNext(tx: { weight: number, fee: number, effectiveFeePerVsize?: number, feePerVsize?: number, rate?: number, txid: string }): void { + let left = this.totalWeight; + const right = this.totalWeight + tx.weight; + if (!this.inBand && right <= this.leftBound) { + this.totalWeight += tx.weight; + return; + } + + while (left < right) { + if (right > this.leftBound) { + this.inBand = true; + const txRate = (tx.rate || tx.effectiveFeePerVsize || tx.feePerVsize || 0); + const weight = Math.min(right, this.rightBound) - Math.max(left, this.leftBound); + this.totalBandFee += (txRate * weight); + this.totalBandWeight += weight; + this.maxBandRate = Math.max(this.maxBandRate, txRate); + this.minBandRate = Math.min(this.minBandRate, txRate); + } + left = Math.min(right, this.rightBound); + + if (left >= this.rightBound) { + this.inBand = false; + const avgBandFeeRate = this.totalBandWeight ? (this.totalBandFee / this.totalBandWeight) : 0; + this.feeRange.unshift({ avg: avgBandFeeRate, min: this.minBandRate, max: this.maxBandRate }); + this.bandIndex++; + this.setNextBounds(); + this.totalBandFee = 0; + this.totalBandWeight = 0; + this.minBandRate = Infinity; + this.maxBandRate = 0; + } + } + this.totalWeight += tx.weight; + } + + private setNextBounds(): void { + const nextPercentile = this.percentiles[this.bandIndex]; + if (nextPercentile != null) { + this.leftBound = ((nextPercentile / 100) * this.maxWeight) - (this.bandWidth / 2); + this.rightBound = this.leftBound + this.bandWidth; + } else { + this.leftBound = Infinity; + this.rightBound = Infinity; + } + } + + getRawFeeStats(): WorkingEffectiveFeeStats { + if (this.totalBandWeight > 0) { + const avgBandFeeRate = this.totalBandWeight ? (this.totalBandFee / this.totalBandWeight) : 0; + this.feeRange.unshift({ avg: avgBandFeeRate, min: this.minBandRate, max: this.maxBandRate }); + } + while (this.feeRange.length < this.percentiles.length) { + this.feeRange.unshift({ avg: 0, min: 0, max: 0 }); + } + return { + minFee: this.feeRange[0].min, + medianFee: this.feeRange[Math.floor(this.feeRange.length / 2)].avg, + maxFee: this.feeRange[this.feeRange.length - 1].max, + feeRange: this.feeRange.map(f => f.avg), + }; + } + + getFeeStats(): EffectiveFeeStats { + const stats = this.getRawFeeStats(); + stats.feeRange[0] = stats.minFee; + stats.feeRange[stats.feeRange.length - 1] = stats.maxFee; + return stats; + } } diff --git a/backend/src/api/cpfp.ts b/backend/src/api/cpfp.ts new file mode 100644 index 0000000000..5818eb1eab --- /dev/null +++ b/backend/src/api/cpfp.ts @@ -0,0 +1,270 @@ +import { Ancestor, CpfpCluster, CpfpInfo, CpfpSummary, MempoolTransactionExtended, TransactionExtended } from '../mempool.interfaces'; +import { GraphTx, convertToGraphTx, expandRelativesGraph, initializeRelatives, makeBlockTemplate, mempoolComparator, removeAncestors, setAncestorScores } from './mini-miner'; +import memPool from './mempool'; +import { Acceleration } from './acceleration/acceleration'; + +const CPFP_UPDATE_INTERVAL = 60_000; // update CPFP info at most once per 60s per transaction +const MAX_CLUSTER_ITERATIONS = 100; + +export function calculateFastBlockCpfp(height: number, transactions: TransactionExtended[], saveRelatives: boolean = false): CpfpSummary { + const clusters: CpfpCluster[] = []; // list of all cpfp clusters in this block + const clusterMap: { [txid: string]: CpfpCluster } = {}; // map transactions to their cpfp cluster + let clusterTxs: TransactionExtended[] = []; // working list of elements of the current cluster + let ancestors: { [txid: string]: boolean } = {}; // working set of ancestors of the current cluster root + const txMap: { [txid: string]: TransactionExtended } = {}; + // initialize the txMap + for (const tx of transactions) { + txMap[tx.txid] = tx; + } + // reverse pass to identify CPFP clusters + for (let i = transactions.length - 1; i >= 0; i--) { + const tx = transactions[i]; + if (!ancestors[tx.txid]) { + let totalFee = 0; + let totalVSize = 0; + clusterTxs.forEach(tx => { + totalFee += tx?.fee || 0; + totalVSize += (tx.weight / 4); + }); + const effectiveFeePerVsize = totalFee / totalVSize; + let cluster: CpfpCluster; + if (clusterTxs.length > 1) { + cluster = { + root: clusterTxs[0].txid, + height, + txs: clusterTxs.map(tx => { return { txid: tx.txid, weight: tx.weight, fee: tx.fee || 0 }; }), + effectiveFeePerVsize, + }; + clusters.push(cluster); + } + clusterTxs.forEach(tx => { + txMap[tx.txid].effectiveFeePerVsize = effectiveFeePerVsize; + if (cluster) { + clusterMap[tx.txid] = cluster; + } + }); + // reset working vars + clusterTxs = []; + ancestors = {}; + } + clusterTxs.push(tx); + tx.vin.forEach(vin => { + ancestors[vin.txid] = true; + }); + } + // forward pass to enforce ancestor rate caps + for (const tx of transactions) { + let minAncestorRate = tx.effectiveFeePerVsize; + for (const vin of tx.vin) { + if (txMap[vin.txid]?.effectiveFeePerVsize) { + minAncestorRate = Math.min(minAncestorRate, txMap[vin.txid].effectiveFeePerVsize); + } + } + // check rounded values to skip cases with almost identical fees + const roundedMinAncestorRate = Math.ceil(minAncestorRate); + const roundedEffectiveFeeRate = Math.floor(tx.effectiveFeePerVsize); + if (roundedMinAncestorRate < roundedEffectiveFeeRate) { + tx.effectiveFeePerVsize = minAncestorRate; + if (!clusterMap[tx.txid]) { + // add a single-tx cluster to record the dependent rate + const cluster = { + root: tx.txid, + height, + txs: [{ txid: tx.txid, weight: tx.weight, fee: tx.fee || 0 }], + effectiveFeePerVsize: minAncestorRate, + }; + clusterMap[tx.txid] = cluster; + clusters.push(cluster); + } else { + // update the existing cluster with the dependent rate + clusterMap[tx.txid].effectiveFeePerVsize = minAncestorRate; + } + } + } + if (saveRelatives) { + for (const cluster of clusters) { + cluster.txs.forEach((member, index) => { + txMap[member.txid].descendants = cluster.txs.slice(0, index).reverse(); + txMap[member.txid].ancestors = cluster.txs.slice(index + 1).reverse(); + txMap[member.txid].effectiveFeePerVsize = cluster.effectiveFeePerVsize; + }); + } + } + return { + transactions, + clusters, + }; +} + +export function calculateGoodBlockCpfp(height: number, transactions: MempoolTransactionExtended[], accelerations: Acceleration[]): CpfpSummary { + const txMap: { [txid: string]: MempoolTransactionExtended } = {}; + for (const tx of transactions) { + txMap[tx.txid] = tx; + } + const template = makeBlockTemplate(transactions, accelerations, 1, Infinity, Infinity); + const clusters = new Map(); + for (const tx of template) { + const cluster = tx.cluster || []; + const root = cluster.length ? cluster[cluster.length - 1] : null; + if (cluster.length > 1 && root && !clusters.has(root)) { + clusters.set(root, cluster); + } + txMap[tx.txid].effectiveFeePerVsize = tx.effectiveFeePerVsize; + } + + const clusterArray: CpfpCluster[] = []; + + for (const cluster of clusters.values()) { + for (const txid of cluster) { + const mempoolTx = txMap[txid]; + if (mempoolTx) { + const ancestors: Ancestor[] = []; + const descendants: Ancestor[] = []; + let matched = false; + cluster.forEach(relativeTxid => { + if (relativeTxid === txid) { + matched = true; + } else { + const relative = { + txid: relativeTxid, + fee: txMap[relativeTxid].fee, + weight: (txMap[relativeTxid].adjustedVsize * 4) || txMap[relativeTxid].weight, + }; + if (matched) { + descendants.push(relative); + } else { + ancestors.push(relative); + } + } + }); + if (mempoolTx.ancestors?.length !== ancestors.length || mempoolTx.descendants?.length !== descendants.length) { + mempoolTx.cpfpDirty = true; + } + Object.assign(mempoolTx, { ancestors, descendants, bestDescendant: null, cpfpChecked: true }); + } + } + const root = cluster[cluster.length - 1]; + clusterArray.push({ + root: root, + height, + txs: cluster.reverse().map(txid => ({ + txid, + fee: txMap[txid].fee, + weight: (txMap[txid].adjustedVsize * 4) || txMap[txid].weight, + })), + effectiveFeePerVsize: txMap[root].effectiveFeePerVsize, + }); + } + + return { + transactions: transactions.map(tx => txMap[tx.txid]), + clusters: clusterArray, + }; +} + +/** + * Takes a mempool transaction and a copy of the current mempool, and calculates the CPFP data for + * that transaction (and all others in the same cluster) + */ +export function calculateMempoolTxCpfp(tx: MempoolTransactionExtended, mempool: { [txid: string]: MempoolTransactionExtended }): CpfpInfo { + if (tx.cpfpUpdated && Date.now() < (tx.cpfpUpdated + CPFP_UPDATE_INTERVAL)) { + tx.cpfpDirty = false; + return { + ancestors: tx.ancestors || [], + bestDescendant: tx.bestDescendant || null, + descendants: tx.descendants || [], + effectiveFeePerVsize: tx.effectiveFeePerVsize || tx.adjustedFeePerVsize || tx.feePerVsize, + sigops: tx.sigops, + fee: tx.fee, + adjustedVsize: tx.adjustedVsize, + acceleration: tx.acceleration + }; + } + + const ancestorMap = new Map(); + const graphTx = convertToGraphTx(tx, memPool.getSpendMap()); + ancestorMap.set(tx.txid, graphTx); + + const allRelatives = expandRelativesGraph(mempool, ancestorMap, memPool.getSpendMap()); + const relativesMap = initializeRelatives(allRelatives); + const cluster = calculateCpfpCluster(tx.txid, relativesMap); + + let totalVsize = 0; + let totalFee = 0; + for (const tx of cluster.values()) { + totalVsize += tx.vsize; + totalFee += tx.fees.base; + } + const effectiveFeePerVsize = totalFee / totalVsize; + for (const tx of cluster.values()) { + mempool[tx.txid].effectiveFeePerVsize = effectiveFeePerVsize; + mempool[tx.txid].ancestors = Array.from(tx.ancestors.values()).map(tx => ({ txid: tx.txid, weight: tx.weight, fee: tx.fees.base })); + mempool[tx.txid].descendants = Array.from(cluster.values()).filter(entry => entry.txid !== tx.txid && !tx.ancestors.has(entry.txid)).map(tx => ({ txid: tx.txid, weight: tx.weight, fee: tx.fees.base })); + mempool[tx.txid].bestDescendant = null; + mempool[tx.txid].cpfpChecked = true; + mempool[tx.txid].cpfpDirty = true; + mempool[tx.txid].cpfpUpdated = Date.now(); + } + + tx = mempool[tx.txid]; + + return { + ancestors: tx.ancestors || [], + bestDescendant: tx.bestDescendant || null, + descendants: tx.descendants || [], + effectiveFeePerVsize: tx.effectiveFeePerVsize || tx.adjustedFeePerVsize || tx.feePerVsize, + sigops: tx.sigops, + fee: tx.fee, + adjustedVsize: tx.adjustedVsize, + acceleration: tx.acceleration + }; +} + +/** + * Given a root transaction and a list of in-mempool ancestors, + * Calculate the CPFP cluster + * + * @param tx + * @param ancestors + */ +function calculateCpfpCluster(txid: string, graph: Map): Map { + const tx = graph.get(txid); + if (!tx) { + return new Map([]); + } + + // Initialize individual & ancestor fee rates + graph.forEach(entry => setAncestorScores(entry)); + + // Sort by descending ancestor score + let sortedRelatives = Array.from(graph.values()).sort(mempoolComparator); + + // Iterate until we reach a cluster that includes our target tx + let maxIterations = MAX_CLUSTER_ITERATIONS; + let best = sortedRelatives.shift(); + let bestCluster = new Map(best?.ancestors?.entries() || []); + while (sortedRelatives.length && best && (best.txid !== tx.txid && !best.ancestors.has(tx.txid)) && maxIterations > 0) { + maxIterations--; + if ((best && best.txid === tx.txid) || (bestCluster && bestCluster.has(tx.txid))) { + break; + } else { + // Remove this cluster (it doesn't include our target tx) + // and update scores, ancestor totals and dependencies for the survivors + removeAncestors(bestCluster, graph); + + // re-sort + sortedRelatives = Array.from(graph.values()).sort(mempoolComparator); + + // Grab the next highest scoring entry + best = sortedRelatives.shift(); + if (best) { + bestCluster = new Map(best?.ancestors?.entries() || []); + bestCluster.set(best?.txid, best); + } + } + } + + bestCluster.set(tx.txid, tx); + + return bestCluster; +} \ No newline at end of file diff --git a/backend/src/api/database-migration.ts b/backend/src/api/database-migration.ts new file mode 100644 index 0000000000..70ff2d5bb6 --- /dev/null +++ b/backend/src/api/database-migration.ts @@ -0,0 +1,1310 @@ +import config from '../config'; +import DB from '../database'; +import logger from '../logger'; +import { Common } from './common'; +import blocksRepository from '../repositories/BlocksRepository'; +import cpfpRepository from '../repositories/CpfpRepository'; +import { RowDataPacket } from 'mysql2'; + +class DatabaseMigration { + private static currentVersion = 80; + private queryTimeout = 3600_000; + private statisticsAddedIndexed = false; + private uniqueLogs: string[] = []; + + private blocksTruncatedMessage = `'blocks' table has been truncated.`; + private hashratesTruncatedMessage = `'hashrates' table has been truncated.`; + + /** + * Avoid printing multiple time the same message + */ + private uniqueLog(loggerFunction: any, msg: string) { + if (this.uniqueLogs.includes(msg)) { + return; + } + this.uniqueLogs.push(msg); + loggerFunction(msg); + } + + /** + * Entry point + */ + public async $initializeOrMigrateDatabase(): Promise { + logger.debug('MIGRATIONS: Running migrations'); + + await this.$printDatabaseVersion(); + + // First of all, if the `state` database does not exist, create it so we can track migration version + if (!await this.$checkIfTableExists('state')) { + logger.debug('MIGRATIONS: `state` table does not exist. Creating it.'); + try { + await this.$createMigrationStateTable(); + } catch (e) { + logger.err('MIGRATIONS: Unable to create `state` table, aborting in 10 seconds. ' + e); + await Common.sleep$(10000); + process.exit(-1); + } + logger.debug('MIGRATIONS: `state` table initialized.'); + } + + let databaseSchemaVersion = 0; + try { + databaseSchemaVersion = await this.$getSchemaVersionFromDatabase(); + } catch (e) { + logger.err('MIGRATIONS: Unable to get current database migration version, aborting in 10 seconds. ' + e); + await Common.sleep$(10000); + process.exit(-1); + } + + if (databaseSchemaVersion === 0) { + logger.info('Initializing database (first run, clean install)'); + } + + if (databaseSchemaVersion <= 2) { + // Disable some spam logs when they're not relevant + this.uniqueLog(logger.notice, this.blocksTruncatedMessage); + this.uniqueLog(logger.notice, this.hashratesTruncatedMessage); + } + + logger.debug('MIGRATIONS: Current state.schema_version ' + databaseSchemaVersion); + logger.debug('MIGRATIONS: Latest DatabaseMigration.version is ' + DatabaseMigration.currentVersion); + if (databaseSchemaVersion >= DatabaseMigration.currentVersion) { + logger.debug('MIGRATIONS: Nothing to do.'); + return; + } + + // Now, create missing tables. Those queries cannot be wrapped into a transaction unfortunately + try { + await this.$createMissingTablesAndIndexes(databaseSchemaVersion); + } catch (e) { + logger.err('MIGRATIONS: Unable to create required tables, aborting in 10 seconds. ' + e); + await Common.sleep$(10000); + process.exit(-1); + } + + if (DatabaseMigration.currentVersion > databaseSchemaVersion) { + try { + await this.$migrateTableSchemaFromVersion(databaseSchemaVersion); + if (databaseSchemaVersion === 0) { + logger.notice(`MIGRATIONS: OK. Database schema has been properly initialized to version ${DatabaseMigration.currentVersion} (latest version)`); + } else { + logger.notice(`MIGRATIONS: OK. Database schema have been migrated from version ${databaseSchemaVersion} to ${DatabaseMigration.currentVersion} (latest version)`); + } + } catch (e) { + logger.err('MIGRATIONS: Unable to migrate database, aborting. ' + e); + } + } + + return; + } + + /** + * Create all missing tables + */ + private async $createMissingTablesAndIndexes(databaseSchemaVersion: number) { + await this.$setStatisticsAddedIndexedFlag(databaseSchemaVersion); + + const isBitcoin = ['mainnet', 'testnet', 'signet'].includes(config.MEMPOOL.NETWORK); + + await this.$executeQuery(this.getCreateElementsTableQuery(), await this.$checkIfTableExists('elements_pegs')); + await this.$executeQuery(this.getCreateStatisticsQuery(), await this.$checkIfTableExists('statistics')); + if (databaseSchemaVersion < 2 && this.statisticsAddedIndexed === false) { + await this.$executeQuery(`CREATE INDEX added ON statistics (added);`); + await this.updateToSchemaVersion(2); + } + if (databaseSchemaVersion < 3) { + await this.$executeQuery(this.getCreatePoolsTableQuery(), await this.$checkIfTableExists('pools')); + await this.updateToSchemaVersion(3); + } + if (databaseSchemaVersion < 4) { + await this.$executeQuery('DROP table IF EXISTS blocks;'); + await this.$executeQuery(this.getCreateBlocksTableQuery(), await this.$checkIfTableExists('blocks')); + await this.updateToSchemaVersion(4); + } + if (databaseSchemaVersion < 5 && isBitcoin === true) { + this.uniqueLog(logger.notice, this.blocksTruncatedMessage); + await this.$executeQuery('TRUNCATE blocks;'); // Need to re-index + await this.$executeQuery('ALTER TABLE blocks ADD `reward` double unsigned NOT NULL DEFAULT "0"'); + await this.updateToSchemaVersion(5); + } + + if (databaseSchemaVersion < 6 && isBitcoin === true) { + this.uniqueLog(logger.notice, this.blocksTruncatedMessage); + await this.$executeQuery('TRUNCATE blocks;'); // Need to re-index + // Cleanup original blocks fields type + await this.$executeQuery('ALTER TABLE blocks MODIFY `height` integer unsigned NOT NULL DEFAULT "0"'); + await this.$executeQuery('ALTER TABLE blocks MODIFY `tx_count` smallint unsigned NOT NULL DEFAULT "0"'); + await this.$executeQuery('ALTER TABLE blocks MODIFY `size` integer unsigned NOT NULL DEFAULT "0"'); + await this.$executeQuery('ALTER TABLE blocks MODIFY `weight` integer unsigned NOT NULL DEFAULT "0"'); + await this.$executeQuery('ALTER TABLE blocks MODIFY `difficulty` double NOT NULL DEFAULT "0"'); + // We also fix the pools.id type so we need to drop/re-create the foreign key + await this.$executeQuery('ALTER TABLE blocks DROP FOREIGN KEY IF EXISTS `blocks_ibfk_1`'); + await this.$executeQuery('ALTER TABLE pools MODIFY `id` smallint unsigned AUTO_INCREMENT'); + await this.$executeQuery('ALTER TABLE blocks MODIFY `pool_id` smallint unsigned NULL'); + await this.$executeQuery('ALTER TABLE blocks ADD FOREIGN KEY (`pool_id`) REFERENCES `pools` (`id`)'); + // Add new block indexing fields + await this.$executeQuery('ALTER TABLE blocks ADD `version` integer unsigned NOT NULL DEFAULT "0"'); + await this.$executeQuery('ALTER TABLE blocks ADD `bits` integer unsigned NOT NULL DEFAULT "0"'); + await this.$executeQuery('ALTER TABLE blocks ADD `nonce` bigint unsigned NOT NULL DEFAULT "0"'); + await this.$executeQuery('ALTER TABLE blocks ADD `merkle_root` varchar(65) NOT NULL DEFAULT ""'); + await this.$executeQuery('ALTER TABLE blocks ADD `previous_block_hash` varchar(65) NULL'); + await this.updateToSchemaVersion(6); + } + + if (databaseSchemaVersion < 7 && isBitcoin === true) { + await this.$executeQuery('DROP table IF EXISTS hashrates;'); + await this.$executeQuery(this.getCreateDailyStatsTableQuery(), await this.$checkIfTableExists('hashrates')); + await this.updateToSchemaVersion(7); + } + + if (databaseSchemaVersion < 8 && isBitcoin === true) { + this.uniqueLog(logger.notice, this.blocksTruncatedMessage); + await this.$executeQuery('TRUNCATE hashrates;'); // Need to re-index + await this.$executeQuery('ALTER TABLE `hashrates` DROP INDEX `PRIMARY`'); + await this.$executeQuery('ALTER TABLE `hashrates` ADD `id` int NOT NULL AUTO_INCREMENT PRIMARY KEY FIRST'); + await this.$executeQuery('ALTER TABLE `hashrates` ADD `share` float NOT NULL DEFAULT "0"'); + await this.$executeQuery('ALTER TABLE `hashrates` ADD `type` enum("daily", "weekly") DEFAULT "daily"'); + await this.updateToSchemaVersion(8); + } + + if (databaseSchemaVersion < 9 && isBitcoin === true) { + this.uniqueLog(logger.notice, this.hashratesTruncatedMessage); + await this.$executeQuery('TRUNCATE hashrates;'); // Need to re-index + await this.$executeQuery('ALTER TABLE `state` CHANGE `name` `name` varchar(100)'); + await this.$executeQuery('ALTER TABLE `hashrates` ADD UNIQUE `hashrate_timestamp_pool_id` (`hashrate_timestamp`, `pool_id`)'); + await this.updateToSchemaVersion(9); + } + + if (databaseSchemaVersion < 10 && isBitcoin === true) { + await this.$executeQuery('ALTER TABLE `blocks` ADD INDEX `blockTimestamp` (`blockTimestamp`)'); + await this.updateToSchemaVersion(10); + } + + if (databaseSchemaVersion < 11 && isBitcoin === true) { + this.uniqueLog(logger.notice, this.blocksTruncatedMessage); + await this.$executeQuery('TRUNCATE blocks;'); // Need to re-index + await this.$executeQuery(`ALTER TABLE blocks + ADD avg_fee INT UNSIGNED NULL, + ADD avg_fee_rate INT UNSIGNED NULL + `); + await this.$executeQuery('ALTER TABLE blocks MODIFY `reward` BIGINT UNSIGNED NOT NULL DEFAULT "0"'); + await this.$executeQuery('ALTER TABLE blocks MODIFY `median_fee` INT UNSIGNED NOT NULL DEFAULT "0"'); + await this.$executeQuery('ALTER TABLE blocks MODIFY `fees` INT UNSIGNED NOT NULL DEFAULT "0"'); + await this.updateToSchemaVersion(11); + } + + if (databaseSchemaVersion < 12 && isBitcoin === true) { + // No need to re-index because the new data type can contain larger values + await this.$executeQuery('ALTER TABLE blocks MODIFY `fees` BIGINT UNSIGNED NOT NULL DEFAULT "0"'); + await this.updateToSchemaVersion(12); + } + + if (databaseSchemaVersion < 13 && isBitcoin === true) { + await this.$executeQuery('ALTER TABLE blocks MODIFY `difficulty` DOUBLE UNSIGNED NOT NULL DEFAULT "0"'); + await this.$executeQuery('ALTER TABLE blocks MODIFY `median_fee` BIGINT UNSIGNED NOT NULL DEFAULT "0"'); + await this.$executeQuery('ALTER TABLE blocks MODIFY `avg_fee` BIGINT UNSIGNED NOT NULL DEFAULT "0"'); + await this.$executeQuery('ALTER TABLE blocks MODIFY `avg_fee_rate` BIGINT UNSIGNED NOT NULL DEFAULT "0"'); + await this.updateToSchemaVersion(13); + } + + if (databaseSchemaVersion < 14 && isBitcoin === true) { + this.uniqueLog(logger.notice, this.hashratesTruncatedMessage); + await this.$executeQuery('TRUNCATE hashrates;'); // Need to re-index + await this.$executeQuery('ALTER TABLE `hashrates` DROP FOREIGN KEY `hashrates_ibfk_1`'); + await this.$executeQuery('ALTER TABLE `hashrates` MODIFY `pool_id` SMALLINT UNSIGNED NOT NULL DEFAULT "0"'); + await this.updateToSchemaVersion(14); + } + + if (databaseSchemaVersion < 16 && isBitcoin === true) { + this.uniqueLog(logger.notice, this.hashratesTruncatedMessage); + await this.$executeQuery('TRUNCATE hashrates;'); // Need to re-index because we changed timestamps + await this.updateToSchemaVersion(16); + } + + if (databaseSchemaVersion < 17 && isBitcoin === true) { + await this.$executeQuery('ALTER TABLE `pools` ADD `slug` CHAR(50) NULL'); + await this.updateToSchemaVersion(17); + } + + if (databaseSchemaVersion < 18 && isBitcoin === true) { + await this.$executeQuery('ALTER TABLE `blocks` ADD INDEX `hash` (`hash`);'); + await this.updateToSchemaVersion(18); + } + + if (databaseSchemaVersion < 19) { + await this.$executeQuery(this.getCreateRatesTableQuery(), await this.$checkIfTableExists('rates')); + await this.updateToSchemaVersion(19); + } + + if (databaseSchemaVersion < 20 && isBitcoin === true) { + await this.$executeQuery(this.getCreateBlocksSummariesTableQuery(), await this.$checkIfTableExists('blocks_summaries')); + await this.updateToSchemaVersion(20); + } + + if (databaseSchemaVersion < 21) { + await this.$executeQuery('DROP TABLE IF EXISTS `rates`'); + await this.$executeQuery(this.getCreatePricesTableQuery(), await this.$checkIfTableExists('prices')); + await this.updateToSchemaVersion(21); + } + + if (databaseSchemaVersion < 22 && isBitcoin === true) { + await this.$executeQuery('DROP TABLE IF EXISTS `difficulty_adjustments`'); + await this.$executeQuery(this.getCreateDifficultyAdjustmentsTableQuery(), await this.$checkIfTableExists('difficulty_adjustments')); + await this.updateToSchemaVersion(22); + } + + if (databaseSchemaVersion < 23) { + await this.$executeQuery('TRUNCATE `prices`'); + await this.$executeQuery('ALTER TABLE `prices` DROP `avg_prices`'); + await this.$executeQuery('ALTER TABLE `prices` ADD `USD` float DEFAULT "0"'); + await this.$executeQuery('ALTER TABLE `prices` ADD `EUR` float DEFAULT "0"'); + await this.$executeQuery('ALTER TABLE `prices` ADD `GBP` float DEFAULT "0"'); + await this.$executeQuery('ALTER TABLE `prices` ADD `CAD` float DEFAULT "0"'); + await this.$executeQuery('ALTER TABLE `prices` ADD `CHF` float DEFAULT "0"'); + await this.$executeQuery('ALTER TABLE `prices` ADD `AUD` float DEFAULT "0"'); + await this.$executeQuery('ALTER TABLE `prices` ADD `JPY` float DEFAULT "0"'); + await this.updateToSchemaVersion(23); + } + + if (databaseSchemaVersion < 24 && isBitcoin == true) { + await this.$executeQuery('DROP TABLE IF EXISTS `blocks_audits`'); + await this.$executeQuery(this.getCreateBlocksAuditsTableQuery(), await this.$checkIfTableExists('blocks_audits')); + await this.updateToSchemaVersion(24); + } + + if (databaseSchemaVersion < 25 && isBitcoin === true) { + await this.$executeQuery(this.getCreateLightningStatisticsQuery(), await this.$checkIfTableExists('lightning_stats')); + await this.$executeQuery(this.getCreateNodesQuery(), await this.$checkIfTableExists('nodes')); + await this.$executeQuery(this.getCreateChannelsQuery(), await this.$checkIfTableExists('channels')); + await this.$executeQuery(this.getCreateNodesStatsQuery(), await this.$checkIfTableExists('node_stats')); + await this.updateToSchemaVersion(25); + } + + if (databaseSchemaVersion < 26 && isBitcoin === true) { + if (config.LIGHTNING.ENABLED) { + this.uniqueLog(logger.notice, `'lightning_stats' table has been truncated.`); + } + await this.$executeQuery(`TRUNCATE lightning_stats`); + await this.$executeQuery('ALTER TABLE `lightning_stats` ADD tor_nodes int(11) NOT NULL DEFAULT "0"'); + await this.$executeQuery('ALTER TABLE `lightning_stats` ADD clearnet_nodes int(11) NOT NULL DEFAULT "0"'); + await this.$executeQuery('ALTER TABLE `lightning_stats` ADD unannounced_nodes int(11) NOT NULL DEFAULT "0"'); + await this.updateToSchemaVersion(26); + } + + if (databaseSchemaVersion < 27 && isBitcoin === true) { + await this.$executeQuery('ALTER TABLE `lightning_stats` ADD avg_capacity bigint(20) unsigned NOT NULL DEFAULT "0"'); + await this.$executeQuery('ALTER TABLE `lightning_stats` ADD avg_fee_rate int(11) unsigned NOT NULL DEFAULT "0"'); + await this.$executeQuery('ALTER TABLE `lightning_stats` ADD avg_base_fee_mtokens bigint(20) unsigned NOT NULL DEFAULT "0"'); + await this.$executeQuery('ALTER TABLE `lightning_stats` ADD med_capacity bigint(20) unsigned NOT NULL DEFAULT "0"'); + await this.$executeQuery('ALTER TABLE `lightning_stats` ADD med_fee_rate int(11) unsigned NOT NULL DEFAULT "0"'); + await this.$executeQuery('ALTER TABLE `lightning_stats` ADD med_base_fee_mtokens bigint(20) unsigned NOT NULL DEFAULT "0"'); + await this.updateToSchemaVersion(27); + } + + if (databaseSchemaVersion < 28 && isBitcoin === true) { + if (config.LIGHTNING.ENABLED) { + this.uniqueLog(logger.notice, `'lightning_stats' and 'node_stats' tables have been truncated.`); + } + await this.$executeQuery(`TRUNCATE lightning_stats`); + await this.$executeQuery(`TRUNCATE node_stats`); + await this.$executeQuery(`ALTER TABLE lightning_stats MODIFY added DATE`); + await this.updateToSchemaVersion(28); + } + + if (databaseSchemaVersion < 29 && isBitcoin === true) { + await this.$executeQuery(this.getCreateGeoNamesTableQuery(), await this.$checkIfTableExists('geo_names')); + await this.$executeQuery('ALTER TABLE `nodes` ADD as_number int(11) unsigned NULL DEFAULT NULL'); + await this.$executeQuery('ALTER TABLE `nodes` ADD city_id int(11) unsigned NULL DEFAULT NULL'); + await this.$executeQuery('ALTER TABLE `nodes` ADD country_id int(11) unsigned NULL DEFAULT NULL'); + await this.$executeQuery('ALTER TABLE `nodes` ADD accuracy_radius int(11) unsigned NULL DEFAULT NULL'); + await this.$executeQuery('ALTER TABLE `nodes` ADD subdivision_id int(11) unsigned NULL DEFAULT NULL'); + await this.$executeQuery('ALTER TABLE `nodes` ADD longitude double NULL DEFAULT NULL'); + await this.$executeQuery('ALTER TABLE `nodes` ADD latitude double NULL DEFAULT NULL'); + await this.updateToSchemaVersion(29); + } + + if (databaseSchemaVersion < 30 && isBitcoin === true) { + await this.$executeQuery('ALTER TABLE `geo_names` CHANGE `type` `type` enum("city","country","division","continent","as_organization") NOT NULL'); + await this.updateToSchemaVersion(30); + } + + if (databaseSchemaVersion < 31 && isBitcoin == true) { // Link blocks to prices + await this.$executeQuery('ALTER TABLE `prices` ADD `id` int NULL AUTO_INCREMENT UNIQUE'); + await this.$executeQuery('DROP TABLE IF EXISTS `blocks_prices`'); + await this.$executeQuery(this.getCreateBlocksPricesTableQuery(), await this.$checkIfTableExists('blocks_prices')); + await this.updateToSchemaVersion(31); + } + + if (databaseSchemaVersion < 32 && isBitcoin == true) { + await this.$executeQuery('ALTER TABLE `blocks_summaries` ADD `template` JSON DEFAULT "[]"'); + await this.updateToSchemaVersion(32); + } + + if (databaseSchemaVersion < 33 && isBitcoin == true) { + await this.$executeQuery('ALTER TABLE `geo_names` CHANGE `type` `type` enum("city","country","division","continent","as_organization", "country_iso_code") NOT NULL'); + await this.updateToSchemaVersion(33); + } + + if (databaseSchemaVersion < 34 && isBitcoin == true) { + await this.$executeQuery('ALTER TABLE `lightning_stats` ADD clearnet_tor_nodes int(11) NOT NULL DEFAULT "0"'); + await this.updateToSchemaVersion(34); + } + + if (databaseSchemaVersion < 35 && isBitcoin == true) { + await this.$executeQuery('DELETE from `lightning_stats` WHERE added > "2021-09-19"'); + await this.$executeQuery('ALTER TABLE `lightning_stats` ADD CONSTRAINT added_unique UNIQUE (added);'); + await this.updateToSchemaVersion(35); + } + + if (databaseSchemaVersion < 36 && isBitcoin == true) { + await this.$executeQuery('ALTER TABLE `nodes` ADD status TINYINT NOT NULL DEFAULT "1"'); + await this.updateToSchemaVersion(36); + } + + if (databaseSchemaVersion < 37 && isBitcoin == true) { + await this.$executeQuery(this.getCreateLNNodesSocketsTableQuery(), await this.$checkIfTableExists('nodes_sockets')); + await this.updateToSchemaVersion(37); + } + + if (databaseSchemaVersion < 38 && isBitcoin == true) { + if (config.LIGHTNING.ENABLED) { + this.uniqueLog(logger.notice, `'lightning_stats' and 'node_stats' tables have been truncated.`); + } + await this.$executeQuery(`TRUNCATE lightning_stats`); + await this.$executeQuery(`TRUNCATE node_stats`); + await this.$executeQuery('ALTER TABLE `lightning_stats` CHANGE `added` `added` timestamp NULL'); + await this.$executeQuery('ALTER TABLE `node_stats` CHANGE `added` `added` timestamp NULL'); + await this.updateToSchemaVersion(38); + } + + if (databaseSchemaVersion < 39 && isBitcoin === true) { + await this.$executeQuery('ALTER TABLE `nodes` ADD alias_search TEXT NULL DEFAULT NULL AFTER `alias`'); + await this.$executeQuery('ALTER TABLE nodes ADD FULLTEXT(alias_search)'); + await this.updateToSchemaVersion(39); + } + + if (databaseSchemaVersion < 40 && isBitcoin === true) { + await this.$executeQuery('ALTER TABLE `nodes` ADD capacity bigint(20) unsigned DEFAULT NULL'); + await this.$executeQuery('ALTER TABLE `nodes` ADD channels int(11) unsigned DEFAULT NULL'); + await this.$executeQuery('ALTER TABLE `nodes` ADD INDEX `capacity` (`capacity`);'); + await this.updateToSchemaVersion(40); + } + + if (databaseSchemaVersion < 41 && isBitcoin === true) { + await this.$executeQuery('UPDATE channels SET closing_reason = NULL WHERE closing_reason = 1'); + await this.updateToSchemaVersion(41); + } + + if (databaseSchemaVersion < 42 && isBitcoin === true) { + await this.$executeQuery('ALTER TABLE `channels` ADD closing_resolved tinyint(1) DEFAULT 0'); + await this.updateToSchemaVersion(42); + } + + if (databaseSchemaVersion < 43 && isBitcoin === true) { + await this.$executeQuery(this.getCreateLNNodeRecordsTableQuery(), await this.$checkIfTableExists('nodes_records')); + await this.updateToSchemaVersion(43); + } + + if (databaseSchemaVersion < 44 && isBitcoin === true) { + await this.$executeQuery('UPDATE blocks_summaries SET template = NULL'); + await this.updateToSchemaVersion(44); + } + + if (databaseSchemaVersion < 45 && isBitcoin === true) { + await this.$executeQuery('ALTER TABLE `blocks_audits` ADD fresh_txs JSON DEFAULT "[]"'); + await this.updateToSchemaVersion(45); + } + + if (databaseSchemaVersion < 46) { + await this.$executeQuery(`ALTER TABLE blocks MODIFY blockTimestamp timestamp NOT NULL DEFAULT 0`); + await this.updateToSchemaVersion(46); + } + + if (databaseSchemaVersion < 47) { + await this.$executeQuery('ALTER TABLE `blocks` ADD cpfp_indexed tinyint(1) DEFAULT 0'); + await this.$executeQuery(this.getCreateCPFPTableQuery(), await this.$checkIfTableExists('cpfp_clusters')); + await this.$executeQuery(this.getCreateTransactionsTableQuery(), await this.$checkIfTableExists('transactions')); + await this.updateToSchemaVersion(47); + } + + if (databaseSchemaVersion < 48 && isBitcoin === true) { + await this.$executeQuery('ALTER TABLE `channels` ADD source_checked tinyint(1) DEFAULT 0'); + await this.$executeQuery('ALTER TABLE `channels` ADD closing_fee bigint(20) unsigned DEFAULT 0'); + await this.$executeQuery('ALTER TABLE `channels` ADD node1_funding_balance bigint(20) unsigned DEFAULT 0'); + await this.$executeQuery('ALTER TABLE `channels` ADD node2_funding_balance bigint(20) unsigned DEFAULT 0'); + await this.$executeQuery('ALTER TABLE `channels` ADD node1_closing_balance bigint(20) unsigned DEFAULT 0'); + await this.$executeQuery('ALTER TABLE `channels` ADD node2_closing_balance bigint(20) unsigned DEFAULT 0'); + await this.$executeQuery('ALTER TABLE `channels` ADD funding_ratio float unsigned DEFAULT NULL'); + await this.$executeQuery('ALTER TABLE `channels` ADD closed_by varchar(66) DEFAULT NULL'); + await this.$executeQuery('ALTER TABLE `channels` ADD single_funded tinyint(1) DEFAULT 0'); + await this.$executeQuery('ALTER TABLE `channels` ADD outputs JSON DEFAULT "[]"'); + await this.updateToSchemaVersion(48); + } + + if (databaseSchemaVersion < 49 && isBitcoin === true) { + await this.$executeQuery('TRUNCATE TABLE `blocks_audits`'); + await this.updateToSchemaVersion(49); + } + + if (databaseSchemaVersion < 50) { + await this.$executeQuery('ALTER TABLE `blocks` DROP COLUMN `cpfp_indexed`'); + await this.updateToSchemaVersion(50); + } + + if (databaseSchemaVersion < 51) { + await this.$executeQuery('ALTER TABLE `cpfp_clusters` ADD INDEX `height` (`height`)'); + await this.updateToSchemaVersion(51); + } + + if (databaseSchemaVersion < 52) { + await this.$executeQuery(this.getCreateCompactCPFPTableQuery(), await this.$checkIfTableExists('compact_cpfp_clusters')); + await this.$executeQuery(this.getCreateCompactTransactionsTableQuery(), await this.$checkIfTableExists('compact_transactions')); + try { + await this.$convertCompactCpfpTables(); + await this.$executeQuery('DROP TABLE IF EXISTS `transactions`'); + await this.$executeQuery('DROP TABLE IF EXISTS `cpfp_clusters`'); + await this.updateToSchemaVersion(52); + } catch (e) { + logger.warn('' + (e instanceof Error ? e.message : e)); + } + } + + if (databaseSchemaVersion < 53) { + await this.$executeQuery('ALTER TABLE statistics MODIFY mempool_byte_weight bigint(20) UNSIGNED NOT NULL'); + await this.updateToSchemaVersion(53); + } + + if (databaseSchemaVersion < 54) { + this.uniqueLog(logger.notice, `'prices' table has been truncated`); + await this.$executeQuery(`TRUNCATE prices`); + if (isBitcoin === true) { + this.uniqueLog(logger.notice, `'blocks_prices' table has been truncated`); + await this.$executeQuery(`TRUNCATE blocks_prices`); + } + await this.updateToSchemaVersion(54); + } + + if (databaseSchemaVersion < 55) { + await this.$executeQuery(this.getAdditionalBlocksDataQuery()); + this.uniqueLog(logger.notice, this.blocksTruncatedMessage); + await this.$executeQuery('TRUNCATE blocks;'); // Need to re-index + await this.updateToSchemaVersion(55); + } + + if (databaseSchemaVersion < 56) { + await this.$executeQuery('ALTER TABLE pools ADD unique_id int NOT NULL DEFAULT -1'); + await this.$executeQuery('TRUNCATE TABLE `blocks`'); + this.uniqueLog(logger.notice, this.blocksTruncatedMessage); + await this.$executeQuery('DELETE FROM `pools`'); + await this.$executeQuery('ALTER TABLE pools AUTO_INCREMENT = 1'); + await this.$executeQuery(`UPDATE state SET string = NULL WHERE name = 'pools_json_sha'`); + this.uniqueLog(logger.notice, '`pools` table has been truncated`'); + await this.updateToSchemaVersion(56); + } + + if (databaseSchemaVersion < 57 && isBitcoin === true) { + await this.$executeQuery(`ALTER TABLE nodes MODIFY updated_at datetime NULL`); + await this.updateToSchemaVersion(57); + } + + if (databaseSchemaVersion < 58) { + // We only run some migration queries for this version + await this.updateToSchemaVersion(58); + } + + if (databaseSchemaVersion < 59 && (config.MEMPOOL.NETWORK === 'signet' || config.MEMPOOL.NETWORK === 'testnet')) { + // https://github.com/mempool/mempool/issues/3360 + await this.$executeQuery(`TRUNCATE prices`); + } + + if (databaseSchemaVersion < 60 && isBitcoin === true) { + await this.$executeQuery('ALTER TABLE `blocks_audits` ADD sigop_txs JSON DEFAULT "[]"'); + await this.updateToSchemaVersion(60); + } + + if (databaseSchemaVersion < 61 && isBitcoin === true) { + // Break block templates into their own table + if (! await this.$checkIfTableExists('blocks_templates')) { + await this.$executeQuery('CREATE TABLE blocks_templates AS SELECT id, template FROM blocks_summaries WHERE template != "[]"'); + } + await this.$executeQuery('ALTER TABLE blocks_templates MODIFY template JSON DEFAULT "[]"'); + await this.$executeQuery('ALTER TABLE blocks_templates ADD PRIMARY KEY (id)'); + await this.$executeQuery('ALTER TABLE blocks_summaries DROP COLUMN template'); + await this.updateToSchemaVersion(61); + } + + if (databaseSchemaVersion < 62 && isBitcoin === true) { + await this.$executeQuery('ALTER TABLE `blocks_audits` ADD expected_fees BIGINT UNSIGNED DEFAULT NULL'); + await this.$executeQuery('ALTER TABLE `blocks_audits` ADD expected_weight BIGINT UNSIGNED DEFAULT NULL'); + await this.updateToSchemaVersion(62); + } + + if (databaseSchemaVersion < 63 && isBitcoin === true) { + await this.$executeQuery('ALTER TABLE `blocks_audits` ADD fullrbf_txs JSON DEFAULT "[]"'); + await this.updateToSchemaVersion(63); + } + + if (databaseSchemaVersion < 64 && isBitcoin === true) { + await this.$executeQuery('ALTER TABLE `nodes` ADD features text NULL'); + await this.updateToSchemaVersion(64); + } + + if (databaseSchemaVersion < 65 && isBitcoin === true) { + await this.$executeQuery('ALTER TABLE `blocks_audits` ADD accelerated_txs JSON DEFAULT "[]"'); + await this.updateToSchemaVersion(65); + } + + if (databaseSchemaVersion < 66) { + await this.$executeQuery('ALTER TABLE `statistics` ADD min_fee FLOAT UNSIGNED DEFAULT NULL'); + await this.updateToSchemaVersion(66); + } + + if (databaseSchemaVersion < 67 && isBitcoin === true) { + await this.$executeQuery('ALTER TABLE `blocks_summaries` ADD version INT NOT NULL DEFAULT 0'); + await this.$executeQuery('ALTER TABLE `blocks_summaries` ADD INDEX `version` (`version`)'); + await this.$executeQuery('ALTER TABLE `blocks_templates` ADD version INT NOT NULL DEFAULT 0'); + await this.$executeQuery('ALTER TABLE `blocks_templates` ADD INDEX `version` (`version`)'); + await this.updateToSchemaVersion(67); + } + + if (databaseSchemaVersion < 68 && config.MEMPOOL.NETWORK === "liquid") { + await this.$executeQuery('TRUNCATE TABLE elements_pegs'); + await this.$executeQuery('ALTER TABLE elements_pegs ADD PRIMARY KEY (txid, txindex);'); + await this.$executeQuery(`UPDATE state SET number = 0 WHERE name = 'last_elements_block';`); + // Create the federation_addresses table and add the two Liquid Federation change addresses in + await this.$executeQuery(this.getCreateFederationAddressesTableQuery(), await this.$checkIfTableExists('federation_addresses')); + await this.$executeQuery(`INSERT INTO federation_addresses (bitcoinaddress) VALUES ('bc1qxvay4an52gcghxq5lavact7r6qe9l4laedsazz8fj2ee2cy47tlqff4aj4')`); // Federation change address + await this.$executeQuery(`INSERT INTO federation_addresses (bitcoinaddress) VALUES ('3EiAcrzq1cELXScc98KeCswGWZaPGceT1d')`); // Federation change address + // Create the federation_txos table that uses the federation_addresses table as a foreign key + await this.$executeQuery(this.getCreateFederationTxosTableQuery(), await this.$checkIfTableExists('federation_txos')); + await this.$executeQuery(`INSERT INTO state VALUES('last_bitcoin_block_audit', 0, NULL);`); + await this.updateToSchemaVersion(68); + } + + if (databaseSchemaVersion < 69 && config.MEMPOOL.NETWORK === 'mainnet') { + await this.$executeQuery(this.getCreateAccelerationsTableQuery(), await this.$checkIfTableExists('accelerations')); + await this.updateToSchemaVersion(69); + } + + if (databaseSchemaVersion < 70 && config.MEMPOOL.NETWORK === 'mainnet') { + await this.$executeQuery('ALTER TABLE accelerations MODIFY COLUMN added DATETIME;'); + await this.updateToSchemaVersion(70); + } + + if (databaseSchemaVersion < 71 && config.MEMPOOL.NETWORK === 'liquid') { + await this.$executeQuery('TRUNCATE TABLE elements_pegs'); + await this.$executeQuery('TRUNCATE TABLE federation_txos'); + await this.$executeQuery('SET FOREIGN_KEY_CHECKS = 0'); + await this.$executeQuery('TRUNCATE TABLE federation_addresses'); + await this.$executeQuery('SET FOREIGN_KEY_CHECKS = 1'); + await this.$executeQuery(`INSERT INTO federation_addresses (bitcoinaddress) VALUES ('bc1qxvay4an52gcghxq5lavact7r6qe9l4laedsazz8fj2ee2cy47tlqff4aj4')`); // Federation change address + await this.$executeQuery(`INSERT INTO federation_addresses (bitcoinaddress) VALUES ('3EiAcrzq1cELXScc98KeCswGWZaPGceT1d')`); // Federation change address + await this.$executeQuery(`UPDATE state SET number = 0 WHERE name = 'last_elements_block';`); + await this.$executeQuery(`UPDATE state SET number = 0 WHERE name = 'last_bitcoin_block_audit';`); + await this.$executeQuery('ALTER TABLE `federation_txos` ADD timelock INT NOT NULL DEFAULT 0'); + await this.$executeQuery('ALTER TABLE `federation_txos` ADD expiredAt INT NOT NULL DEFAULT 0'); + await this.$executeQuery('ALTER TABLE `federation_txos` ADD emergencyKey TINYINT NOT NULL DEFAULT 0'); + await this.updateToSchemaVersion(71); + } + + if (databaseSchemaVersion < 72 && isBitcoin === true) { + // reindex Goggles flags for mined block templates above height 832000 + await this.$executeQuery('UPDATE blocks_summaries SET version = 0 WHERE height >= 832000;'); + await this.updateToSchemaVersion(72); + } + + if (databaseSchemaVersion < 73 && config.MEMPOOL.NETWORK === 'mainnet') { + // Clear bad data + await this.$executeQuery(`TRUNCATE accelerations`); + this.uniqueLog(logger.notice, `'accelerations' table has been truncated`); + await this.updateToSchemaVersion(73); + } + + if (databaseSchemaVersion < 74 && config.MEMPOOL.NETWORK === 'mainnet') { + await this.$executeQuery(`INSERT INTO state(name, number) VALUE ('last_acceleration_block', 0);`); + await this.updateToSchemaVersion(74); + } + + if (databaseSchemaVersion < 75) { + await this.$executeQuery('ALTER TABLE `prices` ADD `BGN` float DEFAULT "-1"'); + await this.$executeQuery('ALTER TABLE `prices` ADD `BRL` float DEFAULT "-1"'); + await this.$executeQuery('ALTER TABLE `prices` ADD `CNY` float DEFAULT "-1"'); + await this.$executeQuery('ALTER TABLE `prices` ADD `CZK` float DEFAULT "-1"'); + await this.$executeQuery('ALTER TABLE `prices` ADD `DKK` float DEFAULT "-1"'); + await this.$executeQuery('ALTER TABLE `prices` ADD `HKD` float DEFAULT "-1"'); + await this.$executeQuery('ALTER TABLE `prices` ADD `HRK` float DEFAULT "-1"'); + await this.$executeQuery('ALTER TABLE `prices` ADD `HUF` float DEFAULT "-1"'); + await this.$executeQuery('ALTER TABLE `prices` ADD `IDR` float DEFAULT "-1"'); + await this.$executeQuery('ALTER TABLE `prices` ADD `ILS` float DEFAULT "-1"'); + await this.$executeQuery('ALTER TABLE `prices` ADD `INR` float DEFAULT "-1"'); + await this.$executeQuery('ALTER TABLE `prices` ADD `ISK` float DEFAULT "-1"'); + await this.$executeQuery('ALTER TABLE `prices` ADD `KRW` float DEFAULT "-1"'); + await this.$executeQuery('ALTER TABLE `prices` ADD `MXN` float DEFAULT "-1"'); + await this.$executeQuery('ALTER TABLE `prices` ADD `MYR` float DEFAULT "-1"'); + await this.$executeQuery('ALTER TABLE `prices` ADD `NOK` float DEFAULT "-1"'); + await this.$executeQuery('ALTER TABLE `prices` ADD `NZD` float DEFAULT "-1"'); + await this.$executeQuery('ALTER TABLE `prices` ADD `PHP` float DEFAULT "-1"'); + await this.$executeQuery('ALTER TABLE `prices` ADD `PLN` float DEFAULT "-1"'); + await this.$executeQuery('ALTER TABLE `prices` ADD `RON` float DEFAULT "-1"'); + await this.$executeQuery('ALTER TABLE `prices` ADD `RUB` float DEFAULT "-1"'); + await this.$executeQuery('ALTER TABLE `prices` ADD `SEK` float DEFAULT "-1"'); + await this.$executeQuery('ALTER TABLE `prices` ADD `SGD` float DEFAULT "-1"'); + await this.$executeQuery('ALTER TABLE `prices` ADD `THB` float DEFAULT "-1"'); + await this.$executeQuery('ALTER TABLE `prices` ADD `TRY` float DEFAULT "-1"'); + await this.$executeQuery('ALTER TABLE `prices` ADD `ZAR` float DEFAULT "-1"'); + + await this.$executeQuery('TRUNCATE hashrates'); + await this.$executeQuery('TRUNCATE difficulty_adjustments'); + await this.$executeQuery(`UPDATE state SET string = NULL WHERE name = 'pools_json_sha'`); + + await this.updateToSchemaVersion(75); + } + + if (databaseSchemaVersion < 76 && isBitcoin === true) { + await this.$executeQuery('ALTER TABLE `blocks_audits` ADD prioritized_txs JSON DEFAULT "[]"'); + await this.updateToSchemaVersion(76); + } + + if (databaseSchemaVersion < 77 && config.MEMPOOL.NETWORK === 'mainnet') { + await this.$executeQuery('ALTER TABLE `accelerations` ADD requested datetime DEFAULT NULL'); + await this.updateToSchemaVersion(77); + } + + if (databaseSchemaVersion < 78) { + await this.$executeQuery('ALTER TABLE `prices` CHANGE `time` `time` datetime NOT NULL'); + await this.updateToSchemaVersion(78); + } + + if (databaseSchemaVersion < 79 && config.MEMPOOL.NETWORK === 'mainnet') { + // Clear bad data + await this.$executeQuery(`TRUNCATE accelerations`); + this.uniqueLog(logger.notice, `'accelerations' table has been truncated`); + await this.$executeQuery(` + UPDATE state + SET number = 0 + WHERE name = 'last_acceleration_block' + `); + await this.updateToSchemaVersion(79); + } + + if (databaseSchemaVersion < 80) { + await this.$executeQuery('ALTER TABLE `blocks` ADD coinbase_addresses JSON DEFAULT NULL'); + await this.updateToSchemaVersion(80); + } + } + + /** + * Special case here for the `statistics` table - It appeared that somehow some dbs already had the `added` field indexed + * while it does not appear in previous schemas. The mariadb command "CREATE INDEX IF NOT EXISTS" is not supported on + * older mariadb version. Therefore we set a flag here in order to know if the index needs to be created or not before + * running the migration process + */ + private async $setStatisticsAddedIndexedFlag(databaseSchemaVersion: number) { + if (databaseSchemaVersion >= 2) { + this.statisticsAddedIndexed = true; + return; + } + + try { + // We don't use "CREATE INDEX IF NOT EXISTS" because it is not supported on old mariadb version 5.X + const query = `SELECT COUNT(1) hasIndex FROM INFORMATION_SCHEMA.STATISTICS + WHERE table_schema=DATABASE() AND table_name='statistics' AND index_name='added';`; + const [rows] = await this.$executeQuery(query, true); + if (rows[0].hasIndex === 0) { + logger.debug('MIGRATIONS: `statistics.added` is not indexed'); + this.statisticsAddedIndexed = false; + } else if (rows[0].hasIndex === 1) { + logger.debug('MIGRATIONS: `statistics.added` is already indexed'); + this.statisticsAddedIndexed = true; + } + } catch (e) { + // Should really never happen but just in case it fails, we just don't execute + // any query related to this indexing so it won't fail if the index actually already exists + logger.err('MIGRATIONS: Unable to check if `statistics.added` INDEX exist or not.'); + this.statisticsAddedIndexed = true; + } + } + + /** + * Small query execution wrapper to log all executed queries + */ + private async $executeQuery(query: string, silent = false): Promise { + if (!silent) { + logger.debug('MIGRATIONS: Execute query:\n' + query); + } + return DB.query({ sql: query, timeout: this.queryTimeout }); + } + + /** + * Check if 'table' exists in the database + */ + private async $checkIfTableExists(table: string): Promise { + const query = `SELECT COUNT(*) FROM information_schema.tables WHERE table_schema = '${config.DATABASE.DATABASE}' AND TABLE_NAME = '${table}'`; + const [rows] = await DB.query({ sql: query, timeout: this.queryTimeout }); + return rows[0]['COUNT(*)'] === 1; + } + + /** + * Get current database version + */ + private async $getSchemaVersionFromDatabase(): Promise { + const query = `SELECT number FROM state WHERE name = 'schema_version';`; + const [rows] = await this.$executeQuery(query, true); + return rows[0]['number']; + } + + /** + * Create the `state` table + */ + private async $createMigrationStateTable(): Promise { + const query = `CREATE TABLE IF NOT EXISTS state ( + name varchar(25) NOT NULL, + number int(11) NULL, + string varchar(100) NULL, + CONSTRAINT name_unique UNIQUE (name) + ) ENGINE=InnoDB DEFAULT CHARSET=utf8;`; + await this.$executeQuery(query); + + // Set initial values + await this.$executeQuery(`INSERT INTO state VALUES('schema_version', 0, NULL);`); + await this.$executeQuery(`INSERT INTO state VALUES('last_elements_block', 0, NULL);`); + } + + /** + * We actually execute the migrations queries here + */ + private async $migrateTableSchemaFromVersion(version: number): Promise { + const transactionQueries: string[] = []; + for (const query of this.getMigrationQueriesFromVersion(version)) { + transactionQueries.push(query); + } + + logger.notice(`MIGRATIONS: ${version > 0 ? 'Upgrading' : 'Initializing'} database schema version number to ${DatabaseMigration.currentVersion}`); + transactionQueries.push(this.getUpdateToLatestSchemaVersionQuery()); + + try { + await this.$executeQuery('START TRANSACTION;'); + for (const query of transactionQueries) { + await this.$executeQuery(query); + } + await this.$executeQuery('COMMIT;'); + } catch (e) { + await this.$executeQuery('ROLLBACK;'); + throw e; + } + } + + /** + * Generate migration queries based on schema version + */ + private getMigrationQueriesFromVersion(version: number): string[] { + const queries: string[] = []; + const isBitcoin = ['mainnet', 'testnet', 'signet'].includes(config.MEMPOOL.NETWORK); + + if (version < 1) { + if (config.MEMPOOL.NETWORK !== 'liquid' && config.MEMPOOL.NETWORK !== 'liquidtestnet') { + if (version > 0) { + logger.notice(`MIGRATIONS: Migrating (shifting) statistics table data`); + } + queries.push(this.getShiftStatisticsQuery()); + } + } + + if (version < 7 && isBitcoin === true) { + queries.push(`INSERT INTO state(name, number, string) VALUES ('last_hashrates_indexing', 0, NULL)`); + } + + if (version < 9 && isBitcoin === true) { + queries.push(`INSERT INTO state(name, number, string) VALUES ('last_weekly_hashrates_indexing', 0, NULL)`); + } + + if (version < 58) { + queries.push(`DELETE FROM state WHERE name = 'last_hashrates_indexing'`); + queries.push(`DELETE FROM state WHERE name = 'last_weekly_hashrates_indexing'`); + } + + return queries; + } + + /** + * Save the schema version in the database + */ + private getUpdateToLatestSchemaVersionQuery(): string { + return `UPDATE state SET number = ${DatabaseMigration.currentVersion} WHERE name = 'schema_version';`; + } + + private async updateToSchemaVersion(version): Promise { + await this.$executeQuery(`UPDATE state SET number = ${version} WHERE name = 'schema_version';`); + } + + /** + * Print current database version + */ + private async $printDatabaseVersion() { + try { + const [rows] = await this.$executeQuery('SELECT VERSION() as version;', true); + logger.debug(`MIGRATIONS: Database engine version '${rows[0].version}'`); + } catch (e) { + logger.debug(`MIGRATIONS: Could not fetch database engine version. ` + e); + } + } + + // Couple of wrappers to clean the main logic + private getShiftStatisticsQuery(): string { + return `UPDATE statistics SET + vsize_1 = vsize_1 + vsize_2, vsize_2 = vsize_3, + vsize_3 = vsize_4, vsize_4 = vsize_5, + vsize_5 = vsize_6, vsize_6 = vsize_8, + vsize_8 = vsize_10, vsize_10 = vsize_12, + vsize_12 = vsize_15, vsize_15 = vsize_20, + vsize_20 = vsize_30, vsize_30 = vsize_40, + vsize_40 = vsize_50, vsize_50 = vsize_60, + vsize_60 = vsize_70, vsize_70 = vsize_80, + vsize_80 = vsize_90, vsize_90 = vsize_100, + vsize_100 = vsize_125, vsize_125 = vsize_150, + vsize_150 = vsize_175, vsize_175 = vsize_200, + vsize_200 = vsize_250, vsize_250 = vsize_300, + vsize_300 = vsize_350, vsize_350 = vsize_400, + vsize_400 = vsize_500, vsize_500 = vsize_600, + vsize_600 = vsize_700, vsize_700 = vsize_800, + vsize_800 = vsize_900, vsize_900 = vsize_1000, + vsize_1000 = vsize_1200, vsize_1200 = vsize_1400, + vsize_1400 = vsize_1800, vsize_1800 = vsize_2000, vsize_2000 = 0;`; + } + + private getCreateStatisticsQuery(): string { + return `CREATE TABLE IF NOT EXISTS statistics ( + id int(11) NOT NULL AUTO_INCREMENT, + added datetime NOT NULL, + unconfirmed_transactions int(11) UNSIGNED NOT NULL, + tx_per_second float UNSIGNED NOT NULL, + vbytes_per_second int(10) UNSIGNED NOT NULL, + mempool_byte_weight int(10) UNSIGNED NOT NULL, + fee_data longtext NOT NULL, + total_fee double UNSIGNED NOT NULL, + vsize_1 int(11) NOT NULL, + vsize_2 int(11) NOT NULL, + vsize_3 int(11) NOT NULL, + vsize_4 int(11) NOT NULL, + vsize_5 int(11) NOT NULL, + vsize_6 int(11) NOT NULL, + vsize_8 int(11) NOT NULL, + vsize_10 int(11) NOT NULL, + vsize_12 int(11) NOT NULL, + vsize_15 int(11) NOT NULL, + vsize_20 int(11) NOT NULL, + vsize_30 int(11) NOT NULL, + vsize_40 int(11) NOT NULL, + vsize_50 int(11) NOT NULL, + vsize_60 int(11) NOT NULL, + vsize_70 int(11) NOT NULL, + vsize_80 int(11) NOT NULL, + vsize_90 int(11) NOT NULL, + vsize_100 int(11) NOT NULL, + vsize_125 int(11) NOT NULL, + vsize_150 int(11) NOT NULL, + vsize_175 int(11) NOT NULL, + vsize_200 int(11) NOT NULL, + vsize_250 int(11) NOT NULL, + vsize_300 int(11) NOT NULL, + vsize_350 int(11) NOT NULL, + vsize_400 int(11) NOT NULL, + vsize_500 int(11) NOT NULL, + vsize_600 int(11) NOT NULL, + vsize_700 int(11) NOT NULL, + vsize_800 int(11) NOT NULL, + vsize_900 int(11) NOT NULL, + vsize_1000 int(11) NOT NULL, + vsize_1200 int(11) NOT NULL, + vsize_1400 int(11) NOT NULL, + vsize_1600 int(11) NOT NULL, + vsize_1800 int(11) NOT NULL, + vsize_2000 int(11) NOT NULL, + CONSTRAINT PRIMARY KEY (id) + ) ENGINE=InnoDB DEFAULT CHARSET=utf8;`; + } + + private getCreateElementsTableQuery(): string { + return `CREATE TABLE IF NOT EXISTS elements_pegs ( + block int(11) NOT NULL, + datetime int(11) NOT NULL, + amount bigint(20) NOT NULL, + txid varchar(65) NOT NULL, + txindex int(11) NOT NULL, + bitcoinaddress varchar(100) NOT NULL, + bitcointxid varchar(65) NOT NULL, + bitcoinindex int(11) NOT NULL, + final_tx int(11) NOT NULL + ) ENGINE=InnoDB DEFAULT CHARSET=utf8;`; + } + + private getCreateFederationAddressesTableQuery(): string { + return `CREATE TABLE IF NOT EXISTS federation_addresses ( + bitcoinaddress varchar(100) NOT NULL, + PRIMARY KEY (bitcoinaddress) + ) ENGINE=InnoDB DEFAULT CHARSET=utf8;`; + } + + private getCreateFederationTxosTableQuery(): string { + return `CREATE TABLE IF NOT EXISTS federation_txos ( + txid varchar(65) NOT NULL, + txindex int(11) NOT NULL, + bitcoinaddress varchar(100) NOT NULL, + amount bigint(20) unsigned NOT NULL, + blocknumber int(11) unsigned NOT NULL, + blocktime int(11) unsigned NOT NULL, + unspent tinyint(1) NOT NULL, + lastblockupdate int(11) unsigned NOT NULL, + lasttimeupdate int(11) unsigned NOT NULL, + pegtxid varchar(65) NOT NULL, + pegindex int(11) NOT NULL, + pegblocktime int(11) unsigned NOT NULL, + PRIMARY KEY (txid, txindex), + FOREIGN KEY (bitcoinaddress) REFERENCES federation_addresses (bitcoinaddress) + ) ENGINE=InnoDB DEFAULT CHARSET=utf8;`; + } + + private getCreatePoolsTableQuery(): string { + return `CREATE TABLE IF NOT EXISTS pools ( + id int(11) NOT NULL AUTO_INCREMENT, + name varchar(50) NOT NULL, + link varchar(255) NOT NULL, + addresses text NOT NULL, + regexes text NOT NULL, + PRIMARY KEY (id) + ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4;`; + } + + private getCreateBlocksTableQuery(): string { + return `CREATE TABLE IF NOT EXISTS blocks ( + height int(11) unsigned NOT NULL, + hash varchar(65) NOT NULL, + blockTimestamp timestamp NOT NULL, + size int(11) unsigned NOT NULL, + weight int(11) unsigned NOT NULL, + tx_count int(11) unsigned NOT NULL, + coinbase_raw text, + difficulty bigint(20) unsigned NOT NULL, + pool_id int(11) DEFAULT -1, + fees double unsigned NOT NULL, + fee_span json NOT NULL, + median_fee double unsigned NOT NULL, + PRIMARY KEY (height), + INDEX (pool_id), + FOREIGN KEY (pool_id) REFERENCES pools (id) + ) ENGINE=InnoDB DEFAULT CHARSET=utf8;`; + } + + private getAdditionalBlocksDataQuery(): string { + return `ALTER TABLE blocks + ADD median_timestamp timestamp NOT NULL, + ADD coinbase_address varchar(100) NULL, + ADD coinbase_signature varchar(500) NULL, + ADD coinbase_signature_ascii varchar(500) NULL, + ADD avg_tx_size double unsigned NOT NULL, + ADD total_inputs int unsigned NOT NULL, + ADD total_outputs int unsigned NOT NULL, + ADD total_output_amt bigint unsigned NOT NULL, + ADD fee_percentiles longtext NULL, + ADD median_fee_amt int unsigned NULL, + ADD segwit_total_txs int unsigned NOT NULL, + ADD segwit_total_size int unsigned NOT NULL, + ADD segwit_total_weight int unsigned NOT NULL, + ADD header varchar(160) NOT NULL, + ADD utxoset_change int NOT NULL, + ADD utxoset_size int unsigned NULL, + ADD total_input_amt bigint unsigned NULL + `; + } + + private getCreateDailyStatsTableQuery(): string { + return `CREATE TABLE IF NOT EXISTS hashrates ( + hashrate_timestamp timestamp NOT NULL, + avg_hashrate double unsigned DEFAULT '0', + pool_id smallint unsigned NULL, + PRIMARY KEY (hashrate_timestamp), + INDEX (pool_id), + FOREIGN KEY (pool_id) REFERENCES pools (id) + ) ENGINE=InnoDB DEFAULT CHARSET=utf8;`; + } + + private getCreateRatesTableQuery(): string { // This table has been replaced by the prices table + return `CREATE TABLE IF NOT EXISTS rates ( + height int(10) unsigned NOT NULL, + bisq_rates JSON NOT NULL, + PRIMARY KEY (height) + ) ENGINE=InnoDB DEFAULT CHARSET=utf8;`; + } + + private getCreateBlocksSummariesTableQuery(): string { + return `CREATE TABLE IF NOT EXISTS blocks_summaries ( + height int(10) unsigned NOT NULL, + id varchar(65) NOT NULL, + transactions JSON NOT NULL, + PRIMARY KEY (id), + INDEX (height) + ) ENGINE=InnoDB DEFAULT CHARSET=utf8;`; + } + + private getCreatePricesTableQuery(): string { + return `CREATE TABLE IF NOT EXISTS prices ( + time timestamp NOT NULL, + avg_prices JSON NOT NULL, + PRIMARY KEY (time) + ) ENGINE=InnoDB DEFAULT CHARSET=utf8;`; + } + + private getCreateDifficultyAdjustmentsTableQuery(): string { + return `CREATE TABLE IF NOT EXISTS difficulty_adjustments ( + time timestamp NOT NULL, + height int(10) unsigned NOT NULL, + difficulty double unsigned NOT NULL, + adjustment float NOT NULL, + PRIMARY KEY (height), + INDEX (time) + ) ENGINE=InnoDB DEFAULT CHARSET=utf8;`; + } + + private getCreateLightningStatisticsQuery(): string { + return `CREATE TABLE IF NOT EXISTS lightning_stats ( + id int(11) NOT NULL AUTO_INCREMENT, + added datetime NOT NULL, + channel_count int(11) NOT NULL, + node_count int(11) NOT NULL, + total_capacity double unsigned NOT NULL, + PRIMARY KEY (id) + ) ENGINE=InnoDB DEFAULT CHARSET=utf8;`; + } + + private getCreateNodesQuery(): string { + return `CREATE TABLE IF NOT EXISTS nodes ( + public_key varchar(66) NOT NULL, + first_seen datetime NOT NULL, + updated_at datetime NOT NULL, + alias varchar(200) CHARACTER SET utf8mb4 NOT NULL, + color varchar(200) NOT NULL, + sockets text DEFAULT NULL, + PRIMARY KEY (public_key), + KEY alias (alias(10)) + ) ENGINE=InnoDB DEFAULT CHARSET=utf8;`; + } + + private getCreateChannelsQuery(): string { + return `CREATE TABLE IF NOT EXISTS channels ( + id bigint(11) unsigned NOT NULL, + short_id varchar(15) NOT NULL DEFAULT '', + capacity bigint(20) unsigned NOT NULL, + transaction_id varchar(64) NOT NULL, + transaction_vout int(11) NOT NULL, + updated_at datetime DEFAULT NULL, + created datetime DEFAULT NULL, + status int(11) NOT NULL DEFAULT 0, + closing_transaction_id varchar(64) DEFAULT NULL, + closing_date datetime DEFAULT NULL, + closing_reason int(11) DEFAULT NULL, + node1_public_key varchar(66) NOT NULL, + node1_base_fee_mtokens bigint(20) unsigned DEFAULT NULL, + node1_cltv_delta int(11) DEFAULT NULL, + node1_fee_rate bigint(11) DEFAULT NULL, + node1_is_disabled tinyint(1) DEFAULT NULL, + node1_max_htlc_mtokens bigint(20) unsigned DEFAULT NULL, + node1_min_htlc_mtokens bigint(20) DEFAULT NULL, + node1_updated_at datetime DEFAULT NULL, + node2_public_key varchar(66) NOT NULL, + node2_base_fee_mtokens bigint(20) unsigned DEFAULT NULL, + node2_cltv_delta int(11) DEFAULT NULL, + node2_fee_rate bigint(11) DEFAULT NULL, + node2_is_disabled tinyint(1) DEFAULT NULL, + node2_max_htlc_mtokens bigint(20) unsigned DEFAULT NULL, + node2_min_htlc_mtokens bigint(20) unsigned DEFAULT NULL, + node2_updated_at datetime DEFAULT NULL, + PRIMARY KEY (id), + KEY node1_public_key (node1_public_key), + KEY node2_public_key (node2_public_key), + KEY status (status), + KEY short_id (short_id), + KEY transaction_id (transaction_id), + KEY closing_transaction_id (closing_transaction_id) + ) ENGINE=InnoDB DEFAULT CHARSET=utf8;`; + } + + private getCreateNodesStatsQuery(): string { + return `CREATE TABLE IF NOT EXISTS node_stats ( + id int(11) unsigned NOT NULL AUTO_INCREMENT, + public_key varchar(66) NOT NULL DEFAULT '', + added date NOT NULL, + capacity bigint(20) unsigned NOT NULL DEFAULT 0, + channels int(11) unsigned NOT NULL DEFAULT 0, + PRIMARY KEY (id), + UNIQUE KEY added (added,public_key), + KEY public_key (public_key) + ) ENGINE=InnoDB DEFAULT CHARSET=utf8;`; + } + + private getCreateBlocksAuditsTableQuery(): string { + return `CREATE TABLE IF NOT EXISTS blocks_audits ( + time timestamp NOT NULL, + hash varchar(65) NOT NULL, + height int(10) unsigned NOT NULL, + missing_txs JSON NOT NULL, + added_txs JSON NOT NULL, + match_rate float unsigned NOT NULL, + PRIMARY KEY (hash), + INDEX (height) + ) ENGINE=InnoDB DEFAULT CHARSET=utf8;`; + } + + private getCreateGeoNamesTableQuery(): string { + return `CREATE TABLE geo_names ( + id int(11) unsigned NOT NULL, + type enum('city','country','division','continent') NOT NULL, + names text DEFAULT NULL, + UNIQUE KEY id (id,type), + KEY id_2 (id) + ) ENGINE=InnoDB DEFAULT CHARSET=utf8;`; + } + + private getCreateBlocksPricesTableQuery(): string { + return `CREATE TABLE IF NOT EXISTS blocks_prices ( + height int(10) unsigned NOT NULL, + price_id int(10) unsigned NOT NULL, + PRIMARY KEY (height), + INDEX (price_id) + ) ENGINE=InnoDB DEFAULT CHARSET=utf8;`; + } + + private getCreateLNNodesSocketsTableQuery(): string { + return `CREATE TABLE IF NOT EXISTS nodes_sockets ( + public_key varchar(66) NOT NULL, + socket varchar(100) NOT NULL, + type enum('ipv4', 'ipv6', 'torv2', 'torv3', 'i2p', 'dns', 'websocket') NULL, + UNIQUE KEY public_key_socket (public_key, socket), + INDEX (public_key) + ) ENGINE=InnoDB DEFAULT CHARSET=utf8;`; + } + + private getCreateLNNodeRecordsTableQuery(): string { + return `CREATE TABLE IF NOT EXISTS nodes_records ( + public_key varchar(66) NOT NULL, + type int(10) unsigned NOT NULL, + payload blob NOT NULL, + UNIQUE KEY public_key_type (public_key, type), + INDEX (public_key), + FOREIGN KEY (public_key) + REFERENCES nodes (public_key) + ON DELETE CASCADE + ) ENGINE=InnoDB DEFAULT CHARSET=utf8;`; + } + + private getCreateCPFPTableQuery(): string { + return `CREATE TABLE IF NOT EXISTS cpfp_clusters ( + root varchar(65) NOT NULL, + height int(10) NOT NULL, + txs JSON DEFAULT NULL, + fee_rate double unsigned NOT NULL, + PRIMARY KEY (root) + ) ENGINE=InnoDB DEFAULT CHARSET=utf8;`; + } + + private getCreateTransactionsTableQuery(): string { + return `CREATE TABLE IF NOT EXISTS transactions ( + txid varchar(65) NOT NULL, + cluster varchar(65) DEFAULT NULL, + PRIMARY KEY (txid), + FOREIGN KEY (cluster) REFERENCES cpfp_clusters (root) ON DELETE SET NULL + ) ENGINE=InnoDB DEFAULT CHARSET=utf8;`; + } + + private getCreateCompactCPFPTableQuery(): string { + return `CREATE TABLE IF NOT EXISTS compact_cpfp_clusters ( + root binary(32) NOT NULL, + height int(10) NOT NULL, + txs BLOB DEFAULT NULL, + fee_rate float unsigned, + PRIMARY KEY (root), + INDEX (height) + ) ENGINE=InnoDB DEFAULT CHARSET=utf8;`; + } + + private getCreateCompactTransactionsTableQuery(): string { + return `CREATE TABLE IF NOT EXISTS compact_transactions ( + txid binary(32) NOT NULL, + cluster binary(32) DEFAULT NULL, + PRIMARY KEY (txid) + ) ENGINE=InnoDB DEFAULT CHARSET=utf8;`; + } + + private getCreateAccelerationsTableQuery(): string { + return `CREATE TABLE IF NOT EXISTS accelerations ( + txid varchar(65) NOT NULL, + added datetime NOT NULL, + height int(10) NOT NULL, + pool smallint unsigned NULL, + effective_vsize int(10) NOT NULL, + effective_fee bigint(20) unsigned NOT NULL, + boost_rate float unsigned, + boost_cost bigint(20) unsigned NOT NULL, + PRIMARY KEY (txid), + INDEX (added), + INDEX (height), + INDEX (pool) + ) ENGINE=InnoDB DEFAULT CHARSET=utf8;`; + } + + public async $blocksReindexingTruncate(): Promise { + logger.warn(`Truncating pools, blocks, hashrates and difficulty_adjustments tables for re-indexing (using '--reindex-blocks'). You can cancel this command within 5 seconds`); + await Common.sleep$(5000); + + await this.$executeQuery(`TRUNCATE blocks`); + await this.$executeQuery(`TRUNCATE hashrates`); + await this.$executeQuery(`TRUNCATE difficulty_adjustments`); + await this.$executeQuery('DELETE FROM `pools`'); + await this.$executeQuery('ALTER TABLE pools AUTO_INCREMENT = 1'); + await this.$executeQuery(`UPDATE state SET string = NULL WHERE name = 'pools_json_sha'`); + } + + private async $convertCompactCpfpTables(): Promise { + try { + const batchSize = 250; + const maxHeight = await blocksRepository.$mostRecentBlockHeight() || 0; + const [minHeightRows]: any = await DB.query(`SELECT MIN(height) AS minHeight from cpfp_clusters`); + const minHeight = (minHeightRows.length && minHeightRows[0].minHeight != null) ? minHeightRows[0].minHeight : maxHeight; + let height = maxHeight; + + // Logging + let timer = new Date().getTime() / 1000; + const startedAt = new Date().getTime() / 1000; + + while (height > minHeight) { + const [rows] = await DB.query( + ` + SELECT * from cpfp_clusters + WHERE height <= ? AND height > ? + ORDER BY height + `, + [height, height - batchSize] + ) as RowDataPacket[][]; + if (rows?.length) { + await cpfpRepository.$batchSaveClusters(rows.map(row => { + return { + root: row.root, + height: row.height, + txs: JSON.parse(row.txs), + effectiveFeePerVsize: row.fee_rate, + }; + })); + } + + const elapsed = new Date().getTime() / 1000 - timer; + const runningFor = new Date().getTime() / 1000 - startedAt; + logger.debug(`Migrated cpfp data from block ${height} to ${height - batchSize} in ${elapsed.toFixed(2)} seconds | total elapsed: ${runningFor.toFixed(2)} seconds`); + timer = new Date().getTime() / 1000; + height -= batchSize; + } + } catch (e) { + logger.warn(`Failed to migrate cpfp transaction data`); + } + } +} + +export default new DatabaseMigration(); diff --git a/backend/src/api/difficulty-adjustment.ts b/backend/src/api/difficulty-adjustment.ts new file mode 100644 index 0000000000..2f3b210299 --- /dev/null +++ b/backend/src/api/difficulty-adjustment.ts @@ -0,0 +1,183 @@ +import config from '../config'; +import { IDifficultyAdjustment } from '../mempool.interfaces'; +import blocks from './blocks'; + +export interface DifficultyAdjustment { + progressPercent: number; // Percent: 0 to 100 + difficultyChange: number; // Percent: -75 to 300 + estimatedRetargetDate: number; // Unix time in ms + remainingBlocks: number; // Block count + remainingTime: number; // Duration of time in ms + previousRetarget: number; // Percent: -75 to 300 + previousTime: number; // Unix time in ms + nextRetargetHeight: number; // Block Height + timeAvg: number; // Duration of time in ms + adjustedTimeAvg; // Expected block interval with hashrate implied over last 504 blocks + timeOffset: number; // (Testnet) Time since last block (cap @ 20min) in ms + expectedBlocks: number; // Block count +} + +/** + * Calculate the difficulty increase/decrease by using the `bits` integer contained in two + * block headers. + * + * Warning: Only compare `bits` from blocks in two adjacent difficulty periods. This code + * assumes the maximum difference is x4 or /4 (as per the protocol) and will throw an + * error if an exponent difference of 2 or more is seen. + * + * @param {number} oldBits The 32 bit `bits` integer from a block header. + * @param {number} newBits The 32 bit `bits` integer from a block header in the next difficulty period. + * @returns {number} A floating point decimal of the difficulty change from old to new. + * (ie. 21.3 means 21.3% increase in difficulty, -21.3 is a 21.3% decrease in difficulty) + */ +export function calcBitsDifference(oldBits: number, newBits: number): number { + // Must be + // - integer + // - highest exponent is 0x20, so max value (as integer) is 0x207fffff + // - min value is 1 (exponent = 0) + // - highest bit of the number-part is +- sign, it must not be 1 + const verifyBits = (bits: number): void => { + if ( + Math.floor(bits) !== bits || + bits > 0x207fffff || + bits < 1 || + (bits & 0x00800000) !== 0 || + (bits & 0x007fffff) === 0 + ) { + throw new Error('Invalid bits'); + } + }; + verifyBits(oldBits); + verifyBits(newBits); + + // No need to mask exponents because we checked the bounds above + const oldExp = oldBits >> 24; + const newExp = newBits >> 24; + const oldNum = oldBits & 0x007fffff; + const newNum = newBits & 0x007fffff; + // The diff can only possibly be 1, 0, -1 + // (because maximum difficulty change is x4 or /4 (2 bits up or down)) + let result: number; + switch (newExp - oldExp) { + // New less than old, target lowered, difficulty increased + case -1: + result = ((oldNum << 8) * 100) / newNum - 100; + break; + // Same exponent, compare numbers as is. + case 0: + result = (oldNum * 100) / newNum - 100; + break; + // Old less than new, target raised, difficulty decreased + case 1: + result = (oldNum * 100) / (newNum << 8) - 100; + break; + default: + throw new Error('Impossible exponent difference'); + } + + // Min/Max values + return result > 300 ? 300 : result < -75 ? -75 : result; +} + +export function calcDifficultyAdjustment( + DATime: number, + quarterEpochTime: number | null, + nowSeconds: number, + blockHeight: number, + previousRetarget: number, + network: string, + latestBlockTimestamp: number, +): DifficultyAdjustment { + const EPOCH_BLOCK_LENGTH = 2016; // Bitcoin mainnet + const BLOCK_SECONDS_TARGET = 600; // Bitcoin mainnet + const TESTNET_MAX_BLOCK_SECONDS = 1200; // Bitcoin testnet + + const diffSeconds = Math.max(0, nowSeconds - DATime); + const blocksInEpoch = (blockHeight >= 0) ? blockHeight % EPOCH_BLOCK_LENGTH : 0; + const progressPercent = (blockHeight >= 0) ? blocksInEpoch / EPOCH_BLOCK_LENGTH * 100 : 100; + const remainingBlocks = EPOCH_BLOCK_LENGTH - blocksInEpoch; + const nextRetargetHeight = (blockHeight >= 0) ? blockHeight + remainingBlocks : 0; + const expectedBlocks = diffSeconds / BLOCK_SECONDS_TARGET; + const actualTimespan = (blocksInEpoch === 2015 ? latestBlockTimestamp : nowSeconds) - DATime; + + let difficultyChange = 0; + let timeAvgSecs = blocksInEpoch ? diffSeconds / blocksInEpoch : BLOCK_SECONDS_TARGET; + let adjustedTimeAvgSecs = timeAvgSecs; + + // for the first 504 blocks of the epoch, calculate the expected avg block interval + // from a sliding window over the last 504 blocks + if (quarterEpochTime && blocksInEpoch < 503) { + const timeLastEpoch = DATime - quarterEpochTime; + const adjustedTimeLastEpoch = timeLastEpoch * (1 + (previousRetarget / 100)); + const adjustedTimeSpan = diffSeconds + adjustedTimeLastEpoch; + adjustedTimeAvgSecs = adjustedTimeSpan / 503; + difficultyChange = (BLOCK_SECONDS_TARGET / (adjustedTimeSpan / 504) - 1) * 100; + } else { + difficultyChange = (BLOCK_SECONDS_TARGET / (actualTimespan / (blocksInEpoch + 1)) - 1) * 100; + } + + // Max increase is x4 (+300%) + if (difficultyChange > 300) { + difficultyChange = 300; + } + // Max decrease is /4 (-75%) + if (difficultyChange < -75) { + difficultyChange = -75; + } + + // Testnet difficulty is set to 1 after 20 minutes of no blocks, + // therefore the time between blocks will always be below 20 minutes (1200s). + let timeOffset = 0; + if (network === 'testnet') { + if (timeAvgSecs > TESTNET_MAX_BLOCK_SECONDS) { + timeAvgSecs = TESTNET_MAX_BLOCK_SECONDS; + } + + const secondsSinceLastBlock = nowSeconds - latestBlockTimestamp; + if (secondsSinceLastBlock + timeAvgSecs > TESTNET_MAX_BLOCK_SECONDS) { + timeOffset = -Math.min(secondsSinceLastBlock, TESTNET_MAX_BLOCK_SECONDS) * 1000; + } + } + + const timeAvg = Math.floor(timeAvgSecs * 1000); + const adjustedTimeAvg = Math.floor(adjustedTimeAvgSecs * 1000); + const remainingTime = remainingBlocks * adjustedTimeAvg; + const estimatedRetargetDate = remainingTime + nowSeconds * 1000; + + return { + progressPercent, + difficultyChange, + estimatedRetargetDate, + remainingBlocks, + remainingTime, + previousRetarget, + previousTime: DATime, + nextRetargetHeight, + timeAvg, + adjustedTimeAvg, + timeOffset, + expectedBlocks, + }; +} + +class DifficultyAdjustmentApi { + public getDifficultyAdjustment(): IDifficultyAdjustment | null { + const DATime = blocks.getLastDifficultyAdjustmentTime(); + const previousRetarget = blocks.getPreviousDifficultyRetarget(); + const blockHeight = blocks.getCurrentBlockHeight(); + const blocksCache = blocks.getBlocks(); + const latestBlock = blocksCache[blocksCache.length - 1]; + if (!latestBlock) { + return null; + } + const nowSeconds = Math.floor(new Date().getTime() / 1000); + const quarterEpochBlockTime = blocks.getQuarterEpochBlockTime(); + + return calcDifficultyAdjustment( + DATime, quarterEpochBlockTime, nowSeconds, blockHeight, previousRetarget, + config.MEMPOOL.NETWORK, latestBlock.timestamp + ); + } +} + +export default new DifficultyAdjustmentApi(); diff --git a/backend/src/api/disk-cache.ts b/backend/src/api/disk-cache.ts index 30683f2772..202f8f4cba 100644 --- a/backend/src/api/disk-cache.ts +++ b/backend/src/api/disk-cache.ts @@ -1,50 +1,297 @@ import * as fs from 'fs'; +const fsPromises = fs.promises; +import cluster from 'cluster'; import memPool from './mempool'; import blocks from './blocks'; +import logger from '../logger'; +import config from '../config'; +import { TransactionExtended } from '../mempool.interfaces'; +import { Common } from './common'; +import rbfCache from './rbf-cache'; class DiskCache { - static FILE_NAME = './cache.json'; + private cacheSchemaVersion = 3; + private rbfCacheSchemaVersion = 1; + + private static TMP_FILE_NAME = config.MEMPOOL.CACHE_DIR + '/tmp-cache.json'; + private static TMP_FILE_NAMES = config.MEMPOOL.CACHE_DIR + '/tmp-cache{number}.json'; + private static FILE_NAME = config.MEMPOOL.CACHE_DIR + '/cache.json'; + private static FILE_NAMES = config.MEMPOOL.CACHE_DIR + '/cache{number}.json'; + private static TMP_RBF_FILE_NAME = config.MEMPOOL.CACHE_DIR + '/tmp-rbfcache.json'; + private static RBF_FILE_NAME = config.MEMPOOL.CACHE_DIR + '/rbfcache.json'; + private static CHUNK_FILES = 25; + private isWritingCache = false; + private ignoreBlocksCache = false; + + private semaphore: { resume: (() => void)[], locks: number } = { + resume: [], + locks: 0, + }; constructor() { - process.on('SIGINT', () => { - this.saveCacheToDisk(); - process.exit(2); + if (!cluster.isPrimary || !config.MEMPOOL.CACHE_ENABLED) { + return; + } + process.on('SIGINT', (e) => { + this.$saveCacheToDisk(true); + process.exit(0); }); + } - process.on('SIGTERM', () => { - this.saveCacheToDisk(); - process.exit(2); - }); + async $saveCacheToDisk(sync: boolean = false): Promise { + if (!cluster.isPrimary || !config.MEMPOOL.CACHE_ENABLED) { + return; + } + if (this.isWritingCache) { + logger.debug('Saving cache already in progress. Skipping.'); + return; + } + try { + logger.debug(`Writing mempool and blocks data to disk cache (${ sync ? 'sync' : 'async' })...`); + this.isWritingCache = true; + + const mempool = memPool.getMempool(); + const mempoolArray: TransactionExtended[] = []; + for (const tx in mempool) { + if (mempool[tx]) { + mempoolArray.push(mempool[tx]); + } + } + + Common.shuffleArray(mempoolArray); + + const chunkSize = Math.floor(mempoolArray.length / DiskCache.CHUNK_FILES); + + if (sync) { + fs.writeFileSync(DiskCache.TMP_FILE_NAME, JSON.stringify({ + network: config.MEMPOOL.NETWORK, + cacheSchemaVersion: this.cacheSchemaVersion, + blocks: blocks.getBlocks(), + blockSummaries: blocks.getBlockSummaries(), + mempool: {}, + mempoolArray: mempoolArray.splice(0, chunkSize), + }), { flag: 'w' }); + for (let i = 1; i < DiskCache.CHUNK_FILES; i++) { + fs.writeFileSync(DiskCache.TMP_FILE_NAMES.replace('{number}', i.toString()), JSON.stringify({ + mempool: {}, + mempoolArray: mempoolArray.splice(0, chunkSize), + }), { flag: 'w' }); + } + + fs.renameSync(DiskCache.TMP_FILE_NAME, DiskCache.FILE_NAME); + for (let i = 1; i < DiskCache.CHUNK_FILES; i++) { + fs.renameSync(DiskCache.TMP_FILE_NAMES.replace('{number}', i.toString()), DiskCache.FILE_NAMES.replace('{number}', i.toString())); + } + } else { + await this.$yield(); + await fsPromises.writeFile(DiskCache.TMP_FILE_NAME, JSON.stringify({ + network: config.MEMPOOL.NETWORK, + cacheSchemaVersion: this.cacheSchemaVersion, + blocks: blocks.getBlocks(), + blockSummaries: blocks.getBlockSummaries(), + mempool: {}, + mempoolArray: mempoolArray.splice(0, chunkSize), + }), { flag: 'w' }); + for (let i = 1; i < DiskCache.CHUNK_FILES; i++) { + await this.$yield(); + await fsPromises.writeFile(DiskCache.TMP_FILE_NAMES.replace('{number}', i.toString()), JSON.stringify({ + mempool: {}, + mempoolArray: mempoolArray.splice(0, chunkSize), + }), { flag: 'w' }); + } + + await fsPromises.rename(DiskCache.TMP_FILE_NAME, DiskCache.FILE_NAME); + for (let i = 1; i < DiskCache.CHUNK_FILES; i++) { + await fsPromises.rename(DiskCache.TMP_FILE_NAMES.replace('{number}', i.toString()), DiskCache.FILE_NAMES.replace('{number}', i.toString())); + } + } + + logger.debug('Mempool and blocks data saved to disk cache'); + this.isWritingCache = false; + } catch (e) { + logger.warn('Error writing to cache file: ' + (e instanceof Error ? e.message : e)); + this.isWritingCache = false; + } + + try { + logger.debug('Writing rbf data to disk cache (async)...'); + this.isWritingCache = true; + const rbfData = rbfCache.dump(); + if (sync) { + fs.writeFileSync(DiskCache.TMP_RBF_FILE_NAME, JSON.stringify({ + network: config.MEMPOOL.NETWORK, + rbfCacheSchemaVersion: this.rbfCacheSchemaVersion, + rbf: rbfData, + }), { flag: 'w' }); + fs.renameSync(DiskCache.TMP_RBF_FILE_NAME, DiskCache.RBF_FILE_NAME); + } else { + await fsPromises.writeFile(DiskCache.TMP_RBF_FILE_NAME, JSON.stringify({ + network: config.MEMPOOL.NETWORK, + rbfCacheSchemaVersion: this.rbfCacheSchemaVersion, + rbf: rbfData, + }), { flag: 'w' }); + await fsPromises.rename(DiskCache.TMP_RBF_FILE_NAME, DiskCache.RBF_FILE_NAME); + } + logger.debug('Rbf data saved to disk cache'); + this.isWritingCache = false; + } catch (e) { + logger.warn('Error writing rbf data to cache file: ' + (e instanceof Error ? e.message : e)); + this.isWritingCache = false; + } } - saveCacheToDisk() { - this.saveData(JSON.stringify({ - mempool: memPool.getMempool(), - blocks: blocks.getBlocks(), - })); - console.log('Mempool and blocks data saved to disk cache'); + wipeCache(): void { + logger.notice(`Wiping nodejs backend cache/cache*.json files`); + try { + fs.unlinkSync(DiskCache.FILE_NAME); + } catch (e: any) { + if (e?.code !== 'ENOENT') { + logger.err(`Cannot wipe cache file ${DiskCache.FILE_NAME}. Exception ${JSON.stringify(e)}`); + } + } + + for (let i = 1; i < DiskCache.CHUNK_FILES; i++) { + const filename = DiskCache.FILE_NAMES.replace('{number}', i.toString()); + try { + fs.unlinkSync(filename); + } catch (e: any) { + if (e?.code !== 'ENOENT') { + logger.err(`Cannot wipe cache file ${filename}. Exception ${JSON.stringify(e)}`); + } + } + } } - loadMempoolCache() { - const cacheData = this.loadData(); - if (cacheData) { - console.log('Restoring mempool and blocks data from disk cache'); - const data = JSON.parse(cacheData); - if (data.mempool) { - memPool.setMempool(data.mempool); + wipeRbfCache() { + logger.notice(`Wipping nodejs backend cache/rbfcache.json file`); + + try { + fs.unlinkSync(DiskCache.RBF_FILE_NAME); + } catch (e: any) { + if (e?.code !== 'ENOENT') { + logger.err(`Cannot wipe cache file ${DiskCache.RBF_FILE_NAME}. Exception ${JSON.stringify(e)}`); + } + } + } + + async $loadMempoolCache(): Promise { + if (!config.MEMPOOL.CACHE_ENABLED || !fs.existsSync(DiskCache.FILE_NAME)) { + return; + } + try { + const start = Date.now(); + let data: any = {}; + const cacheData = fs.readFileSync(DiskCache.FILE_NAME, 'utf8'); + if (cacheData) { + logger.info('Restoring mempool and blocks data from disk cache'); + data = JSON.parse(cacheData); + if (data.cacheSchemaVersion === undefined || data.cacheSchemaVersion !== this.cacheSchemaVersion) { + logger.notice('Disk cache contains an outdated schema version. Clearing it and skipping the cache loading.'); + return this.wipeCache(); + } + if (data.network && data.network !== config.MEMPOOL.NETWORK) { + logger.notice('Disk cache contains data from a different network. Clearing it and skipping the cache loading.'); + return this.wipeCache(); + } + + if (data.mempoolArray) { + for (const tx of data.mempoolArray) { + delete tx.uid; + data.mempool[tx.txid] = tx; + } + } + } + + for (let i = 1; i < DiskCache.CHUNK_FILES; i++) { + const fileName = DiskCache.FILE_NAMES.replace('{number}', i.toString()); + try { + if (fs.existsSync(fileName)) { + const cacheData2 = JSON.parse(fs.readFileSync(fileName, 'utf8')); + if (cacheData2.mempoolArray) { + for (const tx of cacheData2.mempoolArray) { + delete tx.uid; + data.mempool[tx.txid] = tx; + } + } else { + Object.assign(data.mempool, cacheData2.mempool); + } + } + } catch (e) { + logger.err('Error parsing ' + fileName + '. Skipping. Reason: ' + (e instanceof Error ? e.message : e)); + } + } + + logger.info(`Loaded mempool from disk cache in ${Date.now() - start} ms`); + + await memPool.$setMempool(data.mempool); + if (!this.ignoreBlocksCache) { blocks.setBlocks(data.blocks); + blocks.setBlockSummaries(data.blockSummaries || []); } else { - memPool.setMempool(data); + logger.info('Re-saving cache with empty recent blocks data'); + await this.$saveCacheToDisk(true); } + } catch (e) { + logger.warn('Failed to parse mempoool and blocks cache. Skipping. Reason: ' + (e instanceof Error ? e.message : e)); } + + try { + let rbfData: any = {}; + const rbfCacheData = fs.readFileSync(DiskCache.RBF_FILE_NAME, 'utf8'); + if (rbfCacheData) { + logger.info('Restoring rbf data from disk cache'); + rbfData = JSON.parse(rbfCacheData); + if (rbfData.rbfCacheSchemaVersion === undefined || rbfData.rbfCacheSchemaVersion !== this.rbfCacheSchemaVersion) { + logger.notice('Rbf disk cache contains an outdated schema version. Clearing it and skipping the cache loading.'); + return this.wipeRbfCache(); + } + if (rbfData.network && rbfData.network !== config.MEMPOOL.NETWORK) { + logger.notice('Rbf disk cache contains data from a different network. Clearing it and skipping the cache loading.'); + return this.wipeRbfCache(); + } + } + + if (rbfData?.rbf) { + rbfCache.load({ + txs: rbfData.rbf.txs.map(([txid, entry]) => ({ value: entry })), + trees: rbfData.rbf.trees, + expiring: rbfData.rbf.expiring.map(([txid, value]) => ({ key: txid, value })), + mempool: memPool.getMempool(), + }); + } + } catch (e) { + logger.warn('Failed to parse rbf cache. Skipping. Reason: ' + (e instanceof Error ? e.message : e)); + } + } + + private $yield(): Promise { + if (this.semaphore.locks) { + logger.debug('Pause writing mempool and blocks data to disk cache (async)'); + return new Promise((resolve) => { + this.semaphore.resume.push(resolve); + }); + } else { + return Promise.resolve(); + } + } + + public lock(): void { + this.semaphore.locks++; } - private saveData(dataBlob: string) { - fs.writeFileSync(DiskCache.FILE_NAME, dataBlob, 'utf8'); + public unlock(): void { + this.semaphore.locks = Math.max(0, this.semaphore.locks - 1); + if (!this.semaphore.locks && this.semaphore.resume.length) { + const nextResume = this.semaphore.resume.shift(); + if (nextResume) { + logger.debug('Resume writing mempool and blocks data to disk cache (async)'); + nextResume(); + } + } } - private loadData(): string { - return fs.readFileSync(DiskCache.FILE_NAME, 'utf8'); + public setIgnoreBlocksCache(): void { + this.ignoreBlocksCache = true; } } diff --git a/backend/src/api/explorer/channels.api.ts b/backend/src/api/explorer/channels.api.ts new file mode 100644 index 0000000000..2faf06c336 --- /dev/null +++ b/backend/src/api/explorer/channels.api.ts @@ -0,0 +1,735 @@ +import logger from '../../logger'; +import DB from '../../database'; +import nodesApi from './nodes.api'; +import { ResultSetHeader } from 'mysql2'; +import { ILightningApi } from '../lightning/lightning-api.interface'; +import { Common } from '../common'; + +class ChannelsApi { + public async $getAllChannels(): Promise { + try { + const query = `SELECT * FROM channels`; + const [rows]: any = await DB.query(query); + return rows; + } catch (e) { + logger.err('$getAllChannels error: ' + (e instanceof Error ? e.message : e)); + throw e; + } + } + + public async $getAllChannelsGeo(publicKey?: string, style?: string): Promise { + try { + let select: string; + if (style === 'widget') { + select = ` + nodes_1.latitude AS node1_latitude, nodes_1.longitude AS node1_longitude, + nodes_2.latitude AS node2_latitude, nodes_2.longitude AS node2_longitude + `; + } else { + select = ` + nodes_1.public_key as node1_public_key, nodes_1.alias AS node1_alias, + nodes_1.latitude AS node1_latitude, nodes_1.longitude AS node1_longitude, + nodes_2.public_key as node2_public_key, nodes_2.alias AS node2_alias, + nodes_2.latitude AS node2_latitude, nodes_2.longitude AS node2_longitude + `; + } + + const params: string[] = []; + let query = `SELECT ${select} + FROM channels + JOIN nodes AS nodes_1 on nodes_1.public_key = channels.node1_public_key + JOIN nodes AS nodes_2 on nodes_2.public_key = channels.node2_public_key + WHERE channels.status = 1 + AND nodes_1.latitude IS NOT NULL AND nodes_1.longitude IS NOT NULL + AND nodes_2.latitude IS NOT NULL AND nodes_2.longitude IS NOT NULL + `; + + if (publicKey !== undefined) { + query += ' AND (nodes_1.public_key = ? OR nodes_2.public_key = ?)'; + params.push(publicKey); + params.push(publicKey); + } else { + query += ` AND channels.capacity > 1000000 + GROUP BY nodes_1.public_key, nodes_2.public_key + ORDER BY channels.capacity DESC + LIMIT 10000 + `; + } + + const [rows]: any = await DB.query(query, params); + return rows.map((row) => { + if (style === 'widget') { + return [ + row.node1_longitude, row.node1_latitude, + row.node2_longitude, row.node2_latitude, + ]; + } else { + return [ + row.node1_public_key, row.node1_alias, + row.node1_longitude, row.node1_latitude, + row.node2_public_key, row.node2_alias, + row.node2_longitude, row.node2_latitude, + ]; + } + }); + } catch (e) { + logger.err('$getAllChannelsGeo error: ' + (e instanceof Error ? e.message : e)); + throw e; + } + } + + public async $searchChannelsById(search: string): Promise { + try { + // restrict search to valid id/short_id prefix formats + let searchStripped = search.match(/^[0-9]+[0-9x]*$/)?.[0] || ''; + if (!searchStripped.length) { + return []; + } + // add wildcard to search by prefix + searchStripped += '%'; + const query = `SELECT id, short_id, capacity, status FROM channels WHERE id LIKE ? OR short_id LIKE ? LIMIT 10`; + const [rows]: any = await DB.query(query, [searchStripped, searchStripped]); + return rows; + } catch (e) { + logger.err('$searchChannelsById error: ' + (e instanceof Error ? e.message : e)); + throw e; + } + } + + public async $getChannelsByStatus(status: number | number[]): Promise { + try { + let query: string; + if (Array.isArray(status)) { + query = `SELECT * FROM channels WHERE status IN (${status.join(',')})`; + } else { + query = `SELECT * FROM channels WHERE status = ?`; + } + const [rows]: any = await DB.query(query, [status]); + return rows; + } catch (e) { + logger.err('$getChannelsByStatus error: ' + (e instanceof Error ? e.message : e)); + throw e; + } + } + + public async $getClosedChannelsWithoutReason(): Promise { + try { + const query = `SELECT * FROM channels WHERE status = 2 AND closing_reason IS NULL AND closing_transaction_id != ''`; + const [rows]: any = await DB.query(query); + return rows; + } catch (e) { + logger.err('$getClosedChannelsWithoutReason error: ' + (e instanceof Error ? e.message : e)); + throw e; + } + } + + public async $getPenaltyClosedChannels(): Promise { + try { + const query = ` + SELECT n1.alias AS alias_left, + n2.alias AS alias_right, + channels.* + FROM channels + LEFT JOIN nodes AS n1 ON n1.public_key = channels.node1_public_key + LEFT JOIN nodes AS n2 ON n2.public_key = channels.node2_public_key + WHERE channels.status = 2 AND channels.closing_reason = 3 + ORDER BY closing_date DESC + `; + const [rows]: any = await DB.query(query); + return rows; + } catch (e) { + logger.err('$getPenaltyClosedChannels error: ' + (e instanceof Error ? e.message : e)); + throw e; + } + } + + public async $getUnresolvedClosedChannels(): Promise { + try { + const query = `SELECT * FROM channels WHERE status = 2 AND closing_reason = 2 AND closing_resolved = 0 AND closing_transaction_id != ''`; + const [rows]: any = await DB.query(query); + return rows; + } catch (e) { + logger.err('$getUnresolvedClosedChannels error: ' + (e instanceof Error ? e.message : e)); + throw e; + } + } + + public async $getChannelsWithoutSourceChecked(): Promise { + try { + const query = ` + SELECT channels.* + FROM channels + WHERE channels.source_checked != 1 + `; + const [rows]: any = await DB.query(query); + return rows; + } catch (e) { + logger.err('$getUnresolvedClosedChannels error: ' + (e instanceof Error ? e.message : e)); + throw e; + } + } + + public async $getChannelsWithoutCreatedDate(): Promise { + try { + const query = `SELECT * FROM channels WHERE created IS NULL`; + const [rows]: any = await DB.query(query); + return rows; + } catch (e) { + logger.err('$getChannelsWithoutCreatedDate error: ' + (e instanceof Error ? e.message : e)); + throw e; + } + } + + public async $getChannel(id: string): Promise { + try { + const query = ` + SELECT n1.alias AS alias_left, n1.longitude as node1_longitude, n1.latitude as node1_latitude, + n2.alias AS alias_right, n2.longitude as node2_longitude, n2.latitude as node2_latitude, + channels.*, + ns1.channels AS channels_left, ns1.capacity AS capacity_left, ns2.channels AS channels_right, ns2.capacity AS capacity_right + FROM channels + LEFT JOIN nodes AS n1 ON n1.public_key = channels.node1_public_key + LEFT JOIN nodes AS n2 ON n2.public_key = channels.node2_public_key + LEFT JOIN node_stats AS ns1 ON ns1.public_key = channels.node1_public_key + LEFT JOIN node_stats AS ns2 ON ns2.public_key = channels.node2_public_key + WHERE ( + ns1.id = ( + SELECT MAX(id) + FROM node_stats + WHERE public_key = channels.node1_public_key + ) + AND ns2.id = ( + SELECT MAX(id) + FROM node_stats + WHERE public_key = channels.node2_public_key + ) + ) + AND channels.id = ? + `; + + const [rows]: any = await DB.query(query, [id]); + if (rows[0]) { + return this.convertChannel(rows[0]); + } + } catch (e) { + logger.err('$getChannel error: ' + (e instanceof Error ? e.message : e)); + throw e; + } + } + + public async $getChannelsStats(): Promise { + try { + // Feedback from zerofeerouting: + // "I would argue > 5000ppm can be ignored. Channels charging more than .5% fee are ignored by CLN for example." + const ignoredFeeRateThreshold = 5000; + const ignoredBaseFeeThreshold = 5000; + + // Capacity + let query = `SELECT AVG(capacity) AS avgCapacity FROM channels WHERE status = 1 ORDER BY capacity`; + const [avgCapacity]: any = await DB.query(query); + + query = `SELECT capacity FROM channels WHERE status = 1 ORDER BY capacity`; + let [capacity]: any = await DB.query(query); + capacity = capacity.map(capacity => capacity.capacity); + const medianCapacity = capacity[Math.floor(capacity.length / 2)]; + + // Fee rates + query = `SELECT node1_fee_rate FROM channels WHERE node1_fee_rate < ${ignoredFeeRateThreshold} AND status = 1`; + let [feeRates1]: any = await DB.query(query); + feeRates1 = feeRates1.map(rate => rate.node1_fee_rate); + query = `SELECT node2_fee_rate FROM channels WHERE node2_fee_rate < ${ignoredFeeRateThreshold} AND status = 1`; + let [feeRates2]: any = await DB.query(query); + feeRates2 = feeRates2.map(rate => rate.node2_fee_rate); + + let feeRates = (feeRates1.concat(feeRates2)).sort((a, b) => a - b); + let avgFeeRate = 0; + for (const rate of feeRates) { + avgFeeRate += rate; + } + avgFeeRate /= feeRates.length; + const medianFeeRate = feeRates[Math.floor(feeRates.length / 2)]; + + // Base fees + query = `SELECT node1_base_fee_mtokens FROM channels WHERE node1_base_fee_mtokens < ${ignoredBaseFeeThreshold} AND status = 1`; + let [baseFees1]: any = await DB.query(query); + baseFees1 = baseFees1.map(rate => rate.node1_base_fee_mtokens); + query = `SELECT node2_base_fee_mtokens FROM channels WHERE node2_base_fee_mtokens < ${ignoredBaseFeeThreshold} AND status = 1`; + let [baseFees2]: any = await DB.query(query); + baseFees2 = baseFees2.map(rate => rate.node2_base_fee_mtokens); + + let baseFees = (baseFees1.concat(baseFees2)).sort((a, b) => a - b); + let avgBaseFee = 0; + for (const fee of baseFees) { + avgBaseFee += fee; + } + avgBaseFee /= baseFees.length; + const medianBaseFee = feeRates[Math.floor(baseFees.length / 2)]; + + return { + avgCapacity: parseInt(avgCapacity[0].avgCapacity, 10), + avgFeeRate: avgFeeRate, + avgBaseFee: avgBaseFee, + medianCapacity: medianCapacity, + medianFeeRate: medianFeeRate, + medianBaseFee: medianBaseFee, + } + + } catch (e) { + logger.err(`Cannot calculate channels statistics. Reason: ${e instanceof Error ? e.message : e}`); + throw e; + } + } + + public async $getChannelsByTransactionId(transactionIds: string[]): Promise { + try { + const query = ` + SELECT n1.alias AS alias_left, n2.alias AS alias_right, channels.* + FROM channels + LEFT JOIN nodes AS n1 ON n1.public_key = channels.node1_public_key + LEFT JOIN nodes AS n2 ON n2.public_key = channels.node2_public_key + WHERE channels.transaction_id IN ? OR channels.closing_transaction_id IN ? + `; + const [rows]: any = await DB.query(query, [[transactionIds], [transactionIds]]); + const channels = rows.map((row) => this.convertChannel(row)); + return channels; + } catch (e) { + logger.err('$getChannelByTransactionId error: ' + (e instanceof Error ? e.message : e)); + throw e; + } + } + + public async $getChannelByClosingId(transactionId: string): Promise { + try { + const query = ` + SELECT + channels.* + FROM channels + WHERE channels.closing_transaction_id = ? + `; + const [rows]: any = await DB.query(query, [transactionId]); + if (rows.length > 0) { + rows[0].outputs = JSON.parse(rows[0].outputs); + return rows[0]; + } + } catch (e) { + logger.err('$getChannelByClosingId error: ' + (e instanceof Error ? e.message : e)); + // don't throw - this data isn't essential + } + } + + public async $getChannelsByOpeningId(transactionId: string): Promise { + try { + const query = ` + SELECT + channels.* + FROM channels + WHERE channels.transaction_id = ? + `; + const [rows]: any = await DB.query(query, [transactionId]); + if (rows.length > 0) { + return rows.map(row => { + row.outputs = JSON.parse(row.outputs); + return row; + }); + } + } catch (e) { + logger.err('$getChannelsByOpeningId error: ' + (e instanceof Error ? e.message : e)); + // don't throw - this data isn't essential + } + } + + public async $updateClosingInfo(channelInfo: { id: string, node1_closing_balance: number, node2_closing_balance: number, closed_by: string | null, closing_fee: number, outputs: ILightningApi.ForensicOutput[]}): Promise { + try { + const query = ` + UPDATE channels SET + node1_closing_balance = ?, + node2_closing_balance = ?, + closed_by = ?, + closing_fee = ?, + outputs = ? + WHERE channels.id = ? + `; + await DB.query(query, [ + channelInfo.node1_closing_balance || 0, + channelInfo.node2_closing_balance || 0, + channelInfo.closed_by, + channelInfo.closing_fee || 0, + JSON.stringify(channelInfo.outputs), + channelInfo.id, + ]); + } catch (e) { + logger.err('$updateClosingInfo error: ' + (e instanceof Error ? e.message : e)); + // don't throw - this data isn't essential + } + } + + public async $updateOpeningInfo(channelInfo: { id: string, node1_funding_balance: number, node2_funding_balance: number, funding_ratio: number, single_funded: boolean | void }): Promise { + try { + const query = ` + UPDATE channels SET + node1_funding_balance = ?, + node2_funding_balance = ?, + funding_ratio = ?, + single_funded = ? + WHERE channels.id = ? + `; + await DB.query(query, [ + channelInfo.node1_funding_balance || 0, + channelInfo.node2_funding_balance || 0, + channelInfo.funding_ratio, + channelInfo.single_funded ? 1 : 0, + channelInfo.id, + ]); + } catch (e) { + logger.err('$updateOpeningInfo error: ' + (e instanceof Error ? e.message : e)); + // don't throw - this data isn't essential + } + } + + public async $markChannelSourceChecked(id: string): Promise { + try { + const query = ` + UPDATE channels + SET source_checked = 1 + WHERE id = ? + `; + await DB.query(query, [id]); + } catch (e) { + logger.err('$markChannelSourceChecked error: ' + (e instanceof Error ? e.message : e)); + // don't throw - this data isn't essential + } + } + + public async $getChannelsForNode(public_key: string, index: number, length: number, status: string): Promise { + try { + let channelStatusFilter; + if (status === 'open') { + channelStatusFilter = '< 2'; + } else if (status === 'active') { + channelStatusFilter = '= 1'; + } else if (status === 'closed') { + channelStatusFilter = '= 2'; + } else { + throw new Error('getChannelsForNode: Invalid status requested'); + } + + // Channels originating from node + let query = ` + SELECT COALESCE(node2.alias, SUBSTRING(node2_public_key, 0, 20)) AS alias, COALESCE(node2.public_key, node2_public_key) AS public_key, + channels.status, channels.node1_fee_rate, + channels.capacity, channels.short_id, channels.id, channels.closing_reason, + UNIX_TIMESTAMP(closing_date) as closing_date, UNIX_TIMESTAMP(channels.updated_at) as updated_at + FROM channels + LEFT JOIN nodes AS node2 ON node2.public_key = channels.node2_public_key + WHERE node1_public_key = ? AND channels.status ${channelStatusFilter} + `; + const [channelsFromNode]: any = await DB.query(query, [public_key]); + + // Channels incoming to node + query = ` + SELECT COALESCE(node1.alias, SUBSTRING(node1_public_key, 0, 20)) AS alias, COALESCE(node1.public_key, node1_public_key) AS public_key, + channels.status, channels.node2_fee_rate, + channels.capacity, channels.short_id, channels.id, channels.closing_reason, + UNIX_TIMESTAMP(closing_date) as closing_date, UNIX_TIMESTAMP(channels.updated_at) as updated_at + FROM channels + LEFT JOIN nodes AS node1 ON node1.public_key = channels.node1_public_key + WHERE node2_public_key = ? AND channels.status ${channelStatusFilter} + `; + const [channelsToNode]: any = await DB.query(query, [public_key]); + + let allChannels = channelsFromNode.concat(channelsToNode); + allChannels.sort((a, b) => { + if (status === 'closed') { + if (!b.closing_date && !a.closing_date) { + return (b.updated_at ?? 0) - (a.updated_at ?? 0); + } else { + return (b.closing_date ?? 0) - (a.closing_date ?? 0); + } + } else { + return b.capacity - a.capacity; + } + }); + + if (index >= 0) { + allChannels = allChannels.slice(index, index + length); + } else if (index === -1) { // Node channels tree chart + allChannels = allChannels.slice(0, 1000); + } + + const channels: any[] = [] + for (const row of allChannels) { + let channel; + if (index >= 0) { + const activeChannelsStats: any = await nodesApi.$getActiveChannelsStats(row.public_key); + channel = { + status: row.status, + closing_reason: row.closing_reason, + closing_date: row.closing_date, + capacity: row.capacity ?? 0, + short_id: row.short_id, + id: row.id, + fee_rate: row.node1_fee_rate ?? row.node2_fee_rate ?? 0, + node: { + alias: row.alias.length > 0 ? row.alias : row.public_key.slice(0, 20), + public_key: row.public_key, + channels: activeChannelsStats.active_channel_count ?? 0, + capacity: activeChannelsStats.capacity ?? 0, + } + }; + } else if (index === -1) { + channel = { + capacity: row.capacity ?? 0, + short_id: row.short_id, + id: row.id, + node: { + alias: row.alias.length > 0 ? row.alias : row.public_key.slice(0, 20), + public_key: row.public_key, + } + }; + } + + channels.push(channel); + } + + return channels; + } catch (e) { + logger.err('$getChannelsForNode error: ' + (e instanceof Error ? e.message : e)); + throw e; + } + } + + public async $getChannelsCountForNode(public_key: string, status: string): Promise { + try { + // Default active and inactive channels + let statusQuery = '< 2'; + // Closed channels only + if (status === 'closed') { + statusQuery = '= 2'; + } + const query = ` + SELECT COUNT(*) AS count + FROM channels + WHERE (node1_public_key = ? OR node2_public_key = ?) + AND status ${statusQuery} + `; + const [rows]: any = await DB.query(query, [public_key, public_key]); + return rows[0]['count']; + } catch (e) { + logger.err('$getChannelsForNode error: ' + (e instanceof Error ? e.message : e)); + throw e; + } + } + + private convertChannel(channel: any): any { + return { + 'id': channel.id, + 'short_id': channel.short_id, + 'capacity': channel.capacity, + 'transaction_id': channel.transaction_id, + 'transaction_vout': channel.transaction_vout, + 'closing_transaction_id': channel.closing_transaction_id, + 'closing_fee': channel.closing_fee, + 'closing_reason': channel.closing_reason, + 'closing_date': channel.closing_date, + 'updated_at': channel.updated_at, + 'created': channel.created, + 'status': channel.status, + 'funding_ratio': channel.funding_ratio, + 'closed_by': channel.closed_by, + 'single_funded': !!channel.single_funded, + 'node_left': { + 'alias': channel.alias_left, + 'public_key': channel.node1_public_key, + 'channels': channel.channels_left, + 'capacity': channel.capacity_left, + 'base_fee_mtokens': channel.node1_base_fee_mtokens, + 'cltv_delta': channel.node1_cltv_delta, + 'fee_rate': channel.node1_fee_rate, + 'is_disabled': channel.node1_is_disabled, + 'max_htlc_mtokens': channel.node1_max_htlc_mtokens, + 'min_htlc_mtokens': channel.node1_min_htlc_mtokens, + 'updated_at': channel.node1_updated_at, + 'longitude': channel.node1_longitude, + 'latitude': channel.node1_latitude, + 'funding_balance': channel.node1_funding_balance, + 'closing_balance': channel.node1_closing_balance, + 'initiated_close': channel.closed_by === channel.node1_public_key ? true : undefined, + }, + 'node_right': { + 'alias': channel.alias_right, + 'public_key': channel.node2_public_key, + 'channels': channel.channels_right, + 'capacity': channel.capacity_right, + 'base_fee_mtokens': channel.node2_base_fee_mtokens, + 'cltv_delta': channel.node2_cltv_delta, + 'fee_rate': channel.node2_fee_rate, + 'is_disabled': channel.node2_is_disabled, + 'max_htlc_mtokens': channel.node2_max_htlc_mtokens, + 'min_htlc_mtokens': channel.node2_min_htlc_mtokens, + 'updated_at': channel.node2_updated_at, + 'longitude': channel.node2_longitude, + 'latitude': channel.node2_latitude, + 'funding_balance': channel.node2_funding_balance, + 'closing_balance': channel.node2_closing_balance, + 'initiated_close': channel.closed_by === channel.node2_public_key ? true : undefined, + }, + }; + } + + /** + * Save or update a channel present in the graph + */ + public async $saveChannel(channel: ILightningApi.Channel, status = 1): Promise { + const [ txid, vout ] = channel.chan_point.split(':'); + + const policy1: Partial = channel.node1_policy || {}; + const policy2: Partial = channel.node2_policy || {}; + + // https://github.com/mempool/mempool/issues/3006 + if ((channel.last_update ?? 0) < 1514736061) { // January 1st 2018 + channel.last_update = null; + } + if ((policy1.last_update ?? 0) < 1514736061) { // January 1st 2018 + policy1.last_update = null; + } + if ((policy2.last_update ?? 0) < 1514736061) { // January 1st 2018 + policy2.last_update = null; + } + + const query = `INSERT INTO channels + ( + id, + short_id, + capacity, + transaction_id, + transaction_vout, + updated_at, + status, + node1_public_key, + node1_base_fee_mtokens, + node1_cltv_delta, + node1_fee_rate, + node1_is_disabled, + node1_max_htlc_mtokens, + node1_min_htlc_mtokens, + node1_updated_at, + node2_public_key, + node2_base_fee_mtokens, + node2_cltv_delta, + node2_fee_rate, + node2_is_disabled, + node2_max_htlc_mtokens, + node2_min_htlc_mtokens, + node2_updated_at + ) + VALUES (?, ?, ?, ?, ?, ?, ${status}, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) + ON DUPLICATE KEY UPDATE + capacity = ?, + updated_at = ?, + status = ${status}, + node1_public_key = ?, + node1_base_fee_mtokens = ?, + node1_cltv_delta = ?, + node1_fee_rate = ?, + node1_is_disabled = ?, + node1_max_htlc_mtokens = ?, + node1_min_htlc_mtokens = ?, + node1_updated_at = ?, + node2_public_key = ?, + node2_base_fee_mtokens = ?, + node2_cltv_delta = ?, + node2_fee_rate = ?, + node2_is_disabled = ?, + node2_max_htlc_mtokens = ?, + node2_min_htlc_mtokens = ?, + node2_updated_at = ? + ;`; + + await DB.query(query, [ + Common.channelShortIdToIntegerId(channel.channel_id), + Common.channelIntegerIdToShortId(channel.channel_id), + channel.capacity, + txid, + vout, + Common.utcDateToMysql(channel.last_update), + channel.node1_pub, + policy1.fee_base_msat, + policy1.time_lock_delta, + policy1.fee_rate_milli_msat, + policy1.disabled, + policy1.max_htlc_msat, + policy1.min_htlc, + Common.utcDateToMysql(policy1.last_update), + channel.node2_pub, + policy2.fee_base_msat, + policy2.time_lock_delta, + policy2.fee_rate_milli_msat, + policy2.disabled, + policy2.max_htlc_msat, + policy2.min_htlc, + Common.utcDateToMysql(policy2.last_update), + channel.capacity, + Common.utcDateToMysql(channel.last_update), + channel.node1_pub, + policy1.fee_base_msat, + policy1.time_lock_delta, + policy1.fee_rate_milli_msat, + policy1.disabled, + policy1.max_htlc_msat, + policy1.min_htlc, + Common.utcDateToMysql(policy1.last_update), + channel.node2_pub, + policy2.fee_base_msat, + policy2.time_lock_delta, + policy2.fee_rate_milli_msat, + policy2.disabled, + policy2.max_htlc_msat, + policy2.min_htlc, + Common.utcDateToMysql(policy2.last_update) + ]); + } + + /** + * Set all channels not in `graphChannelsIds` as inactive (status = 0) + */ + public async $setChannelsInactive(graphChannelsIds: string[]): Promise { + if (graphChannelsIds.length === 0) { + return; + } + + try { + const result = await DB.query(` + UPDATE channels + SET status = 0 + WHERE id NOT IN ( + ${graphChannelsIds.map(id => `"${id}"`).join(',')} + ) + AND status != 2 + `); + if (result[0].changedRows ?? 0 > 0) { + logger.debug(`Marked ${result[0].changedRows} channels as inactive because they are not in the graph`, logger.tags.ln); + } + } catch (e) { + logger.err('$setChannelsInactive() error: ' + (e instanceof Error ? e.message : e)); + } + } + + public async $getLatestChannelUpdateForNode(publicKey: string): Promise { + try { + const query = ` + SELECT MAX(UNIX_TIMESTAMP(updated_at)) as updated_at + FROM channels + WHERE node1_public_key = ? + `; + const [rows]: any[] = await DB.query(query, [publicKey]); + if (rows.length > 0) { + return rows[0].updated_at; + } + } catch (e) { + logger.err(`Can't getLatestChannelUpdateForNode for ${publicKey}. Reason ${e instanceof Error ? e.message : e}`); + } + return 0; + } +} + +export default new ChannelsApi(); diff --git a/backend/src/api/explorer/channels.routes.ts b/backend/src/api/explorer/channels.routes.ts new file mode 100644 index 0000000000..391bf628e8 --- /dev/null +++ b/backend/src/api/explorer/channels.routes.ts @@ -0,0 +1,141 @@ +import config from '../../config'; +import { Application, Request, Response } from 'express'; +import channelsApi from './channels.api'; + +class ChannelsRoutes { + constructor() { } + + public initRoutes(app: Application) { + app + .get(config.MEMPOOL.API_URL_PREFIX + 'lightning/channels/txids', this.$getChannelsByTransactionIds) + .get(config.MEMPOOL.API_URL_PREFIX + 'lightning/channels/search/:search', this.$searchChannelsById) + .get(config.MEMPOOL.API_URL_PREFIX + 'lightning/channels/:short_id', this.$getChannel) + .get(config.MEMPOOL.API_URL_PREFIX + 'lightning/channels', this.$getChannelsForNode) + .get(config.MEMPOOL.API_URL_PREFIX + 'lightning/penalties', this.$getPenaltyClosedChannels) + .get(config.MEMPOOL.API_URL_PREFIX + 'lightning/channels-geo', this.$getAllChannelsGeo) + .get(config.MEMPOOL.API_URL_PREFIX + 'lightning/channels-geo/:publicKey', this.$getAllChannelsGeo) + ; + } + + private async $searchChannelsById(req: Request, res: Response) { + try { + const channels = await channelsApi.$searchChannelsById(req.params.search); + res.json(channels); + } catch (e) { + res.status(500).send(e instanceof Error ? e.message : e); + } + } + + private async $getChannel(req: Request, res: Response) { + try { + const channel = await channelsApi.$getChannel(req.params.short_id); + if (!channel) { + res.status(404).send('Channel not found'); + return; + } + res.header('Pragma', 'public'); + res.header('Cache-control', 'public'); + res.setHeader('Expires', new Date(Date.now() + 1000 * 60).toUTCString()); + res.json(channel); + } catch (e) { + res.status(500).send(e instanceof Error ? e.message : e); + } + } + + private async $getChannelsForNode(req: Request, res: Response) { + try { + if (typeof req.query.public_key !== 'string') { + res.status(400).send('Missing parameter: public_key'); + return; + } + + const index = parseInt(typeof req.query.index === 'string' ? req.query.index : '0', 10) || 0; + const status: string = typeof req.query.status === 'string' ? req.query.status : ''; + + if (index < -1) { + res.status(400).send('Invalid index'); + return; + } + if (['open', 'active', 'closed'].includes(status) === false) { + res.status(400).send('Invalid status'); + return; + } + + const channels = await channelsApi.$getChannelsForNode(req.query.public_key, index, 10, status); + const channelsCount = await channelsApi.$getChannelsCountForNode(req.query.public_key, status); + res.header('Pragma', 'public'); + res.header('Cache-control', 'public'); + res.setHeader('Expires', new Date(Date.now() + 1000 * 60).toUTCString()); + res.header('X-Total-Count', channelsCount.toString()); + res.json(channels); + } catch (e) { + res.status(500).send(e instanceof Error ? e.message : e); + } + } + + private async $getChannelsByTransactionIds(req: Request, res: Response): Promise { + try { + if (!Array.isArray(req.query.txId)) { + res.status(400).send('Not an array'); + return; + } + const txIds: string[] = []; + for (const _txId in req.query.txId) { + if (typeof req.query.txId[_txId] === 'string') { + txIds.push(req.query.txId[_txId].toString()); + } + } + const channels = await channelsApi.$getChannelsByTransactionId(txIds); + const result: any[] = []; + for (const txid of txIds) { + const inputs: any = {}; + const outputs: any = {}; + // Assuming that we only have one lightning close input in each transaction. This may not be true in the future + const foundChannelsFromInput = channels.find((channel) => channel.closing_transaction_id === txid); + if (foundChannelsFromInput) { + inputs[0] = foundChannelsFromInput; + } + const foundChannelsFromOutputs = channels.filter((channel) => channel.transaction_id === txid); + for (const output of foundChannelsFromOutputs) { + outputs[output.transaction_vout] = output; + } + result.push({ + inputs, + outputs, + }); + } + + res.json(result); + } catch (e) { + res.status(500).send(e instanceof Error ? e.message : e); + } + } + + private async $getPenaltyClosedChannels(req: Request, res: Response): Promise { + try { + const channels = await channelsApi.$getPenaltyClosedChannels(); + res.header('Pragma', 'public'); + res.header('Cache-control', 'public'); + res.setHeader('Expires', new Date(Date.now() + 1000 * 60).toUTCString()); + res.json(channels); + } catch (e) { + res.status(500).send(e instanceof Error ? e.message : e); + } + } + + private async $getAllChannelsGeo(req: Request, res: Response) { + try { + const style: string = typeof req.query.style === 'string' ? req.query.style : ''; + const channels = await channelsApi.$getAllChannelsGeo(req.params?.publicKey, style); + res.header('Pragma', 'public'); + res.header('Cache-control', 'public'); + res.setHeader('Expires', new Date(Date.now() + 1000 * 60).toUTCString()); + res.json(channels); + } catch (e) { + res.status(500).send(e instanceof Error ? e.message : e); + } + } + +} + +export default new ChannelsRoutes(); diff --git a/backend/src/api/explorer/general.routes.ts b/backend/src/api/explorer/general.routes.ts new file mode 100644 index 0000000000..07620e84ab --- /dev/null +++ b/backend/src/api/explorer/general.routes.ts @@ -0,0 +1,58 @@ +import config from '../../config'; +import { Application, Request, Response } from 'express'; +import nodesApi from './nodes.api'; +import channelsApi from './channels.api'; +import statisticsApi from './statistics.api'; +class GeneralLightningRoutes { + constructor() { } + + public initRoutes(app: Application) { + app + .get(config.MEMPOOL.API_URL_PREFIX + 'lightning/search', this.$searchNodesAndChannels) + .get(config.MEMPOOL.API_URL_PREFIX + 'lightning/statistics/latest', this.$getGeneralStats) + .get(config.MEMPOOL.API_URL_PREFIX + 'lightning/statistics/:interval', this.$getStatistics) + ; + } + + private async $searchNodesAndChannels(req: Request, res: Response) { + if (typeof req.query.searchText !== 'string') { + res.status(400).send('Missing parameter: searchText'); + return; + } + try { + const nodes = await nodesApi.$searchNodeByPublicKeyOrAlias(req.query.searchText); + const channels = await channelsApi.$searchChannelsById(req.query.searchText); + res.json({ + nodes: nodes, + channels: channels, + }); + } catch (e) { + res.status(500).send(e instanceof Error ? e.message : e); + } + } + + private async $getStatistics(req: Request, res: Response) { + try { + const statistics = await statisticsApi.$getStatistics(req.params.interval); + const statisticsCount = await statisticsApi.$getStatisticsCount(); + res.header('Pragma', 'public'); + res.header('Cache-control', 'public'); + res.header('X-total-count', statisticsCount.toString()); + res.setHeader('Expires', new Date(Date.now() + 1000 * 60).toUTCString()); + res.json(statistics); + } catch (e) { + res.status(500).send(e instanceof Error ? e.message : e); + } + } + + private async $getGeneralStats(req: Request, res: Response) { + try { + const statistics = await statisticsApi.$getLatestStatistics(); + res.json(statistics); + } catch (e) { + res.status(500).send(e instanceof Error ? e.message : e); + } + } +} + +export default new GeneralLightningRoutes(); diff --git a/backend/src/api/explorer/nodes.api.ts b/backend/src/api/explorer/nodes.api.ts new file mode 100644 index 0000000000..22c854fcca --- /dev/null +++ b/backend/src/api/explorer/nodes.api.ts @@ -0,0 +1,757 @@ +import logger from '../../logger'; +import DB from '../../database'; +import { ResultSetHeader } from 'mysql2'; +import { ILightningApi } from '../lightning/lightning-api.interface'; +import { ITopNodesPerCapacity, ITopNodesPerChannels } from '../../mempool.interfaces'; +import { bin2hex } from '../../utils/format'; + +class NodesApi { + public async $getWorldNodes(): Promise { + try { + let query = ` + SELECT nodes.public_key as publicKey, IF(nodes.alias = '', SUBSTRING(nodes.public_key, 1, 20), alias) as alias, + CAST(COALESCE(nodes.capacity, 0) as INT) as capacity, + CAST(COALESCE(nodes.channels, 0) as INT) as channels, + nodes.longitude, nodes.latitude, + geo_names_country.names as country, geo_names_iso.names as isoCode + FROM nodes + JOIN geo_names geo_names_country ON geo_names_country.id = nodes.country_id AND geo_names_country.type = 'country' + JOIN geo_names geo_names_iso ON geo_names_iso.id = nodes.country_id AND geo_names_iso.type = 'country_iso_code' + WHERE status = 1 AND nodes.as_number IS NOT NULL + ORDER BY capacity + `; + + const [nodes]: any[] = await DB.query(query); + + for (let i = 0; i < nodes.length; ++i) { + nodes[i].country = JSON.parse(nodes[i].country); + } + + query = ` + SELECT MAX(nodes.capacity) as maxLiquidity, MAX(nodes.channels) as maxChannels + FROM nodes + WHERE status = 1 AND nodes.as_number IS NOT NULL + `; + + const [maximums]: any[] = await DB.query(query); + + return { + maxLiquidity: maximums[0].maxLiquidity, + maxChannels: maximums[0].maxChannels, + nodes: nodes.map(node => [ + node.longitude, node.latitude, + node.publicKey, node.alias, node.capacity, node.channels, + node.country, node.isoCode + ]) + }; + } catch (e) { + logger.err(`Can't get world nodes list. Reason: ${e instanceof Error ? e.message : e}`); + } + } + + public async $getNode(public_key: string): Promise { + try { + // General info + let query = ` + SELECT public_key, alias, UNIX_TIMESTAMP(first_seen) AS first_seen, + UNIX_TIMESTAMP(updated_at) AS updated_at, color, sockets as sockets, + as_number, city_id, country_id, subdivision_id, longitude, latitude, + geo_names_iso.names as iso_code, geo_names_as.names as as_organization, geo_names_city.names as city, + geo_names_country.names as country, geo_names_subdivision.names as subdivision, + features + FROM nodes + LEFT JOIN geo_names geo_names_as on geo_names_as.id = as_number + LEFT JOIN geo_names geo_names_city on geo_names_city.id = city_id + LEFT JOIN geo_names geo_names_subdivision on geo_names_subdivision.id = subdivision_id + LEFT JOIN geo_names geo_names_country on geo_names_country.id = country_id + LEFT JOIN geo_names geo_names_iso ON geo_names_iso.id = nodes.country_id AND geo_names_iso.type = 'country_iso_code' + WHERE public_key = ? + `; + let [rows]: any[] = await DB.query(query, [public_key]); + if (rows.length === 0) { + throw new Error(`This node does not exist, or our node is not seeing it yet`); + } + + const node = rows[0]; + node.as_organization = JSON.parse(node.as_organization); + node.subdivision = JSON.parse(node.subdivision); + node.city = JSON.parse(node.city); + node.country = JSON.parse(node.country); + + // Features + node.features = JSON.parse(node.features); + node.featuresBits = null; + if (node.features) { + let maxBit = 0; + for (const feature of node.features) { + maxBit = Math.max(maxBit, feature.bit); + } + maxBit = Math.ceil(maxBit / 4) * 4 - 1; + + node.featuresBits = new Array(maxBit + 1).fill(0); + for (const feature of node.features) { + node.featuresBits[feature.bit] = 1; + } + node.featuresBits = bin2hex(node.featuresBits.reverse().join('')); + } + + // Active channels and capacity + const activeChannelsStats: any = await this.$getActiveChannelsStats(public_key); + node.active_channel_count = activeChannelsStats.active_channel_count ?? 0; + node.capacity = activeChannelsStats.capacity ?? 0; + + // Opened channels count + query = ` + SELECT count(short_id) as opened_channel_count + FROM channels + WHERE status != 2 AND (channels.node1_public_key = ? OR channels.node2_public_key = ?) + `; + [rows] = await DB.query(query, [public_key, public_key]); + node.opened_channel_count = 0; + if (rows.length > 0) { + node.opened_channel_count = rows[0].opened_channel_count; + } + + // Closed channels count + query = ` + SELECT count(short_id) as closed_channel_count + FROM channels + WHERE status = 2 AND (channels.node1_public_key = ? OR channels.node2_public_key = ?) + `; + [rows] = await DB.query(query, [public_key, public_key]); + node.closed_channel_count = 0; + if (rows.length > 0) { + node.closed_channel_count = rows[0].closed_channel_count; + } + + // Custom records + query = ` + SELECT type, payload + FROM nodes_records + WHERE public_key = ? + `; + [rows] = await DB.query(query, [public_key]); + node.custom_records = {}; + for (const record of rows) { + node.custom_records[record.type] = Buffer.from(record.payload, 'binary').toString('hex'); + } + + return node; + } catch (e) { + logger.err(`Cannot get node information for ${public_key}. Reason: ${(e instanceof Error ? e.message : e)}`); + throw e; + } + } + + public async $getActiveChannelsStats(node_public_key: string): Promise { + const query = ` + SELECT count(short_id) as active_channel_count, sum(capacity) as capacity + FROM channels + WHERE status = 1 AND (channels.node1_public_key = ? OR channels.node2_public_key = ?) + `; + const [rows]: any[] = await DB.query(query, [node_public_key, node_public_key]); + if (rows.length > 0) { + return { + active_channel_count: rows[0].active_channel_count, + capacity: rows[0].capacity + }; + } else { + return null; + } + } + + public async $getFeeHistogram(node_public_key: string): Promise { + try { + const inQuery = ` + SELECT CASE WHEN fee_rate <= 10.0 THEN CEIL(fee_rate) + WHEN (fee_rate > 10.0 and fee_rate <= 100.0) THEN CEIL(fee_rate / 10.0) * 10.0 + WHEN (fee_rate > 100.0 and fee_rate <= 1000.0) THEN CEIL(fee_rate / 100.0) * 100.0 + WHEN fee_rate > 1000.0 THEN CEIL(fee_rate / 1000.0) * 1000.0 + END as bucket, + count(short_id) as count, + sum(capacity) as capacity + FROM ( + SELECT CASE WHEN node1_public_key = ? THEN node2_fee_rate WHEN node2_public_key = ? THEN node1_fee_rate END as fee_rate, + short_id as short_id, + capacity as capacity + FROM channels + WHERE status = 1 AND (channels.node1_public_key = ? OR channels.node2_public_key = ?) + ) as fee_rate_table + GROUP BY bucket; + `; + const [inRows]: any[] = await DB.query(inQuery, [node_public_key, node_public_key, node_public_key, node_public_key]); + + const outQuery = ` + SELECT CASE WHEN fee_rate <= 10.0 THEN CEIL(fee_rate) + WHEN (fee_rate > 10.0 and fee_rate <= 100.0) THEN CEIL(fee_rate / 10.0) * 10.0 + WHEN (fee_rate > 100.0 and fee_rate <= 1000.0) THEN CEIL(fee_rate / 100.0) * 100.0 + WHEN fee_rate > 1000.0 THEN CEIL(fee_rate / 1000.0) * 1000.0 + END as bucket, + count(short_id) as count, + sum(capacity) as capacity + FROM ( + SELECT CASE WHEN node1_public_key = ? THEN node1_fee_rate WHEN node2_public_key = ? THEN node2_fee_rate END as fee_rate, + short_id as short_id, + capacity as capacity + FROM channels + WHERE status = 1 AND (channels.node1_public_key = ? OR channels.node2_public_key = ?) + ) as fee_rate_table + GROUP BY bucket; + `; + const [outRows]: any[] = await DB.query(outQuery, [node_public_key, node_public_key, node_public_key, node_public_key]); + + return { + incoming: inRows.length > 0 ? inRows : [], + outgoing: outRows.length > 0 ? outRows : [], + }; + } catch (e) { + logger.err(`Cannot get node fee distribution for ${node_public_key}. Reason: ${(e instanceof Error ? e.message : e)}`); + throw e; + } + } + + public async $getAllNodes(): Promise { + try { + const query = `SELECT * FROM nodes`; + const [rows]: any = await DB.query(query); + return rows; + } catch (e) { + logger.err('$getAllNodes error: ' + (e instanceof Error ? e.message : e)); + throw e; + } + } + + public async $getNodeStats(public_key: string): Promise { + try { + const query = ` + SELECT UNIX_TIMESTAMP(added) AS added, capacity, channels + FROM node_stats + WHERE public_key = ? + ORDER BY added DESC + `; + const [rows]: any = await DB.query(query, [public_key]); + return rows; + } catch (e) { + logger.err('$getNodeStats error: ' + (e instanceof Error ? e.message : e)); + throw e; + } + } + + public async $getTopCapacityNodes(full: boolean): Promise { + try { + let rows: any; + let query: string; + if (full === false) { + query = ` + SELECT nodes.public_key AS publicKey, IF(nodes.alias = '', SUBSTRING(nodes.public_key, 1, 20), alias) as alias, + nodes.capacity + FROM nodes + ORDER BY capacity DESC + LIMIT 6 + `; + + [rows] = await DB.query(query); + } else { + query = ` + SELECT nodes.public_key AS publicKey, IF(nodes.alias = '', SUBSTRING(nodes.public_key, 1, 20), alias) as alias, + CAST(COALESCE(nodes.capacity, 0) as INT) as capacity, + CAST(COALESCE(nodes.channels, 0) as INT) as channels, + UNIX_TIMESTAMP(nodes.first_seen) as firstSeen, UNIX_TIMESTAMP(nodes.updated_at) as updatedAt, + geo_names_city.names as city, geo_names_country.names as country, + geo_names_iso.names as iso_code, geo_names_subdivision.names as subdivision + FROM nodes + LEFT JOIN geo_names geo_names_country ON geo_names_country.id = nodes.country_id AND geo_names_country.type = 'country' + LEFT JOIN geo_names geo_names_city ON geo_names_city.id = nodes.city_id AND geo_names_city.type = 'city' + LEFT JOIN geo_names geo_names_iso ON geo_names_iso.id = nodes.country_id AND geo_names_iso.type = 'country_iso_code' + LEFT JOIN geo_names geo_names_subdivision on geo_names_subdivision.id = nodes.subdivision_id AND geo_names_subdivision.type = 'division' + ORDER BY capacity DESC + LIMIT 100 + `; + + [rows] = await DB.query(query); + for (let i = 0; i < rows.length; ++i) { + rows[i].country = JSON.parse(rows[i].country); + rows[i].city = JSON.parse(rows[i].city); + } + } + + return rows; + } catch (e) { + logger.err('$getTopCapacityNodes error: ' + (e instanceof Error ? e.message : e)); + throw e; + } + } + + public async $getTopChannelsNodes(full: boolean): Promise { + try { + let rows: any; + let query: string; + if (full === false) { + query = ` + SELECT + nodes.public_key as publicKey, + IF(nodes.alias = '', SUBSTRING(nodes.public_key, 1, 20), alias) as alias, + nodes.channels, + geo_names_city.names as city, geo_names_country.names as country, + geo_names_iso.names as iso_code, geo_names_subdivision.names as subdivision + FROM nodes + LEFT JOIN geo_names geo_names_country ON geo_names_country.id = nodes.country_id AND geo_names_country.type = 'country' + LEFT JOIN geo_names geo_names_city ON geo_names_city.id = nodes.city_id AND geo_names_city.type = 'city' + LEFT JOIN geo_names geo_names_iso ON geo_names_iso.id = nodes.country_id AND geo_names_iso.type = 'country_iso_code' + LEFT JOIN geo_names geo_names_subdivision on geo_names_subdivision.id = nodes.subdivision_id AND geo_names_subdivision.type = 'division' + ORDER BY channels DESC + LIMIT 6; + `; + + [rows] = await DB.query(query); + for (let i = 0; i < rows.length; ++i) { + rows[i].country = JSON.parse(rows[i].country); + rows[i].city = JSON.parse(rows[i].city); + } + } else { + query = ` + SELECT nodes.public_key AS publicKey, IF(nodes.alias = '', SUBSTRING(nodes.public_key, 1, 20), alias) as alias, + CAST(COALESCE(nodes.channels, 0) as INT) as channels, + CAST(COALESCE(nodes.capacity, 0) as INT) as capacity, + UNIX_TIMESTAMP(nodes.first_seen) as firstSeen, UNIX_TIMESTAMP(nodes.updated_at) as updatedAt, + geo_names_city.names as city, geo_names_country.names as country, + geo_names_iso.names as iso_code, geo_names_subdivision.names as subdivision + FROM nodes + LEFT JOIN geo_names geo_names_country ON geo_names_country.id = nodes.country_id AND geo_names_country.type = 'country' + LEFT JOIN geo_names geo_names_city ON geo_names_city.id = nodes.city_id AND geo_names_city.type = 'city' + LEFT JOIN geo_names geo_names_iso ON geo_names_iso.id = nodes.country_id AND geo_names_iso.type = 'country_iso_code' + LEFT JOIN geo_names geo_names_subdivision on geo_names_subdivision.id = nodes.subdivision_id AND geo_names_subdivision.type = 'division' + ORDER BY channels DESC + LIMIT 100 + `; + + [rows] = await DB.query(query); + for (let i = 0; i < rows.length; ++i) { + rows[i].country = JSON.parse(rows[i].country); + rows[i].city = JSON.parse(rows[i].city); + } + } + + return rows; + } catch (e) { + logger.err('$getTopChannelsNodes error: ' + (e instanceof Error ? e.message : e)); + throw e; + } + } + + public async $getOldestNodes(full: boolean): Promise { + try { + let [rows]: any[] = await DB.query('SELECT UNIX_TIMESTAMP(MAX(added)) as maxAdded FROM node_stats'); + const latestDate = rows[0].maxAdded; + + let query: string; + if (full === false) { + query = ` + SELECT nodes.public_key, IF(nodes.alias = '', SUBSTRING(nodes.public_key, 1, 20), alias) as alias, + node_stats.channels + FROM node_stats + JOIN nodes ON nodes.public_key = node_stats.public_key + WHERE added = FROM_UNIXTIME(${latestDate}) + ORDER BY first_seen + LIMIT 100; + `; + + [rows] = await DB.query(query); + } else { + query = ` + SELECT node_stats.public_key AS publicKey, IF(nodes.alias = '', SUBSTRING(node_stats.public_key, 1, 20), alias) as alias, + CAST(COALESCE(node_stats.channels, 0) as INT) as channels, + CAST(COALESCE(node_stats.capacity, 0) as INT) as capacity, + UNIX_TIMESTAMP(nodes.first_seen) as firstSeen, UNIX_TIMESTAMP(nodes.updated_at) as updatedAt, + geo_names_city.names as city, geo_names_country.names as country, + geo_names_iso.names as iso_code, geo_names_subdivision.names as subdivision + FROM node_stats + RIGHT JOIN nodes ON nodes.public_key = node_stats.public_key + LEFT JOIN geo_names geo_names_country ON geo_names_country.id = nodes.country_id AND geo_names_country.type = 'country' + LEFT JOIN geo_names geo_names_city ON geo_names_city.id = nodes.city_id AND geo_names_city.type = 'city' + LEFT JOIN geo_names geo_names_iso ON geo_names_iso.id = nodes.country_id AND geo_names_iso.type = 'country_iso_code' + LEFT JOIN geo_names geo_names_subdivision on geo_names_subdivision.id = nodes.subdivision_id AND geo_names_subdivision.type = 'division' + WHERE added = FROM_UNIXTIME(${latestDate}) + ORDER BY first_seen + LIMIT 100 + `; + + [rows] = await DB.query(query); + for (let i = 0; i < rows.length; ++i) { + rows[i].country = JSON.parse(rows[i].country); + rows[i].city = JSON.parse(rows[i].city); + } + } + + return rows; + } catch (e) { + logger.err('$getTopChannelsNodes error: ' + (e instanceof Error ? e.message : e)); + throw e; + } + } + + public async $searchNodeByPublicKeyOrAlias(search: string) { + try { + const publicKeySearch = search.replace(/[^a-zA-Z0-9]/g, '') + '%'; + const aliasSearch = search + .replace(/[-_.]/g, ' ') // Replace all -_. characters with empty space. Eg: "ln.nicehash" becomes "ln nicehash". + .replace(/[^a-zA-Z0-9 ]/g, '') // Remove all special characters and keep just A to Z, 0 to 9. + .split(' ') + .filter(key => key.length) + .map((search) => '+' + search + '*').join(' '); + // %keyword% is wildcard search and can't be indexed so it's slower as the node database grow. keyword% can be indexed but then you can't search for "Nicehash" and get result for ln.nicehash.com. So we use fulltext index for words "ln, nicehash, com" and nicehash* will find it instantly. + const query = `SELECT public_key, alias, capacity, channels, status FROM nodes WHERE public_key LIKE ? OR MATCH alias_search AGAINST (? IN BOOLEAN MODE) ORDER BY capacity DESC LIMIT 10`; + const [rows]: any = await DB.query(query, [publicKeySearch, aliasSearch]); + return rows; + } catch (e) { + logger.err('$searchNodeByPublicKeyOrAlias error: ' + (e instanceof Error ? e.message : e)); + throw e; + } + } + + public async $getNodesISPRanking() { + try { + let query = ''; + + // List all channels and the two linked ISP + query = ` + SELECT short_id, channels.capacity, + channels.node1_public_key AS node1PublicKey, isp1.names AS isp1, isp1.id as isp1ID, + channels.node2_public_key AS node2PublicKey, isp2.names AS isp2, isp2.id as isp2ID + FROM channels + JOIN nodes node1 ON node1.public_key = channels.node1_public_key + JOIN nodes node2 ON node2.public_key = channels.node2_public_key + JOIN geo_names isp1 ON isp1.id = node1.as_number + JOIN geo_names isp2 ON isp2.id = node2.as_number + WHERE channels.status = 1 + ORDER BY short_id DESC + `; + const [channelsIsp]: any = await DB.query(query); + + // Sum channels capacity and node count per ISP + const ispList = {}; + for (const channel of channelsIsp) { + const isp1 = JSON.parse(channel.isp1); + const isp2 = JSON.parse(channel.isp2); + + if (!ispList[isp1]) { + ispList[isp1] = { + ids: [channel.isp1ID], + capacity: 0, + channels: 0, + nodes: {}, + }; + } else if (ispList[isp1].ids.includes(channel.isp1ID) === false) { + ispList[isp1].ids.push(channel.isp1ID); + } + + if (!ispList[isp2]) { + ispList[isp2] = { + ids: [channel.isp2ID], + capacity: 0, + channels: 0, + nodes: {}, + }; + } else if (ispList[isp2].ids.includes(channel.isp2ID) === false) { + ispList[isp2].ids.push(channel.isp2ID); + } + + ispList[isp1].capacity += channel.capacity; + ispList[isp1].channels += 1; + ispList[isp1].nodes[channel.node1PublicKey] = true; + ispList[isp2].capacity += channel.capacity; + ispList[isp2].channels += 1; + ispList[isp2].nodes[channel.node2PublicKey] = true; + } + + const ispRanking: any[] = []; + for (const isp of Object.keys(ispList)) { + ispRanking.push([ + ispList[isp].ids.sort((a, b) => a - b).join(','), + isp, + ispList[isp].capacity, + ispList[isp].channels, + Object.keys(ispList[isp].nodes).length, + ]); + } + + // Total active channels capacity + query = `SELECT SUM(capacity) AS capacity FROM channels WHERE status = 1`; + const [totalCapacity]: any = await DB.query(query); + + // Get the total capacity of all channels which have at least one node on clearnet + query = ` + SELECT SUM(capacity) as capacity + FROM ( + SELECT capacity, GROUP_CONCAT(socket1.type, socket2.type) as networks + FROM channels + JOIN nodes_sockets socket1 ON node1_public_key = socket1.public_key + JOIN nodes_sockets socket2 ON node2_public_key = socket2.public_key + AND channels.status = 1 + GROUP BY short_id + ) channels_tmp + WHERE channels_tmp.networks LIKE '%ipv%' + `; + const [clearnetCapacity]: any = await DB.query(query); + + // Get the total capacity of all channels which have both nodes on Tor + query = ` + SELECT SUM(capacity) as capacity + FROM ( + SELECT capacity, GROUP_CONCAT(socket1.type, socket2.type) as networks + FROM channels + JOIN nodes_sockets socket1 ON node1_public_key = socket1.public_key + JOIN nodes_sockets socket2 ON node2_public_key = socket2.public_key + AND channels.status = 1 + GROUP BY short_id + ) channels_tmp + WHERE channels_tmp.networks NOT LIKE '%ipv%' AND + channels_tmp.networks NOT LIKE '%dns%' AND + channels_tmp.networks NOT LIKE '%websocket%' + `; + const [torCapacity]: any = await DB.query(query); + + const clearnetCapacityValue = parseInt(clearnetCapacity[0].capacity, 10); + const torCapacityValue = parseInt(torCapacity[0].capacity, 10); + const unknownCapacityValue = parseInt(totalCapacity[0].capacity) - clearnetCapacityValue - torCapacityValue; + + return { + clearnetCapacity: clearnetCapacityValue, + torCapacity: torCapacityValue, + unknownCapacity: unknownCapacityValue, + ispRanking: ispRanking, + }; + } catch (e) { + logger.err(`Cannot get LN ISP ranking. Reason: ${e instanceof Error ? e.message : e}`); + throw e; + } + } + + public async $getNodesPerCountry(countryId: string) { + try { + const query = ` + SELECT nodes.public_key, CAST(COALESCE(nodes.capacity, 0) as INT) as capacity, CAST(COALESCE(nodes.channels, 0) as INT) as channels, + nodes.alias, UNIX_TIMESTAMP(nodes.first_seen) as first_seen, UNIX_TIMESTAMP(nodes.updated_at) as updated_at, + geo_names_city.names as city, geo_names_country.names as country, + geo_names_iso.names as iso_code, geo_names_subdivision.names as subdivision, + nodes.longitude, nodes.latitude, nodes.as_number, geo_names_isp.names as isp + FROM nodes + LEFT JOIN geo_names geo_names_country ON geo_names_country.id = nodes.country_id AND geo_names_country.type = 'country' + LEFT JOIN geo_names geo_names_city ON geo_names_city.id = nodes.city_id AND geo_names_city.type = 'city' + LEFT JOIN geo_names geo_names_iso ON geo_names_iso.id = nodes.country_id AND geo_names_iso.type = 'country_iso_code' + LEFT JOIN geo_names geo_names_subdivision on geo_names_subdivision.id = nodes.subdivision_id AND geo_names_subdivision.type = 'division' + LEFT JOIN geo_names geo_names_isp on geo_names_isp.id = nodes.as_number AND geo_names_isp.type = 'as_organization' + WHERE geo_names_country.id = ? + ORDER BY capacity DESC + `; + + const [rows]: any = await DB.query(query, [countryId]); + for (let i = 0; i < rows.length; ++i) { + rows[i].country = JSON.parse(rows[i].country); + rows[i].city = JSON.parse(rows[i].city); + rows[i].subdivision = JSON.parse(rows[i].subdivision); + rows[i].isp = JSON.parse(rows[i].isp); + } + return rows; + } catch (e) { + logger.err(`Cannot get nodes for country id ${countryId}. Reason: ${e instanceof Error ? e.message : e}`); + throw e; + } + } + + public async $getNodesPerISP(ISPId: string) { + try { + let query = ` + SELECT channels.node1_public_key AS node1PublicKey, isp1.id as isp1ID, + channels.node2_public_key AS node2PublicKey, isp2.id as isp2ID + FROM channels + JOIN nodes node1 ON node1.public_key = channels.node1_public_key + JOIN nodes node2 ON node2.public_key = channels.node2_public_key + JOIN geo_names isp1 ON isp1.id = node1.as_number + JOIN geo_names isp2 ON isp2.id = node2.as_number + WHERE channels.status = 1 AND (node1.as_number IN (?) OR node2.as_number IN (?)) + ORDER BY short_id DESC + `; + + const IPSIds = ISPId.split(','); + const [rows]: any = await DB.query(query, [IPSIds, IPSIds]); + if (!rows || rows.length === 0) { + return []; + } + + const nodes = {}; + + const intISPIds: number[] = []; + for (const ispId of IPSIds) { + intISPIds.push(parseInt(ispId, 10)); + } + + for (const channel of rows) { + if (intISPIds.includes(channel.isp1ID)) { + nodes[channel.node1PublicKey] = true; + } + if (intISPIds.includes(channel.isp2ID)) { + nodes[channel.node2PublicKey] = true; + } + } + + query = ` + SELECT nodes.public_key, CAST(COALESCE(nodes.capacity, 0) as INT) as capacity, CAST(COALESCE(nodes.channels, 0) as INT) as channels, + nodes.alias, UNIX_TIMESTAMP(nodes.first_seen) as first_seen, UNIX_TIMESTAMP(nodes.updated_at) as updated_at, + geo_names_city.names as city, geo_names_country.names as country, + geo_names_iso.names as iso_code, geo_names_subdivision.names as subdivision, + nodes.longitude, nodes.latitude + FROM nodes + LEFT JOIN geo_names geo_names_country ON geo_names_country.id = nodes.country_id AND geo_names_country.type = 'country' + LEFT JOIN geo_names geo_names_city ON geo_names_city.id = nodes.city_id AND geo_names_city.type = 'city' + LEFT JOIN geo_names geo_names_iso ON geo_names_iso.id = nodes.country_id AND geo_names_iso.type = 'country_iso_code' + LEFT JOIN geo_names geo_names_subdivision on geo_names_subdivision.id = nodes.subdivision_id AND geo_names_subdivision.type = 'division' + WHERE nodes.public_key IN (?) + ORDER BY capacity DESC + `; + + const [rows2]: any = await DB.query(query, [Object.keys(nodes)]); + for (let i = 0; i < rows2.length; ++i) { + rows2[i].country = JSON.parse(rows2[i].country); + rows2[i].city = JSON.parse(rows2[i].city); + rows2[i].subdivision = JSON.parse(rows2[i].subdivision); + } + return rows2; + + } catch (e) { + logger.err(`Cannot get nodes for ISP id ${ISPId}. Reason: ${e instanceof Error ? e.message : e}`); + throw e; + } + } + + public async $getNodesCountries() { + try { + let query = `SELECT geo_names.names as names, geo_names_iso.names as iso_code, COUNT(DISTINCT nodes.public_key) as nodesCount, SUM(capacity) as capacity + FROM nodes + JOIN geo_names ON geo_names.id = nodes.country_id AND geo_names.type = 'country' + JOIN geo_names geo_names_iso ON geo_names_iso.id = nodes.country_id AND geo_names_iso.type = 'country_iso_code' + GROUP BY country_id + ORDER BY COUNT(DISTINCT nodes.public_key) DESC + `; + const [nodesCountPerCountry]: any = await DB.query(query); + + query = `SELECT COUNT(*) as total FROM nodes WHERE country_id IS NOT NULL`; + const [nodesWithAS]: any = await DB.query(query); + + const nodesPerCountry: any[] = []; + for (const country of nodesCountPerCountry) { + nodesPerCountry.push({ + name: JSON.parse(country.names), + iso: country.iso_code, + count: country.nodesCount, + share: Math.floor(country.nodesCount / nodesWithAS[0].total * 10000) / 100, + capacity: country.capacity, + }) + } + + return nodesPerCountry; + } catch (e) { + logger.err(`Cannot get nodes grouped by AS. Reason: ${e instanceof Error ? e.message : e}`); + throw e; + } + } + + /** + * Save or update a node present in the graph + */ + public async $saveNode(node: ILightningApi.Node): Promise { + try { + // https://github.com/mempool/mempool/issues/3006 + if ((node.last_update ?? 0) < 1514736061) { // January 1st 2018 + node.last_update = null; + } + + const uniqueAddr = [...new Set(node.addresses?.map(a => a.addr))]; + const formattedSockets = (uniqueAddr.join(',')) ?? ''; + + const query = `INSERT INTO nodes( + public_key, + first_seen, + updated_at, + alias, + alias_search, + color, + sockets, + status, + features + ) + VALUES (?, NOW(), FROM_UNIXTIME(?), ?, ?, ?, ?, 1, ?) + ON DUPLICATE KEY UPDATE + updated_at = FROM_UNIXTIME(?), + alias = ?, + alias_search = ?, + color = ?, + sockets = ?, + status = 1, + features = ? + `; + + await DB.query(query, [ + node.pub_key, + node.last_update, + node.alias, + this.aliasToSearchText(node.alias), + node.color, + formattedSockets, + JSON.stringify(node.features), + node.last_update, + node.alias, + this.aliasToSearchText(node.alias), + node.color, + formattedSockets, + JSON.stringify(node.features), + ]); + } catch (e) { + logger.err('$saveNode() error: ' + (e instanceof Error ? e.message : e)); + } + } + + /** + * Update node sockets + */ + public async $updateNodeSockets(publicKey: string, sockets: {network: string; addr: string}[]): Promise { + const uniqueAddr = [...new Set(sockets.map(a => a.addr))]; + + const formattedSockets = (uniqueAddr.join(',')) ?? ''; + try { + await DB.query(`UPDATE nodes SET sockets = ? WHERE public_key = ?`, [formattedSockets, publicKey]); + } catch (e) { + logger.err(`Cannot update node sockets for ${publicKey}. Reason: ${e instanceof Error ? e.message : e}`); + } + } + + /** + * Set all nodes not in `nodesPubkeys` as inactive (status = 0) + */ + public async $setNodesInactive(graphNodesPubkeys: string[]): Promise { + if (graphNodesPubkeys.length === 0) { + return; + } + + try { + const result = await DB.query(` + UPDATE nodes + SET status = 0 + WHERE public_key NOT IN ( + ${graphNodesPubkeys.map(pubkey => `"${pubkey}"`).join(',')} + ) + `); + if (result[0].changedRows ?? 0 > 0) { + logger.debug(`Marked ${result[0].changedRows} nodes as inactive because they are not in the graph`, logger.tags.ln); + } + } catch (e) { + logger.err('$setNodesInactive() error: ' + (e instanceof Error ? e.message : e)); + } + } + + private aliasToSearchText(str: string): string { + return str.replace(/[-_.]/g, ' ').replace(/[^a-zA-Z0-9 ]/g, ''); + } +} + +export default new NodesApi(); diff --git a/backend/src/api/explorer/nodes.routes.ts b/backend/src/api/explorer/nodes.routes.ts new file mode 100644 index 0000000000..9d63738455 --- /dev/null +++ b/backend/src/api/explorer/nodes.routes.ts @@ -0,0 +1,382 @@ +import config from '../../config'; +import { Application, Request, Response } from 'express'; +import nodesApi from './nodes.api'; +import DB from '../../database'; +import { INodesRanking } from '../../mempool.interfaces'; + +class NodesRoutes { + constructor() { } + + public initRoutes(app: Application) { + app + .get(config.MEMPOOL.API_URL_PREFIX + 'lightning/nodes/world', this.$getWorldNodes) + .get(config.MEMPOOL.API_URL_PREFIX + 'lightning/nodes/country/:country', this.$getNodesPerCountry) + .get(config.MEMPOOL.API_URL_PREFIX + 'lightning/nodes/search/:search', this.$searchNode) + .get(config.MEMPOOL.API_URL_PREFIX + 'lightning/nodes/isp-ranking', this.$getISPRanking) + .get(config.MEMPOOL.API_URL_PREFIX + 'lightning/nodes/isp/:isp', this.$getNodesPerISP) + .get(config.MEMPOOL.API_URL_PREFIX + 'lightning/nodes/countries', this.$getNodesCountries) + .get(config.MEMPOOL.API_URL_PREFIX + 'lightning/nodes/rankings', this.$getNodesRanking) + .get(config.MEMPOOL.API_URL_PREFIX + 'lightning/nodes/rankings/liquidity', this.$getTopNodesByCapacity) + .get(config.MEMPOOL.API_URL_PREFIX + 'lightning/nodes/rankings/connectivity', this.$getTopNodesByChannels) + .get(config.MEMPOOL.API_URL_PREFIX + 'lightning/nodes/rankings/age', this.$getOldestNodes) + .get(config.MEMPOOL.API_URL_PREFIX + 'lightning/nodes/:public_key/statistics', this.$getHistoricalNodeStats) + .get(config.MEMPOOL.API_URL_PREFIX + 'lightning/nodes/:public_key/fees/histogram', this.$getFeeHistogram) + .get(config.MEMPOOL.API_URL_PREFIX + 'lightning/nodes/:public_key', this.$getNode) + .get(config.MEMPOOL.API_URL_PREFIX + 'lightning/nodes/group/:name', this.$getNodeGroup) + ; + } + + private async $searchNode(req: Request, res: Response) { + try { + const nodes = await nodesApi.$searchNodeByPublicKeyOrAlias(req.params.search); + res.json(nodes); + } catch (e) { + res.status(500).send(e instanceof Error ? e.message : e); + } + } + + private async $getNodeGroup(req: Request, res: Response) { + try { + let nodesList; + let nodes: any[] = []; + switch (config.MEMPOOL.NETWORK) { + case 'testnet': + nodesList = [ + '0259db43b4e4ac0ff12a805f2d81e521253ba2317f6739bc611d8e2fa156d64256', + '0352b9944b9a52bd2116c91f1ba70c4ef851ac5ba27e1b20f1d92da3ade010dd10', + '03424f5a7601eaa47482cb17100b31a84a04d14fb44b83a57eeceffd8e299878e3', + '032850492ee61a5f7006a2fda6925e4b4ec3782f2b6de2ff0e439ef5a38c3b2470', + '022c80bace98831c44c32fb69755f2b353434e0ee9e7fbda29507f7ef8abea1421', + '02c3559c833e6f99f9ca05fe503e0b4e7524dea9121344edfd3e811101e0c28680', + '02b36a324fa2dd3af2a63ac65f241907882829bed5002b4e14171d25c219e0d470', + '0231b6e8f21f9f6c057f6bf8a812f79e396ee16a66ece91939a1576ce9fb9e87a5', + '034b6aac206bffcbd651b7ead1ab8a0991c945dfafe19ff27dcdeadc6843ebd15c', + '039c065f7e344acd969ebdd4a94550915b6f24e8782ae2be540bb96c8a4fcfb86b', + '03d9f9f4803fc75920f14dd13d83fbecc53229a65d4ee4cd2d86fdf211f7337576', + '0357fe48c4dece744f70865eda66e396aab5d05e09e1145cd3b7da83f11446d4cf', + '02bca4d642eda631f2c8659758e2a2868e518b93503f2bfcd767749c6530a10679', + '03f32c99c0bb9f62dae53671d1d300565773455248f34134cc02779b881561174e', + '032c7c7819276c4f706a04df1a0f1e10a5495994a7be4c1d3d28ca766e5a2b957b', + '025a7e38c2834dd843591a4d23d5f09cdeb77ddca85f673c2d944a14220ff14cf7', + '0395e2731a1673ef21d7a16a727c4fc4d4c35a861c428ce2c819c53d2b81c8bd55', + '032ab2028c0b614c6d87824e2373529652fd7e4221b4c70cc4da7c7005c49afcf0', + '029001b22fe70b48bee12d014df91982eb85ff1bd404ec772d5c83c4ee3e88d2c3', + '0212e2848d79f928411da5f2ff0a8c95ec6ccb5a09d2031b6f71e91309dcde63af', + '03e871a2229523d34f76e6311ff197cfe7f26c2fbec13554b93a46f4e710c47dab', + '032202ec98d976b0e928bd1d91924e8bd3eab07231fc39feb3737b010071073df8', + '02fa7c5a948d03d563a9f36940c2205a814e594d17c0042ced242c71a857d72605', + '039c14fdec2d958e3d14cebf657451bbd9e039196615785e82c917f274e3fb2205', + '033589bbcb233ffc416cefd5437c7f37e9d7cb7942d405e39e72c4c846d9b37f18', + '029293110441c6e2eacb57e1255bf6ef05c41a6a676fe474922d33c19f98a7d584', + '038eb09bed4532ff36d12acc1279f55cbe8d95212d19f809e057bb50de00051fba', + '027b7c0278366a0268e8bd0072b14539f6cb455a7bd588ae22d888bed541f65311', + '02f4dd78f6eda8838029b2cdbaaea6e875e2fa373cd348ee41a7c1bb177d3fca66', + '036b3fb692da214a3edaac5b67903b958f5ccd8712e09aa61b67ea7acfd94b40c2', + '023bc8915d308e0b65f8de6867f95960141372436fce3edad5cec3f364d6ac948f', + '0341690503ef21d0e203dddd9e62646380d0dfc32c499e055e7f698b9064d1c736', + '0355d573805c018a37a5b2288378d70e9b5b438f7394abd6f467cb9b47c90eeb93', + '0361aa68deb561a8b47b41165848edcccb98a1b56a5ea922d9d5b30a09bb7282ea', + '0235ad0b56ed8c42c4354444c24e971c05e769ec0b5fb0ccea42880095dc02ea2c', + '029700819a37afea630f80e6cc461f3fd3c4ace2598a21cfbbe64d1c78d0ee69a5', + '02c2d8b2dbf87c7894af2f1d321290e2fe6db5446cd35323987cee98f06e2e0075', + '030b0ca1ea7b1075716d2a555630e6fd47ef11bc7391fe68963ec06cf370a5e382', + '031adb9eb2d66693f85fa31a4adca0319ba68219f3ad5f9a2ef9b34a6b40755fa1', + '02ccd07faa47eda810ecf5591ccf5ca50f6c1034d0d175052898d32a00b9bae24f', + ]; + break; + case 'signet': + nodesList = [ + '029fe3621fc0c6e08056a14b868f8fb9acca1aa28a129512f6cea0f0d7654d9f92', + '02f60cd7a3a4f1c953dd9554a6ebd51a34f8b10b8124b7fc43a0b381139b55c883', + '03cbbf581774700865eebd1be42d022bc004ba30881274ab304e088a25d70e773d', + '0243348cb3741cfe2d8485fa8375c29c7bc7cbb67577c363cb6987a5e5fd0052cc', + '02cb73e631af44bee600d80f8488a9194c9dc5c7590e575c421a070d1be05bc8e9', + '0306f55ee631aa1e2cd4d9b2bfcbc14404faec5c541cef8b2e6f779061029d09c4', + '030bbbd8495561a894e301fe6ba5b22f8941fc661cc0e673e0206158231d8ac130', + '03ee1f08e516ed083475f39c6cae4fa1eec686d004d2f105218269e27d7f2da5a4', + '028c378b998f476ed22d6815c170dd2a3388a43fdf791a7cff70b9997349b8447a', + '036f19f044d19cb1b04f14d91b6e7e5443ce337217a8c14d43861f3e86dd07bd7f', + '03058d61869e8b88436493648b2e3e530627edf5a0b253c285cd565c1477a5c237', + '0279dfedc87b47a941f1797f2c422c03aa3108914ea6b519d76537d60860535a9a', + '0353486b8016761e58ec8aee7305ee58d5dc66b55ef5bd8cbaf49508f66d52d62e', + '03df5db8eccfabcae47ff15553cfdecb2d3f56979f43a0c3578f28d056b5e35104', + '03ddab321b760433cbf561b615ef62ac7d318630c5f51d523aaf5395b90b751956', + '033d92c7bfd213ef1b34c90e985fb5dc77f9ec2409d391492484e57a44c4aca1de', + '02ad010dda54253c1eb9efe38b0760657a3b43ecad62198c359c051c9d99d45781', + '025196512905b8a3f1597428b867bec63ec9a95e5089eb7dc7e63e2d2691669029', + '027c625aa1fbe3768db68ebcb05b53b6dc0ce68b7b54b8900d326d167363e684fe', + '03f1629af3101fcc56b7aac2667016be84e3defbf3d0c8719f836c9b41c9a57a43', + '02dfb81e2f7a3c4c9e8a51b70ef82b4a24549cc2fab1f5b2fd636501774a918991', + '02d01ccf832944c68f10d39006093769c5b8bda886d561b128534e313d729fdb34', + '02499ed23027d4698a6904ff4ec1b6085a61f10b9a6937f90438f9947e38e8ea86', + '038310e3a786340f2bd7770704c7ccfe560fd163d9a1c99d67894597419d12cbf7', + '03e5e9d879b72c7d67ecd483bae023bd33e695bb32b981a4021260f7b9d62bc761', + '028d16e1a0ace4c0c0a421536d8d32ce484dfe6e2f726b7b0e7c30f12a195f8cc7', + '0326cf9a4ca67a5b9cdffae57293dbd6f7c5113b93010dc6f6fe4af3afde1a1739', + '034867e16f62cebb8c2c2c22b91117c173bbece9c8a1e5bd001374a3699551cd8f', + '038dfb1f1b637a8c27e342ffc6f9feca20e0b47be3244e09ae78df4998e2ae83b9', + '03cb1cea3394d973355c11bc61c2f689f9d3e1c3db60d205f27770f5ad83200f77', + '03535447b592cbdb153189b3e06a455452b1011380cb3e6511a31090c15d8efc9f', + '028e90e9984d262ebfa3c23fb3f335a2ae061a0bdedee03f45f72b438d9e7d2ce3', + '03ee0176289dc4a6111fa5ef22eed5273758c420fbe58cc1d2d76def75dd7e640c', + '0370b2cd9f0eaf436d5c25c93fb39210d8cc06b31f688fc2f54418aabe394aed79', + '02ff690d06c187ab994bf83c5a2114fe5bf50112c2c817af0f788f736be9fa2070', + '02a9f570c51a2526a5ee85802e88f9281bed771eb66a0c8a7d898430dd5d0eae45', + '038c3de773255d3bd7a50e31e58d423baac5c90826a74d75e64b74c95475de1097', + '0242c7f7d315095f37ad1421ae0a2fc967d4cbe65b61b079c5395a769436959853', + '02a909e70eb03742f12666ebb1f56ac42a5fbaab0c0e8b5b1df4aa9f10f8a09240', + '03a26efa12489803c07f3ac2f1dba63812e38f0f6e866ce3ebb34df7de1f458cd2', + ]; + break; + default: + nodesList = [ + '02b12b889fe3c943cb05645921040ef13d6d397a2e7a4ad000e28500c505ff26d6', + '0302240ac9d71b39617cbde2764837ec3d6198bd6074b15b75d2ff33108e89d2e1', + '03364a8ace313376e5e4b68c954e287c6388e16df9e9fdbaf0363ecac41105cbf6', + '03229ab4b7f692753e094b93df90530150680f86b535b5183b0cffd75b3df583fc', + '03a696eb7acde991c1be97a58a9daef416659539ae462b897f5e9ae361f990228e', + '0248bf26cf3a63ab8870f34dc0ec9e6c8c6288cdba96ba3f026f34ec0f13ac4055', + '021b28ecdd782fd909705d6be354db268977b1a2ac5a5275186fc19e08bb8fca93', + '031bec1fbd8eb7fe94d2bda108c9c3cc8c22ecfc1c3a5c11d36f5881b01b4a81a6', + '03879c4f827a3188574d5757e002f574265a966d70aea942169785b31369b067d5', + '0228d4b5a4fd73a03967b76f8b8cb37b9d0b6e7039126a9397bb732c15bed78e9b', + '03f58dbb629f4427f5a1dbc02e6a7ec79345fdf13a0e4163d4f3b7aea2539cf095', + '021cdcb8123aa670cdfc9f43909dbb297363c093883409e9e7fc82e7267f7c72bd', + '02f2aa2c2b7b432a70dc4d0b04afa19d48715ed3b90594d49c1c8744f2e9ebb030', + '03709a02fb3ab4857689a8ea0bd489a6ab6f56f8a397be578bc6d5ad22efbe3756', + '03fbc17549ec667bccf397ababbcb4cdc0e3394345e4773079ab2774612ec9be61', + '03da9a8623241ccf95f19cd645c6cecd4019ac91570e976eb0a128bebbc4d8a437', + '03ca5340cf85cb2e7cf076e489f785410838de174e40be62723e8a60972ad75144', + '0238bd27f02d67d6c51e269692bc8c9a32357a00e7777cba7f4f1f18a2a700b108', + '03f983dcabed6baa1eab5b56c8b2e8fdc846ab3fd931155377897335e85a9fa57c', + '03e399589533581e48796e29a825839a010036a61b20744fda929d6709fcbffcc5', + '021f5288b5f72c42cd0d8801086af7ce09a816d8ee9a4c47a4b436399b26cb601a', + '032b01b7585f781420cd4148841a82831ba37fa952342052cec16750852d4f2dd9', + '02848036488d4b8fb1f1c4064261ec36151f43b085f0b51bd239ade3ddfc940c34', + '02b6b1640fe029e304c216951af9fbefdb23b0bdc9baaf327540d31b6107841fdf', + '03694289827203a5b3156d753071ddd5bf92e371f5a462943f9555eef6d2d6606c', + '0283d850db7c3e8ea7cc9c4abc7afaab12bbdf72b677dcba1d608350d2537d7d43', + '03b4dda7878d3b7b71ecd6d4738322c7f9a9c1fb583374d2724f4ccc4947f37570', + '0279a35f05b5acf159429549e56fd426685c4fec191431c58738968bbc77a39f25', + '03cb102d796ddcf08610cd03fae8b7a1df69ff48e9e8a152af315f9edf71762eb8', + '036b89526f4d5ac4c317f4fd23cb9f8e4ad844498bc7950a41114d060101d995d4', + '0313eade145959d7036db009fd5b0bf1947a739c7c3c790b491ec9161b94e6ad1e', + '02b670ca4c4bb2c5ea89c3b691da98a194cfc48fcd5c072df02a20290bddd60610', + '02a9196d5e08598211397a83cf013a5962b84bd61198abfdd204dff987e54f7a0d', + '036d015cd2f486fb38348182980b7e596e6c9733873102ea126fed7b4152be03b8', + '02521287789f851268a39c9eccc9d6180d2c614315b583c9e6ae0addbd6d79df06', + '0258c2a7b7f8af2585b4411b1ec945f70988f30412bb1df179de941f14d0b1bc3e', + '03c3389ff1a896f84d921ed01a19fc99c6724ce8dc4b960cd3b7b2362b62cd60d7', + '038d118996b3eaa15dcd317b32a539c9ecfdd7698f204acf8a087336af655a9192', + '02a928903d93d78877dacc3642b696128a3636e9566dd42d2d132325b2c8891c09', + '0328cd17f3a9d3d90b532ade0d1a67e05eb8a51835b3dce0a2e38eac04b5a62a57', + ]; + } + + for (let pubKey of nodesList) { + try { + const node = await nodesApi.$getNode(pubKey); + if (node) { + nodes.push(node); + } + } catch (e) {} + } + + res.header('Pragma', 'public'); + res.header('Cache-control', 'public'); + res.setHeader('Expires', new Date(Date.now() + 1000 * 60).toUTCString()); + res.json(nodes); + } catch (e) { + res.status(500).send(e instanceof Error ? e.message : e); + } + } + + private async $getNode(req: Request, res: Response) { + try { + const node = await nodesApi.$getNode(req.params.public_key); + if (!node) { + res.status(404).send('Node not found'); + return; + } + res.header('Pragma', 'public'); + res.header('Cache-control', 'public'); + res.setHeader('Expires', new Date(Date.now() + 1000 * 60).toUTCString()); + res.json(node); + } catch (e) { + res.status(500).send(e instanceof Error ? e.message : e); + } + } + + private async $getHistoricalNodeStats(req: Request, res: Response) { + try { + const statistics = await nodesApi.$getNodeStats(req.params.public_key); + res.header('Pragma', 'public'); + res.header('Cache-control', 'public'); + res.setHeader('Expires', new Date(Date.now() + 1000 * 60).toUTCString()); + res.json(statistics); + } catch (e) { + res.status(500).send(e instanceof Error ? e.message : e); + } + } + + private async $getFeeHistogram(req: Request, res: Response) { + try { + const node = await nodesApi.$getFeeHistogram(req.params.public_key); + if (!node) { + res.status(404).send('Node not found'); + return; + } + res.header('Pragma', 'public'); + res.header('Cache-control', 'public'); + res.setHeader('Expires', new Date(Date.now() + 1000 * 60).toUTCString()); + res.json(node); + } catch (e) { + res.status(500).send(e instanceof Error ? e.message : e); + } + } + + private async $getNodesRanking(req: Request, res: Response): Promise { + try { + const topCapacityNodes = await nodesApi.$getTopCapacityNodes(false); + const topChannelsNodes = await nodesApi.$getTopChannelsNodes(false); + res.header('Pragma', 'public'); + res.header('Cache-control', 'public'); + res.setHeader('Expires', new Date(Date.now() + 1000 * 60).toUTCString()); + res.json({ + topByCapacity: topCapacityNodes, + topByChannels: topChannelsNodes, + }); + } catch (e) { + res.status(500).send(e instanceof Error ? e.message : e); + } + } + + private async $getTopNodesByCapacity(req: Request, res: Response): Promise { + try { + const topCapacityNodes = await nodesApi.$getTopCapacityNodes(true); + res.header('Pragma', 'public'); + res.header('Cache-control', 'public'); + res.setHeader('Expires', new Date(Date.now() + 1000 * 60).toUTCString()); + res.json(topCapacityNodes); + } catch (e) { + res.status(500).send(e instanceof Error ? e.message : e); + } + } + + private async $getTopNodesByChannels(req: Request, res: Response): Promise { + try { + const topCapacityNodes = await nodesApi.$getTopChannelsNodes(true); + res.header('Pragma', 'public'); + res.header('Cache-control', 'public'); + res.setHeader('Expires', new Date(Date.now() + 1000 * 60).toUTCString()); + res.json(topCapacityNodes); + } catch (e) { + res.status(500).send(e instanceof Error ? e.message : e); + } + } + + private async $getOldestNodes(req: Request, res: Response): Promise { + try { + const topCapacityNodes = await nodesApi.$getOldestNodes(true); + res.header('Pragma', 'public'); + res.header('Cache-control', 'public'); + res.setHeader('Expires', new Date(Date.now() + 1000 * 60).toUTCString()); + res.json(topCapacityNodes); + } catch (e) { + res.status(500).send(e instanceof Error ? e.message : e); + } + } + + private async $getISPRanking(req: Request, res: Response): Promise { + try { + const nodesPerAs = await nodesApi.$getNodesISPRanking(); + res.header('Pragma', 'public'); + res.header('Cache-control', 'public'); + res.setHeader('Expires', new Date(Date.now() + 1000 * 600).toUTCString()); + res.json(nodesPerAs); + } catch (e) { + res.status(500).send(e instanceof Error ? e.message : e); + } + } + + private async $getWorldNodes(req: Request, res: Response) { + try { + const worldNodes = await nodesApi.$getWorldNodes(); + res.header('Pragma', 'public'); + res.header('Cache-control', 'public'); + res.setHeader('Expires', new Date(Date.now() + 1000 * 600).toUTCString()); + res.json(worldNodes); + } catch (e) { + res.status(500).send(e instanceof Error ? e.message : e); + } + } + + private async $getNodesPerCountry(req: Request, res: Response) { + try { + const [country]: any[] = await DB.query( + `SELECT geo_names.id, geo_names_country.names as country_names + FROM geo_names + JOIN geo_names geo_names_country on geo_names.id = geo_names_country.id AND geo_names_country.type = 'country' + WHERE geo_names.type = 'country_iso_code' AND geo_names.names = ?`, + [req.params.country] + ); + + if (country.length === 0) { + res.status(404).send(`This country does not exist or does not host any lightning nodes on clearnet`); + return; + } + + const nodes = await nodesApi.$getNodesPerCountry(country[0].id); + res.header('Pragma', 'public'); + res.header('Cache-control', 'public'); + res.setHeader('Expires', new Date(Date.now() + 1000 * 60).toUTCString()); + res.json({ + country: JSON.parse(country[0].country_names), + nodes: nodes, + }); + } catch (e) { + res.status(500).send(e instanceof Error ? e.message : e); + } + } + + private async $getNodesPerISP(req: Request, res: Response) { + try { + const [isp]: any[] = await DB.query( + `SELECT geo_names.names as isp_name + FROM geo_names + WHERE geo_names.type = 'as_organization' AND geo_names.id = ?`, + [req.params.isp] + ); + + if (isp.length === 0) { + res.status(404).send(`This ISP does not exist or does not host any lightning nodes on clearnet`); + return; + } + + const nodes = await nodesApi.$getNodesPerISP(req.params.isp); + res.header('Pragma', 'public'); + res.header('Cache-control', 'public'); + res.setHeader('Expires', new Date(Date.now() + 1000 * 60).toUTCString()); + res.json({ + isp: JSON.parse(isp[0].isp_name), + nodes: nodes, + }); + } catch (e) { + res.status(500).send(e instanceof Error ? e.message : e); + } + } + + private async $getNodesCountries(req: Request, res: Response) { + try { + const nodesPerAs = await nodesApi.$getNodesCountries(); + res.header('Pragma', 'public'); + res.header('Cache-control', 'public'); + res.setHeader('Expires', new Date(Date.now() + 1000 * 600).toUTCString()); + res.json(nodesPerAs); + } catch (e) { + res.status(500).send(e instanceof Error ? e.message : e); + } + } +} + +export default new NodesRoutes(); diff --git a/backend/src/api/explorer/statistics.api.ts b/backend/src/api/explorer/statistics.api.ts new file mode 100644 index 0000000000..cab8bfc296 --- /dev/null +++ b/backend/src/api/explorer/statistics.api.ts @@ -0,0 +1,53 @@ +import logger from '../../logger'; +import DB from '../../database'; +import { Common } from '../common'; + +class StatisticsApi { + public async $getStatistics(interval: string | null = null): Promise { + interval = Common.getSqlInterval(interval); + + let query = `SELECT UNIX_TIMESTAMP(added) AS added, channel_count, total_capacity, + tor_nodes, clearnet_nodes, unannounced_nodes, clearnet_tor_nodes + FROM lightning_stats`; + + if (interval) { + query += ` WHERE added BETWEEN DATE_SUB(NOW(), INTERVAL ${interval}) AND NOW()`; + } + + query += ` ORDER BY added DESC`; + + try { + const [rows]: any = await DB.query(query); + return rows; + } catch (e) { + logger.err('$getStatistics error: ' + (e instanceof Error ? e.message : e)); + throw e; + } + } + + public async $getLatestStatistics(): Promise { + try { + const [rows]: any = await DB.query(`SELECT * FROM lightning_stats ORDER BY added DESC LIMIT 1`); + const [rows2]: any = await DB.query(`SELECT * FROM lightning_stats WHERE DATE(added) = DATE(NOW() - INTERVAL 7 DAY)`); + return { + latest: rows[0], + previous: rows2[0], + }; + } catch (e) { + logger.err('$getLatestStatistics error: ' + (e instanceof Error ? e.message : e)); + throw e; + } + } + + public async $getStatisticsCount(): Promise { + try { + const [rows]: any = await DB.query(`SELECT count(*) as count FROM lightning_stats`); + return rows[0].count; + } catch (e) { + logger.err('$getLatestStatistics error: ' + (e instanceof Error ? e.message : e)); + throw e; + } + } +} + +export default new StatisticsApi(); diff --git a/backend/src/api/fee-api.ts b/backend/src/api/fee-api.ts index dfca7f96ae..24fd25a4bd 100644 --- a/backend/src/api/fee-api.ts +++ b/backend/src/api/fee-api.ts @@ -1,47 +1,82 @@ +import { MempoolBlock } from '../mempool.interfaces'; +import config from '../config'; +import mempool from './mempool'; import projectedBlocks from './mempool-blocks'; -import { DB } from '../database'; + +const isLiquid = config.MEMPOOL.NETWORK === 'liquid' || config.MEMPOOL.NETWORK === 'liquidtestnet'; + +interface RecommendedFees { + fastestFee: number, + halfHourFee: number, + hourFee: number, + economyFee: number, + minimumFee: number, +} class FeeApi { constructor() { } - public getRecommendedFee() { + defaultFee = isLiquid ? 0.1 : 1; + minimumIncrement = isLiquid ? 0.1 : 1; + + public getRecommendedFee(): RecommendedFees { const pBlocks = projectedBlocks.getMempoolBlocks(); + const mPool = mempool.getMempoolInfo(); + const minimumFee = this.roundUpToNearest(mPool.mempoolminfee * 100000, this.minimumIncrement); + const defaultMinFee = Math.max(minimumFee, this.defaultFee); + if (!pBlocks.length) { return { - 'fastestFee': 0, - 'halfHourFee': 0, - 'hourFee': 0, + 'fastestFee': defaultMinFee, + 'halfHourFee': defaultMinFee, + 'hourFee': defaultMinFee, + 'economyFee': minimumFee, + 'minimumFee': minimumFee, }; } - let firstMedianFee = Math.ceil(pBlocks[0].medianFee); - if (pBlocks.length === 1 && pBlocks[0].blockVSize <= 500000) { - firstMedianFee = 1; - } + const firstMedianFee = this.optimizeMedianFee(pBlocks[0], pBlocks[1]); + const secondMedianFee = pBlocks[1] ? this.optimizeMedianFee(pBlocks[1], pBlocks[2], firstMedianFee) : this.defaultFee; + const thirdMedianFee = pBlocks[2] ? this.optimizeMedianFee(pBlocks[2], pBlocks[3], secondMedianFee) : this.defaultFee; + + let fastestFee = Math.max(minimumFee, firstMedianFee); + let halfHourFee = Math.max(minimumFee, secondMedianFee); + let hourFee = Math.max(minimumFee, thirdMedianFee); + const economyFee = Math.max(minimumFee, Math.min(2 * minimumFee, thirdMedianFee)); - const secondMedianFee = pBlocks[1] ? Math.ceil(pBlocks[1].medianFee) : firstMedianFee; - const thirdMedianFee = pBlocks[2] ? Math.ceil(pBlocks[2].medianFee) : secondMedianFee; + // ensure recommendations always increase w/ priority + fastestFee = Math.max(fastestFee, halfHourFee, hourFee, economyFee); + halfHourFee = Math.max(halfHourFee, hourFee, economyFee); + hourFee = Math.max(hourFee, economyFee); + // explicitly enforce a minimum of ceil(mempoolminfee) on all recommendations. + // simply rounding up recommended rates is insufficient, as the purging rate + // can exceed the median rate of projected blocks in some extreme scenarios + // (see https://bitcoin.stackexchange.com/a/120024) return { - 'fastestFee': firstMedianFee, - 'halfHourFee': secondMedianFee, - 'hourFee': thirdMedianFee, + 'fastestFee': fastestFee, + 'halfHourFee': halfHourFee, + 'hourFee': hourFee, + 'economyFee': economyFee, + 'minimumFee': minimumFee, }; } - public async $getTransactionsForBlock(blockHeight: number): Promise { - try { - const connection = await DB.pool.getConnection(); - const query = `SELECT feePerVsize AS fpv FROM transactions WHERE blockheight = ? ORDER BY feePerVsize ASC`; - const [rows] = await connection.query(query, [blockHeight]); - connection.release(); - return rows; - } catch (e) { - console.log('$getTransactionsForBlock() error', e); - return []; + private optimizeMedianFee(pBlock: MempoolBlock, nextBlock: MempoolBlock | undefined, previousFee?: number): number { + const useFee = previousFee ? (pBlock.medianFee + previousFee) / 2 : pBlock.medianFee; + if (pBlock.blockVSize <= 500000) { + return this.defaultFee; } + if (pBlock.blockVSize <= 950000 && !nextBlock) { + const multiplier = (pBlock.blockVSize - 500000) / 500000; + return Math.max(Math.round(useFee * multiplier), this.defaultFee); + } + return this.roundUpToNearest(useFee, this.minimumIncrement); } + private roundUpToNearest(value: number, nearest: number): number { + return Math.ceil(value / nearest) * nearest; + } } export default new FeeApi(); diff --git a/backend/src/api/fetch-version.ts b/backend/src/api/fetch-version.ts new file mode 100644 index 0000000000..cb0813c35f --- /dev/null +++ b/backend/src/api/fetch-version.ts @@ -0,0 +1,37 @@ +import fs from 'fs'; +import path from "path"; +const { spawnSync } = require('child_process'); + +function getVersion(): string { + const packageJson = fs.readFileSync('package.json').toString(); + return JSON.parse(packageJson).version; +} + +function getGitCommit(): string { + if (process.env.MEMPOOL_COMMIT_HASH) { + return process.env.MEMPOOL_COMMIT_HASH; + } else { + const gitRevParse = spawnSync('git', ['rev-parse', '--short', 'HEAD']); + if (!gitRevParse.error) { + const output = gitRevParse.stdout.toString('utf-8').replace(/[\n\r\s]+$/, ''); + if (output) { + return output; + } else { + console.log('Could not fetch git commit: No repo available'); + } + } else if (gitRevParse.error.code === 'ENOENT') { + console.log('Could not fetch git commit: Command `git` is unavailable'); + } + } + return '?'; +} + +const versionInfo = { + version: getVersion(), + gitCommit: getGitCommit() +} + +fs.writeFileSync( + path.join(__dirname, 'version.json'), + JSON.stringify(versionInfo, null, 2) + "\n" +); diff --git a/backend/src/api/fiat-conversion.ts b/backend/src/api/fiat-conversion.ts deleted file mode 100644 index 959d8ae27e..0000000000 --- a/backend/src/api/fiat-conversion.ts +++ /dev/null @@ -1,32 +0,0 @@ -import * as request from 'request'; - -class FiatConversion { - private tickers = { - 'BTCUSD': { - 'USD': 4110.78 - }, - }; - - constructor() { } - - public startService() { - console.log('Starting currency rates service'); - setInterval(this.updateCurrency.bind(this), 1000 * 60 * 60); - this.updateCurrency(); - } - - public getTickers() { - return this.tickers; - } - - private updateCurrency() { - request('https://api.opennode.co/v1/rates', { json: true }, (err, res, body) => { - if (err) { return console.log(err); } - if (body && body.data) { - this.tickers = body.data; - } - }); - } -} - -export default new FiatConversion(); diff --git a/backend/src/api/lightning/clightning/clightning-client.ts b/backend/src/api/lightning/clightning/clightning-client.ts new file mode 100644 index 0000000000..d803410639 --- /dev/null +++ b/backend/src/api/lightning/clightning/clightning-client.ts @@ -0,0 +1,270 @@ +// Imported from https://github.com/shesek/lightning-client-js + +'use strict'; + +const methods = [ + 'addgossip', + 'autocleaninvoice', + 'check', + 'checkmessage', + 'close', + 'connect', + 'createinvoice', + 'createinvoicerequest', + 'createoffer', + 'createonion', + 'decode', + 'decodepay', + 'delexpiredinvoice', + 'delinvoice', + 'delpay', + 'dev-listaddrs', + 'dev-rescan-outputs', + 'disableoffer', + 'disconnect', + 'estimatefees', + 'feerates', + 'fetchinvoice', + 'fundchannel', + 'fundchannel_cancel', + 'fundchannel_complete', + 'fundchannel_start', + 'fundpsbt', + 'getchaininfo', + 'getinfo', + 'getlog', + 'getrawblockbyheight', + 'getroute', + 'getsharedsecret', + 'getutxout', + 'help', + 'invoice', + 'keysend', + 'legacypay', + 'listchannels', + 'listconfigs', + 'listforwards', + 'listfunds', + 'listinvoices', + 'listnodes', + 'listoffers', + 'listpays', + 'listpeers', + 'listsendpays', + 'listtransactions', + 'multifundchannel', + 'multiwithdraw', + 'newaddr', + 'notifications', + 'offer', + 'offerout', + 'openchannel_abort', + 'openchannel_bump', + 'openchannel_init', + 'openchannel_signed', + 'openchannel_update', + 'pay', + 'payersign', + 'paystatus', + 'ping', + 'plugin', + 'reserveinputs', + 'sendinvoice', + 'sendonion', + 'sendonionmessage', + 'sendpay', + 'sendpsbt', + 'sendrawtransaction', + 'setchannelfee', + 'signmessage', + 'signpsbt', + 'stop', + 'txdiscard', + 'txprepare', + 'txsend', + 'unreserveinputs', + 'utxopsbt', + 'waitanyinvoice', + 'waitblockheight', + 'waitinvoice', + 'waitsendpay', + 'withdraw' +]; + + +import EventEmitter from 'events'; +import { existsSync, statSync } from 'fs'; +import { createConnection, Socket } from 'net'; +import { homedir } from 'os'; +import path from 'path'; +import { createInterface, Interface } from 'readline'; +import logger from '../../../logger'; +import { AbstractLightningApi } from '../lightning-api-abstract-factory'; +import { ILightningApi } from '../lightning-api.interface'; +import { convertAndmergeBidirectionalChannels, convertNode } from './clightning-convert'; + +class LightningError extends Error { + type: string = 'lightning'; + message: string = 'lightning-client error'; + + constructor(error) { + super(); + this.type = error.type; + this.message = error.message; + } +} + +const defaultRpcPath = path.join(homedir(), '.lightning') + , fStat = (...p) => statSync(path.join(...p)) + , fExists = (...p) => existsSync(path.join(...p)) + +export default class CLightningClient extends EventEmitter implements AbstractLightningApi { + private rpcPath: string; + private reconnectWait: number; + private reconnectTimeout; + private reqcount: number; + private client: Socket; + private rl: Interface; + private clientConnectionPromise: Promise; + + constructor(rpcPath = defaultRpcPath) { + if (!path.isAbsolute(rpcPath)) { + throw new Error('The rpcPath must be an absolute path'); + } + + if (!fExists(rpcPath) || !fStat(rpcPath).isSocket()) { + // network directory provided, use the lightning-rpc within in + if (fExists(rpcPath, 'lightning-rpc')) { + rpcPath = path.join(rpcPath, 'lightning-rpc'); + } + + // main data directory provided, default to using the bitcoin mainnet subdirectory + // to be removed in v0.2.0 + else if (fExists(rpcPath, 'bitcoin', 'lightning-rpc')) { + logger.warn(`${rpcPath}/lightning-rpc is missing, using the bitcoin mainnet subdirectory at ${rpcPath}/bitcoin instead.`, logger.tags.ln) + logger.warn(`specifying the main lightning data directory is deprecated, please specify the network directory explicitly.\n`, logger.tags.ln) + rpcPath = path.join(rpcPath, 'bitcoin', 'lightning-rpc') + } + } + + logger.debug(`Connecting to ${rpcPath}`, logger.tags.ln); + + super(); + this.rpcPath = rpcPath; + this.reconnectWait = 0.5; + this.reconnectTimeout = null; + this.reqcount = 0; + + const _self = this; + + this.client = createConnection(rpcPath).on( + 'error', () => { + _self.increaseWaitTime(); + _self.reconnect(); + } + ); + this.rl = createInterface({ input: this.client }).on( + 'error', () => { + _self.increaseWaitTime(); + _self.reconnect(); + } + ); + + this.clientConnectionPromise = new Promise(resolve => { + _self.client.on('connect', () => { + logger.info(`CLightning client connected`, logger.tags.ln); + _self.reconnectWait = 1; + resolve(); + }); + + _self.client.on('end', () => { + logger.err(`CLightning client connection closed, reconnecting`, logger.tags.ln); + _self.increaseWaitTime(); + _self.reconnect(); + }); + + _self.client.on('error', error => { + logger.err(`CLightning client connection error: ${error}`, logger.tags.ln); + _self.increaseWaitTime(); + _self.reconnect(); + }); + }); + + this.rl.on('line', line => { + line = line.trim(); + if (!line) { + return; + } + const data = JSON.parse(line); + _self.emit('res:' + data.id, data); + }); + } + + increaseWaitTime(): void { + if (this.reconnectWait >= 16) { + this.reconnectWait = 16; + } else { + this.reconnectWait *= 2; + } + } + + reconnect(): void { + const _self = this; + + if (this.reconnectTimeout) { + return; + } + + this.reconnectTimeout = setTimeout(() => { + logger.debug(`Trying to reconnect...`, logger.tags.ln); + + _self.client.connect(_self.rpcPath); + _self.reconnectTimeout = null; + }, this.reconnectWait * 1000); + } + + call(method, args = []): Promise { + const _self = this; + + const callInt = ++this.reqcount; + const sendObj = { + jsonrpc: '2.0', + method, + params: args, + id: '' + callInt + }; + + + // Wait for the client to connect + return this.clientConnectionPromise + .then(() => new Promise((resolve, reject) => { + // Wait for a response + this.once('res:' + callInt, res => res.error == null + ? resolve(res.result) + : reject(new LightningError(res.error)) + ); + + // Send the command + _self.client.write(JSON.stringify(sendObj)); + })); + } + + async $getNetworkGraph(): Promise { + const listnodes: any[] = await this.call('listnodes'); + const listchannels: any[] = await this.call('listchannels'); + const channelsList = await convertAndmergeBidirectionalChannels(listchannels['channels']); + + return { + nodes: listnodes['nodes'].map(node => convertNode(node)), + edges: channelsList, + }; + } +} + +const protify = s => s.replace(/-([a-z])/g, m => m[1].toUpperCase()); + +methods.forEach(k => { + CLightningClient.prototype[protify(k)] = function (...args: any) { + return this.call(k, args); + }; +}); diff --git a/backend/src/api/lightning/clightning/clightning-convert.ts b/backend/src/api/lightning/clightning/clightning-convert.ts new file mode 100644 index 0000000000..0db60f6496 --- /dev/null +++ b/backend/src/api/lightning/clightning/clightning-convert.ts @@ -0,0 +1,275 @@ +import { ILightningApi } from '../lightning-api.interface'; +import FundingTxFetcher from '../../../tasks/lightning/sync-tasks/funding-tx-fetcher'; +import logger from '../../../logger'; +import { Common } from '../../common'; +import { hex2bin } from '../../../utils/format'; +import config from '../../../config'; + +// https://github.com/lightningnetwork/lnd/blob/master/lnwire/features.go +export enum FeatureBits { + DataLossProtectRequired = 0, + DataLossProtectOptional = 1, + InitialRoutingSync = 3, + UpfrontShutdownScriptRequired = 4, + UpfrontShutdownScriptOptional = 5, + GossipQueriesRequired = 6, + GossipQueriesOptional = 7, + TLVOnionPayloadRequired = 8, + TLVOnionPayloadOptional = 9, + StaticRemoteKeyRequired = 12, + StaticRemoteKeyOptional = 13, + PaymentAddrRequired = 14, + PaymentAddrOptional = 15, + MPPRequired = 16, + MPPOptional = 17, + WumboChannelsRequired = 18, + WumboChannelsOptional = 19, + AnchorsRequired = 20, + AnchorsOptional = 21, + AnchorsZeroFeeHtlcTxRequired = 22, + AnchorsZeroFeeHtlcTxOptional = 23, + ShutdownAnySegwitRequired = 26, + ShutdownAnySegwitOptional = 27, + AMPRequired = 30, + AMPOptional = 31, + ExplicitChannelTypeRequired = 44, + ExplicitChannelTypeOptional = 45, + ScidAliasRequired = 46, + ScidAliasOptional = 47, + PaymentMetadataRequired = 48, + PaymentMetadataOptional = 49, + ZeroConfRequired = 50, + ZeroConfOptional = 51, + KeysendRequired = 54, + KeysendOptional = 55, + ScriptEnforcedLeaseRequired = 2022, + ScriptEnforcedLeaseOptional = 2023, + SimpleTaprootChannelsRequiredFinal = 80, + SimpleTaprootChannelsOptionalFinal = 81, + SimpleTaprootChannelsRequiredStaging = 180, + SimpleTaprootChannelsOptionalStaging = 181, + MaxBolt11Feature = 5114, +}; + +export const FeaturesMap = new Map([ + [FeatureBits.DataLossProtectRequired, 'data-loss-protect'], + [FeatureBits.DataLossProtectOptional, 'data-loss-protect'], + [FeatureBits.InitialRoutingSync, 'initial-routing-sync'], + [FeatureBits.UpfrontShutdownScriptRequired, 'upfront-shutdown-script'], + [FeatureBits.UpfrontShutdownScriptOptional, 'upfront-shutdown-script'], + [FeatureBits.GossipQueriesRequired, 'gossip-queries'], + [FeatureBits.GossipQueriesOptional, 'gossip-queries'], + [FeatureBits.TLVOnionPayloadRequired, 'tlv-onion'], + [FeatureBits.TLVOnionPayloadOptional, 'tlv-onion'], + [FeatureBits.StaticRemoteKeyOptional, 'static-remote-key'], + [FeatureBits.StaticRemoteKeyRequired, 'static-remote-key'], + [FeatureBits.PaymentAddrOptional, 'payment-addr'], + [FeatureBits.PaymentAddrRequired, 'payment-addr'], + [FeatureBits.MPPOptional, 'multi-path-payments'], + [FeatureBits.MPPRequired, 'multi-path-payments'], + [FeatureBits.AnchorsRequired, 'anchor-commitments'], + [FeatureBits.AnchorsOptional, 'anchor-commitments'], + [FeatureBits.AnchorsZeroFeeHtlcTxRequired, 'anchors-zero-fee-htlc-tx'], + [FeatureBits.AnchorsZeroFeeHtlcTxOptional, 'anchors-zero-fee-htlc-tx'], + [FeatureBits.WumboChannelsRequired, 'wumbo-channels'], + [FeatureBits.WumboChannelsOptional, 'wumbo-channels'], + [FeatureBits.AMPRequired, 'amp'], + [FeatureBits.AMPOptional, 'amp'], + [FeatureBits.PaymentMetadataOptional, 'payment-metadata'], + [FeatureBits.PaymentMetadataRequired, 'payment-metadata'], + [FeatureBits.ExplicitChannelTypeOptional, 'explicit-commitment-type'], + [FeatureBits.ExplicitChannelTypeRequired, 'explicit-commitment-type'], + [FeatureBits.KeysendOptional, 'keysend'], + [FeatureBits.KeysendRequired, 'keysend'], + [FeatureBits.ScriptEnforcedLeaseRequired, 'script-enforced-lease'], + [FeatureBits.ScriptEnforcedLeaseOptional, 'script-enforced-lease'], + [FeatureBits.ScidAliasRequired, 'scid-alias'], + [FeatureBits.ScidAliasOptional, 'scid-alias'], + [FeatureBits.ZeroConfRequired, 'zero-conf'], + [FeatureBits.ZeroConfOptional, 'zero-conf'], + [FeatureBits.ShutdownAnySegwitRequired, 'shutdown-any-segwit'], + [FeatureBits.ShutdownAnySegwitOptional, 'shutdown-any-segwit'], + [FeatureBits.SimpleTaprootChannelsRequiredFinal, 'taproot-channels'], + [FeatureBits.SimpleTaprootChannelsOptionalFinal, 'taproot-channels'], + [FeatureBits.SimpleTaprootChannelsRequiredStaging, 'taproot-channels-staging'], + [FeatureBits.SimpleTaprootChannelsOptionalStaging, 'taproot-channels-staging'], +]); + +/** + * Convert a clightning "listnode" entry to a lnd node entry + */ +export function convertNode(clNode: any): ILightningApi.Node { + let custom_records: { [type: number]: string } | undefined = undefined; + if (clNode.option_will_fund) { + try { + custom_records = { '1': Buffer.from(clNode.option_will_fund.compact_lease || '', 'hex').toString('base64') }; + } catch (e) { + logger.err(`Cannot decode option_will_fund compact_lease for ${clNode.nodeid}). Reason: ` + (e instanceof Error ? e.message : e)); + custom_records = undefined; + } + } + + const nodeFeatures: ILightningApi.Feature[] = []; + const nodeFeaturesBinary = hex2bin(clNode.features).split('').reverse().join(''); + + for (let i = 0; i < nodeFeaturesBinary.length; i++) { + if (nodeFeaturesBinary[i] === '0') { + continue; + } + const feature = FeaturesMap.get(i); + if (!feature) { + nodeFeatures.push({ + bit: i, + name: 'unknown', + is_required: i % 2 === 0, + is_known: false + }); + } else { + nodeFeatures.push({ + bit: i, + name: feature, + is_required: i % 2 === 0, + is_known: true + }); + } + } + + return { + alias: clNode.alias ?? '', + color: `#${clNode.color ?? ''}`, + features: nodeFeatures, + pub_key: clNode.nodeid, + addresses: clNode.addresses?.map((addr) => { + let address = addr.address; + if (addr.type === 'ipv6') { + address = `[${address}]`; + } + return { + network: addr.type, + addr: `${address}:${addr.port}` + }; + }) ?? [], + last_update: clNode?.last_timestamp ?? 0, + custom_records + }; +} + +/** + * Convert clightning "listchannels" response to lnd "describegraph.edges" format + */ +export async function convertAndmergeBidirectionalChannels(clChannels: any[]): Promise { + logger.debug(`Converting clightning nodes and channels to lnd graph format`, logger.tags.ln); + + let loggerTimer = new Date().getTime() / 1000; + let channelProcessed = 0; + + const consolidatedChannelList: ILightningApi.Channel[] = []; + const clChannelsDict = {}; + const clChannelsDictCount = {}; + + for (const clChannel of clChannels) { + if (!clChannelsDict[clChannel.short_channel_id]) { + clChannelsDict[clChannel.short_channel_id] = clChannel; + clChannelsDictCount[clChannel.short_channel_id] = 1; + } else { + const fullChannel = await buildFullChannel(clChannel, clChannelsDict[clChannel.short_channel_id]); + if (fullChannel !== null) { + consolidatedChannelList.push(fullChannel); + delete clChannelsDict[clChannel.short_channel_id]; + clChannelsDictCount[clChannel.short_channel_id]++; + } + } + + const elapsedSeconds = Math.round((new Date().getTime() / 1000) - loggerTimer); + if (elapsedSeconds > config.LIGHTNING.LOGGER_UPDATE_INTERVAL) { + logger.info(`Building complete channels from clightning output. Channels processed: ${channelProcessed + 1} of ${clChannels.length}`, logger.tags.ln); + loggerTimer = new Date().getTime() / 1000; + } + + ++channelProcessed; + } + + channelProcessed = 0; + const keys = Object.keys(clChannelsDict); + for (const short_channel_id of keys) { + const incompleteChannel = await buildIncompleteChannel(clChannelsDict[short_channel_id]); + if (incompleteChannel !== null) { + consolidatedChannelList.push(incompleteChannel); + } + + const elapsedSeconds = Math.round((new Date().getTime() / 1000) - loggerTimer); + if (elapsedSeconds > config.LIGHTNING.LOGGER_UPDATE_INTERVAL) { + logger.info(`Building partial channels from clightning output. Channels processed: ${channelProcessed + 1} of ${keys.length}`); + loggerTimer = new Date().getTime() / 1000; + } + + channelProcessed++; + } + + return consolidatedChannelList; +} + +/** + * Convert two clightning "getchannels" entries into a full a lnd "describegraph.edges" format + * In this case, clightning knows the channel policy for both nodes + */ +async function buildFullChannel(clChannelA: any, clChannelB: any): Promise { + const lastUpdate = Math.max(clChannelA.last_update ?? 0, clChannelB.last_update ?? 0); + + const tx = await FundingTxFetcher.$fetchChannelOpenTx(clChannelA.short_channel_id); + if (!tx) { + return null; + } + const parts = clChannelA.short_channel_id.split('x'); + const outputIdx = parts[2]; + + return { + channel_id: Common.channelShortIdToIntegerId(clChannelA.short_channel_id), + capacity: (clChannelA.amount_msat / 1000).toString(), + last_update: lastUpdate, + node1_policy: convertPolicy(clChannelA), + node2_policy: convertPolicy(clChannelB), + chan_point: `${tx.txid}:${outputIdx}`, + node1_pub: clChannelA.source, + node2_pub: clChannelB.source, + }; +} + +/** + * Convert one clightning "getchannels" entry into a full a lnd "describegraph.edges" format + * In this case, clightning knows the channel policy of only one node + */ +async function buildIncompleteChannel(clChannel: any): Promise { + const tx = await FundingTxFetcher.$fetchChannelOpenTx(clChannel.short_channel_id); + if (!tx) { + return null; + } + const parts = clChannel.short_channel_id.split('x'); + const outputIdx = parts[2]; + + return { + channel_id: Common.channelShortIdToIntegerId(clChannel.short_channel_id), + capacity: (clChannel.amount_msat / 1000).toString(), + last_update: clChannel.last_update ?? 0, + node1_policy: convertPolicy(clChannel), + node2_policy: null, + chan_point: `${tx.txid}:${outputIdx}`, + node1_pub: clChannel.source, + node2_pub: clChannel.destination, + }; +} + +/** + * Convert a clightning "listnode" response to a lnd channel policy format + */ +function convertPolicy(clChannel: any): ILightningApi.RoutingPolicy { + return { + time_lock_delta: clChannel.delay, + min_htlc: clChannel.htlc_minimum_msat.toString(), + max_htlc_msat: clChannel.htlc_maximum_msat.toString(), + fee_base_msat: clChannel.base_fee_millisatoshi, + fee_rate_milli_msat: clChannel.fee_per_millionth, + disabled: !clChannel.active, + last_update: clChannel.last_update ?? 0, + }; +} diff --git a/backend/src/api/lightning/lightning-api-abstract-factory.ts b/backend/src/api/lightning/lightning-api-abstract-factory.ts new file mode 100644 index 0000000000..e6691b0a45 --- /dev/null +++ b/backend/src/api/lightning/lightning-api-abstract-factory.ts @@ -0,0 +1,5 @@ +import { ILightningApi } from './lightning-api.interface'; + +export interface AbstractLightningApi { + $getNetworkGraph(): Promise; +} diff --git a/backend/src/api/lightning/lightning-api-factory.ts b/backend/src/api/lightning/lightning-api-factory.ts new file mode 100644 index 0000000000..fdadd8230a --- /dev/null +++ b/backend/src/api/lightning/lightning-api-factory.ts @@ -0,0 +1,16 @@ +import config from '../../config'; +import CLightningClient from './clightning/clightning-client'; +import { AbstractLightningApi } from './lightning-api-abstract-factory'; +import LndApi from './lnd/lnd-api'; + +function lightningApiFactory(): AbstractLightningApi { + switch (config.LIGHTNING.ENABLED === true && config.LIGHTNING.BACKEND) { + case 'cln': + return new CLightningClient(config.CLIGHTNING.SOCKET); + case 'lnd': + default: + return new LndApi(); + } +} + +export default lightningApiFactory(); diff --git a/backend/src/api/lightning/lightning-api.interface.ts b/backend/src/api/lightning/lightning-api.interface.ts new file mode 100644 index 0000000000..ef26646a06 --- /dev/null +++ b/backend/src/api/lightning/lightning-api.interface.ts @@ -0,0 +1,93 @@ +export namespace ILightningApi { + export interface NetworkInfo { + graph_diameter: number; + avg_out_degree: number; + max_out_degree: number; + num_nodes: number; + num_channels: number; + total_network_capacity: string; + avg_channel_size: number; + min_channel_size: string; + max_channel_size: string; + median_channel_size_sat: string; + num_zombie_chans: string; + } + + export interface NetworkGraph { + nodes: Node[]; + edges: Channel[]; + } + + export interface Channel { + channel_id: string; + chan_point: string; + last_update: number | null; + node1_pub: string; + node2_pub: string; + capacity: string; + node1_policy: RoutingPolicy | null; + node2_policy: RoutingPolicy | null; + } + + export interface RoutingPolicy { + time_lock_delta: number; + min_htlc: string; + fee_base_msat: string; + fee_rate_milli_msat: string; + disabled: boolean; + max_htlc_msat: string; + last_update: number | null; + } + + export interface Node { + last_update: number | null; + pub_key: string; + alias: string; + addresses: { + network: string; + addr: string; + }[]; + color: string; + features: { [key: number]: Feature }; + custom_records?: { [type: number]: string }; + } + + export interface Info { + identity_pubkey: string; + alias: string; + num_pending_channels: number; + num_active_channels: number; + num_peers: number; + block_height: number; + block_hash: string; + synced_to_chain: boolean; + testnet: boolean; + uris: string[]; + best_header_timestamp: string; + version: string; + num_inactive_channels: number; + chains: { + chain: string; + network: string; + }[]; + color: string; + synced_to_graph: boolean; + features: { [key: number]: Feature }; + commit_hash: string; + /** Available on LND since v0.15.0-beta */ + require_htlc_interceptor?: boolean; + } + + export interface Feature { + bit: number; + name: string; + is_required: boolean; + is_known: boolean; + } + + export interface ForensicOutput { + node?: 1 | 2; + type: number; + value: number; + } +} \ No newline at end of file diff --git a/backend/src/api/lightning/lnd/lnd-api.ts b/backend/src/api/lightning/lnd/lnd-api.ts new file mode 100644 index 0000000000..f4099e82be --- /dev/null +++ b/backend/src/api/lightning/lnd/lnd-api.ts @@ -0,0 +1,64 @@ +import axios, { AxiosRequestConfig } from 'axios'; +import { Agent } from 'https'; +import * as fs from 'fs'; +import { AbstractLightningApi } from '../lightning-api-abstract-factory'; +import { ILightningApi } from '../lightning-api.interface'; +import config from '../../../config'; +import logger from '../../../logger'; + +class LndApi implements AbstractLightningApi { + axiosConfig: AxiosRequestConfig = {}; + + constructor() { + if (!config.LIGHTNING.ENABLED) { + return; + } + try { + this.axiosConfig = { + headers: { + 'Grpc-Metadata-macaroon': fs.readFileSync(config.LND.MACAROON_PATH).toString('hex'), + }, + httpsAgent: new Agent({ + ca: fs.readFileSync(config.LND.TLS_CERT_PATH) + }), + timeout: config.LND.TIMEOUT + }; + } catch (e) { + config.LIGHTNING.ENABLED = false; + logger.updateNetwork(); + logger.err(`Could not initialize LND Macaroon/TLS Cert. Disabling LIGHTNING. ` + (e instanceof Error ? e.message : e)); + } + } + + async $getNetworkInfo(): Promise { + return axios.get(config.LND.REST_API_URL + '/v1/graph/info', this.axiosConfig) + .then((response) => response.data); + } + + async $getInfo(): Promise { + return axios.get(config.LND.REST_API_URL + '/v1/getinfo', this.axiosConfig) + .then((response) => response.data); + } + + async $getNetworkGraph(): Promise { + const graph = await axios.get(config.LND.REST_API_URL + '/v1/graph', this.axiosConfig) + .then((response) => response.data); + + for (const node of graph.nodes) { + const nodeFeatures: ILightningApi.Feature[] = []; + for (const bit in node.features) { + nodeFeatures.push({ + bit: parseInt(bit, 10), + name: node.features[bit].name, + is_required: node.features[bit].is_required, + is_known: node.features[bit].is_known, + }); + } + node.features = nodeFeatures; + } + + return graph; + } +} + +export default LndApi; diff --git a/backend/src/api/liquid/elements-parser.ts b/backend/src/api/liquid/elements-parser.ts new file mode 100644 index 0000000000..727865b95a --- /dev/null +++ b/backend/src/api/liquid/elements-parser.ts @@ -0,0 +1,493 @@ +import { IBitcoinApi } from '../bitcoin/bitcoin-api.interface'; +import bitcoinClient from '../bitcoin/bitcoin-client'; +import bitcoinSecondClient from '../bitcoin/bitcoin-second-client'; +import { Common } from '../common'; +import DB from '../../database'; +import logger from '../../logger'; + +const federationChangeAddresses = ['bc1qxvay4an52gcghxq5lavact7r6qe9l4laedsazz8fj2ee2cy47tlqff4aj4', '3EiAcrzq1cELXScc98KeCswGWZaPGceT1d']; +const auditBlockOffsetWithTip = 1; // Wait for 1 block confirmation before processing the block in the audit process to reduce the risk of reorgs + +class ElementsParser { + private isRunning = false; + private isUtxosUpdatingRunning = false; + + constructor() { } + + public async $parse() { + if (this.isRunning) { + return; + } + try { + this.isRunning = true; + const result = await bitcoinClient.getChainTips(); + const tip = result[0].height; + const latestBlockHeight = await this.$getLatestBlockHeightFromDatabase(); + for (let height = latestBlockHeight + 1; height <= tip; height++) { + const blockHash: IBitcoinApi.ChainTips = await bitcoinClient.getBlockHash(height); + const block: IBitcoinApi.Block = await bitcoinClient.getBlock(blockHash, 2); + await this.$parseBlock(block); + await this.$saveLatestBlockToDatabase(block.height); + } + this.isRunning = false; + } catch (e) { + this.isRunning = false; + throw new Error(e instanceof Error ? e.message : 'Error'); + } + } + + protected async $parseBlock(block: IBitcoinApi.Block) { + for (const tx of block.tx) { + await this.$parseInputs(tx, block); + await this.$parseOutputs(tx, block); + } + } + + protected async $parseInputs(tx: IBitcoinApi.Transaction, block: IBitcoinApi.Block) { + for (const [index, input] of tx.vin.entries()) { + if (input.is_pegin) { + await this.$parsePegIn(input, index, tx.txid, block); + } + } + } + + protected async $parsePegIn(input: IBitcoinApi.Vin, vindex: number, txid: string, block: IBitcoinApi.Block) { + const bitcoinTx: IBitcoinApi.Transaction = await bitcoinSecondClient.getRawTransaction(input.txid, true); + const bitcoinBlock: IBitcoinApi.Block = await bitcoinSecondClient.getBlock(bitcoinTx.blockhash); + const prevout = bitcoinTx.vout[input.vout || 0]; + const outputAddress = prevout.scriptPubKey.address || (prevout.scriptPubKey.addresses && prevout.scriptPubKey.addresses[0]) || ''; + await this.$savePegToDatabase(block.height, block.time, prevout.value * 100000000, txid, vindex, + outputAddress, bitcoinTx.txid, prevout.n, bitcoinBlock.height, bitcoinBlock.time, 1); + } + + protected async $parseOutputs(tx: IBitcoinApi.Transaction, block: IBitcoinApi.Block) { + for (const output of tx.vout) { + if (output.scriptPubKey.pegout_chain) { + await this.$savePegToDatabase(block.height, block.time, 0 - output.value * 100000000, tx.txid, output.n, + (output.scriptPubKey.pegout_address || ''), '', 0, 0, 0, 0); + } + if (!output.scriptPubKey.pegout_chain && output.scriptPubKey.type === 'nulldata' + && output.value && output.value > 0 && output.asset && output.asset === Common.nativeAssetId) { + await this.$savePegToDatabase(block.height, block.time, 0 - output.value * 100000000, tx.txid, output.n, + (output.scriptPubKey.pegout_address || ''), '', 0, 0, 0, 1); + } + } + } + + protected async $savePegToDatabase(height: number, blockTime: number, amount: number, txid: string, + txindex: number, bitcoinaddress: string, bitcointxid: string, bitcoinindex: number, bitcoinblock: number, bitcoinBlockTime: number, final_tx: number): Promise { + const query = `INSERT IGNORE INTO elements_pegs( + block, datetime, amount, txid, txindex, bitcoinaddress, bitcointxid, bitcoinindex, final_tx + ) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?)`; + + const params: (string | number)[] = [ + height, blockTime, amount, txid, txindex, bitcoinaddress, bitcointxid, bitcoinindex, final_tx + ]; + await DB.query(query, params); + logger.debug(`Saved L-BTC peg from Liquid block height #${height} with TXID ${txid}.`); + + if (amount > 0) { // Peg-in + + // Add the address to the federation addresses table + await DB.query(`INSERT IGNORE INTO federation_addresses (bitcoinaddress) VALUES (?)`, [bitcoinaddress]); + + // Add the UTXO to the federation txos table + const query_utxos = `INSERT IGNORE INTO federation_txos (txid, txindex, bitcoinaddress, amount, blocknumber, blocktime, unspent, lastblockupdate, lasttimeupdate, timelock, expiredAt, emergencyKey, pegtxid, pegindex, pegblocktime) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`; + const params_utxos: (string | number)[] = [bitcointxid, bitcoinindex, bitcoinaddress, amount, bitcoinblock, bitcoinBlockTime, 1, bitcoinblock - 1, 0, 4032, 0, 0, txid, txindex, blockTime]; + await DB.query(query_utxos, params_utxos); + const [minBlockUpdate] = await DB.query(`SELECT MIN(lastblockupdate) AS lastblockupdate FROM federation_txos WHERE unspent = 1`) + await this.$saveLastBlockAuditToDatabase(minBlockUpdate[0]['lastblockupdate']); + logger.debug(`Saved new Federation UTXO ${bitcointxid}:${bitcoinindex} belonging to ${bitcoinaddress} to federation txos`); + + } + } + + protected async $getLatestBlockHeightFromDatabase(): Promise { + const query = `SELECT number FROM state WHERE name = 'last_elements_block'`; + const [rows] = await DB.query(query); + return rows[0]['number']; + } + + protected async $saveLatestBlockToDatabase(blockHeight: number) { + const query = `UPDATE state SET number = ? WHERE name = 'last_elements_block'`; + await DB.query(query, [blockHeight]); + } + + ///////////// FEDERATION AUDIT ////////////// + + public async $updateFederationUtxos() { + if (this.isUtxosUpdatingRunning) { + return; + } + + this.isUtxosUpdatingRunning = true; + + try { + let auditProgress = await this.$getAuditProgress(); + // If no peg in transaction was found in the database, return + if (!auditProgress.lastBlockAudit) { + logger.debug(`No Federation UTXOs found in the database. Waiting for some to be confirmed before starting the Federation UTXOs audit`); + this.isUtxosUpdatingRunning = false; + return; + } + + const bitcoinBlocksToSync = await this.$getBitcoinBlockchainState(); + // If the bitcoin blockchain is not synced yet, return + if (bitcoinBlocksToSync.bitcoinHeaders > bitcoinBlocksToSync.bitcoinBlocks + 1) { + logger.debug(`Bitcoin client is not synced yet. ${bitcoinBlocksToSync.bitcoinHeaders - bitcoinBlocksToSync.bitcoinBlocks} blocks remaining to sync before the Federation audit process can start`); + this.isUtxosUpdatingRunning = false; + return; + } + + auditProgress.lastBlockAudit++; + + // Logging + let indexedThisRun = 0; + let timer = Date.now() / 1000; + const startedAt = Date.now() / 1000; + const indexingSpeeds: number[] = []; + + while (auditProgress.lastBlockAudit <= auditProgress.confirmedTip) { + + // First, get the current UTXOs that need to be scanned in the block + const utxos = await this.$getFederationUtxosToScan(auditProgress.lastBlockAudit); + + // Get the peg-out addresses that need to be scanned + const redeemAddresses = await this.$getRedeemAddressesToScan(); + + // The fast way: check if these UTXOs are still unspent as of the current block with gettxout + let spentAsTip: any[]; + let unspentAsTip: any[]; + if (auditProgress.confirmedTip - auditProgress.lastBlockAudit <= 150) { // If the audit status is not too far in the past, we can use gettxout (fast way) + const utxosToParse = await this.$getFederationUtxosToParse(utxos); + spentAsTip = utxosToParse.spentAsTip; + unspentAsTip = utxosToParse.unspentAsTip; + logger.debug(`Found ${utxos.length} Federation UTXOs and ${redeemAddresses.length} Peg-Out Addresses to scan in Bitcoin block height #${auditProgress.lastBlockAudit} / #${auditProgress.confirmedTip}`); + logger.debug(`${unspentAsTip.length} / ${utxos.length} Federation UTXOs are unspent as of tip`); + } else { // If the audit status is too far in the past, it is useless and wasteful to look for still unspent txos since they will all be spent as of the tip + spentAsTip = utxos; + unspentAsTip = []; + + // Logging + const elapsedSeconds = (Date.now() / 1000) - timer; + if (elapsedSeconds > 5) { + const runningFor = (Date.now() / 1000) - startedAt; + const blockPerSeconds = indexedThisRun / elapsedSeconds; + indexingSpeeds.push(blockPerSeconds); + if (indexingSpeeds.length > 100) indexingSpeeds.shift(); // Keep the length of the up to 100 last indexing speeds + const meanIndexingSpeed = indexingSpeeds.reduce((a, b) => a + b, 0) / indexingSpeeds.length; + const eta = (auditProgress.confirmedTip - auditProgress.lastBlockAudit) / meanIndexingSpeed; + logger.debug(`Scanning ${utxos.length} Federation UTXOs and ${redeemAddresses.length} Peg-Out Addresses at Bitcoin block height #${auditProgress.lastBlockAudit} / #${auditProgress.confirmedTip} | ~${meanIndexingSpeed.toFixed(2)} blocks/sec | elapsed: ${(runningFor / 60).toFixed(0)} minutes | ETA: ${(eta / 60).toFixed(0)} minutes`); + timer = Date.now() / 1000; + indexedThisRun = 0; + } + } + + // The slow way: parse the block to look for the spending tx + const blockHash: IBitcoinApi.ChainTips = await bitcoinSecondClient.getBlockHash(auditProgress.lastBlockAudit); + const block: IBitcoinApi.Block = await bitcoinSecondClient.getBlock(blockHash, 2); + await this.$parseBitcoinBlock(block, spentAsTip, unspentAsTip, auditProgress.confirmedTip, redeemAddresses); + + // Finally, update the lastblockupdate of the remaining UTXOs and save to the database + const [minBlockUpdate] = await DB.query(`SELECT MIN(lastblockupdate) AS lastblockupdate FROM federation_txos WHERE unspent = 1`) + await this.$saveLastBlockAuditToDatabase(minBlockUpdate[0]['lastblockupdate']); + + auditProgress = await this.$getAuditProgress(); + auditProgress.lastBlockAudit++; + indexedThisRun++; + } + + this.isUtxosUpdatingRunning = false; + } catch (e) { + this.isUtxosUpdatingRunning = false; + throw new Error(e instanceof Error ? e.message : 'Error'); + } + } + + // Get the UTXOs that need to be scanned in block height (UTXOs that were last updated in the block height - 1) + protected async $getFederationUtxosToScan(height: number) { + const query = `SELECT txid, txindex, bitcoinaddress, amount, blocknumber, timelock, expiredAt FROM federation_txos WHERE lastblockupdate = ? AND unspent = 1`; + const [rows] = await DB.query(query, [height - 1]); + return rows as any[]; + } + + // Returns the UTXOs that are spent as of tip and need to be scanned + protected async $getFederationUtxosToParse(utxos: any[]): Promise { + const spentAsTip: any[] = []; + const unspentAsTip: any[] = []; + + for (const utxo of utxos) { + const result = await bitcoinSecondClient.getTxOut(utxo.txid, utxo.txindex, false); + result ? unspentAsTip.push(utxo) : spentAsTip.push(utxo); + } + + return {spentAsTip, unspentAsTip}; + } + + protected async $parseBitcoinBlock(block: IBitcoinApi.Block, spentAsTip: any[], unspentAsTip: any[], confirmedTip: number, redeemAddressesData: any[] = []) { + const redeemAddresses: string[] = redeemAddressesData.map(redeemAddress => redeemAddress.bitcoinaddress); + for (const tx of block.tx) { + let mightRedeemInThisTx = false; + // Check if the Federation UTXOs that was spent as of tip are spent in this block + for (const input of tx.vin) { + const txo = spentAsTip.find(txo => txo.txid === input.txid && txo.txindex === input.vout); + if (txo) { + mightRedeemInThisTx = true; // A Federation UTXO is spent in this block: we might find a peg-out address in the outputs + if (txo.expiredAt > 0 ) { + if (input.txinwitness?.length !== 13) { // Check if the witness data of the input contains the 11 signatures: if it doesn't, emergency keys are being used + await DB.query(`UPDATE federation_txos SET unspent = 0, lastblockupdate = ?, lasttimeupdate = ?, emergencyKey = 1 WHERE txid = ? AND txindex = ?`, [block.height, block.time, txo.txid, txo.txindex]); + logger.debug(`Expired Federation UTXO ${txo.txid}:${txo.txindex} (${txo.amount} sats) was spent in block ${block.height} using emergency keys!`); + } else { + await DB.query(`UPDATE federation_txos SET unspent = 0, lastblockupdate = ?, lasttimeupdate = ? WHERE txid = ? AND txindex = ?`, [block.height, block.time, txo.txid, txo.txindex]); + logger.debug(`Expired Federation UTXO ${txo.txid}:${txo.txindex} (${txo.amount} sats) was spent in block ${block.height} using regular 11-of-15 signatures`); + } + } else { + await DB.query(`UPDATE federation_txos SET unspent = 0, lastblockupdate = ?, lasttimeupdate = ? WHERE txid = ? AND txindex = ?`, [block.height, block.time, txo.txid, txo.txindex]); + logger.debug(`Federation UTXO ${txo.txid}:${txo.txindex} (${txo.amount} sats) was spent in block ${block.height}`); + } + // Remove the TXO from the utxo array + spentAsTip.splice(spentAsTip.indexOf(txo), 1); + } + } + // Check if an output is sent to a change address of the federation + for (const output of tx.vout) { + if (output.scriptPubKey.address && federationChangeAddresses.includes(output.scriptPubKey.address)) { + // Check that the UTXO was not already added in the DB by previous scans + const [rows_check] = await DB.query(`SELECT txid FROM federation_txos WHERE txid = ? AND txindex = ?`, [tx.txid, output.n]) as any[]; + if (rows_check.length === 0) { + const timelock = output.scriptPubKey.address === federationChangeAddresses[0] ? 4032 : 2016; // P2WSH change address has a 4032 timelock, P2SH change address has a 2016 timelock + const query_utxos = `INSERT INTO federation_txos (txid, txindex, bitcoinaddress, amount, blocknumber, blocktime, unspent, lastblockupdate, lasttimeupdate, timelock, expiredAt, emergencyKey, pegtxid, pegindex, pegblocktime) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`; + const params_utxos: (string | number)[] = [tx.txid, output.n, output.scriptPubKey.address, output.value * 100000000, block.height, block.time, 1, block.height, 0, timelock, 0, 0, '', 0, 0]; + await DB.query(query_utxos, params_utxos); + // Add the UTXO to the utxo array + spentAsTip.push({ + txid: tx.txid, + txindex: output.n, + bitcoinaddress: output.scriptPubKey.address, + amount: output.value * 100000000, + blocknumber: block.height, + timelock: timelock, + expiredAt: 0, + }); + logger.debug(`Added new Federation UTXO ${tx.txid}:${output.n} (${Math.round(output.value * 100000000)} sats), change address: ${output.scriptPubKey.address}`); + } + } + if (mightRedeemInThisTx && output.scriptPubKey.address && redeemAddresses.includes(output.scriptPubKey.address)) { + // Find the number of times output.scriptPubKey.address appears in redeemAddresses. There can be address reuse for peg-outs... + const matchingAddress: any[] = redeemAddressesData.filter(redeemAddress => redeemAddress.bitcoinaddress === output.scriptPubKey.address && -redeemAddress.amount === Math.round(output.value * 100000000)); + if (matchingAddress.length > 0) { + if (matchingAddress.length > 1) { + // If there are more than one peg out address with the same amount, we can't know which one redeemed the UTXO: we take the oldest one + matchingAddress.sort((a, b) => a.datetime - b.datetime); + logger.debug(`Found redeem txid ${tx.txid}:${output.n} to peg-out address ${matchingAddress[0].bitcoinaddress}, amount ${matchingAddress[0].amount}, datetime ${matchingAddress[0].datetime}`); + } else { + logger.debug(`Found redeem txid ${tx.txid}:${output.n} to peg-out address ${matchingAddress[0].bitcoinaddress}, amount ${matchingAddress[0].amount}`); + } + const query_add_redeem = `UPDATE elements_pegs SET bitcointxid = ?, bitcoinindex = ? WHERE bitcoinaddress = ? AND amount = ? AND datetime = ?`; + const params_add_redeem: (string | number)[] = [tx.txid, output.n, matchingAddress[0].bitcoinaddress, matchingAddress[0].amount, matchingAddress[0].datetime]; + await DB.query(query_add_redeem, params_add_redeem); + const index = redeemAddressesData.indexOf(matchingAddress[0]); + redeemAddressesData.splice(index, 1); + redeemAddresses.splice(index, 1); + } else { // The output amount does not match the peg-out amount... log it + logger.debug(`Found redeem txid ${tx.txid}:${output.n} to peg-out address ${output.scriptPubKey.address} but output amount ${Math.round(output.value * 100000000)} does not match the peg-out amount!`); + } + } + } + } + + for (const utxo of spentAsTip) { + if (utxo.expiredAt === 0 && block.height >= utxo.blocknumber + utxo.timelock) { // The UTXO is expiring in this block + await DB.query(`UPDATE federation_txos SET lastblockupdate = ?, expiredAt = ? WHERE txid = ? AND txindex = ?`, [block.height, block.time, utxo.txid, utxo.txindex]); + } else { + await DB.query(`UPDATE federation_txos SET lastblockupdate = ? WHERE txid = ? AND txindex = ?`, [block.height, utxo.txid, utxo.txindex]); + } + } + + for (const utxo of unspentAsTip) { + if (utxo.expiredAt === 0 && block.height >= utxo.blocknumber + utxo.timelock) { // The UTXO is expiring in this block + await DB.query(`UPDATE federation_txos SET unspent = 0, lastblockupdate = ?, expiredAt = ? WHERE txid = ? AND txindex = ?`, [confirmedTip, block.time, utxo.txid, utxo.txindex]); + } else if (utxo.expiredAt === 0 && confirmedTip >= utxo.blocknumber + utxo.timelock) { // The UTXO is expiring before the tip: we need to keep track of it + await DB.query(`UPDATE federation_txos SET lastblockupdate = ? WHERE txid = ? AND txindex = ?`, [utxo.blocknumber + utxo.timelock - 1, utxo.txid, utxo.txindex]); + } else { + await DB.query(`UPDATE federation_txos SET lastblockupdate = ? WHERE txid = ? AND txindex = ?`, [confirmedTip, utxo.txid, utxo.txindex]); + } + } + } + + protected async $saveLastBlockAuditToDatabase(blockHeight: number) { + const query = `UPDATE state SET number = ? WHERE name = 'last_bitcoin_block_audit'`; + await DB.query(query, [blockHeight]); + } + + // Get the bitcoin block where the audit process was last updated + protected async $getAuditProgress(): Promise { + const lastblockaudit = await this.$getLastBlockAudit(); + const bitcoinBlocksToSync = await this.$getBitcoinBlockchainState(); + return { + lastBlockAudit: lastblockaudit, + confirmedTip: bitcoinBlocksToSync.bitcoinBlocks - auditBlockOffsetWithTip, + }; + } + + // Get the bitcoin blocks remaining to be synced + protected async $getBitcoinBlockchainState(): Promise { + const result = await bitcoinSecondClient.getBlockchainInfo(); + return { + bitcoinBlocks: result.blocks, + bitcoinHeaders: result.headers, + } + } + + protected async $getLastBlockAudit(): Promise { + const query = `SELECT number FROM state WHERE name = 'last_bitcoin_block_audit'`; + const [rows] = await DB.query(query); + return rows[0]['number']; + } + + protected async $getRedeemAddressesToScan(): Promise { + const query = `SELECT datetime, amount, bitcoinaddress FROM elements_pegs where amount < 0 AND bitcoinaddress != '' AND bitcointxid = '';`; + const [rows]: any[] = await DB.query(query); + return rows; + } + + protected isDust(amount: number, feeRate: number): boolean { + return amount <= (450 * feeRate); // A P2WSH 11-of-15 multisig input is around 450 bytes + } + + ///////////// DATA QUERY ////////////// + + public async $getAuditStatus(): Promise { + const lastBlockAudit = await this.$getLastBlockAudit(); + const bitcoinBlocksToSync = await this.$getBitcoinBlockchainState(); + return { + bitcoinBlocks: bitcoinBlocksToSync.bitcoinBlocks, + bitcoinHeaders: bitcoinBlocksToSync.bitcoinHeaders, + lastBlockAudit: lastBlockAudit, + isAuditSynced: bitcoinBlocksToSync.bitcoinHeaders - bitcoinBlocksToSync.bitcoinBlocks <= 2 && bitcoinBlocksToSync.bitcoinBlocks - lastBlockAudit <= 3, + }; + } + + public async $getPegDataByMonth(): Promise { + const query = `SELECT SUM(amount) AS amount, DATE_FORMAT(FROM_UNIXTIME(datetime), '%Y-%m-01') AS date FROM elements_pegs GROUP BY DATE_FORMAT(FROM_UNIXTIME(datetime), '%Y%m')`; + const [rows] = await DB.query(query); + return rows; + } + + public async $getFederationReservesByMonth(): Promise { + const query = ` + SELECT SUM(amount) AS amount, DATE_FORMAT(FROM_UNIXTIME(blocktime), '%Y-%m-01') AS date FROM federation_txos + WHERE + (blocktime > UNIX_TIMESTAMP(LAST_DAY(FROM_UNIXTIME(blocktime) - INTERVAL 1 MONTH) + INTERVAL 1 DAY)) + AND + ((unspent = 1) OR (unspent = 0 AND lasttimeupdate > UNIX_TIMESTAMP(LAST_DAY(FROM_UNIXTIME(blocktime)) + INTERVAL 1 DAY))) + AND + (expiredAt = 0 OR expiredAt > UNIX_TIMESTAMP(LAST_DAY(FROM_UNIXTIME(blocktime)) + INTERVAL 1 DAY)) + GROUP BY + date;`; + const [rows] = await DB.query(query); + return rows; + } + + // Get the current L-BTC pegs and the last Liquid block it was updated + public async $getCurrentLbtcSupply(): Promise { + const [rows] = await DB.query(`SELECT SUM(amount) AS LBTC_supply FROM elements_pegs;`); + const lastblockupdate = await this.$getLatestBlockHeightFromDatabase(); + const hash = await bitcoinClient.getBlockHash(lastblockupdate); + return { + amount: rows[0]['LBTC_supply'], + lastBlockUpdate: lastblockupdate, + hash: hash + }; + } + + // Get the current reserves of the federation and the last Bitcoin block it was updated + public async $getCurrentFederationReserves(): Promise { + const [rows] = await DB.query(`SELECT SUM(amount) AS total_balance FROM federation_txos WHERE unspent = 1 AND expiredAt = 0;`); + const lastblockaudit = await this.$getLastBlockAudit(); + const hash = await bitcoinSecondClient.getBlockHash(lastblockaudit); + return { + amount: rows[0]['total_balance'], + lastBlockUpdate: lastblockaudit, + hash: hash + }; + } + + // Get all of the federation addresses, most balances first + public async $getFederationAddresses(): Promise { + const query = `SELECT bitcoinaddress, SUM(amount) AS balance FROM federation_txos WHERE unspent = 1 AND expiredAt = 0 GROUP BY bitcoinaddress ORDER BY balance DESC;`; + const [rows] = await DB.query(query); + return rows; + } + + // Get all of the UTXOs held by the federation, most recent first + public async $getFederationUtxos(): Promise { + const query = `SELECT txid, txindex, bitcoinaddress, amount, blocknumber, blocktime, pegtxid, pegindex, pegblocktime, timelock, expiredAt FROM federation_txos WHERE unspent = 1 AND expiredAt = 0 ORDER BY blocktime DESC;`; + const [rows] = await DB.query(query); + return rows; + } + + // Get expired UTXOs, most recent first + public async $getExpiredUtxos(): Promise { + const query = `SELECT txid, txindex, bitcoinaddress, amount, blocknumber, blocktime, pegtxid, pegindex, pegblocktime, timelock, expiredAt FROM federation_txos WHERE unspent = 1 AND expiredAt > 0 ORDER BY blocktime DESC;`; + const [rows]: any[] = await DB.query(query); + const feeRate = Math.round((await bitcoinSecondClient.estimateSmartFee(1)).feerate * 100000000 / 1000); + for (const row of rows) { + row.isDust = this.isDust(row.amount, feeRate); + } + return rows; + } + + // Get utxos that were spent using emergency keys + public async $getEmergencySpentUtxos(): Promise { + const query = `SELECT txid, txindex, bitcoinaddress, amount, blocknumber, blocktime, pegtxid, pegindex, pegblocktime, timelock, expiredAt FROM federation_txos WHERE emergencyKey = 1 ORDER BY blocktime DESC;`; + const [rows] = await DB.query(query); + return rows; + } + + // Get the total number of federation addresses + public async $getFederationAddressesNumber(): Promise { + const query = `SELECT COUNT(DISTINCT bitcoinaddress) AS address_count FROM federation_txos WHERE unspent = 1 AND expiredAt = 0;`; + const [rows] = await DB.query(query); + return rows[0]; + } + + // Get the total number of federation utxos + public async $getFederationUtxosNumber(): Promise { + const query = `SELECT COUNT(*) AS utxo_count FROM federation_txos WHERE unspent = 1 AND expiredAt = 0;`; + const [rows] = await DB.query(query); + return rows[0]; + } + + // Get the total number of emergency spent utxos and their total amount + public async $getEmergencySpentUtxosStats(): Promise { + const query = `SELECT COUNT(*) AS utxo_count, SUM(amount) AS total_amount FROM federation_txos WHERE emergencyKey = 1;`; + const [rows] = await DB.query(query); + return rows[0]; + } + + // Get recent pegs in / out + public async $getPegsList(count: number = 0): Promise { + const query = `SELECT txid, txindex, amount, bitcoinaddress, bitcointxid, bitcoinindex, datetime AS blocktime FROM elements_pegs ORDER BY block DESC LIMIT 15 OFFSET ?;`; + const [rows] = await DB.query(query, [count]); + return rows; + } + + // Get all peg in / out from the last month + public async $getPegsVolumeDaily(): Promise { + const pegInQuery = await DB.query(`SELECT SUM(amount) AS volume, COUNT(*) AS number FROM elements_pegs WHERE amount > 0 and datetime > UNIX_TIMESTAMP(TIMESTAMPADD(DAY, -1, CURRENT_TIMESTAMP()));`); + const pegOutQuery = await DB.query(`SELECT SUM(amount) AS volume, COUNT(*) AS number FROM elements_pegs WHERE amount < 0 and datetime > UNIX_TIMESTAMP(TIMESTAMPADD(DAY, -1, CURRENT_TIMESTAMP()));`); + return [ + pegInQuery[0][0], + pegOutQuery[0][0] + ]; + } + + // Get the total pegs number + public async $getPegsCount(): Promise { + const [rows] = await DB.query(`SELECT COUNT(*) AS pegs_count FROM elements_pegs;`); + return rows[0]; + } +} + +export default new ElementsParser(); diff --git a/backend/src/api/liquid/icons.ts b/backend/src/api/liquid/icons.ts new file mode 100644 index 0000000000..a963c703c3 --- /dev/null +++ b/backend/src/api/liquid/icons.ts @@ -0,0 +1,38 @@ +import * as fs from 'fs'; +import logger from '../../logger'; + +class Icons { + private static FILE_NAME = '/elements/asset_registry_db/icons.json'; + private iconIds: string[] = []; + private icons: { [assetId: string]: string; } = {}; + + constructor() {} + + public loadIcons() { + if (!fs.existsSync(Icons.FILE_NAME)) { + logger.warn(`${Icons.FILE_NAME} does not exist. No Liquid icons loaded.`); + return; + } + const cacheData = fs.readFileSync(Icons.FILE_NAME, 'utf8'); + this.icons = JSON.parse(cacheData); + + for (const i in this.icons) { + this.iconIds.push(i); + } + logger.debug(`Liquid icons has been loaded.`); + } + + public getIconByAssetId(assetId: string): Buffer | undefined { + const icon = this.icons[assetId]; + if (icon) { + return Buffer.from(icon, 'base64'); + } + } + + public getAllIconIds() { + return this.iconIds; + } + +} + +export default new Icons(); diff --git a/backend/src/api/liquid/liquid.routes.ts b/backend/src/api/liquid/liquid.routes.ts new file mode 100644 index 0000000000..9ea61ca31c --- /dev/null +++ b/backend/src/api/liquid/liquid.routes.ts @@ -0,0 +1,259 @@ +import axios from 'axios'; +import { Application, Request, Response } from 'express'; +import config from '../../config'; +import elementsParser from './elements-parser'; +import icons from './icons'; + +class LiquidRoutes { + public initRoutes(app: Application) { + app + .get(config.MEMPOOL.API_URL_PREFIX + 'assets/icons', this.getAllLiquidIcon) + .get(config.MEMPOOL.API_URL_PREFIX + 'assets/featured', this.$getAllFeaturedLiquidAssets) + .get(config.MEMPOOL.API_URL_PREFIX + 'asset/:assetId/icon', this.getLiquidIcon) + .get(config.MEMPOOL.API_URL_PREFIX + 'assets/group/:id', this.$getAssetGroup) + ; + + if (config.DATABASE.ENABLED) { + app + .get(config.MEMPOOL.API_URL_PREFIX + 'liquid/pegs', this.$getElementsPegs) + .get(config.MEMPOOL.API_URL_PREFIX + 'liquid/pegs/month', this.$getElementsPegsByMonth) + .get(config.MEMPOOL.API_URL_PREFIX + 'liquid/pegs/list/:count', this.$getPegsList) + .get(config.MEMPOOL.API_URL_PREFIX + 'liquid/pegs/volume', this.$getPegsVolumeDaily) + .get(config.MEMPOOL.API_URL_PREFIX + 'liquid/pegs/count', this.$getPegsCount) + .get(config.MEMPOOL.API_URL_PREFIX + 'liquid/reserves', this.$getFederationReserves) + .get(config.MEMPOOL.API_URL_PREFIX + 'liquid/reserves/month', this.$getFederationReservesByMonth) + .get(config.MEMPOOL.API_URL_PREFIX + 'liquid/reserves/addresses', this.$getFederationAddresses) + .get(config.MEMPOOL.API_URL_PREFIX + 'liquid/reserves/addresses/total', this.$getFederationAddressesNumber) + .get(config.MEMPOOL.API_URL_PREFIX + 'liquid/reserves/utxos', this.$getFederationUtxos) + .get(config.MEMPOOL.API_URL_PREFIX + 'liquid/reserves/utxos/total', this.$getFederationUtxosNumber) + .get(config.MEMPOOL.API_URL_PREFIX + 'liquid/reserves/utxos/expired', this.$getExpiredUtxos) + .get(config.MEMPOOL.API_URL_PREFIX + 'liquid/reserves/utxos/emergency-spent', this.$getEmergencySpentUtxos) + .get(config.MEMPOOL.API_URL_PREFIX + 'liquid/reserves/utxos/emergency-spent/stats', this.$getEmergencySpentUtxosStats) + .get(config.MEMPOOL.API_URL_PREFIX + 'liquid/reserves/status', this.$getFederationAuditStatus) + ; + } + } + + + private getLiquidIcon(req: Request, res: Response) { + const result = icons.getIconByAssetId(req.params.assetId); + if (result) { + res.setHeader('content-type', 'image/png'); + res.setHeader('content-length', result.length); + res.send(result); + } else { + res.status(404).send('Asset icon not found'); + } + } + + private getAllLiquidIcon(req: Request, res: Response) { + const result = icons.getAllIconIds(); + if (result) { + res.json(result); + } else { + res.status(404).send('Asset icons not found'); + } + } + + private async $getAllFeaturedLiquidAssets(req: Request, res: Response) { + try { + const response = await axios.get(`${config.EXTERNAL_DATA_SERVER.LIQUID_API}/assets/featured`, { responseType: 'stream', timeout: 10000 }); + response.data.pipe(res); + } catch (e) { + res.status(500).end(); + } + } + + private async $getAssetGroup(req: Request, res: Response) { + try { + const response = await axios.get(`${config.EXTERNAL_DATA_SERVER.LIQUID_API}/assets/group/${parseInt(req.params.id, 10)}`, + { responseType: 'stream', timeout: 10000 }); + response.data.pipe(res); + } catch (e) { + res.status(500).end(); + } + } + + private async $getElementsPegsByMonth(req: Request, res: Response) { + try { + const pegs = await elementsParser.$getPegDataByMonth(); + res.header('Pragma', 'public'); + res.header('Cache-control', 'public'); + res.setHeader('Expires', new Date(Date.now() + 1000 * 60 * 60).toUTCString()); + res.json(pegs); + } catch (e) { + res.status(500).send(e instanceof Error ? e.message : e); + } + } + + private async $getFederationReservesByMonth(req: Request, res: Response) { + try { + const reserves = await elementsParser.$getFederationReservesByMonth(); + res.header('Pragma', 'public'); + res.header('Cache-control', 'public'); + res.setHeader('Expires', new Date(Date.now() + 1000 * 60 * 60).toUTCString()); + res.json(reserves); + } catch (e) { + res.status(500).send(e instanceof Error ? e.message : e); + } + } + + private async $getElementsPegs(req: Request, res: Response) { + try { + const currentSupply = await elementsParser.$getCurrentLbtcSupply(); + res.header('Pragma', 'public'); + res.header('Cache-control', 'public'); + res.setHeader('Expires', new Date(Date.now() + 1000 * 30).toUTCString()); + res.json(currentSupply); + } catch (e) { + res.status(500).send(e instanceof Error ? e.message : e); + } + } + + private async $getFederationReserves(req: Request, res: Response) { + try { + const currentReserves = await elementsParser.$getCurrentFederationReserves(); + res.header('Pragma', 'public'); + res.header('Cache-control', 'public'); + res.setHeader('Expires', new Date(Date.now() + 1000 * 30).toUTCString()); + res.json(currentReserves); + } catch (e) { + res.status(500).send(e instanceof Error ? e.message : e); + } + } + + private async $getFederationAuditStatus(req: Request, res: Response) { + try { + const auditStatus = await elementsParser.$getAuditStatus(); + res.header('Pragma', 'public'); + res.header('Cache-control', 'public'); + res.setHeader('Expires', new Date(Date.now() + 1000 * 30).toUTCString()); + res.json(auditStatus); + } catch (e) { + res.status(500).send(e instanceof Error ? e.message : e); + } + } + + private async $getFederationAddresses(req: Request, res: Response) { + try { + const federationAddresses = await elementsParser.$getFederationAddresses(); + res.header('Pragma', 'public'); + res.header('Cache-control', 'public'); + res.setHeader('Expires', new Date(Date.now() + 1000 * 30).toUTCString()); + res.json(federationAddresses); + } catch (e) { + res.status(500).send(e instanceof Error ? e.message : e); + } + } + + private async $getFederationAddressesNumber(req: Request, res: Response) { + try { + const federationAddresses = await elementsParser.$getFederationAddressesNumber(); + res.header('Pragma', 'public'); + res.header('Cache-control', 'public'); + res.setHeader('Expires', new Date(Date.now() + 1000 * 30).toUTCString()); + res.json(federationAddresses); + } catch (e) { + res.status(500).send(e instanceof Error ? e.message : e); + } + } + + private async $getFederationUtxos(req: Request, res: Response) { + try { + const federationUtxos = await elementsParser.$getFederationUtxos(); + res.header('Pragma', 'public'); + res.header('Cache-control', 'public'); + res.setHeader('Expires', new Date(Date.now() + 1000 * 30).toUTCString()); + res.json(federationUtxos); + } catch (e) { + res.status(500).send(e instanceof Error ? e.message : e); + } + } + + private async $getExpiredUtxos(req: Request, res: Response) { + try { + const expiredUtxos = await elementsParser.$getExpiredUtxos(); + res.header('Pragma', 'public'); + res.header('Cache-control', 'public'); + res.setHeader('Expires', new Date(Date.now() + 1000 * 30).toUTCString()); + res.json(expiredUtxos); + } catch (e) { + res.status(500).send(e instanceof Error ? e.message : e); + } + } + + private async $getFederationUtxosNumber(req: Request, res: Response) { + try { + const federationUtxos = await elementsParser.$getFederationUtxosNumber(); + res.header('Pragma', 'public'); + res.header('Cache-control', 'public'); + res.setHeader('Expires', new Date(Date.now() + 1000 * 30).toUTCString()); + res.json(federationUtxos); + } catch (e) { + res.status(500).send(e instanceof Error ? e.message : e); + } + } + + private async $getEmergencySpentUtxos(req: Request, res: Response) { + try { + const emergencySpentUtxos = await elementsParser.$getEmergencySpentUtxos(); + res.header('Pragma', 'public'); + res.header('Cache-control', 'public'); + res.setHeader('Expires', new Date(Date.now() + 1000 * 30).toUTCString()); + res.json(emergencySpentUtxos); + } catch (e) { + res.status(500).send(e instanceof Error ? e.message : e); + } + } + + private async $getEmergencySpentUtxosStats(req: Request, res: Response) { + try { + const emergencySpentUtxos = await elementsParser.$getEmergencySpentUtxosStats(); + res.header('Pragma', 'public'); + res.header('Cache-control', 'public'); + res.setHeader('Expires', new Date(Date.now() + 1000 * 30).toUTCString()); + res.json(emergencySpentUtxos); + } catch (e) { + res.status(500).send(e instanceof Error ? e.message : e); + } + } + + private async $getPegsList(req: Request, res: Response) { + try { + const recentPegs = await elementsParser.$getPegsList(parseInt(req.params?.count)); + res.header('Pragma', 'public'); + res.header('Cache-control', 'public'); + res.setHeader('Expires', new Date(Date.now() + 1000 * 30).toUTCString()); + res.json(recentPegs); + } catch (e) { + res.status(500).send(e instanceof Error ? e.message : e); + } + } + + private async $getPegsVolumeDaily(req: Request, res: Response) { + try { + const pegsVolume = await elementsParser.$getPegsVolumeDaily(); + res.header('Pragma', 'public'); + res.header('Cache-control', 'public'); + res.setHeader('Expires', new Date(Date.now() + 1000 * 30).toUTCString()); + res.json(pegsVolume); + } catch (e) { + res.status(500).send(e instanceof Error ? e.message : e); + } + } + + private async $getPegsCount(req: Request, res: Response) { + try { + const pegsCount = await elementsParser.$getPegsCount(); + res.header('Pragma', 'public'); + res.header('Cache-control', 'public'); + res.setHeader('Expires', new Date(Date.now() + 1000 * 30).toUTCString()); + res.json(pegsCount); + } catch (e) { + res.status(500).send(e instanceof Error ? e.message : e); + } + } + +} + +export default new LiquidRoutes(); diff --git a/backend/src/api/loading-indicators.ts b/backend/src/api/loading-indicators.ts new file mode 100644 index 0000000000..38d5aea96f --- /dev/null +++ b/backend/src/api/loading-indicators.ts @@ -0,0 +1,32 @@ +import { ILoadingIndicators } from '../mempool.interfaces'; + +class LoadingIndicators { + private loadingIndicators: ILoadingIndicators = { + 'mempool': 0, + }; + private progressChangedCallback: ((loadingIndicators: ILoadingIndicators) => void) | undefined; + + constructor() { } + + public setProgressChangedCallback(fn: (loadingIndicators: ILoadingIndicators) => void) { + this.progressChangedCallback = fn; + } + + public setProgress(name: string, progressPercent: number, rounded: boolean = true) { + const newProgress = rounded === true ? Math.round(progressPercent) : progressPercent; + if (newProgress >= 100) { + delete this.loadingIndicators[name]; + } else { + this.loadingIndicators[name] = newProgress; + } + if (this.progressChangedCallback) { + this.progressChangedCallback(this.loadingIndicators); + } + } + + public getLoadingIndicators() { + return this.loadingIndicators; + } +} + +export default new LoadingIndicators(); diff --git a/backend/src/api/memory-cache.ts b/backend/src/api/memory-cache.ts new file mode 100644 index 0000000000..e71aaa6a25 --- /dev/null +++ b/backend/src/api/memory-cache.ts @@ -0,0 +1,38 @@ +interface ICache { + type: string; + id: string; + expires: Date; + data: any; +} + +class MemoryCache { + private cache: ICache[] = []; + constructor() { + setInterval(this.cleanup.bind(this), 1000); + } + + public set(type: string, id: string, data: any, secondsExpiry: number) { + const expiry = new Date(); + expiry.setSeconds(expiry.getSeconds() + secondsExpiry); + this.cache.push({ + type: type, + id: id, + data: data, + expires: expiry, + }); + } + + public get(type: string, id: string): T | null { + const found = this.cache.find((cache) => cache.type === type && cache.id === id); + if (found) { + return found.data; + } + return null; + } + + private cleanup() { + this.cache = this.cache.filter((cache) => cache.expires > (new Date())); + } +} + +export default new MemoryCache(); diff --git a/backend/src/api/mempool-blocks.ts b/backend/src/api/mempool-blocks.ts index 353c11b1de..e655601e50 100644 --- a/backend/src/api/mempool-blocks.ts +++ b/backend/src/api/mempool-blocks.ts @@ -1,11 +1,28 @@ -const config = require('../../mempool-config.json'); -import { MempoolBlock, TransactionExtended, MempoolBlockWithTransactions } from '../interfaces'; -import { Common } from './common'; +import { GbtGenerator, GbtResult, ThreadTransaction as RustThreadTransaction, ThreadAcceleration as RustThreadAcceleration } from 'rust-gbt'; +import logger from '../logger'; +import { MempoolBlock, MempoolTransactionExtended, MempoolBlockWithTransactions, MempoolBlockDelta, Ancestor, CompactThreadTransaction, EffectiveFeeStats, TransactionClassified, TransactionCompressed, MempoolDeltaChange, GbtCandidates, PoolTag } from '../mempool.interfaces'; +import { Common, OnlineFeeStatsCalculator } from './common'; +import config from '../config'; +import { Worker } from 'worker_threads'; +import path from 'path'; +import mempool from './mempool'; +import { Acceleration } from './services/acceleration'; +import PoolsRepository from '../repositories/PoolsRepository'; + +const MAX_UINT32 = Math.pow(2, 32) - 1; class MempoolBlocks { private mempoolBlocks: MempoolBlockWithTransactions[] = []; + private mempoolBlockDeltas: MempoolBlockDelta[] = []; + private txSelectionWorker: Worker | null = null; + private rustInitialized: boolean = false; + private rustGbtGenerator: GbtGenerator = new GbtGenerator(config.MEMPOOL.BLOCK_WEIGHT_UNITS, config.MEMPOOL.MEMPOOL_BLOCKS_AMOUNT); + + private nextUid: number = 1; + private uidMap: Map = new Map(); // map short numerical uids to full txids + private txidMap: Map = new Map(); // map full txids back to short numerical uids - constructor() {} + private pools: { [id: number]: PoolTag } = {}; public getMempoolBlocks(): MempoolBlock[] { return this.mempoolBlocks.map((block) => { @@ -24,63 +41,728 @@ class MempoolBlocks { return this.mempoolBlocks; } - public updateMempoolBlocks(memPool: { [txid: string]: TransactionExtended }): void { - const latestMempool = memPool; - const memPoolArray: TransactionExtended[] = []; - for (const i in latestMempool) { - if (latestMempool.hasOwnProperty(i)) { - memPoolArray.push(latestMempool[i]); + public getMempoolBlockDeltas(): MempoolBlockDelta[] { + return this.mempoolBlockDeltas; + } + + public async updatePools$(): Promise { + if (['mainnet', 'testnet', 'signet'].includes(config.MEMPOOL.NETWORK) === false) { + this.pools = {}; + return; + } + const allPools = await PoolsRepository.$getPools(); + this.pools = {}; + for (const pool of allPools) { + this.pools[pool.uniqueId] = pool; + } + } + + private calculateMempoolDeltas(prevBlocks: MempoolBlockWithTransactions[], mempoolBlocks: MempoolBlockWithTransactions[]): MempoolBlockDelta[] { + const mempoolBlockDeltas: MempoolBlockDelta[] = []; + for (let i = 0; i < Math.max(mempoolBlocks.length, prevBlocks.length); i++) { + let added: TransactionClassified[] = []; + let removed: string[] = []; + const changed: TransactionClassified[] = []; + if (mempoolBlocks[i] && !prevBlocks[i]) { + added = mempoolBlocks[i].transactions; + } else if (!mempoolBlocks[i] && prevBlocks[i]) { + removed = prevBlocks[i].transactions.map(tx => tx.txid); + } else if (mempoolBlocks[i] && prevBlocks[i]) { + const prevIds = {}; + const newIds = {}; + prevBlocks[i].transactions.forEach(tx => { + prevIds[tx.txid] = tx; + }); + mempoolBlocks[i].transactions.forEach(tx => { + newIds[tx.txid] = true; + }); + prevBlocks[i].transactions.forEach(tx => { + if (!newIds[tx.txid]) { + removed.push(tx.txid); + } + }); + mempoolBlocks[i].transactions.forEach(tx => { + if (!prevIds[tx.txid]) { + added.push(tx); + } else if (tx.rate !== prevIds[tx.txid].rate || tx.acc !== prevIds[tx.txid].acc) { + changed.push(tx); + } + }); + } + mempoolBlockDeltas.push({ + added: added.map(this.compressTx), + removed, + changed: changed.map(this.compressDeltaChange), + }); + } + return mempoolBlockDeltas; + } + + public async $makeBlockTemplates(transactions: string[], newMempool: { [txid: string]: MempoolTransactionExtended }, candidates: GbtCandidates | undefined, saveResults: boolean = false, useAccelerations: boolean = false, accelerationPool?: number): Promise { + const start = Date.now(); + + // reset mempool short ids + if (saveResults) { + this.resetUids(); + } + // set missing short ids + for (const txid of transactions) { + const tx = newMempool[txid]; + this.setUid(tx, !saveResults); + } + + const accelerations = useAccelerations ? mempool.getAccelerations() : {}; + + // prepare a stripped down version of the mempool with only the minimum necessary data + // to reduce the overhead of passing this data to the worker thread + const strippedMempool: Map = new Map(); + for (const txid of transactions) { + const entry = newMempool[txid]; + if (entry.uid !== null && entry.uid !== undefined) { + const stripped = { + uid: entry.uid, + fee: entry.fee + (useAccelerations && (!accelerationPool || accelerations[entry.txid]?.pools?.includes(accelerationPool)) ? (accelerations[entry.txid]?.feeDelta || 0) : 0), + weight: (entry.adjustedVsize * 4), + sigops: entry.sigops, + feePerVsize: entry.adjustedFeePerVsize || entry.feePerVsize, + effectiveFeePerVsize: entry.effectiveFeePerVsize || entry.adjustedFeePerVsize || entry.feePerVsize, + inputs: entry.vin.map(v => this.getUid(newMempool[v.txid])).filter(uid => (uid !== null && uid !== undefined)) as number[], + }; + strippedMempool.set(entry.uid, stripped); + } + } + + // (re)initialize tx selection worker thread + if (!this.txSelectionWorker) { + this.txSelectionWorker = new Worker(path.resolve(__dirname, './tx-selection-worker.js')); + // if the thread throws an unexpected error, or exits for any other reason, + // reset worker state so that it will be re-initialized on the next run + this.txSelectionWorker.once('error', () => { + this.txSelectionWorker = null; + }); + this.txSelectionWorker.once('exit', () => { + this.txSelectionWorker = null; + }); + } + + // run the block construction algorithm in a separate thread, and wait for a result + let threadErrorListener; + try { + const workerResultPromise = new Promise<{ blocks: number[][], rates: Map, clusters: Map }>((resolve, reject) => { + threadErrorListener = reject; + this.txSelectionWorker?.once('message', (result): void => { + resolve(result); + }); + this.txSelectionWorker?.once('error', reject); + }); + this.txSelectionWorker.postMessage({ type: 'set', mempool: strippedMempool }); + const { blocks, rates, clusters } = this.convertResultTxids(await workerResultPromise); + + // clean up thread error listener + this.txSelectionWorker?.removeListener('error', threadErrorListener); + + const processed = this.processBlockTemplates(newMempool, blocks, null, Object.entries(rates), Object.values(clusters), candidates, accelerations, accelerationPool, saveResults); + + logger.debug(`makeBlockTemplates completed in ${(Date.now() - start)/1000} seconds`); + + return processed; + } catch (e) { + logger.err('makeBlockTemplates failed. ' + (e instanceof Error ? e.message : e)); + } + return this.mempoolBlocks; + } + + public async $updateBlockTemplates(transactions: string[], newMempool: { [txid: string]: MempoolTransactionExtended }, added: MempoolTransactionExtended[], removed: MempoolTransactionExtended[], candidates: GbtCandidates | undefined, accelerationDelta: string[] = [], saveResults: boolean = false, useAccelerations: boolean = false): Promise { + if (!this.txSelectionWorker) { + // need to reset the worker + await this.$makeBlockTemplates(transactions, newMempool, candidates, saveResults, useAccelerations); + return; + } + + const start = Date.now(); + + const accelerations = useAccelerations ? mempool.getAccelerations() : {}; + const addedAndChanged: MempoolTransactionExtended[] = useAccelerations ? accelerationDelta.map(txid => newMempool[txid]).filter(tx => tx != null).concat(added) : added; + + for (const tx of addedAndChanged) { + this.setUid(tx, false); + } + const removedTxs = removed.filter(tx => tx.uid != null) as MempoolTransactionExtended[]; + + // prepare a stripped down version of the mempool with only the minimum necessary data + // to reduce the overhead of passing this data to the worker thread + const addedStripped: CompactThreadTransaction[] = addedAndChanged.filter(entry => entry.uid != null).map(entry => { + return { + uid: entry.uid || 0, + fee: entry.fee + (useAccelerations ? (accelerations[entry.txid]?.feeDelta || 0) : 0), + weight: (entry.adjustedVsize * 4), + sigops: entry.sigops, + feePerVsize: entry.adjustedFeePerVsize || entry.feePerVsize, + effectiveFeePerVsize: entry.effectiveFeePerVsize || entry.adjustedFeePerVsize || entry.feePerVsize, + inputs: entry.vin.map(v => this.getUid(newMempool[v.txid])).filter(uid => (uid !== null && uid !== undefined)) as number[], + }; + }); + + // run the block construction algorithm in a separate thread, and wait for a result + let threadErrorListener; + try { + const workerResultPromise = new Promise<{ blocks: number[][], rates: Map, clusters: Map }>((resolve, reject) => { + threadErrorListener = reject; + this.txSelectionWorker?.once('message', (result): void => { + resolve(result); + }); + this.txSelectionWorker?.once('error', reject); + }); + this.txSelectionWorker.postMessage({ type: 'update', added: addedStripped, removed: removedTxs.map(tx => tx.uid) as number[] }); + const { blocks, rates, clusters } = this.convertResultTxids(await workerResultPromise); + + this.removeUids(removedTxs); + + // clean up thread error listener + this.txSelectionWorker?.removeListener('error', threadErrorListener); + + this.processBlockTemplates(newMempool, blocks, null, Object.entries(rates), Object.values(clusters), candidates, accelerations, null, saveResults); + logger.debug(`updateBlockTemplates completed in ${(Date.now() - start) / 1000} seconds`); + } catch (e) { + logger.err('updateBlockTemplates failed. ' + (e instanceof Error ? e.message : e)); + } + } + + private resetRustGbt(): void { + this.rustInitialized = false; + this.rustGbtGenerator = new GbtGenerator(config.MEMPOOL.BLOCK_WEIGHT_UNITS, config.MEMPOOL.MEMPOOL_BLOCKS_AMOUNT); + } + + public async $rustMakeBlockTemplates(txids: string[], newMempool: { [txid: string]: MempoolTransactionExtended }, candidates: GbtCandidates | undefined, saveResults: boolean = false, useAccelerations: boolean = false, accelerationPool?: number): Promise { + const start = Date.now(); + + // reset mempool short ids + if (saveResults) { + this.resetUids(); + } + + const transactions = txids.map(txid => newMempool[txid]).filter(tx => tx != null); + // set missing short ids + for (const tx of transactions) { + this.setUid(tx, !saveResults); + } + // set short ids for transaction inputs + for (const tx of transactions) { + tx.inputs = tx.vin.map(v => this.getUid(newMempool[v.txid])).filter(uid => (uid !== null && uid !== undefined)) as number[]; + } + + const accelerations = useAccelerations ? mempool.getAccelerations() : {}; + const acceleratedList = accelerationPool ? Object.values(accelerations).filter(acc => newMempool[acc.txid] && acc.pools.includes(accelerationPool)) : Object.values(accelerations).filter(acc => newMempool[acc.txid]); + const convertedAccelerations = acceleratedList.map(acc => { + this.setUid(newMempool[acc.txid], true); + return { + uid: this.getUid(newMempool[acc.txid]), + delta: acc.feeDelta, + }; + }); + + // run the block construction algorithm in a separate thread, and wait for a result + const rustGbt = saveResults ? this.rustGbtGenerator : new GbtGenerator(config.MEMPOOL.BLOCK_WEIGHT_UNITS, config.MEMPOOL.MEMPOOL_BLOCKS_AMOUNT); + try { + const { blocks, blockWeights, rates, clusters, overflow } = this.convertNapiResultTxids( + await rustGbt.make(transactions as RustThreadTransaction[], convertedAccelerations as RustThreadAcceleration[], this.nextUid), + ); + if (saveResults) { + this.rustInitialized = true; + } + const expectedSize = transactions.length; + const resultMempoolSize = blocks.reduce((total, block) => total + block.length, 0) + overflow.length; + logger.debug(`RUST updateBlockTemplates returned ${resultMempoolSize} txs out of ${expectedSize} in the mempool, ${overflow.length} were unmineable`); + const processed = this.processBlockTemplates(newMempool, blocks, blockWeights, rates, clusters, candidates, accelerations, accelerationPool, saveResults); + logger.debug(`RUST makeBlockTemplates completed in ${(Date.now() - start)/1000} seconds`); + return processed; + } catch (e) { + logger.err('RUST makeBlockTemplates failed. ' + (e instanceof Error ? e.message : e)); + if (saveResults) { + this.resetRustGbt(); + } + } + return this.mempoolBlocks; + } + + public async $oneOffRustBlockTemplates(transactions: string[], newMempool: { [txid: string]: MempoolTransactionExtended }, candidates: GbtCandidates | undefined, useAccelerations: boolean, accelerationPool?: number): Promise { + return this.$rustMakeBlockTemplates(transactions, newMempool, candidates, false, useAccelerations, accelerationPool); + } + + public async $rustUpdateBlockTemplates(transactions: string[], newMempool: { [txid: string]: MempoolTransactionExtended }, added: MempoolTransactionExtended[], removed: MempoolTransactionExtended[], candidates: GbtCandidates | undefined, useAccelerations: boolean, accelerationPool?: number): Promise { + // GBT optimization requires that uids never get too sparse + // as a sanity check, we should also explicitly prevent uint32 uid overflow + if (this.nextUid + added.length >= Math.min(Math.max(262144, 2 * transactions.length), MAX_UINT32)) { + this.resetRustGbt(); + } + + if (!this.rustInitialized) { + // need to reset the worker + return this.$rustMakeBlockTemplates(transactions, newMempool, candidates, true, useAccelerations, accelerationPool); + } + + const start = Date.now(); + // set missing short ids + for (const tx of added) { + this.setUid(tx, false); + } + // set short ids for transaction inputs + for (const tx of added) { + tx.inputs = tx.vin.map(v => this.getUid(newMempool[v.txid])).filter(uid => (uid !== null && uid !== undefined)) as number[]; + } + const removedTxs = removed.filter(tx => tx.uid != null) as MempoolTransactionExtended[]; + + const accelerations = useAccelerations ? mempool.getAccelerations() : {}; + const acceleratedList = accelerationPool ? Object.values(accelerations).filter(acc => newMempool[acc.txid] && acc.pools.includes(accelerationPool)) : Object.values(accelerations).filter(acc => newMempool[acc.txid]); + const convertedAccelerations = acceleratedList.map(acc => { + this.setUid(newMempool[acc.txid], true); + return { + uid: this.getUid(newMempool[acc.txid]), + delta: acc.feeDelta, + }; + }); + + // run the block construction algorithm in a separate thread, and wait for a result + try { + const { blocks, blockWeights, rates, clusters, overflow } = this.convertNapiResultTxids( + await this.rustGbtGenerator.update( + added as RustThreadTransaction[], + removedTxs.map(tx => tx.uid) as number[], + convertedAccelerations as RustThreadAcceleration[], + this.nextUid, + ), + ); + const resultMempoolSize = blocks.reduce((total, block) => total + block.length, 0) + overflow.length; + logger.debug(`RUST updateBlockTemplates returned ${resultMempoolSize} txs out of ${transactions.length} candidates, ${overflow.length} were unmineable`); + if (transactions.length !== resultMempoolSize) { + throw new Error(`GBT returned wrong number of transactions ${transactions.length} vs ${resultMempoolSize}, cache is probably out of sync`); + } else { + const processed = this.processBlockTemplates(newMempool, blocks, blockWeights, rates, clusters, candidates, accelerations, accelerationPool, true); + this.removeUids(removedTxs); + logger.debug(`RUST updateBlockTemplates completed in ${(Date.now() - start)/1000} seconds`); + return processed; } + } catch (e) { + logger.err('RUST updateBlockTemplates failed. ' + (e instanceof Error ? e.message : e)); + this.resetRustGbt(); + return this.mempoolBlocks; } - memPoolArray.sort((a, b) => b.feePerVsize - a.feePerVsize); - const transactionsSorted = memPoolArray.filter((tx) => tx.feePerVsize); - this.mempoolBlocks = this.calculateMempoolBlocks(transactionsSorted); } - private calculateMempoolBlocks(transactionsSorted: TransactionExtended[]): MempoolBlockWithTransactions[] { - const mempoolBlocks: MempoolBlockWithTransactions[] = []; - let blockVSize = 0; - let blockSize = 0; - let transactions: TransactionExtended[] = []; - transactionsSorted.forEach((tx) => { - if (blockVSize + tx.vsize <= 1000000 || mempoolBlocks.length === config.DEFAULT_PROJECTED_BLOCKS_AMOUNT - 1) { - blockVSize += tx.vsize; - blockSize += tx.size; - transactions.push(tx); + private processBlockTemplates(mempool: { [txid: string]: MempoolTransactionExtended }, blocks: string[][], blockWeights: number[] | null, rates: [string, number][], clusters: string[][], candidates: GbtCandidates | undefined, accelerations: { [txid: string]: Acceleration }, accelerationPool, saveResults): MempoolBlockWithTransactions[] { + for (const txid of Object.keys(candidates?.txs ?? mempool)) { + if (txid in mempool) { + mempool[txid].cpfpDirty = false; + mempool[txid].ancestors = []; + mempool[txid].descendants = []; + mempool[txid].bestDescendant = null; + } + } + for (const [txid, rate] of rates) { + if (txid in mempool) { + mempool[txid].cpfpDirty = (rate !== mempool[txid].effectiveFeePerVsize); + mempool[txid].effectiveFeePerVsize = rate; + mempool[txid].cpfpChecked = true; + } + } + + const lastBlockIndex = blocks.length - 1; + let hasBlockStack = blocks.length >= 8; + let stackWeight; + let feeStatsCalculator: OnlineFeeStatsCalculator | void; + if (hasBlockStack) { + if (blockWeights && blockWeights[7] !== null) { + stackWeight = blockWeights[7]; } else { - mempoolBlocks.push(this.dataToMempoolBlocks(transactions, blockSize, blockVSize, mempoolBlocks.length)); - blockVSize = tx.vsize; - blockSize = tx.size; - transactions = [tx]; + stackWeight = blocks[lastBlockIndex].reduce((total, tx) => total + (mempool[tx]?.weight || 0), 0); } + hasBlockStack = stackWeight > config.MEMPOOL.BLOCK_WEIGHT_UNITS; + feeStatsCalculator = new OnlineFeeStatsCalculator(stackWeight, 0.5, [10, 20, 30, 40, 50, 60, 70, 80, 90]); + } + + for (const cluster of clusters) { + for (const memberTxid of cluster) { + const mempoolTx = mempool[memberTxid]; + if (mempoolTx) { + const ancestors: Ancestor[] = []; + const descendants: Ancestor[] = []; + let matched = false; + cluster.forEach(txid => { + if (txid === memberTxid) { + matched = true; + } else { + if (!mempool[txid]) { + console.log('txid missing from mempool! ', txid, candidates?.txs[txid]); + } + const relative = { + txid: txid, + fee: mempool[txid].fee, + weight: (mempool[txid].adjustedVsize * 4), + }; + if (matched) { + descendants.push(relative); + mempoolTx.lastBoosted = Math.max(mempoolTx.lastBoosted || 0, mempool[txid].firstSeen || 0); + } else { + ancestors.push(relative); + } + } + }); + if (mempoolTx.ancestors?.length !== ancestors.length || mempoolTx.descendants?.length !== descendants.length) { + mempoolTx.cpfpDirty = true; + } + Object.assign(mempoolTx, {ancestors, descendants, bestDescendant: null, cpfpChecked: true}); + } + } + } + + const isAcceleratedBy : { [txid: string]: number[] | false } = {}; + + const sizeLimit = (config.MEMPOOL.BLOCK_WEIGHT_UNITS / 4) * 1.2; + // update this thread's mempool with the results + let mempoolTx: MempoolTransactionExtended; + const mempoolBlocks: MempoolBlockWithTransactions[] = blocks.map((block, blockIndex) => { + let totalSize = 0; + let totalVsize = 0; + let totalWeight = 0; + let totalFees = 0; + const transactions: MempoolTransactionExtended[] = []; + + // backfill purged transactions + if (candidates?.txs && blockIndex === blocks.length - 1) { + for (const txid of Object.keys(mempool)) { + if (!candidates.txs[txid]) { + block.push(txid); + } + } + } + + for (const txid of block) { + if (txid) { + mempoolTx = mempool[txid]; + // save position in projected blocks + mempoolTx.position = { + block: blockIndex, + vsize: totalVsize + (mempoolTx.vsize / 2), + }; + + const acceleration = accelerations[txid]; + if (isAcceleratedBy[txid] || (acceleration && (!accelerationPool || acceleration.pools.includes(accelerationPool)))) { + if (!mempoolTx.acceleration) { + mempoolTx.cpfpDirty = true; + } + mempoolTx.acceleration = true; + mempoolTx.acceleratedBy = isAcceleratedBy[txid] || acceleration?.pools; + mempoolTx.acceleratedAt = acceleration?.added; + for (const ancestor of mempoolTx.ancestors || []) { + if (!mempool[ancestor.txid].acceleration) { + mempool[ancestor.txid].cpfpDirty = true; + } + mempool[ancestor.txid].acceleration = true; + mempool[ancestor.txid].acceleratedBy = mempoolTx.acceleratedBy; + mempool[ancestor.txid].acceleratedAt = mempoolTx.acceleratedAt; + isAcceleratedBy[ancestor.txid] = mempoolTx.acceleratedBy; + } + } else { + if (mempoolTx.acceleration) { + mempoolTx.cpfpDirty = true; + } + delete mempoolTx.acceleration; + } + + // online calculation of stack-of-blocks fee stats + if (hasBlockStack && blockIndex === lastBlockIndex && feeStatsCalculator) { + feeStatsCalculator.processNext(mempoolTx); + } + + totalSize += mempoolTx.size; + totalVsize += mempoolTx.vsize; + totalWeight += mempoolTx.weight; + totalFees += mempoolTx.fee; + + if (totalVsize <= sizeLimit) { + transactions.push(mempoolTx); + } + } + } + return this.dataToMempoolBlocks( + block, + transactions, + totalSize, + totalWeight, + totalFees, + (hasBlockStack && blockIndex === lastBlockIndex && feeStatsCalculator) ? feeStatsCalculator.getRawFeeStats() : undefined, + ); }); - if (transactions.length) { - mempoolBlocks.push(this.dataToMempoolBlocks(transactions, blockSize, blockVSize, mempoolBlocks.length)); + + if (saveResults) { + const deltas = this.calculateMempoolDeltas(this.mempoolBlocks, mempoolBlocks); + this.mempoolBlocks = mempoolBlocks; + this.mempoolBlockDeltas = deltas; + this.updateAccelerationPositions(mempool, accelerations, mempoolBlocks); } + return mempoolBlocks; } - private dataToMempoolBlocks(transactions: TransactionExtended[], - blockSize: number, blockVSize: number, blocksIndex: number): MempoolBlockWithTransactions { - let rangeLength = 4; - if (blocksIndex === 0) { - rangeLength = 8; - } - if (transactions.length > 4000) { - rangeLength = 6; - } else if (transactions.length > 10000) { - rangeLength = 8; + private dataToMempoolBlocks(transactionIds: string[], transactions: MempoolTransactionExtended[], totalSize: number, totalWeight: number, totalFees: number, feeStats?: EffectiveFeeStats ): MempoolBlockWithTransactions { + if (!feeStats) { + feeStats = Common.calcEffectiveFeeStatistics(transactions); } return { - blockSize: blockSize, - blockVSize: blockVSize, - nTx: transactions.length, - totalFees: transactions.reduce((acc, cur) => acc + cur.fee, 0), - medianFee: Common.median(transactions.map((tx) => tx.feePerVsize)), - feeRange: Common.getFeesInRange(transactions, rangeLength), - transactionIds: transactions.map((tx) => tx.txid), + blockSize: totalSize, + blockVSize: (totalWeight / 4), // fractional vsize to avoid rounding errors + nTx: transactionIds.length, + totalFees: totalFees, + medianFee: feeStats.medianFee, // Common.percentile(transactions.map((tx) => tx.effectiveFeePerVsize), config.MEMPOOL.RECOMMENDED_FEE_PERCENTILE), + feeRange: feeStats.feeRange, //Common.getFeesInRange(transactions, rangeLength), + transactionIds: transactionIds, + transactions: transactions.map((tx) => Common.classifyTransaction(tx)), }; } + + private resetUids(): void { + this.uidMap.clear(); + this.txidMap.clear(); + this.nextUid = 1; + } + + private setUid(tx: MempoolTransactionExtended, skipSet = false): number { + if (!this.txidMap.has(tx.txid) || !skipSet) { + const uid = this.nextUid; + this.nextUid++; + this.uidMap.set(uid, tx.txid); + this.txidMap.set(tx.txid, uid); + tx.uid = uid; + return uid; + } else { + tx.uid = this.txidMap.get(tx.txid) as number; + return tx.uid; + } + } + + private getUid(tx: MempoolTransactionExtended): number | void { + if (tx) { + return this.txidMap.get(tx.txid); + } + } + + private removeUids(txs: MempoolTransactionExtended[]): void { + for (const tx of txs) { + const uid = this.txidMap.get(tx.txid); + if (uid != null) { + this.uidMap.delete(uid); + this.txidMap.delete(tx.txid); + } + tx.uid = undefined; + } + } + + private convertResultTxids({ blocks, rates, clusters }: { blocks: number[][], rates: Map, clusters: Map}) + : { blocks: string[][], rates: { [root: string]: number }, clusters: { [root: string]: string[] }} { + const convertedBlocks: string[][] = blocks.map(block => block.map(uid => { + return this.uidMap.get(uid) || ''; + })); + const convertedRates = {}; + for (const rateUid of rates.keys()) { + const rateTxid = this.uidMap.get(rateUid); + if (rateTxid) { + convertedRates[rateTxid] = rates.get(rateUid); + } + } + const convertedClusters = {}; + for (const rootUid of clusters.keys()) { + const rootTxid = this.uidMap.get(rootUid); + if (rootTxid) { + const members = clusters.get(rootUid)?.map(uid => { + return this.uidMap.get(uid); + }); + convertedClusters[rootTxid] = members; + } + } + return { blocks: convertedBlocks, rates: convertedRates, clusters: convertedClusters } as { blocks: string[][], rates: { [root: string]: number }, clusters: { [root: string]: string[] }}; + } + + private convertNapiResultTxids({ blocks, blockWeights, rates, clusters, overflow }: GbtResult) + : { blocks: string[][], blockWeights: number[], rates: [string, number][], clusters: string[][], overflow: string[] } { + const convertedBlocks: string[][] = blocks.map(block => block.map(uid => { + const txid = this.uidMap.get(uid); + if (txid !== undefined) { + return txid; + } else { + throw new Error('GBT returned a block containing a transaction with unknown uid'); + } + })); + const convertedRates: [string, number][] = []; + for (const [rateUid, rate] of rates) { + const rateTxid = this.uidMap.get(rateUid) as string; + convertedRates.push([rateTxid, rate]); + } + const convertedClusters: string[][] = []; + for (const cluster of clusters) { + convertedClusters.push(cluster.map(uid => this.uidMap.get(uid)) as string[]); + } + const convertedOverflow: string[] = overflow.map(uid => { + const txid = this.uidMap.get(uid); + if (txid !== undefined) { + return txid; + } else { + throw new Error('GBT returned an unmineable transaction with unknown uid'); + } + }); + return { blocks: convertedBlocks, blockWeights, rates: convertedRates, clusters: convertedClusters, overflow: convertedOverflow }; + } + + public compressTx(tx: TransactionClassified): TransactionCompressed { + if (tx.acc) { + return [ + tx.txid, + tx.fee, + tx.vsize, + tx.value, + Math.round((tx.rate || (tx.fee / tx.vsize)) * 100) / 100, + tx.flags, + tx.time || 0, + 1, + ]; + } else { + return [ + tx.txid, + tx.fee, + tx.vsize, + tx.value, + Math.round((tx.rate || (tx.fee / tx.vsize)) * 100) / 100, + tx.flags, + tx.time || 0, + ]; + } + } + + public compressDeltaChange(tx: TransactionClassified): MempoolDeltaChange { + return [ + tx.txid, + Math.round((tx.rate || (tx.fee / tx.vsize)) * 100) / 100, + tx.flags, + tx.acc ? 1 : 0, + ]; + } + + // estimates and saves positions of accelerations in mining partner mempools + private updateAccelerationPositions(mempoolCache: { [txid: string]: MempoolTransactionExtended }, accelerations: { [txid: string]: Acceleration }, mempoolBlocks: MempoolBlockWithTransactions[]): void { + const accelerationPositions: { [txid: string]: { poolId: number, pool: string, block: number, vsize: number }[] } = {}; + // keep track of simulated mempool blocks for each active pool + const pools: { + [pool: string]: { name: string, block: number, vsize: number, accelerations: string[], complete: boolean }; + } = {}; + // prepare a list of accelerations in ascending order (we'll pop items off the end of the list) + const accQueue: { acceleration: Acceleration, rate: number, vsize: number }[] = Object.values(accelerations).map(acc => { + let vsize = mempoolCache[acc.txid].vsize; + for (const ancestor of mempoolCache[acc.txid].ancestors || []) { + vsize += (ancestor.weight / 4); + } + return { + acceleration: acc, + rate: mempoolCache[acc.txid].effectiveFeePerVsize, + vsize + }; + }).sort((a, b) => a.rate - b.rate); + // initialize the pool tracker + for (const { acceleration } of accQueue) { + accelerationPositions[acceleration.txid] = []; + for (const pool of acceleration.pools) { + if (!pools[pool]) { + pools[pool] = { + name: this.pools[pool]?.name || 'unknown', + block: 0, + vsize: 0, + accelerations: [], + complete: false, + }; + } + pools[pool].accelerations.push(acceleration.txid); + } + for (const ancestor of mempoolCache[acceleration.txid].ancestors || []) { + accelerationPositions[ancestor.txid] = []; + } + } + + for (const pool of Object.keys(pools)) { + // if any pools accepted *every* acceleration, we can just use the GBT result positions directly + if (pools[pool].accelerations.length === Object.keys(accelerations).length) { + pools[pool].complete = true; + } + } + + let block = 0; + let index = 0; + let next = accQueue.pop(); + // build simulated blocks for each pool by taking the best option from + // either the mempool or the list of accelerations. + while (next && block < mempoolBlocks.length) { + while (next && index < mempoolBlocks[block].transactions.length) { + const nextTx = mempoolBlocks[block].transactions[index]; + if (next.rate >= (nextTx.rate || (nextTx.fee / nextTx.vsize))) { + for (const pool of next.acceleration.pools) { + if (pools[pool].vsize + next.vsize <= 999_000) { + pools[pool].vsize += next.vsize; + } else { + pools[pool].block++; + pools[pool].vsize = next.vsize; + } + // insert the acceleration into matching pool's blocks + if (pools[pool].complete && mempoolCache[next.acceleration.txid]?.position !== undefined) { + accelerationPositions[next.acceleration.txid].push({ + ...mempoolCache[next.acceleration.txid].position as { block: number, vsize: number }, + poolId: pool, + pool: pools[pool].name + }); + } else { + accelerationPositions[next.acceleration.txid].push({ + poolId: pool, + pool: pools[pool].name, + block: pools[pool].block, + vsize: pools[pool].vsize - (next.vsize / 2), + }); + } + // and any accelerated ancestors + for (const ancestor of mempoolCache[next.acceleration.txid].ancestors || []) { + if (pools[pool].complete && mempoolCache[ancestor.txid]?.position !== undefined) { + accelerationPositions[ancestor.txid].push({ + ...mempoolCache[ancestor.txid].position as { block: number, vsize: number }, + poolId: pool, + pool: pools[pool].name, + }); + } else { + accelerationPositions[ancestor.txid].push({ + poolId: pool, + pool: pools[pool].name, + block: pools[pool].block, + vsize: pools[pool].vsize - (next.vsize / 2), + }); + } + } + } + next = accQueue.pop(); + } else { + // skip accelerated transactions and their CPFP ancestors + if (accelerationPositions[nextTx.txid] == null) { + // insert into all pools' blocks + for (const pool of Object.keys(pools)) { + if (pools[pool].vsize + nextTx.vsize <= 999_000) { + pools[pool].vsize += nextTx.vsize; + } else { + pools[pool].block++; + pools[pool].vsize = nextTx.vsize; + } + } + } + index++; + } + } + block++; + index = 0; + } + mempool.setAccelerationPositions(accelerationPositions); + } } export default new MempoolBlocks(); diff --git a/backend/src/api/mempool.ts b/backend/src/api/mempool.ts index 05d3104624..89377335d2 100644 --- a/backend/src/api/mempool.ts +++ b/backend/src/api/mempool.ts @@ -1,13 +1,33 @@ -const config = require('../../mempool-config.json'); -import bitcoinApi from './bitcoin/electrs-api'; -import { MempoolInfo, TransactionExtended, Transaction, VbytesPerSecond } from '../interfaces'; +import config from '../config'; +import bitcoinApi from './bitcoin/bitcoin-api-factory'; +import { MempoolTransactionExtended, TransactionExtended, VbytesPerSecond, GbtCandidates } from '../mempool.interfaces'; +import logger from '../logger'; +import { Common } from './common'; +import transactionUtils from './transaction-utils'; +import { IBitcoinApi } from './bitcoin/bitcoin-api.interface'; +import loadingIndicators from './loading-indicators'; +import bitcoinClient from './bitcoin/bitcoin-client'; +import bitcoinSecondClient from './bitcoin/bitcoin-second-client'; +import rbfCache from './rbf-cache'; +import { Acceleration } from './services/acceleration'; +import redisCache from './redis-cache'; +import blocks from './blocks'; class Mempool { private inSync: boolean = false; - private mempoolCache: { [txId: string]: TransactionExtended } = {}; - private mempoolInfo: MempoolInfo = { size: 0, bytes: 0 }; - private mempoolChangedCallback: ((newMempool: { [txId: string]: TransactionExtended; }, newTransactions: TransactionExtended[], - deletedTransactions: TransactionExtended[]) => void) | undefined; + private mempoolCacheDelta: number = -1; + private mempoolCache: { [txId: string]: MempoolTransactionExtended } = {}; + private mempoolCandidates: { [txid: string ]: boolean } = {}; + private spendMap = new Map(); + private mempoolInfo: IBitcoinApi.MempoolInfo = { loaded: false, size: 0, bytes: 0, usage: 0, total_fee: 0, + maxmempool: 300000000, mempoolminfee: Common.isLiquid() ? 0.00000100 : 0.00001000, minrelaytxfee: Common.isLiquid() ? 0.00000100 : 0.00001000 }; + private mempoolChangedCallback: ((newMempool: {[txId: string]: MempoolTransactionExtended; }, newTransactions: MempoolTransactionExtended[], + deletedTransactions: MempoolTransactionExtended[], accelerationDelta: string[]) => void) | undefined; + private $asyncMempoolChangedCallback: ((newMempool: {[txId: string]: MempoolTransactionExtended; }, mempoolSize: number, newTransactions: MempoolTransactionExtended[], + deletedTransactions: MempoolTransactionExtended[], accelerationDelta: string[], candidates?: GbtCandidates) => Promise) | undefined; + + private accelerations: { [txId: string]: Acceleration } = {}; + private accelerationPositions: { [txid: string]: { poolId: number, pool: string, block: number, vsize: number }[] } = {}; private txPerSecondArray: number[] = []; private txPerSecond: number = 0; @@ -15,40 +35,153 @@ class Mempool { private vBytesPerSecondArray: VbytesPerSecond[] = []; private vBytesPerSecond: number = 0; private mempoolProtection = 0; + private latestTransactions: any[] = []; + + private ESPLORA_MISSING_TX_WARNING_THRESHOLD = 100; + private SAMPLE_TIME = 10000; // In ms + private timer = new Date().getTime(); + private missingTxCount = 0; + private mainLoopTimeout: number = 120000; + + public limitGBT = config.MEMPOOL.USE_SECOND_NODE_FOR_MINFEE && config.MEMPOOL.LIMIT_GBT; constructor() { setInterval(this.updateTxPerSecond.bind(this), 1000); } - public isInSync() { + /** + * Return true if we should leave resources available for mempool tx caching + */ + public hasPriority(): boolean { + if (this.inSync) { + return false; + } else { + return this.mempoolCacheDelta == -1 || this.mempoolCacheDelta > 25; + } + } + + public isInSync(): boolean { return this.inSync; } - public setMempoolChangedCallback(fn: (newMempool: { [txId: string]: TransactionExtended; }, - newTransactions: TransactionExtended[], deletedTransactions: TransactionExtended[]) => void) { + public setOutOfSync(): void { + this.inSync = false; + loadingIndicators.setProgress('mempool', 99); + } + + public getLatestTransactions() { + return this.latestTransactions; + } + + public setMempoolChangedCallback(fn: (newMempool: { [txId: string]: MempoolTransactionExtended; }, + newTransactions: MempoolTransactionExtended[], deletedTransactions: MempoolTransactionExtended[], accelerationDelta: string[]) => void): void { this.mempoolChangedCallback = fn; } - public getMempool(): { [txid: string]: TransactionExtended } { + public setAsyncMempoolChangedCallback(fn: (newMempool: { [txId: string]: MempoolTransactionExtended; }, mempoolSize: number, + newTransactions: MempoolTransactionExtended[], deletedTransactions: MempoolTransactionExtended[], accelerationDelta: string[], + candidates?: GbtCandidates) => Promise): void { + this.$asyncMempoolChangedCallback = fn; + } + + public getMempool(): { [txid: string]: MempoolTransactionExtended } { return this.mempoolCache; } - public setMempool(mempoolData: { [txId: string]: TransactionExtended }) { + public getSpendMap(): Map { + return this.spendMap; + } + + public getFromSpendMap(txid, index): MempoolTransactionExtended | void { + return this.spendMap.get(`${txid}:${index}`); + } + + public async $setMempool(mempoolData: { [txId: string]: MempoolTransactionExtended }) { this.mempoolCache = mempoolData; + let count = 0; + const redisTimer = Date.now(); + if (config.MEMPOOL.CACHE_ENABLED && config.REDIS.ENABLED) { + logger.debug(`Migrating ${Object.keys(this.mempoolCache).length} transactions from disk cache to Redis cache`); + } + for (const txid of Object.keys(this.mempoolCache)) { + if (!this.mempoolCache[txid].adjustedVsize || this.mempoolCache[txid].sigops == null || this.mempoolCache[txid].effectiveFeePerVsize == null) { + this.mempoolCache[txid] = transactionUtils.extendMempoolTransaction(this.mempoolCache[txid]); + } + if (this.mempoolCache[txid].order == null) { + this.mempoolCache[txid].order = transactionUtils.txidToOrdering(txid); + } + for (const vin of this.mempoolCache[txid].vin) { + transactionUtils.addInnerScriptsToVin(vin); + } + count++; + if (config.MEMPOOL.CACHE_ENABLED && config.REDIS.ENABLED) { + await redisCache.$addTransaction(this.mempoolCache[txid]); + } + this.mempoolCache[txid].flags = Common.getTransactionFlags(this.mempoolCache[txid]); + this.mempoolCache[txid].cpfpChecked = false; + this.mempoolCache[txid].cpfpDirty = true; + this.mempoolCache[txid].cpfpUpdated = undefined; + } + if (config.MEMPOOL.CACHE_ENABLED && config.REDIS.ENABLED) { + await redisCache.$flushTransactions(); + logger.debug(`Finished migrating cache transactions in ${((Date.now() - redisTimer) / 1000).toFixed(2)} seconds`); + } if (this.mempoolChangedCallback) { - this.mempoolChangedCallback(this.mempoolCache, [], []); + this.mempoolChangedCallback(this.mempoolCache, [], [], []); } + if (this.$asyncMempoolChangedCallback) { + await this.$asyncMempoolChangedCallback(this.mempoolCache, count, [], [], [], this.limitGBT ? { txs: {}, added: [], removed: [] } : undefined); + } + this.addToSpendMap(Object.values(this.mempoolCache)); } - public async updateMemPoolInfo() { - try { - this.mempoolInfo = await bitcoinApi.getMempoolInfo(); - } catch (err) { - console.log('Error getMempoolInfo', err); + public async $reloadMempool(expectedCount: number): Promise { + let count = 0; + let done = false; + let last_txid; + const newTransactions: MempoolTransactionExtended[] = []; + loadingIndicators.setProgress('mempool', count / expectedCount * 100); + while (!done) { + try { + const result = await bitcoinApi.$getAllMempoolTransactions(last_txid, config.ESPLORA.BATCH_QUERY_BASE_SIZE); + if (result) { + for (const tx of result) { + const extendedTransaction = transactionUtils.extendMempoolTransaction(tx); + if (!this.mempoolCache[extendedTransaction.txid]) { + newTransactions.push(extendedTransaction); + this.mempoolCache[extendedTransaction.txid] = extendedTransaction; + } + count++; + } + logger.info(`Fetched ${count} of ${expectedCount} mempool transactions from esplora`); + if (result.length > 0) { + last_txid = result[result.length - 1].txid; + } else { + done = true; + } + if (Math.floor((count / expectedCount) * 100) < 100) { + loadingIndicators.setProgress('mempool', count / expectedCount * 100); + } + } else { + done = true; + } + } catch(err) { + logger.err('failed to fetch bulk mempool transactions from esplora'); + } } + logger.info(`Done inserting loaded mempool transactions into local cache`); + return newTransactions; } - public getMempoolInfo(): MempoolInfo | undefined { + public getMempoolCandidates(): { [txid: string]: boolean } { + return this.mempoolCandidates; + } + + public async $updateMemPoolInfo() { + this.mempoolInfo = await this.$getMempoolInfo(); + } + + public getMempoolInfo(): IBitcoinApi.MempoolInfo { return this.mempoolInfo; } @@ -63,8 +196,9 @@ class Mempool { public getFirstSeenForTransactions(txIds: string[]): number[] { const txTimes: number[] = []; txIds.forEach((txId: string) => { - if (this.mempoolCache[txId]) { - txTimes.push(this.mempoolCache[txId].firstSeen); + const tx = this.mempoolCache[txId]; + if (tx && tx.firstSeen) { + txTimes.push(tx.firstSeen); } else { txTimes.push(0); } @@ -72,124 +206,409 @@ class Mempool { return txTimes; } - public async getTransactionExtended(txId: string): Promise { - try { - const transaction: Transaction = await bitcoinApi.getRawTransaction(txId); - return Object.assign({ - vsize: transaction.weight / 4, - feePerVsize: transaction.fee / (transaction.weight / 4), - firstSeen: Math.round((new Date().getTime() / 1000)), - }, transaction); - } catch (e) { - console.log(txId + ' not found'); - return false; - } - } + public async $updateMempool(transactions: string[], accelerations: Acceleration[] | null, minFeeMempool: string[], minFeeTip: number, pollRate: number): Promise { + logger.debug(`Updating mempool...`); + + // warn if this run stalls the main loop for more than 2 minutes + const timer = this.startTimer(); - public async updateMempool() { - console.log('Updating mempool'); const start = new Date().getTime(); let hasChange: boolean = false; const currentMempoolSize = Object.keys(this.mempoolCache).length; - let txCount = 0; - try { - const transactions = await bitcoinApi.getRawMempool(); - const diff = transactions.length - currentMempoolSize; - const newTransactions: TransactionExtended[] = []; - - for (const txid of transactions) { - if (!this.mempoolCache[txid]) { - const transaction = await this.getTransactionExtended(txid); - if (transaction) { - this.mempoolCache[txid] = transaction; - txCount++; - if (this.inSync) { - this.txPerSecondArray.push(new Date().getTime()); - this.vBytesPerSecondArray.push({ - unixTime: new Date().getTime(), - vSize: transaction.vsize, - }); - } - hasChange = true; - if (diff > 0) { - console.log('Fetched transaction ' + txCount + ' / ' + diff); - } else { - console.log('Fetched transaction ' + txCount); - } - newTransactions.push(transaction); - } else { - console.log('Error finding transaction in mempool.'); + this.updateTimerProgress(timer, 'got raw mempool'); + const diff = transactions.length - currentMempoolSize; + let newTransactions: MempoolTransactionExtended[] = []; + + this.mempoolCacheDelta = Math.abs(diff); + + if (!this.inSync) { + loadingIndicators.setProgress('mempool', currentMempoolSize / transactions.length * 100); + } + + // https://github.com/mempool/mempool/issues/3283 + const logEsplora404 = (missingTxCount, threshold, time) => { + const log = `In the past ${time / 1000} seconds, esplora tx API replied ${missingTxCount} times with a 404 error code while updating nodejs backend mempool`; + if (missingTxCount >= threshold) { + logger.warn(log); + } else if (missingTxCount > 0) { + logger.debug(log); + } + }; + + let intervalTimer = Date.now(); + + let loaded = false; + if (config.MEMPOOL.BACKEND === 'esplora' && currentMempoolSize < transactions.length * 0.5 && transactions.length > 20_000) { + this.inSync = false; + logger.info(`Missing ${transactions.length - currentMempoolSize} mempool transactions, attempting to reload in bulk from esplora`); + try { + newTransactions = await this.$reloadMempool(transactions.length); + if (config.REDIS.ENABLED) { + for (const tx of newTransactions) { + await redisCache.$addTransaction(tx); } } + loaded = true; + } catch (e) { + logger.err('failed to load mempool in bulk from esplora, falling back to fetching individual transactions'); + } + } - if ((new Date().getTime()) - start > config.MEMPOOL_REFRESH_RATE_MS * 10) { - break; + if (!loaded) { + const remainingTxids = transactions.filter(txid => !this.mempoolCache[txid]); + const sliceLength = config.ESPLORA.BATCH_QUERY_BASE_SIZE; + for (let i = 0; i < Math.ceil(remainingTxids.length / sliceLength); i++) { + const slice = remainingTxids.slice(i * sliceLength, (i + 1) * sliceLength); + const txs = await transactionUtils.$getMempoolTransactionsExtended(slice, false, false, false); + logger.debug(`fetched ${txs.length} transactions`); + this.updateTimerProgress(timer, 'fetched new transactions'); + + for (const transaction of txs) { + this.mempoolCache[transaction.txid] = transaction; + if (this.inSync) { + this.txPerSecondArray.push(new Date().getTime()); + this.vBytesPerSecondArray.push({ + unixTime: new Date().getTime(), + vSize: transaction.vsize, + }); + } + hasChange = true; + newTransactions.push(transaction); + + if (config.REDIS.ENABLED) { + await redisCache.$addTransaction(transaction); + } + } + + if (txs.length < slice.length) { + const missing = slice.length - txs.length; + if (config.MEMPOOL.BACKEND === 'esplora') { + this.missingTxCount += missing; + } + logger.debug(`Error finding ${missing} transactions in the mempool: `); + } + + if (Date.now() - intervalTimer > Math.max(pollRate * 2, 5_000)) { + if (this.inSync) { + // Break and restart mempool loop if we spend too much time processing + // new transactions that may lead to falling behind on block height + logger.debug('Breaking mempool loop because the 5s time limit exceeded.'); + break; + } else { + const progress = (currentMempoolSize + newTransactions.length) / transactions.length * 100; + logger.debug(`Mempool is synchronizing. Processed ${newTransactions.length}/${diff} txs (${Math.round(progress)}%)`); + if (Math.floor(progress) < 100) { + loadingIndicators.setProgress('mempool', progress); + } + intervalTimer = Date.now(); + } } } + } - // Prevent mempool from clear on bitcoind restart by delaying the deletion - if (this.mempoolProtection === 0 && transactions.length / currentMempoolSize <= 0.80) { - this.mempoolProtection = 1; - this.inSync = false; - console.log('Mempool clear protection triggered.'); - setTimeout(() => { - this.mempoolProtection = 2; - console.log('Mempool clear protection resumed.'); - }, 1000 * 60 * 2); + // Reset esplora 404 counter and log a warning if needed + const elapsedTime = new Date().getTime() - this.timer; + if (elapsedTime > this.SAMPLE_TIME) { + logEsplora404(this.missingTxCount, this.ESPLORA_MISSING_TX_WARNING_THRESHOLD, elapsedTime); + this.timer = new Date().getTime(); + this.missingTxCount = 0; + } + + // Prevent mempool from clear on bitcoind restart by delaying the deletion + if (this.mempoolProtection === 0 + && currentMempoolSize > 20000 + && transactions.length / currentMempoolSize <= 0.80 + ) { + this.mempoolProtection = 1; + this.inSync = false; + logger.warn(`Mempool clear protection triggered because transactions.length: ${transactions.length} and currentMempoolSize: ${currentMempoolSize}.`); + setTimeout(() => { + this.mempoolProtection = 2; + logger.warn('Mempool clear protection ended, normal operation resumed.'); + }, 1000 * 60 * config.MEMPOOL.CLEAR_PROTECTION_MINUTES); + } + + const deletedTransactions: MempoolTransactionExtended[] = []; + + if (this.mempoolProtection !== 1) { + this.mempoolProtection = 0; + // Index object for faster search + const transactionsObject = {}; + transactions.forEach((txId) => transactionsObject[txId] = true); + + // Delete evicted transactions from mempool + for (const tx in this.mempoolCache) { + if (!transactionsObject[tx]) { + deletedTransactions.push(this.mempoolCache[tx]); + } } + for (const tx of deletedTransactions) { + delete this.mempoolCache[tx.txid]; + } + } - let newMempool = {}; - const deletedTransactions: TransactionExtended[] = []; + const candidates = await this.getNextCandidates(minFeeMempool, minFeeTip, deletedTransactions); - if (this.mempoolProtection !== 1) { - this.mempoolProtection = 0; - // Index object for faster search - const transactionsObject = {}; - transactions.forEach((txId) => transactionsObject[txId] = true); + const newMempoolSize = currentMempoolSize + newTransactions.length - deletedTransactions.length; + const newTransactionsStripped = newTransactions.map((tx) => Common.stripTransaction(tx)); + this.latestTransactions = newTransactionsStripped.concat(this.latestTransactions).slice(0, 6); - // Replace mempool to separate deleted transactions - for (const tx in this.mempoolCache) { - if (transactionsObject[tx]) { - newMempool[tx] = this.mempoolCache[tx]; - } else { - deletedTransactions.push(this.mempoolCache[tx]); + const accelerationDelta = accelerations != null ? await this.$updateAccelerations(accelerations) : []; + if (accelerationDelta.length) { + hasChange = true; + } + + this.mempoolCacheDelta = Math.abs(transactions.length - newMempoolSize); + + const candidatesChanged = candidates?.added?.length || candidates?.removed?.length; + + if (this.mempoolChangedCallback && (hasChange || deletedTransactions.length)) { + this.mempoolChangedCallback(this.mempoolCache, newTransactions, deletedTransactions, accelerationDelta); + } + if (this.$asyncMempoolChangedCallback && (hasChange || deletedTransactions.length || candidatesChanged)) { + this.updateTimerProgress(timer, 'running async mempool callback'); + await this.$asyncMempoolChangedCallback(this.mempoolCache, newMempoolSize, newTransactions, deletedTransactions, accelerationDelta, candidates); + this.updateTimerProgress(timer, 'completed async mempool callback'); + } + + if (!this.inSync && transactions.length === newMempoolSize) { + this.inSync = true; + logger.notice('The mempool is now in sync!'); + loadingIndicators.setProgress('mempool', 100); + } + + // Update Redis cache + if (config.REDIS.ENABLED) { + await redisCache.$flushTransactions(); + await redisCache.$removeTransactions(deletedTransactions.map(tx => tx.txid)); + await rbfCache.updateCache(); + } + + const end = new Date().getTime(); + const time = end - start; + logger.debug(`Mempool updated in ${time / 1000} seconds. New size: ${Object.keys(this.mempoolCache).length} (${diff > 0 ? '+' + diff : diff})`); + + this.clearTimer(timer); + } + + public getAccelerations(): { [txid: string]: Acceleration } { + return this.accelerations; + } + + public $updateAccelerations(newAccelerations: Acceleration[]): string[] { + if (!config.MEMPOOL_SERVICES.ACCELERATIONS) { + return []; + } + + try { + const changed: string[] = []; + + const newAccelerationMap: { [txid: string]: Acceleration } = {}; + for (const acceleration of newAccelerations) { + // skip transactions we don't know about + if (!this.mempoolCache[acceleration.txid]) { + continue; + } + newAccelerationMap[acceleration.txid] = acceleration; + if (this.accelerations[acceleration.txid] == null) { + // new acceleration + changed.push(acceleration.txid); + } else { + if (this.accelerations[acceleration.txid].feeDelta !== acceleration.feeDelta) { + // feeDelta changed + changed.push(acceleration.txid); + } else if (this.accelerations[acceleration.txid].pools?.length) { + let poolsChanged = false; + const pools = new Set(); + this.accelerations[acceleration.txid].pools.forEach(pool => { + pools.add(pool); + }); + acceleration.pools.forEach(pool => { + if (!pools.has(pool)) { + poolsChanged = true; + } else { + pools.delete(pool); + } + }); + if (pools.size > 0) { + poolsChanged = true; + } + if (poolsChanged) { + // pools changed + changed.push(acceleration.txid); + } } } + } + + for (const oldTxid of Object.keys(this.accelerations)) { + if (!newAccelerationMap[oldTxid]) { + // removed + changed.push(oldTxid); + } + } + + this.accelerations = newAccelerationMap; + + return changed; + } catch (e: any) { + logger.debug(`Failed to update accelerations: ` + (e instanceof Error ? e.message : e)); + return []; + } + } + + public async getNextCandidates(minFeeTransactions: string[], blockHeight: number, deletedTransactions: MempoolTransactionExtended[]): Promise { + if (this.limitGBT) { + const deletedTxsMap = {}; + for (const tx of deletedTransactions) { + deletedTxsMap[tx.txid] = tx; + } + const newCandidateTxMap = {}; + for (const txid of minFeeTransactions) { + if (this.mempoolCache[txid]) { + newCandidateTxMap[txid] = true; + } + } + const accelerations = this.getAccelerations(); + for (const txid of Object.keys(accelerations)) { + if (this.mempoolCache[txid]) { + newCandidateTxMap[txid] = true; + } + } + const removed: MempoolTransactionExtended[] = []; + const added: MempoolTransactionExtended[] = []; + // don't prematurely remove txs included in a new block + if (blockHeight > blocks.getCurrentBlockHeight()) { + for (const txid of Object.keys(this.mempoolCandidates)) { + newCandidateTxMap[txid] = true; + } } else { - newMempool = this.mempoolCache; + for (const txid of Object.keys(this.mempoolCandidates)) { + if (!newCandidateTxMap[txid]) { + if (this.mempoolCache[txid]) { + removed.push(this.mempoolCache[txid]); + this.mempoolCache[txid].effectiveFeePerVsize = this.mempoolCache[txid].adjustedFeePerVsize; + this.mempoolCache[txid].ancestors = []; + this.mempoolCache[txid].descendants = []; + this.mempoolCache[txid].bestDescendant = null; + this.mempoolCache[txid].cpfpChecked = false; + this.mempoolCache[txid].cpfpUpdated = undefined; + } else if (deletedTxsMap[txid]) { + removed.push(deletedTxsMap[txid]); + } + } + } } - if (!this.inSync && transactions.length === Object.keys(newMempool).length) { - this.inSync = true; - console.log('The mempool is now in sync!'); + for (const txid of Object.keys(newCandidateTxMap)) { + if (!this.mempoolCandidates[txid]) { + added.push(this.mempoolCache[txid]); + } } - if (this.mempoolChangedCallback && (hasChange || deletedTransactions.length)) { - this.mempoolCache = newMempool; - this.mempoolChangedCallback(this.mempoolCache, newTransactions, deletedTransactions); + this.mempoolCandidates = newCandidateTxMap; + return { + txs: this.mempoolCandidates, + added, + removed + }; + } + } + + setAccelerationPositions(positions: { [txid: string]: { poolId: number, pool: string, block: number, vsize: number }[] }): void { + this.accelerationPositions = positions; + } + + getAccelerationPositions(txid: string): { [pool: number]: { poolId: number, pool: string, block: number, vsize: number } } | undefined { + return this.accelerationPositions[txid]; + } + + private startTimer() { + const state: any = { + start: Date.now(), + progress: 'begin $updateMempool', + timer: null, + }; + state.timer = setTimeout(() => { + logger.err(`$updateMempool stalled at "${state.progress}"`); + }, this.mainLoopTimeout); + return state; + } + + private updateTimerProgress(state, msg) { + state.progress = msg; + } + + private clearTimer(state) { + if (state.timer) { + clearTimeout(state.timer); + } + } + + public handleRbfTransactions(rbfTransactions: { [txid: string]: MempoolTransactionExtended[]; }): void { + for (const rbfTransaction in rbfTransactions) { + if (this.mempoolCache[rbfTransaction] && rbfTransactions[rbfTransaction]?.length) { + // Store replaced transactions + rbfCache.add(rbfTransactions[rbfTransaction], this.mempoolCache[rbfTransaction]); + } + } + } + + public handleMinedRbfTransactions(rbfTransactions: { [txid: string]: { replaced: MempoolTransactionExtended[], replacedBy: TransactionExtended }}): void { + for (const rbfTransaction in rbfTransactions) { + if (rbfTransactions[rbfTransaction].replacedBy && rbfTransactions[rbfTransaction]?.replaced?.length) { + // Store replaced transactions + rbfCache.add(rbfTransactions[rbfTransaction].replaced, transactionUtils.extendMempoolTransaction(rbfTransactions[rbfTransaction].replacedBy)); + } + } + } + + public addToSpendMap(transactions: MempoolTransactionExtended[]): void { + for (const tx of transactions) { + for (const vin of tx.vin) { + this.spendMap.set(`${vin.txid}:${vin.vout}`, tx); } + } + } - const end = new Date().getTime(); - const time = end - start; - console.log(`New mempool size: ${Object.keys(newMempool).length} Change: ${diff}`); - console.log('Mempool updated in ' + time / 1000 + ' seconds'); - } catch (err) { - console.log('getRawMempool error.', err); + public removeFromSpendMap(transactions: TransactionExtended[]): void { + for (const tx of transactions) { + for (const vin of tx.vin) { + const key = `${vin.txid}:${vin.vout}`; + if (this.spendMap.get(key)?.txid === tx.txid) { + this.spendMap.delete(key); + } + } } } private updateTxPerSecond() { - const nowMinusTimeSpan = new Date().getTime() - (1000 * config.TX_PER_SECOND_SPAN_SECONDS); + const nowMinusTimeSpan = new Date().getTime() - (1000 * config.STATISTICS.TX_PER_SECOND_SAMPLE_PERIOD); this.txPerSecondArray = this.txPerSecondArray.filter((unixTime) => unixTime > nowMinusTimeSpan); - this.txPerSecond = this.txPerSecondArray.length / config.TX_PER_SECOND_SPAN_SECONDS || 0; + this.txPerSecond = this.txPerSecondArray.length / config.STATISTICS.TX_PER_SECOND_SAMPLE_PERIOD || 0; this.vBytesPerSecondArray = this.vBytesPerSecondArray.filter((data) => data.unixTime > nowMinusTimeSpan); if (this.vBytesPerSecondArray.length) { this.vBytesPerSecond = Math.round( - this.vBytesPerSecondArray.map((data) => data.vSize).reduce((a, b) => a + b) / config.TX_PER_SECOND_SPAN_SECONDS + this.vBytesPerSecondArray.map((data) => data.vSize).reduce((a, b) => a + b) / config.STATISTICS.TX_PER_SECOND_SAMPLE_PERIOD ); } } + + private $getMempoolInfo() { + if (config.MEMPOOL.USE_SECOND_NODE_FOR_MINFEE) { + return Promise.all([ + bitcoinClient.getMempoolInfo(), + bitcoinSecondClient.getMempoolInfo() + ]).then(([mempoolInfo, secondMempoolInfo]) => { + mempoolInfo.maxmempool = secondMempoolInfo.maxmempool; + mempoolInfo.mempoolminfee = secondMempoolInfo.mempoolminfee; + mempoolInfo.minrelaytxfee = secondMempoolInfo.minrelaytxfee; + return mempoolInfo; + }); + } + return bitcoinClient.getMempoolInfo(); + } } export default new Mempool(); diff --git a/backend/src/api/mini-miner.ts b/backend/src/api/mini-miner.ts new file mode 100644 index 0000000000..4a4ef5daad --- /dev/null +++ b/backend/src/api/mini-miner.ts @@ -0,0 +1,515 @@ +import { Acceleration } from './acceleration/acceleration'; +import { MempoolTransactionExtended } from '../mempool.interfaces'; +import logger from '../logger'; + +const BLOCK_WEIGHT_UNITS = 4_000_000; +const BLOCK_SIGOPS = 80_000; +const MAX_RELATIVE_GRAPH_SIZE = 100; + +export interface GraphTx { + txid: string; + vsize: number; + weight: number; + depends: string[]; + spentby: string[]; + + ancestorcount: number; + ancestorsize: number; + fees: { // in sats + base: number; + ancestor: number; + }; + + ancestors: Map, + ancestorRate: number; + individualRate: number; + score: number; +} + +interface TemplateTransaction { + txid: string; + order: number; + weight: number; + adjustedVsize: number; // sigop-adjusted vsize, rounded up to the nearest integer + sigops: number; + fee: number; + feeDelta: number; + ancestors: string[]; + cluster: string[]; + effectiveFeePerVsize: number; +} + +interface MinerTransaction extends TemplateTransaction { + inputs: string[]; + feePerVsize: number; + relativesSet: boolean; + ancestorMap: Map; + children: Set; + ancestorFee: number; + ancestorVsize: number; + ancestorSigops: number; + score: number; + used: boolean; + modified: boolean; + dependencyRate: number; +} + +/** + * Takes a raw transaction, and builds a graph of same-block relatives, + * and returns as a GraphTx + * + * @param tx + */ +export function getSameBlockRelatives(tx: MempoolTransactionExtended, transactions: MempoolTransactionExtended[]): Map { + const blockTxs = new Map(); // map of txs in this block + const spendMap = new Map(); // map of outpoints to spending txids + for (const tx of transactions) { + blockTxs.set(tx.txid, tx); + for (const vin of tx.vin) { + spendMap.set(`${vin.txid}:${vin.vout}`, tx.txid); + } + } + + const relatives: Map = new Map(); + const stack: string[] = [tx.txid]; + + // build set of same-block ancestors + while (stack.length > 0) { + const nextTxid = stack.pop(); + const nextTx = nextTxid ? blockTxs.get(nextTxid) : null; + if (!nextTx || relatives.has(nextTx.txid)) { + continue; + } + + const mempoolTx = convertToGraphTx(nextTx, spendMap); + + for (const txid of [...mempoolTx.depends, ...mempoolTx.spentby]) { + if (txid) { + stack.push(txid); + } + } + + relatives.set(mempoolTx.txid, mempoolTx); + } + + return relatives; +} + +/** + * Takes a raw transaction and converts it to GraphTx format + * fee and ancestor data is initialized with dummy/null values + * + * @param tx + */ +export function convertToGraphTx(tx: MempoolTransactionExtended, spendMap?: Map): GraphTx { + return { + txid: tx.txid, + vsize: Math.max(tx.sigops * 5, Math.ceil(tx.weight / 4)), + weight: tx.weight, + fees: { + base: tx.fee || 0, + ancestor: tx.fee || 0, + }, + depends: (tx.vin.map(vin => vin.txid).filter(depend => depend) as string[]), + spentby: spendMap ? (tx.vout.map((vout, index) => { const spend = spendMap.get(`${tx.txid}:${index}`); return (spend?.['txid'] || spend); }).filter(spent => spent) as string[]) : [], + + ancestorcount: 1, + ancestorsize: Math.max(tx.sigops * 5, Math.ceil(tx.weight / 4)), + ancestors: new Map(), + ancestorRate: 0, + individualRate: 0, + score: 0, + }; +} + +/** + * Takes a map of transaction ancestors, and expands it into a full graph of up to MAX_GRAPH_SIZE in-mempool relatives + */ +export function expandRelativesGraph(mempool: { [txid: string]: MempoolTransactionExtended }, ancestors: Map, spendMap: Map): Map { + const relatives: Map = new Map(); + const stack: GraphTx[] = Array.from(ancestors.values()); + while (stack.length > 0) { + if (relatives.size > MAX_RELATIVE_GRAPH_SIZE) { + return relatives; + } + + const nextTx = stack.pop(); + if (!nextTx) { + continue; + } + relatives.set(nextTx.txid, nextTx); + + for (const relativeTxid of [...nextTx.depends, ...nextTx.spentby]) { + if (relatives.has(relativeTxid)) { + // already processed this tx + continue; + } + let ancestorTx = ancestors.get(relativeTxid); + if (!ancestorTx && relativeTxid in mempool) { + const mempoolTx = mempool[relativeTxid]; + ancestorTx = convertToGraphTx(mempoolTx, spendMap); + } + if (ancestorTx) { + stack.push(ancestorTx); + } + } + } + + return relatives; +} + +/** + * Recursively traverses an in-mempool dependency graph, and sets a Map of in-mempool ancestors + * for each transaction. + * + * @param tx + * @param all + */ +function setAncestors(tx: GraphTx, all: Map, visited: Map>, depth: number = 0): Map { + // sanity check for infinite recursion / too many ancestors (should never happen) + if (depth > MAX_RELATIVE_GRAPH_SIZE) { + logger.warn('cpfp dependency calculation failed: setAncestors reached depth of 100, unable to proceed'); + return tx.ancestors; + } + + // initialize the ancestor map for this tx + tx.ancestors = new Map(); + tx.depends.forEach(parentId => { + const parent = all.get(parentId); + if (parent) { + // add the parent + tx.ancestors?.set(parentId, parent); + // check for a cached copy of this parent's ancestors + let ancestors = visited.get(parent.txid); + if (!ancestors) { + // recursively fetch the parent's ancestors + ancestors = setAncestors(parent, all, visited, depth + 1); + } + // and add to this tx's map + ancestors.forEach((ancestor, ancestorId) => { + tx.ancestors?.set(ancestorId, ancestor); + }); + } + }); + visited.set(tx.txid, tx.ancestors); + + return tx.ancestors; +} + +/** + * Efficiently sets a Map of in-mempool ancestors for each member of an expanded relative graph + * by running setAncestors on each leaf, and caching intermediate results. + * then initializes ancestor data for each transaction + * + * @param all + */ +export function initializeRelatives(mempoolTxs: Map): Map { + const visited: Map> = new Map(); + const leaves: GraphTx[] = Array.from(mempoolTxs.values()).filter(entry => entry.spentby.length === 0); + for (const leaf of leaves) { + setAncestors(leaf, mempoolTxs, visited); + } + mempoolTxs.forEach(entry => { + entry.ancestors?.forEach(ancestor => { + entry.ancestorcount++; + entry.ancestorsize += ancestor.vsize; + entry.fees.ancestor += ancestor.fees.base; + }); + setAncestorScores(entry); + }); + return mempoolTxs; +} + +/** + * Remove a cluster of transactions from an in-mempool dependency graph + * and update the survivors' scores and ancestors + * + * @param cluster + * @param ancestors + */ +export function removeAncestors(cluster: Map, all: Map): void { + // remove + cluster.forEach(tx => { + all.delete(tx.txid); + }); + + // update survivors + all.forEach(tx => { + cluster.forEach(remove => { + if (tx.ancestors?.has(remove.txid)) { + // remove as dependency + tx.ancestors.delete(remove.txid); + tx.depends = tx.depends.filter(parent => parent !== remove.txid); + // update ancestor sizes and fees + tx.ancestorsize -= remove.vsize; + tx.fees.ancestor -= remove.fees.base; + } + }); + // recalculate fee rates + setAncestorScores(tx); + }); +} + +/** + * Take a mempool transaction, and set the fee rates and ancestor score + * + * @param tx + */ +export function setAncestorScores(tx: GraphTx): void { + tx.individualRate = tx.fees.base / tx.vsize; + tx.ancestorRate = tx.fees.ancestor / tx.ancestorsize; + tx.score = Math.min(tx.individualRate, tx.ancestorRate); +} + +// Sort by descending score +export function mempoolComparator(a: GraphTx, b: GraphTx): number { + return b.score - a.score; +} + +/* +* Build a block using an approximation of the transaction selection algorithm from Bitcoin Core +* (see BlockAssembler in https://github.com/bitcoin/bitcoin/blob/master/src/node/miner.cpp) +*/ +export function makeBlockTemplate(candidates: MempoolTransactionExtended[], accelerations: Acceleration[], maxBlocks: number = 8, weightLimit: number = BLOCK_WEIGHT_UNITS, sigopLimit: number = BLOCK_SIGOPS): TemplateTransaction[] { + const auditPool: Map = new Map(); + const mempoolArray: MinerTransaction[] = []; + + candidates.forEach(tx => { + // initializing everything up front helps V8 optimize property access later + const adjustedVsize = Math.ceil(Math.max(tx.weight / 4, 5 * (tx.sigops || 0))); + const feePerVsize = (tx.fee / adjustedVsize); + auditPool.set(tx.txid, { + txid: tx.txid, + order: txidToOrdering(tx.txid), + fee: tx.fee, + feeDelta: 0, + weight: tx.weight, + adjustedVsize, + feePerVsize: feePerVsize, + effectiveFeePerVsize: feePerVsize, + dependencyRate: feePerVsize, + sigops: tx.sigops || 0, + inputs: (tx.vin?.map(vin => vin.txid) || []) as string[], + relativesSet: false, + ancestors: [], + cluster: [], + ancestorMap: new Map(), + children: new Set(), + ancestorFee: 0, + ancestorVsize: 0, + ancestorSigops: 0, + score: 0, + used: false, + modified: false, + }); + mempoolArray.push(auditPool.get(tx.txid) as MinerTransaction); + }); + + // set accelerated effective fee + for (const acceleration of accelerations) { + const tx = auditPool.get(acceleration.txid); + if (tx) { + tx.feeDelta = acceleration.max_bid; + tx.feePerVsize = ((tx.fee + tx.feeDelta) / tx.adjustedVsize); + tx.effectiveFeePerVsize = tx.feePerVsize; + tx.dependencyRate = tx.feePerVsize; + } + } + + // Build relatives graph & calculate ancestor scores + for (const tx of mempoolArray) { + if (!tx.relativesSet) { + setRelatives(tx, auditPool); + } + } + + // Sort by descending ancestor score + mempoolArray.sort(priorityComparator); + + // Build blocks by greedily choosing the highest feerate package + // (i.e. the package rooted in the transaction with the best ancestor score) + const blocks: number[][] = []; + let blockWeight = 0; + let blockSigops = 0; + const transactions: MinerTransaction[] = []; + let modified: MinerTransaction[] = []; + const overflow: MinerTransaction[] = []; + let failures = 0; + while (mempoolArray.length || modified.length) { + // skip invalid transactions + while (mempoolArray[0].used || mempoolArray[0].modified) { + mempoolArray.shift(); + } + + // Select best next package + let nextTx; + const nextPoolTx = mempoolArray[0]; + const nextModifiedTx = modified[0]; + if (nextPoolTx && (!nextModifiedTx || (nextPoolTx.score || 0) > (nextModifiedTx.score || 0))) { + nextTx = nextPoolTx; + mempoolArray.shift(); + } else { + modified.shift(); + if (nextModifiedTx) { + nextTx = nextModifiedTx; + } + } + + if (nextTx && !nextTx?.used) { + // Check if the package fits into this block + if (blocks.length >= (maxBlocks - 1) || ((blockWeight + (4 * nextTx.ancestorVsize) < weightLimit) && (blockSigops + nextTx.ancestorSigops <= sigopLimit))) { + const ancestors: MinerTransaction[] = Array.from(nextTx.ancestorMap.values()); + // sort ancestors by dependency graph (equivalent to sorting by ascending ancestor count) + const sortedTxSet = [...ancestors.sort((a, b) => { return (a.ancestorMap.size || 0) - (b.ancestorMap.size || 0); }), nextTx]; + const clusterTxids = sortedTxSet.map(tx => tx.txid); + const effectiveFeeRate = Math.min(nextTx.dependencyRate || Infinity, nextTx.ancestorFee / nextTx.ancestorVsize); + const used: MinerTransaction[] = []; + while (sortedTxSet.length) { + const ancestor = sortedTxSet.pop(); + if (!ancestor) { + continue; + } + ancestor.used = true; + ancestor.usedBy = nextTx.txid; + // update this tx with effective fee rate & relatives data + if (ancestor.effectiveFeePerVsize !== effectiveFeeRate) { + ancestor.effectiveFeePerVsize = effectiveFeeRate; + } + ancestor.cluster = clusterTxids; + transactions.push(ancestor); + blockWeight += ancestor.weight; + blockSigops += ancestor.sigops; + used.push(ancestor); + } + + // remove these as valid package ancestors for any descendants remaining in the mempool + if (used.length) { + used.forEach(tx => { + modified = updateDescendants(tx, auditPool, modified, effectiveFeeRate); + }); + } + + failures = 0; + } else { + // hold this package in an overflow list while we check for smaller options + overflow.push(nextTx); + failures++; + } + } + + // this block is full + const exceededPackageTries = failures > 1000 && blockWeight > (weightLimit - 4000); + const queueEmpty = !mempoolArray.length && !modified.length; + + if (exceededPackageTries || queueEmpty) { + break; + } + } + + for (const tx of transactions) { + tx.ancestors = Object.values(tx.ancestorMap); + } + + return transactions; +} + +// traverse in-mempool ancestors +// recursion unavoidable, but should be limited to depth < 25 by mempool policy +function setRelatives( + tx: MinerTransaction, + mempool: Map, +): void { + for (const parent of tx.inputs) { + const parentTx = mempool.get(parent); + if (parentTx && !tx.ancestorMap?.has(parent)) { + tx.ancestorMap.set(parent, parentTx); + parentTx.children.add(tx); + // visit each node only once + if (!parentTx.relativesSet) { + setRelatives(parentTx, mempool); + } + parentTx.ancestorMap.forEach((ancestor) => { + tx.ancestorMap.set(ancestor.txid, ancestor); + }); + } + }; + tx.ancestorFee = (tx.fee + tx.feeDelta); + tx.ancestorVsize = tx.adjustedVsize || 0; + tx.ancestorSigops = tx.sigops || 0; + tx.ancestorMap.forEach((ancestor) => { + tx.ancestorFee += (ancestor.fee + ancestor.feeDelta); + tx.ancestorVsize += ancestor.adjustedVsize; + tx.ancestorSigops += ancestor.sigops; + }); + tx.score = tx.ancestorFee / tx.ancestorVsize; + tx.relativesSet = true; +} + +// iterate over remaining descendants, removing the root as a valid ancestor & updating the ancestor score +// avoids recursion to limit call stack depth +function updateDescendants( + rootTx: MinerTransaction, + mempool: Map, + modified: MinerTransaction[], + clusterRate: number, +): MinerTransaction[] { + const descendantSet: Set = new Set(); + // stack of nodes left to visit + const descendants: MinerTransaction[] = []; + let descendantTx: MinerTransaction | undefined; + rootTx.children.forEach(childTx => { + if (!descendantSet.has(childTx)) { + descendants.push(childTx); + descendantSet.add(childTx); + } + }); + while (descendants.length) { + descendantTx = descendants.pop(); + if (descendantTx && descendantTx.ancestorMap && descendantTx.ancestorMap.has(rootTx.txid)) { + // remove tx as ancestor + descendantTx.ancestorMap.delete(rootTx.txid); + descendantTx.ancestorFee -= (rootTx.fee + rootTx.feeDelta); + descendantTx.ancestorVsize -= rootTx.adjustedVsize; + descendantTx.ancestorSigops -= rootTx.sigops; + descendantTx.score = descendantTx.ancestorFee / descendantTx.ancestorVsize; + descendantTx.dependencyRate = descendantTx.dependencyRate ? Math.min(descendantTx.dependencyRate, clusterRate) : clusterRate; + + if (!descendantTx.modified) { + descendantTx.modified = true; + modified.push(descendantTx); + } + + // add this node's children to the stack + descendantTx.children.forEach(childTx => { + // visit each node only once + if (!descendantSet.has(childTx)) { + descendants.push(childTx); + descendantSet.add(childTx); + } + }); + } + } + // return new, resorted modified list + return modified.sort(priorityComparator); +} + +// Used to sort an array of MinerTransactions by descending ancestor score +function priorityComparator(a: MinerTransaction, b: MinerTransaction): number { + if (b.score === a.score) { + // tie-break by txid for stability + return a.order - b.order; + } else { + return b.score - a.score; + } +} + +// returns the most significant 4 bytes of the txid as an integer +function txidToOrdering(txid: string): number { + return parseInt( + txid.substring(62, 64) + + txid.substring(60, 62) + + txid.substring(58, 60) + + txid.substring(56, 58), + 16 + ); +} diff --git a/backend/src/api/mining/mining-routes.ts b/backend/src/api/mining/mining-routes.ts new file mode 100644 index 0000000000..bdfc83d431 --- /dev/null +++ b/backend/src/api/mining/mining-routes.ts @@ -0,0 +1,450 @@ +import { Application, Request, Response } from 'express'; +import config from "../../config"; +import logger from '../../logger'; +import BlocksAuditsRepository from '../../repositories/BlocksAuditsRepository'; +import BlocksRepository from '../../repositories/BlocksRepository'; +import DifficultyAdjustmentsRepository from '../../repositories/DifficultyAdjustmentsRepository'; +import HashratesRepository from '../../repositories/HashratesRepository'; +import bitcoinClient from '../bitcoin/bitcoin-client'; +import mining from "./mining"; +import PricesRepository from '../../repositories/PricesRepository'; +import AccelerationRepository from '../../repositories/AccelerationRepository'; + +class MiningRoutes { + public initRoutes(app: Application) { + app + .get(config.MEMPOOL.API_URL_PREFIX + 'mining/pools', this.$listPools) + .get(config.MEMPOOL.API_URL_PREFIX + 'mining/pools/:interval', this.$getPools) + .get(config.MEMPOOL.API_URL_PREFIX + 'mining/pool/:slug/hashrate', this.$getPoolHistoricalHashrate) + .get(config.MEMPOOL.API_URL_PREFIX + 'mining/pool/:slug/blocks', this.$getPoolBlocks) + .get(config.MEMPOOL.API_URL_PREFIX + 'mining/pool/:slug/blocks/:height', this.$getPoolBlocks) + .get(config.MEMPOOL.API_URL_PREFIX + 'mining/pool/:slug', this.$getPool) + .get(config.MEMPOOL.API_URL_PREFIX + 'mining/hashrate/pools/:interval', this.$getPoolsHistoricalHashrate) + .get(config.MEMPOOL.API_URL_PREFIX + 'mining/hashrate/:interval', this.$getHistoricalHashrate) + .get(config.MEMPOOL.API_URL_PREFIX + 'mining/difficulty-adjustments', this.$getDifficultyAdjustments) + .get(config.MEMPOOL.API_URL_PREFIX + 'mining/reward-stats/:blockCount', this.$getRewardStats) + .get(config.MEMPOOL.API_URL_PREFIX + 'mining/blocks/fees/:interval', this.$getHistoricalBlockFees) + .get(config.MEMPOOL.API_URL_PREFIX + 'mining/blocks/fees', this.$getBlockFeesTimespan) + .get(config.MEMPOOL.API_URL_PREFIX + 'mining/blocks/rewards/:interval', this.$getHistoricalBlockRewards) + .get(config.MEMPOOL.API_URL_PREFIX + 'mining/blocks/fee-rates/:interval', this.$getHistoricalBlockFeeRates) + .get(config.MEMPOOL.API_URL_PREFIX + 'mining/blocks/sizes-weights/:interval', this.$getHistoricalBlockSizeAndWeight) + .get(config.MEMPOOL.API_URL_PREFIX + 'mining/difficulty-adjustments/:interval', this.$getDifficultyAdjustments) + .get(config.MEMPOOL.API_URL_PREFIX + 'mining/blocks/predictions/:interval', this.$getHistoricalBlocksHealth) + .get(config.MEMPOOL.API_URL_PREFIX + 'mining/blocks/audit/scores', this.$getBlockAuditScores) + .get(config.MEMPOOL.API_URL_PREFIX + 'mining/blocks/audit/scores/:height', this.$getBlockAuditScores) + .get(config.MEMPOOL.API_URL_PREFIX + 'mining/blocks/audit/score/:hash', this.$getBlockAuditScore) + .get(config.MEMPOOL.API_URL_PREFIX + 'mining/blocks/audit/:hash', this.$getBlockAudit) + .get(config.MEMPOOL.API_URL_PREFIX + 'mining/blocks/timestamp/:timestamp', this.$getHeightFromTimestamp) + .get(config.MEMPOOL.API_URL_PREFIX + 'historical-price', this.$getHistoricalPrice) + + .get(config.MEMPOOL.API_URL_PREFIX + 'accelerations/pool/:slug', this.$getAccelerationsByPool) + .get(config.MEMPOOL.API_URL_PREFIX + 'accelerations/block/:height', this.$getAccelerationsByHeight) + .get(config.MEMPOOL.API_URL_PREFIX + 'accelerations/recent/:interval', this.$getRecentAccelerations) + .get(config.MEMPOOL.API_URL_PREFIX + 'accelerations/total', this.$getAccelerationTotals) + ; + } + + private async $getHistoricalPrice(req: Request, res: Response): Promise { + try { + res.header('Pragma', 'public'); + res.header('Cache-control', 'public'); + res.setHeader('Expires', new Date(Date.now() + 1000 * 300).toUTCString()); + if (['testnet', 'signet', 'liquidtestnet'].includes(config.MEMPOOL.NETWORK)) { + res.status(400).send('Prices are not available on testnets.'); + return; + } + const timestamp = parseInt(req.query.timestamp as string, 10) || 0; + const currency = req.query.currency as string; + + let response; + if (timestamp && currency) { + response = await PricesRepository.$getNearestHistoricalPrice(timestamp, currency); + } else if (timestamp) { + response = await PricesRepository.$getNearestHistoricalPrice(timestamp); + } else if (currency) { + response = await PricesRepository.$getHistoricalPrices(currency); + } else { + response = await PricesRepository.$getHistoricalPrices(); + } + res.status(200).send(response); + } catch (e) { + res.status(500).send(e instanceof Error ? e.message : e); + } + } + + private async $getPool(req: Request, res: Response): Promise { + try { + const stats = await mining.$getPoolStat(req.params.slug); + res.header('Pragma', 'public'); + res.header('Cache-control', 'public'); + res.setHeader('Expires', new Date(Date.now() + 1000 * 60).toUTCString()); + res.json(stats); + } catch (e) { + if (e instanceof Error && e.message.indexOf('This mining pool does not exist') > -1) { + res.status(404).send(e.message); + } else { + res.status(500).send(e instanceof Error ? e.message : e); + } + } + } + + private async $getPoolBlocks(req: Request, res: Response) { + try { + const poolBlocks = await BlocksRepository.$getBlocksByPool( + req.params.slug, + req.params.height === undefined ? undefined : parseInt(req.params.height, 10), + ); + res.header('Pragma', 'public'); + res.header('Cache-control', 'public'); + res.setHeader('Expires', new Date(Date.now() + 1000 * 60).toUTCString()); + res.json(poolBlocks); + } catch (e) { + if (e instanceof Error && e.message.indexOf('This mining pool does not exist') > -1) { + res.status(404).send(e.message); + } else { + res.status(500).send(e instanceof Error ? e.message : e); + } + } + } + + private async $listPools(req: Request, res: Response): Promise { + try { + res.header('Pragma', 'public'); + res.header('Cache-control', 'public'); + res.setHeader('Expires', new Date(Date.now() + 1000 * 60).toUTCString()); + + const pools = await mining.$listPools(); + if (!pools) { + res.status(500).end(); + return; + } + + res.header('X-total-count', pools.length.toString()); + if (pools.length === 0) { + res.status(204).send(); + } else { + res.json(pools); + } + } catch (e) { + res.status(500).send(e instanceof Error ? e.message : e); + } + } + + private async $getPools(req: Request, res: Response) { + try { + const stats = await mining.$getPoolsStats(req.params.interval); + const blockCount = await BlocksRepository.$blockCount(null, null); + res.header('Pragma', 'public'); + res.header('Cache-control', 'public'); + res.header('X-total-count', blockCount.toString()); + res.setHeader('Expires', new Date(Date.now() + 1000 * 60).toUTCString()); + res.json(stats); + } catch (e) { + res.status(500).send(e instanceof Error ? e.message : e); + } + } + + private async $getPoolsHistoricalHashrate(req: Request, res: Response) { + try { + const hashrates = await HashratesRepository.$getPoolsWeeklyHashrate(req.params.interval); + const blockCount = await BlocksRepository.$blockCount(null, null); + res.header('Pragma', 'public'); + res.header('Cache-control', 'public'); + res.header('X-total-count', blockCount.toString()); + res.setHeader('Expires', new Date(Date.now() + 1000 * 300).toUTCString()); + res.json(hashrates); + } catch (e) { + res.status(500).send(e instanceof Error ? e.message : e); + } + } + + private async $getPoolHistoricalHashrate(req: Request, res: Response) { + try { + const hashrates = await HashratesRepository.$getPoolWeeklyHashrate(req.params.slug); + const blockCount = await BlocksRepository.$blockCount(null, null); + res.header('Pragma', 'public'); + res.header('Cache-control', 'public'); + res.header('X-total-count', blockCount.toString()); + res.setHeader('Expires', new Date(Date.now() + 1000 * 300).toUTCString()); + res.json(hashrates); + } catch (e) { + if (e instanceof Error && e.message.indexOf('This mining pool does not exist') > -1) { + res.status(404).send(e.message); + } else { + res.status(500).send(e instanceof Error ? e.message : e); + } + } + } + + private async $getHistoricalHashrate(req: Request, res: Response) { + let currentHashrate = 0, currentDifficulty = 0; + try { + currentHashrate = await bitcoinClient.getNetworkHashPs(); + currentDifficulty = await bitcoinClient.getDifficulty(); + } catch (e) { + logger.debug('Bitcoin Core is not available, using zeroed value for current hashrate and difficulty'); + } + + try { + const hashrates = await HashratesRepository.$getNetworkDailyHashrate(req.params.interval); + const difficulty = await DifficultyAdjustmentsRepository.$getAdjustments(req.params.interval, false); + const blockCount = await BlocksRepository.$blockCount(null, null); + res.header('Pragma', 'public'); + res.header('Cache-control', 'public'); + res.header('X-total-count', blockCount.toString()); + res.setHeader('Expires', new Date(Date.now() + 1000 * 300).toUTCString()); + res.json({ + hashrates: hashrates, + difficulty: difficulty, + currentHashrate: currentHashrate, + currentDifficulty: currentDifficulty, + }); + } catch (e) { + res.status(500).send(e instanceof Error ? e.message : e); + } + } + + private async $getHistoricalBlockFees(req: Request, res: Response) { + try { + const blockFees = await mining.$getHistoricalBlockFees(req.params.interval); + const blockCount = await BlocksRepository.$blockCount(null, null); + res.header('Pragma', 'public'); + res.header('Cache-control', 'public'); + res.header('X-total-count', blockCount.toString()); + res.setHeader('Expires', new Date(Date.now() + 1000 * 60).toUTCString()); + res.json(blockFees); + } catch (e) { + res.status(500).send(e instanceof Error ? e.message : e); + } + } + + private async $getBlockFeesTimespan(req: Request, res: Response) { + try { + if (!parseInt(req.query.from as string, 10) || !parseInt(req.query.to as string, 10)) { + throw new Error('Invalid timestamp range'); + } + if (parseInt(req.query.from as string, 10) > parseInt(req.query.to as string, 10)) { + throw new Error('from must be less than to'); + } + const blockFees = await mining.$getBlockFeesTimespan(parseInt(req.query.from as string, 10), parseInt(req.query.to as string, 10)); + res.header('Pragma', 'public'); + res.header('Cache-control', 'public'); + res.setHeader('Expires', new Date(Date.now() + 1000 * 60).toUTCString()); + res.json(blockFees); + } catch (e) { + res.status(500).send(e instanceof Error ? e.message : e); + } + } + + private async $getHistoricalBlockRewards(req: Request, res: Response) { + try { + const blockRewards = await mining.$getHistoricalBlockRewards(req.params.interval); + const blockCount = await BlocksRepository.$blockCount(null, null); + res.header('Pragma', 'public'); + res.header('Cache-control', 'public'); + res.header('X-total-count', blockCount.toString()); + res.setHeader('Expires', new Date(Date.now() + 1000 * 60).toUTCString()); + res.json(blockRewards); + } catch (e) { + res.status(500).send(e instanceof Error ? e.message : e); + } + } + + private async $getHistoricalBlockFeeRates(req: Request, res: Response) { + try { + const blockFeeRates = await mining.$getHistoricalBlockFeeRates(req.params.interval); + const blockCount = await BlocksRepository.$blockCount(null, null); + res.header('Pragma', 'public'); + res.header('Cache-control', 'public'); + res.header('X-total-count', blockCount.toString()); + res.setHeader('Expires', new Date(Date.now() + 1000 * 60).toUTCString()); + res.json(blockFeeRates); + } catch (e) { + res.status(500).send(e instanceof Error ? e.message : e); + } + } + + private async $getHistoricalBlockSizeAndWeight(req: Request, res: Response) { + try { + const blockSizes = await mining.$getHistoricalBlockSizes(req.params.interval); + const blockWeights = await mining.$getHistoricalBlockWeights(req.params.interval); + const blockCount = await BlocksRepository.$blockCount(null, null); + res.header('Pragma', 'public'); + res.header('Cache-control', 'public'); + res.header('X-total-count', blockCount.toString()); + res.setHeader('Expires', new Date(Date.now() + 1000 * 60).toUTCString()); + res.json({ + sizes: blockSizes, + weights: blockWeights + }); + } catch (e) { + res.status(500).send(e instanceof Error ? e.message : e); + } + } + + private async $getDifficultyAdjustments(req: Request, res: Response) { + try { + const difficulty = await DifficultyAdjustmentsRepository.$getRawAdjustments(req.params.interval, true); + res.header('Pragma', 'public'); + res.header('Cache-control', 'public'); + res.setHeader('Expires', new Date(Date.now() + 1000 * 300).toUTCString()); + res.json(difficulty.map(adj => [adj.time, adj.height, adj.difficulty, adj.adjustment])); + } catch (e) { + res.status(500).send(e instanceof Error ? e.message : e); + } + } + + private async $getRewardStats(req: Request, res: Response) { + try { + const response = await mining.$getRewardStats(parseInt(req.params.blockCount, 10)); + res.setHeader('Expires', new Date(Date.now() + 1000 * 60).toUTCString()); + res.json(response); + } catch (e) { + res.status(500).end(); + } + } + + private async $getHistoricalBlocksHealth(req: Request, res: Response) { + try { + const blocksHealth = await mining.$getBlocksHealthHistory(req.params.interval); + const blockCount = await BlocksAuditsRepository.$getBlocksHealthCount(); + res.header('Pragma', 'public'); + res.header('Cache-control', 'public'); + res.header('X-total-count', blockCount.toString()); + res.setHeader('Expires', new Date(Date.now() + 1000 * 60).toUTCString()); + res.json(blocksHealth.map(health => [health.time, health.height, health.match_rate])); + } catch (e) { + res.status(500).send(e instanceof Error ? e.message : e); + } + } + + public async $getBlockAudit(req: Request, res: Response) { + try { + const audit = await BlocksAuditsRepository.$getBlockAudit(req.params.hash); + + if (!audit) { + res.status(204).send(`This block has not been audited.`); + return; + } + + res.header('Pragma', 'public'); + res.header('Cache-control', 'public'); + res.setHeader('Expires', new Date(Date.now() + 1000 * 3600 * 24).toUTCString()); + res.json(audit); + } catch (e) { + res.status(500).send(e instanceof Error ? e.message : e); + } + } + + private async $getHeightFromTimestamp(req: Request, res: Response) { + try { + const timestamp = parseInt(req.params.timestamp, 10); + // This will prevent people from entering milliseconds etc. + // Block timestamps are allowed to be up to 2 hours off, so 24 hours + // will never put the maximum value before the most recent block + const nowPlus1day = Math.floor(Date.now() / 1000) + 60 * 60 * 24; + // Prevent non-integers that are not seconds + if (!/^[1-9][0-9]*$/.test(req.params.timestamp) || timestamp > nowPlus1day) { + throw new Error(`Invalid timestamp, value must be Unix seconds`); + } + const result = await BlocksRepository.$getBlockHeightFromTimestamp( + timestamp, + ); + res.header('Pragma', 'public'); + res.header('Cache-control', 'public'); + res.setHeader('Expires', new Date(Date.now() + 1000 * 300).toUTCString()); + res.json(result); + } catch (e) { + res.status(500).send(e instanceof Error ? e.message : e); + } + } + + private async $getBlockAuditScores(req: Request, res: Response) { + try { + let height = req.params.height === undefined ? undefined : parseInt(req.params.height, 10); + if (height == null) { + height = await BlocksRepository.$mostRecentBlockHeight(); + } + res.setHeader('Expires', new Date(Date.now() + 1000 * 60).toUTCString()); + res.json(await BlocksAuditsRepository.$getBlockAuditScores(height, height - 15)); + } catch (e) { + res.status(500).send(e instanceof Error ? e.message : e); + } + } + + public async $getBlockAuditScore(req: Request, res: Response) { + try { + const audit = await BlocksAuditsRepository.$getBlockAuditScore(req.params.hash); + + res.header('Pragma', 'public'); + res.header('Cache-control', 'public'); + res.setHeader('Expires', new Date(Date.now() + 1000 * 3600 * 24).toUTCString()); + res.json(audit || 'null'); + } catch (e) { + res.status(500).send(e instanceof Error ? e.message : e); + } + } + + private async $getAccelerationsByPool(req: Request, res: Response): Promise { + try { + res.header('Pragma', 'public'); + res.header('Cache-control', 'public'); + res.setHeader('Expires', new Date(Date.now() + 1000 * 60).toUTCString()); + if (!config.MEMPOOL_SERVICES.ACCELERATIONS || ['testnet', 'signet', 'liquidtestnet', 'liquid'].includes(config.MEMPOOL.NETWORK)) { + res.status(400).send('Acceleration data is not available.'); + return; + } + res.status(200).send(await AccelerationRepository.$getAccelerationInfo(req.params.slug)); + } catch (e) { + res.status(500).send(e instanceof Error ? e.message : e); + } + } + + private async $getAccelerationsByHeight(req: Request, res: Response): Promise { + try { + res.header('Pragma', 'public'); + res.header('Cache-control', 'public'); + res.setHeader('Expires', new Date(Date.now() + 1000 * 3600 * 24).toUTCString()); + if (!config.MEMPOOL_SERVICES.ACCELERATIONS || ['testnet', 'signet', 'liquidtestnet', 'liquid'].includes(config.MEMPOOL.NETWORK)) { + res.status(400).send('Acceleration data is not available.'); + return; + } + const height = req.params.height === undefined ? undefined : parseInt(req.params.height, 10); + res.status(200).send(await AccelerationRepository.$getAccelerationInfo(null, height)); + } catch (e) { + res.status(500).send(e instanceof Error ? e.message : e); + } + } + + private async $getRecentAccelerations(req: Request, res: Response): Promise { + try { + res.header('Pragma', 'public'); + res.header('Cache-control', 'public'); + res.setHeader('Expires', new Date(Date.now() + 1000 * 60).toUTCString()); + if (!config.MEMPOOL_SERVICES.ACCELERATIONS || ['testnet', 'signet', 'liquidtestnet', 'liquid'].includes(config.MEMPOOL.NETWORK)) { + res.status(400).send('Acceleration data is not available.'); + return; + } + res.status(200).send(await AccelerationRepository.$getAccelerationInfo(null, null, req.params.interval)); + } catch (e) { + res.status(500).send(e instanceof Error ? e.message : e); + } + } + + private async $getAccelerationTotals(req: Request, res: Response): Promise { + try { + res.header('Pragma', 'public'); + res.header('Cache-control', 'public'); + res.setHeader('Expires', new Date(Date.now() + 1000 * 60).toUTCString()); + if (!config.MEMPOOL_SERVICES.ACCELERATIONS || ['testnet', 'signet', 'liquidtestnet', 'liquid'].includes(config.MEMPOOL.NETWORK)) { + res.status(400).send('Acceleration data is not available.'); + return; + } + res.status(200).send(await AccelerationRepository.$getAccelerationTotals(req.query.pool, req.query.interval)); + } catch (e) { + res.status(500).send(e instanceof Error ? e.message : e); + } + } +} + +export default new MiningRoutes(); diff --git a/backend/src/api/mining/mining.ts b/backend/src/api/mining/mining.ts new file mode 100644 index 0000000000..21ee4b35a6 --- /dev/null +++ b/backend/src/api/mining/mining.ts @@ -0,0 +1,690 @@ +import { BlockPrice, PoolInfo, PoolStats, RewardStats } from '../../mempool.interfaces'; +import BlocksRepository from '../../repositories/BlocksRepository'; +import PoolsRepository from '../../repositories/PoolsRepository'; +import HashratesRepository from '../../repositories/HashratesRepository'; +import bitcoinClient from '../bitcoin/bitcoin-client'; +import logger from '../../logger'; +import { Common } from '../common'; +import loadingIndicators from '../loading-indicators'; +import { escape } from 'mysql2'; +import DifficultyAdjustmentsRepository from '../../repositories/DifficultyAdjustmentsRepository'; +import config from '../../config'; +import BlocksAuditsRepository from '../../repositories/BlocksAuditsRepository'; +import PricesRepository from '../../repositories/PricesRepository'; +import bitcoinApi from '../bitcoin/bitcoin-api-factory'; +import { IEsploraApi } from '../bitcoin/esplora-api.interface'; +import database from '../../database'; + +interface DifficultyBlock { + timestamp: number, + height: number, + bits: number, + difficulty: number, +} + +class Mining { + private blocksPriceIndexingRunning = false; + public lastHashrateIndexingDate: number | null = null; + public lastWeeklyHashrateIndexingDate: number | null = null; + + public reindexHashrateRequested = false; + public reindexDifficultyAdjustmentRequested = false; + + /** + * Get historical blocks health + */ + public async $getBlocksHealthHistory(interval: string | null = null): Promise { + return await BlocksAuditsRepository.$getBlocksHealthHistory( + this.getTimeRange(interval), + Common.getSqlInterval(interval) + ); + } + + /** + * Get historical block total fee + */ + public async $getHistoricalBlockFees(interval: string | null = null): Promise { + return await BlocksRepository.$getHistoricalBlockFees( + this.getTimeRange(interval), + Common.getSqlInterval(interval) + ); + } + + /** + * Get timespan block total fees + */ + public async $getBlockFeesTimespan(from: number, to: number): Promise { + return await BlocksRepository.$getHistoricalBlockFees( + this.getTimeRangeFromTimespan(from, to), + null, + {from, to} + ); + } + + /** + * Get historical block rewards + */ + public async $getHistoricalBlockRewards(interval: string | null = null): Promise { + return await BlocksRepository.$getHistoricalBlockRewards( + this.getTimeRange(interval), + Common.getSqlInterval(interval) + ); + } + + /** + * Get historical block fee rates percentiles + */ + public async $getHistoricalBlockFeeRates(interval: string | null = null): Promise { + return await BlocksRepository.$getHistoricalBlockFeeRates( + this.getTimeRange(interval), + Common.getSqlInterval(interval) + ); + } + + /** + * Get historical block sizes + */ + public async $getHistoricalBlockSizes(interval: string | null = null): Promise { + return await BlocksRepository.$getHistoricalBlockSizes( + this.getTimeRange(interval), + Common.getSqlInterval(interval) + ); + } + + /** + * Get historical block weights + */ + public async $getHistoricalBlockWeights(interval: string | null = null): Promise { + return await BlocksRepository.$getHistoricalBlockWeights( + this.getTimeRange(interval), + Common.getSqlInterval(interval) + ); + } + + /** + * Generate high level overview of the pool ranks and general stats + */ + public async $getPoolsStats(interval: string | null): Promise { + const poolsStatistics = {}; + + const poolsInfo: PoolInfo[] = await PoolsRepository.$getPoolsInfo(interval); + const emptyBlocks: any[] = await BlocksRepository.$countEmptyBlocks(null, interval); + + const poolsStats: PoolStats[] = []; + let rank = 1; + + poolsInfo.forEach((poolInfo: PoolInfo) => { + const emptyBlocksCount = emptyBlocks.filter((emptyCount) => emptyCount.poolId === poolInfo.poolId); + const poolStat: PoolStats = { + poolId: poolInfo.poolId, // mysql row id + name: poolInfo.name, + link: poolInfo.link, + blockCount: poolInfo.blockCount, + rank: rank++, + emptyBlocks: emptyBlocksCount.length > 0 ? emptyBlocksCount[0]['count'] : 0, + slug: poolInfo.slug, + avgMatchRate: poolInfo.avgMatchRate !== null ? Math.round(100 * poolInfo.avgMatchRate) / 100 : null, + avgFeeDelta: poolInfo.avgFeeDelta, + poolUniqueId: poolInfo.poolUniqueId + }; + poolsStats.push(poolStat); + }); + + poolsStatistics['pools'] = poolsStats; + + const blockCount: number = await BlocksRepository.$blockCount(null, interval); + poolsStatistics['blockCount'] = blockCount; + + const totalBlock24h: number = await BlocksRepository.$blockCount(null, '24h'); + + try { + poolsStatistics['lastEstimatedHashrate'] = await bitcoinClient.getNetworkHashPs(totalBlock24h); + } catch (e) { + poolsStatistics['lastEstimatedHashrate'] = 0; + logger.debug('Bitcoin Core is not available, using zeroed value for current hashrate', logger.tags.mining); + } + + return poolsStatistics; + } + + /** + * Get all mining pool stats for a pool + */ + public async $getPoolStat(slug: string): Promise { + const pool = await PoolsRepository.$getPool(slug); + if (!pool) { + throw new Error('This mining pool does not exist'); + } + + const blockCount: number = await BlocksRepository.$blockCount(pool.id); + const totalBlock: number = await BlocksRepository.$blockCount(null, null); + + const blockCount24h: number = await BlocksRepository.$blockCount(pool.id, '24h'); + const totalBlock24h: number = await BlocksRepository.$blockCount(null, '24h'); + + const blockCount1w: number = await BlocksRepository.$blockCount(pool.id, '1w'); + const totalBlock1w: number = await BlocksRepository.$blockCount(null, '1w'); + + const avgHealth = await BlocksRepository.$getAvgBlockHealthPerPoolId(pool.id); + const totalReward = await BlocksRepository.$getTotalRewardForPoolId(pool.id); + + let currentEstimatedHashrate = 0; + try { + currentEstimatedHashrate = await bitcoinClient.getNetworkHashPs(totalBlock24h); + } catch (e) { + logger.debug('Bitcoin Core is not available, using zeroed value for current hashrate', logger.tags.mining); + } + + return { + pool: pool, + blockCount: { + 'all': blockCount, + '24h': blockCount24h, + '1w': blockCount1w, + }, + blockShare: { + 'all': blockCount / totalBlock, + '24h': blockCount24h / totalBlock24h, + '1w': blockCount1w / totalBlock1w, + }, + estimatedHashrate: currentEstimatedHashrate * (blockCount24h / totalBlock24h), + reportedHashrate: null, + avgBlockHealth: avgHealth, + totalReward: totalReward, + }; + } + + /** + * Get miner reward stats + */ + public async $getRewardStats(blockCount: number): Promise { + return await BlocksRepository.$getBlockStats(blockCount); + } + + /** + * Generate weekly mining pool hashrate history + */ + public async $generatePoolHashrateHistory(): Promise { + const now = new Date(); + + // Run only if: + // * this.lastWeeklyHashrateIndexingDate is set to null (node backend restart, reorg) + // * we started a new week (around Monday midnight) + const runIndexing = this.lastWeeklyHashrateIndexingDate === null || + now.getUTCDay() === 1 && this.lastWeeklyHashrateIndexingDate !== now.getUTCDate(); + if (!runIndexing) { + logger.debug(`Pool hashrate history indexing is up to date, nothing to do`, logger.tags.mining); + return; + } + + try { + const oldestConsecutiveBlockTimestamp = 1000 * (await BlocksRepository.$getOldestConsecutiveBlock()).timestamp; + + const genesisBlock: IEsploraApi.Block = await bitcoinApi.$getBlock(await bitcoinApi.$getBlockHash(0)); + const genesisTimestamp = genesisBlock.timestamp * 1000; + + const indexedTimestamp = await HashratesRepository.$getWeeklyHashrateTimestamps(); + const hashrates: any[] = []; + + const lastMonday = new Date(now.setDate(now.getDate() - (now.getDay() + 6) % 7)); + const lastMondayMidnight = this.getDateMidnight(lastMonday); + let toTimestamp = lastMondayMidnight.getTime(); + + const totalWeekIndexed = (await BlocksRepository.$blockCount(null, null)) / 1008; + let indexedThisRun = 0; + let totalIndexed = 0; + let newlyIndexed = 0; + const startedAt = new Date().getTime() / 1000; + let timer = new Date().getTime() / 1000; + + logger.debug(`Indexing weekly mining pool hashrate`, logger.tags.mining); + loadingIndicators.setProgress('weekly-hashrate-indexing', 0); + + while (toTimestamp > genesisTimestamp && toTimestamp > oldestConsecutiveBlockTimestamp) { + const fromTimestamp = toTimestamp - 604800000; + + // Skip already indexed weeks + if (indexedTimestamp.includes(toTimestamp / 1000)) { + toTimestamp -= 604800000; + ++totalIndexed; + continue; + } + + const blockStats: any = await BlocksRepository.$blockCountBetweenTimestamp( + null, fromTimestamp / 1000, toTimestamp / 1000); + const lastBlockHashrate = await bitcoinClient.getNetworkHashPs(blockStats.blockCount, + blockStats.lastBlockHeight); + + let pools = await PoolsRepository.$getPoolsInfoBetween(fromTimestamp / 1000, toTimestamp / 1000); + const totalBlocks = pools.reduce((acc, pool) => acc + pool.blockCount, 0); + if (totalBlocks > 0) { + pools = pools.map((pool: any) => { + pool.hashrate = (pool.blockCount / totalBlocks) * lastBlockHashrate; + pool.share = (pool.blockCount / totalBlocks); + return pool; + }); + + for (const pool of pools) { + hashrates.push({ + hashrateTimestamp: toTimestamp / 1000, + avgHashrate: pool['hashrate'] , + poolId: pool.poolId, + share: pool['share'], + type: 'weekly', + }); + } + + newlyIndexed += hashrates.length / Math.max(1, pools.length); + await HashratesRepository.$saveHashrates(hashrates); + hashrates.length = 0; + } + + const elapsedSeconds = Math.max(1, Math.round((new Date().getTime() / 1000) - timer)); + if (elapsedSeconds > 1) { + const runningFor = Math.max(1, Math.round((new Date().getTime() / 1000) - startedAt)); + const weeksPerSeconds = Math.max(1, Math.round(indexedThisRun / elapsedSeconds)); + const progress = Math.round(totalIndexed / totalWeekIndexed * 10000) / 100; + const formattedDate = new Date(fromTimestamp).toUTCString(); + logger.debug(`Getting weekly pool hashrate for ${formattedDate} | ~${weeksPerSeconds.toFixed(2)} weeks/sec | total: ~${totalIndexed}/${Math.round(totalWeekIndexed)} (${progress}%) | elapsed: ${runningFor} seconds`, logger.tags.mining); + timer = new Date().getTime() / 1000; + indexedThisRun = 0; + loadingIndicators.setProgress('weekly-hashrate-indexing', progress, false); + } + + toTimestamp -= 604800000; + ++indexedThisRun; + ++totalIndexed; + } + this.lastWeeklyHashrateIndexingDate = new Date().getUTCDate(); + if (newlyIndexed > 0) { + logger.info(`Weekly mining pools hashrates indexing completed: indexed ${newlyIndexed} weeks`, logger.tags.mining); + } else { + logger.debug(`Weekly mining pools hashrates indexing completed: indexed ${newlyIndexed} weeks`, logger.tags.mining); + } + loadingIndicators.setProgress('weekly-hashrate-indexing', 100); + } catch (e) { + loadingIndicators.setProgress('weekly-hashrate-indexing', 100); + logger.err(`Weekly mining pools hashrates indexing failed. Trying again in 10 seconds. Reason: ${(e instanceof Error ? e.message : e)}`, logger.tags.mining); + throw e; + } + } + + /** + * Generate daily hashrate data + */ + public async $generateNetworkHashrateHistory(): Promise { + // If a re-index was requested, truncate first + if (this.reindexHashrateRequested === true) { + logger.notice(`hashrates will now be re-indexed`); + await database.query(`TRUNCATE hashrates`); + this.lastHashrateIndexingDate = 0; + this.reindexHashrateRequested = false; + } + + // We only run this once a day around midnight + const today = new Date().getUTCDate(); + if (today === this.lastHashrateIndexingDate) { + logger.debug(`Network hashrate history indexing is up to date, nothing to do`, logger.tags.mining); + return; + } + + const oldestConsecutiveBlockTimestamp = 1000 * (await BlocksRepository.$getOldestConsecutiveBlock()).timestamp; + + try { + const genesisBlock: IEsploraApi.Block = await bitcoinApi.$getBlock(await bitcoinApi.$getBlockHash(0)); + const genesisTimestamp = genesisBlock.timestamp * 1000; + const indexedTimestamp = (await HashratesRepository.$getRawNetworkDailyHashrate(null)).map(hashrate => hashrate.timestamp); + const lastMidnight = this.getDateMidnight(new Date()); + let toTimestamp = Math.round(lastMidnight.getTime()); + const hashrates: any[] = []; + + const totalDayIndexed = (await BlocksRepository.$blockCount(null, null)) / 144; + let indexedThisRun = 0; + let totalIndexed = 0; + let newlyIndexed = 0; + const startedAt = new Date().getTime() / 1000; + let timer = new Date().getTime() / 1000; + + logger.debug(`Indexing daily network hashrate`, logger.tags.mining); + loadingIndicators.setProgress('daily-hashrate-indexing', 0); + + while (toTimestamp > genesisTimestamp && toTimestamp > oldestConsecutiveBlockTimestamp) { + const fromTimestamp = toTimestamp - 86400000; + + // Skip already indexed days + if (indexedTimestamp.includes(toTimestamp / 1000)) { + toTimestamp -= 86400000; + ++totalIndexed; + continue; + } + + const blockStats: any = await BlocksRepository.$blockCountBetweenTimestamp( + null, fromTimestamp / 1000, toTimestamp / 1000); + const lastBlockHashrate = blockStats.blockCount === 0 ? 0 : await bitcoinClient.getNetworkHashPs(blockStats.blockCount, + blockStats.lastBlockHeight); + + hashrates.push({ + hashrateTimestamp: toTimestamp / 1000, + avgHashrate: lastBlockHashrate, + poolId: 0, + share: 1, + type: 'daily', + }); + + if (hashrates.length > 10) { + newlyIndexed += hashrates.length; + await HashratesRepository.$saveHashrates(hashrates); + hashrates.length = 0; + } + + const elapsedSeconds = Math.max(1, Math.round((new Date().getTime() / 1000) - timer)); + if (elapsedSeconds > 1) { + const runningFor = Math.max(1, Math.round((new Date().getTime() / 1000) - startedAt)); + const daysPerSeconds = Math.max(1, Math.round(indexedThisRun / elapsedSeconds)); + const progress = Math.round(totalIndexed / totalDayIndexed * 10000) / 100; + const formattedDate = new Date(fromTimestamp).toUTCString(); + logger.debug(`Getting network daily hashrate for ${formattedDate} | ~${daysPerSeconds.toFixed(2)} days/sec | total: ~${totalIndexed}/${Math.round(totalDayIndexed)} (${progress}%) | elapsed: ${runningFor} seconds`, logger.tags.mining); + timer = new Date().getTime() / 1000; + indexedThisRun = 0; + loadingIndicators.setProgress('daily-hashrate-indexing', progress); + } + + toTimestamp -= 86400000; + ++indexedThisRun; + ++totalIndexed; + } + + // Add genesis block manually + if (config.MEMPOOL.INDEXING_BLOCKS_AMOUNT === -1 && !indexedTimestamp.includes(genesisTimestamp / 1000)) { + hashrates.push({ + hashrateTimestamp: genesisTimestamp / 1000, + avgHashrate: await bitcoinClient.getNetworkHashPs(1, 1), + poolId: 0, + share: 1, + type: 'daily', + }); + } + + newlyIndexed += hashrates.length; + await HashratesRepository.$saveHashrates(hashrates); + + this.lastHashrateIndexingDate = new Date().getUTCDate(); + if (newlyIndexed > 0) { + logger.info(`Daily network hashrate indexing completed: indexed ${newlyIndexed} days`, logger.tags.mining); + } else { + logger.debug(`Daily network hashrate indexing completed: indexed ${newlyIndexed} days`, logger.tags.mining); + } + loadingIndicators.setProgress('daily-hashrate-indexing', 100); + } catch (e) { + loadingIndicators.setProgress('daily-hashrate-indexing', 100); + logger.err(`Daily network hashrate indexing failed. Trying again later. Reason: ${(e instanceof Error ? e.message : e)}`, logger.tags.mining); + throw e; + } + } + + /** + * Index difficulty adjustments + */ + public async $indexDifficultyAdjustments(): Promise { + // If a re-index was requested, truncate first + if (this.reindexDifficultyAdjustmentRequested === true) { + logger.notice(`difficulty_adjustments will now be re-indexed`); + await database.query(`TRUNCATE difficulty_adjustments`); + this.reindexDifficultyAdjustmentRequested = false; + } + + const indexedHeightsArray = await DifficultyAdjustmentsRepository.$getAdjustmentsHeights(); + const indexedHeights = {}; + for (const height of indexedHeightsArray) { + indexedHeights[height] = true; + } + + // gets {time, height, difficulty, bits} of blocks in ascending order of height + const blocks: any = await BlocksRepository.$getBlocksDifficulty(); + const genesisBlock: IEsploraApi.Block = await bitcoinApi.$getBlock(await bitcoinApi.$getBlockHash(0)); + let currentDifficulty = genesisBlock.difficulty; + let currentBits = genesisBlock.bits; + let totalIndexed = 0; + + if (config.MEMPOOL.INDEXING_BLOCKS_AMOUNT === -1 && indexedHeights[0] !== true) { + await DifficultyAdjustmentsRepository.$saveAdjustments({ + time: genesisBlock.timestamp, + height: 0, + difficulty: currentDifficulty, + adjustment: 0.0, + }); + } + + if (!blocks?.length) { + // no blocks in database yet + return; + } + + const oldestConsecutiveBlock = this.getOldestConsecutiveBlock(blocks); + + currentBits = oldestConsecutiveBlock.bits; + currentDifficulty = oldestConsecutiveBlock.difficulty; + + let totalBlockChecked = 0; + let timer = new Date().getTime() / 1000; + + for (const block of blocks) { + // skip until the first block after the oldest consecutive block + if (block.height <= oldestConsecutiveBlock.height) { + continue; + } + + // difficulty has changed between two consecutive blocks! + if (block.bits !== currentBits) { + // skip if already indexed + if (indexedHeights[block.height] !== true) { + let adjustment = block.difficulty / currentDifficulty; + adjustment = Math.round(adjustment * 1000000) / 1000000; // Remove float point noise + + await DifficultyAdjustmentsRepository.$saveAdjustments({ + time: block.time, + height: block.height, + difficulty: block.difficulty, + adjustment: adjustment, + }); + + totalIndexed++; + } + // update the current difficulty + currentDifficulty = block.difficulty; + currentBits = block.bits; + } + + totalBlockChecked++; + const elapsedSeconds = Math.max(1, Math.round((new Date().getTime() / 1000) - timer)); + if (elapsedSeconds > 5) { + const progress = Math.round(totalBlockChecked / blocks.length * 100); + logger.debug(`Indexing difficulty adjustment at block #${block.height} | Progress: ${progress}%`, logger.tags.mining); + timer = new Date().getTime() / 1000; + } + } + + if (totalIndexed > 0) { + logger.info(`Indexed ${totalIndexed} difficulty adjustments`, logger.tags.mining); + } else { + logger.debug(`Indexed ${totalIndexed} difficulty adjustments`, logger.tags.mining); + } + } + + /** + * Create a link between blocks and the latest price at when they were mined + */ + public async $indexBlockPrices(): Promise { + if (this.blocksPriceIndexingRunning === true) { + return; + } + this.blocksPriceIndexingRunning = true; + + let totalInserted = 0; + try { + const prices: any[] = await PricesRepository.$getPricesTimesAndId(); + const blocksWithoutPrices: any[] = await BlocksRepository.$getBlocksWithoutPrice(); + + const blocksPrices: BlockPrice[] = []; + + for (const block of blocksWithoutPrices) { + // Quick optimisation, out mtgox feed only goes back to 2010-07-19 02:00:00, so skip the first 68951 blocks + if (['mainnet', 'testnet'].includes(config.MEMPOOL.NETWORK) && block.height < 68951) { + blocksPrices.push({ + height: block.height, + priceId: prices[0].id, + }); + continue; + } + for (const price of prices) { + if (block.timestamp < price.time) { + blocksPrices.push({ + height: block.height, + priceId: price.id, + }); + break; + }; + } + + if (blocksPrices.length >= 100000) { + totalInserted += blocksPrices.length; + let logStr = `Linking ${blocksPrices.length} blocks to their closest price`; + if (blocksWithoutPrices.length > 200000) { + logStr += ` | Progress ${Math.round(totalInserted / blocksWithoutPrices.length * 100)}%`; + } + logger.debug(logStr, logger.tags.mining); + await BlocksRepository.$saveBlockPrices(blocksPrices); + blocksPrices.length = 0; + } + } + + if (blocksPrices.length > 0) { + totalInserted += blocksPrices.length; + let logStr = `Linking ${blocksPrices.length} blocks to their closest price`; + if (blocksWithoutPrices.length > 200000) { + logStr += ` | Progress ${Math.round(totalInserted / blocksWithoutPrices.length * 100)}%`; + } + logger.debug(logStr, logger.tags.mining); + await BlocksRepository.$saveBlockPrices(blocksPrices); + } + } catch (e) { + this.blocksPriceIndexingRunning = false; + logger.err(`Cannot index block prices. ${e}`); + } + + if (totalInserted > 0) { + logger.info(`Indexing blocks prices completed. Indexed ${totalInserted}`, logger.tags.mining); + } else { + logger.debug(`Indexing blocks prices completed. Indexed 0.`, logger.tags.mining); + } + + this.blocksPriceIndexingRunning = false; + } + + /** + * Index core coinstatsindex + */ + public async $indexCoinStatsIndex(): Promise { + let timer = new Date().getTime() / 1000; + let totalIndexed = 0; + + const blockchainInfo = await bitcoinClient.getBlockchainInfo(); + let currentBlockHeight = blockchainInfo.blocks; + + while (currentBlockHeight > 0) { + const indexedBlocks = await BlocksRepository.$getBlocksMissingCoinStatsIndex( + currentBlockHeight, currentBlockHeight - 10000); + + for (const block of indexedBlocks) { + const txoutset = await bitcoinClient.getTxoutSetinfo('none', block.height); + await BlocksRepository.$updateCoinStatsIndexData(block.hash, txoutset.txouts, + Math.round(txoutset.block_info.prevout_spent * 100000000)); + ++totalIndexed; + + const elapsedSeconds = Math.max(1, new Date().getTime() / 1000 - timer); + if (elapsedSeconds > 5) { + logger.info(`Indexing coinstatsindex data for block #${block.height}. Indexed ${totalIndexed} blocks.`, logger.tags.mining); + timer = new Date().getTime() / 1000; + } + } + + currentBlockHeight -= 10000; + } + + if (totalIndexed > 0) { + logger.info(`Indexing missing coinstatsindex data completed. Indexed ${totalIndexed}`, logger.tags.mining); + } else { + logger.debug(`Indexing missing coinstatsindex data completed. Indexed 0.`, logger.tags.mining); + } + } + + /** + * List existing mining pools + */ + public async $listPools(): Promise<{name: string, slug: string, unique_id: number}[] | null> { + const [rows] = await database.query(` + SELECT + name, + slug, + unique_id + FROM pools` + ); + return rows as {name: string, slug: string, unique_id: number}[]; + } + + private getDateMidnight(date: Date): Date { + date.setUTCHours(0); + date.setUTCMinutes(0); + date.setUTCSeconds(0); + date.setUTCMilliseconds(0); + + return date; + } + + private getTimeRange(interval: string | null, scale = 1): number { + switch (interval) { + case '4y': return 43200 * scale; // 12h + case '3y': return 43200 * scale; // 12h + case '2y': return 28800 * scale; // 8h + case '1y': return 28800 * scale; // 8h + case '6m': return 10800 * scale; // 3h + case '3m': return 7200 * scale; // 2h + case '1m': return 1800 * scale; // 30min + case '1w': return 300 * scale; // 5min + case '3d': return 1 * scale; + case '24h': return 1 * scale; + default: return 86400 * scale; + } + } + + private getTimeRangeFromTimespan(from: number, to: number, scale = 1): number { + const timespan = to - from; + switch (true) { + case timespan > 3600 * 24 * 365 * 4: return 86400 * scale; // 24h + case timespan > 3600 * 24 * 365 * 3: return 43200 * scale; // 12h + case timespan > 3600 * 24 * 365 * 2: return 43200 * scale; // 12h + case timespan > 3600 * 24 * 365: return 28800 * scale; // 8h + case timespan > 3600 * 24 * 30 * 6: return 28800 * scale; // 8h + case timespan > 3600 * 24 * 30 * 3: return 10800 * scale; // 3h + case timespan > 3600 * 24 * 30: return 7200 * scale; // 2h + case timespan > 3600 * 24 * 7: return 1800 * scale; // 30min + case timespan > 3600 * 24 * 3: return 300 * scale; // 5min + case timespan > 3600 * 24: return 1 * scale; + default: return 1 * scale; + } + } + + + // Finds the oldest block in a consecutive chain back from the tip + // assumes `blocks` is sorted in ascending height order + private getOldestConsecutiveBlock(blocks: DifficultyBlock[]): DifficultyBlock { + for (let i = blocks.length - 1; i > 0; i--) { + if ((blocks[i].height - blocks[i - 1].height) > 1) { + return blocks[i]; + } + } + return blocks[0]; + } +} + +export default new Mining(); diff --git a/backend/src/api/pools-parser.ts b/backend/src/api/pools-parser.ts new file mode 100644 index 0000000000..289389d5e2 --- /dev/null +++ b/backend/src/api/pools-parser.ts @@ -0,0 +1,225 @@ +import DB from '../database'; +import logger from '../logger'; +import config from '../config'; +import PoolsRepository from '../repositories/PoolsRepository'; +import { PoolTag } from '../mempool.interfaces'; +import diskCache from './disk-cache'; +import mining from './mining/mining'; +import transactionUtils from './transaction-utils'; +import BlocksRepository from '../repositories/BlocksRepository'; +import redisCache from './redis-cache'; + +class PoolsParser { + miningPools: any[] = []; + unknownPool: any = { + 'id': 0, + 'name': 'Unknown', + 'link': 'https://learnmeabitcoin.com/technical/coinbase-transaction', + 'regexes': '[]', + 'addresses': '[]', + 'slug': 'unknown' + }; + private uniqueLogs: string[] = []; + + private uniqueLog(loggerFunction: any, msg: string): void { + if (this.uniqueLogs.includes(msg)) { + return; + } + this.uniqueLogs.push(msg); + loggerFunction(msg); + } + + public setMiningPools(pools): void { + for (const pool of pools) { + pool.regexes = pool.tags; + pool.slug = pool.name.replace(/[^a-z0-9]/gi, '').toLowerCase(); + delete(pool.tags); + } + this.miningPools = pools; + } + + /** + * Populate our db with updated mining pool definition + * @param pools + */ + public async migratePoolsJson(): Promise { + // We also need to wipe the backend cache to make sure we don't serve blocks with + // the wrong mining pool (usually happen with unknown blocks) + diskCache.setIgnoreBlocksCache(); + redisCache.setIgnoreBlocksCache(); + + await this.$insertUnknownPool(); + + let reindexUnknown = false; + + for (const pool of this.miningPools) { + if (!pool.id) { + logger.info(`Mining pool ${pool.name} has no unique 'id' defined. Skipping.`); + continue; + } + + // One of the two fields 'addresses' or 'regexes' must be a non-empty array + if (!pool.addresses && !pool.regexes) { + logger.err(`Mining pool ${pool.name} must have at least one of the fields 'addresses' or 'regexes'. Skipping.`); + continue; + } + + pool.addresses = pool.addresses || []; + pool.regexes = pool.regexes || []; + + if (pool.addresses.length === 0 && pool.regexes.length === 0) { + logger.err(`Mining pool ${pool.name} has no 'addresses' nor 'regexes' defined. Skipping.`); + continue; + } + + if (pool.addresses.length === 0) { + logger.warn(`Mining pool ${pool.name} has no 'addresses' defined.`); + } + + if (pool.regexes.length === 0) { + logger.warn(`Mining pool ${pool.name} has no 'regexes' defined.`); + } + + const poolDB = await PoolsRepository.$getPoolByUniqueId(pool.id, false); + if (!poolDB) { + // New mining pool + const slug = pool.name.replace(/[^a-z0-9]/gi, '').toLowerCase(); + logger.debug(`Inserting new mining pool ${pool.name}`); + await PoolsRepository.$insertNewMiningPool(pool, slug); + reindexUnknown = true; + } else { + if (poolDB.name !== pool.name) { + // Pool has been renamed + const newSlug = pool.name.replace(/[^a-z0-9]/gi, '').toLowerCase(); + logger.warn(`Renaming ${poolDB.name} mining pool to ${pool.name}. Slug has been updated. Maybe you want to make a redirection from 'https://mempool.space/mining/pool/${poolDB.slug}' to 'https://mempool.space/mining/pool/${newSlug}`); + await PoolsRepository.$renameMiningPool(poolDB.id, newSlug, pool.name); + } + if (poolDB.link !== pool.link) { + // Pool link has changed + logger.debug(`Updating link for ${pool.name} mining pool`); + await PoolsRepository.$updateMiningPoolLink(poolDB.id, pool.link); + } + if (JSON.stringify(pool.addresses) !== poolDB.addresses || + JSON.stringify(pool.regexes) !== poolDB.regexes) { + // Pool addresses changed or coinbase tags changed + logger.notice(`Updating addresses and/or coinbase tags for ${pool.name} mining pool.`); + await PoolsRepository.$updateMiningPoolTags(poolDB.id, pool.addresses, pool.regexes); + reindexUnknown = true; + await this.$reindexBlocksForPool(poolDB.id); + } + } + } + + if (reindexUnknown) { + logger.notice(`Updating addresses and/or coinbase tags for unknown mining pool.`); + let unknownPool; + if (config.DATABASE.ENABLED === true) { + unknownPool = await PoolsRepository.$getUnknownPool(); + } else { + unknownPool = this.unknownPool; + } + await this.$reindexBlocksForPool(unknownPool.id); + } + } + + public matchBlockMiner(scriptsig: string, addresses: string[], pools: PoolTag[]): PoolTag | undefined { + const asciiScriptSig = transactionUtils.hex2ascii(scriptsig); + + for (let i = 0; i < pools.length; ++i) { + if (addresses.length) { + const poolAddresses: string[] = typeof pools[i].addresses === 'string' ? + JSON.parse(pools[i].addresses) : pools[i].addresses; + for (let y = 0; y < poolAddresses.length; y++) { + if (addresses.indexOf(poolAddresses[y]) !== -1) { + return pools[i]; + } + } + } + + const regexes: string[] = typeof pools[i].regexes === 'string' ? + JSON.parse(pools[i].regexes) : pools[i].regexes; + for (let y = 0; y < regexes.length; ++y) { + const regex = new RegExp(regexes[y], 'i'); + const match = asciiScriptSig.match(regex); + if (match !== null) { + return pools[i]; + } + } + } + } + + /** + * Manually add the 'unknown pool' + */ + public async $insertUnknownPool(): Promise { + if (!config.DATABASE.ENABLED) { + return; + } + + try { + const [rows]: any[] = await DB.query({ sql: 'SELECT name from pools where name="Unknown"', timeout: 120000 }); + if (rows.length === 0) { + await DB.query({ + sql: `INSERT INTO pools(name, link, regexes, addresses, slug, unique_id) + VALUES("${this.unknownPool.name}", "${this.unknownPool.link}", "[]", "[]", "${this.unknownPool.slug}", 0); + `}); + } else { + await DB.query(`UPDATE pools + SET name='${this.unknownPool.name}', link='${this.unknownPool.link}', + regexes='[]', addresses='[]', + slug='${this.unknownPool.slug}', + unique_id=0 + WHERE slug='${this.unknownPool.slug}' + `); + } + } catch (e) { + logger.err(`Unable to insert or update "Unknown" mining pool. Reason: ${e instanceof Error ? e.message : e}`); + } + } + + /** + * re-index pool assignment for blocks previously associated with pool + * + * @param pool local id of existing pool to reindex + */ + private async $reindexBlocksForPool(poolId: number): Promise { + let firstKnownBlockPool = 130635; // https://mempool.space/block/0000000000000a067d94ff753eec72830f1205ad3a4c216a08a80c832e551a52 + if (config.MEMPOOL.NETWORK === 'testnet') { + firstKnownBlockPool = 21106; // https://mempool.space/testnet/block/0000000070b701a5b6a1b965f6a38e0472e70b2bb31b973e4638dec400877581 + } else if (config.MEMPOOL.NETWORK === 'signet') { + firstKnownBlockPool = 0; + } + + const [blocks]: any[] = await DB.query(` + SELECT height, hash, coinbase_raw, coinbase_addresses + FROM blocks + WHERE pool_id = ? + AND height >= ? + ORDER BY height DESC + `, [poolId, firstKnownBlockPool]); + + let pools: PoolTag[] = []; + if (config.DATABASE.ENABLED === true) { + pools = await PoolsRepository.$getPools(); + } else { + pools = this.miningPools; + } + + let changed = 0; + for (const block of blocks) { + const addresses = JSON.parse(block.coinbase_addresses) || []; + const newPool = this.matchBlockMiner(block.coinbase_raw, addresses, pools); + if (newPool && newPool.id !== poolId) { + changed++; + await BlocksRepository.$savePool(block.hash, newPool.id); + } + } + + logger.info(`${changed} blocks assigned to a new pool`, logger.tags.mining); + + // Re-index hashrates and difficulty adjustments later + mining.reindexHashrateRequested = true; + } +} + +export default new PoolsParser(); diff --git a/backend/src/api/prices/prices.routes.ts b/backend/src/api/prices/prices.routes.ts new file mode 100644 index 0000000000..b46331b73e --- /dev/null +++ b/backend/src/api/prices/prices.routes.ts @@ -0,0 +1,19 @@ +import { Application, Request, Response } from 'express'; +import config from '../../config'; +import pricesUpdater from '../../tasks/price-updater'; + +class PricesRoutes { + public initRoutes(app: Application): void { + app.get(config.MEMPOOL.API_URL_PREFIX + 'prices', this.$getCurrentPrices.bind(this)); + } + + private $getCurrentPrices(req: Request, res: Response): void { + res.header('Pragma', 'public'); + res.header('Cache-control', 'public'); + res.setHeader('Expires', new Date(Date.now() + 360_0000 / config.MEMPOOL.PRICE_UPDATES_PER_HOUR).toUTCString()); + + res.json(pricesUpdater.getLatestPrices()); + } +} + +export default new PricesRoutes(); diff --git a/backend/src/api/rbf-cache.ts b/backend/src/api/rbf-cache.ts new file mode 100644 index 0000000000..a087abbe00 --- /dev/null +++ b/backend/src/api/rbf-cache.ts @@ -0,0 +1,543 @@ +import config from "../config"; +import logger from "../logger"; +import { MempoolTransactionExtended, TransactionStripped } from "../mempool.interfaces"; +import bitcoinApi from './bitcoin/bitcoin-api-factory'; +import { IEsploraApi } from "./bitcoin/esplora-api.interface"; +import { Common } from "./common"; +import redisCache from "./redis-cache"; + +export interface RbfTransaction extends TransactionStripped { + rbf?: boolean; + mined?: boolean; + fullRbf?: boolean; +} + +export interface RbfTree { + tx: RbfTransaction; + time: number; + interval?: number; + mined?: boolean; + fullRbf: boolean; + replaces: RbfTree[]; +} + +export interface ReplacementInfo { + mined: boolean; + fullRbf: boolean; + txid: string; + oldFee: number; + oldVsize: number; + newFee: number; + newVsize: number; +} + +enum CacheOp { + Remove = 0, + Add = 1, + Change = 2, +} + +interface CacheEvent { + op: CacheOp; + type: 'tx' | 'tree' | 'exp'; + txid: string, + value?: any, +} + +class RbfCache { + private replacedBy: Map = new Map(); + private replaces: Map = new Map(); + private rbfTrees: Map = new Map(); // sequences of consecutive replacements + private dirtyTrees: Set = new Set(); + private treeMap: Map = new Map(); // map of txids to sequence ids + private txs: Map = new Map(); + private expiring: Map = new Map(); + private cacheQueue: CacheEvent[] = []; + + private evictionCount = 0; + private staleCount = 0; + + constructor() { + setInterval(this.cleanup.bind(this), 1000 * 60 * 10); + } + + private addTx(txid: string, tx: MempoolTransactionExtended): void { + this.txs.set(txid, tx); + this.cacheQueue.push({ op: CacheOp.Add, type: 'tx', txid }); + } + + private addTree(txid: string, tree: RbfTree): void { + this.rbfTrees.set(txid, tree); + this.dirtyTrees.add(txid); + this.cacheQueue.push({ op: CacheOp.Add, type: 'tree', txid }); + } + + private addExpiration(txid: string, expiry: number): void { + this.expiring.set(txid, expiry); + this.cacheQueue.push({ op: CacheOp.Add, type: 'exp', txid, value: expiry }); + } + + private removeTx(txid: string): void { + this.txs.delete(txid); + this.cacheQueue.push({ op: CacheOp.Remove, type: 'tx', txid }); + } + + private removeTree(txid: string): void { + this.rbfTrees.delete(txid); + this.cacheQueue.push({ op: CacheOp.Remove, type: 'tree', txid }); + } + + private removeExpiration(txid: string): void { + this.expiring.delete(txid); + this.cacheQueue.push({ op: CacheOp.Remove, type: 'exp', txid }); + } + + public add(replaced: MempoolTransactionExtended[], newTxExtended: MempoolTransactionExtended): void { + if (!newTxExtended || !replaced?.length || this.txs.has(newTxExtended.txid)) { + return; + } + + newTxExtended.replacement = true; + + const newTx = Common.stripTransaction(newTxExtended) as RbfTransaction; + const newTime = newTxExtended.firstSeen || (Date.now() / 1000); + newTx.rbf = newTxExtended.vin.some((v) => v.sequence < 0xfffffffe); + this.addTx(newTx.txid, newTxExtended); + + // maintain rbf trees + let txFullRbf = false; + let treeFullRbf = false; + const replacedTrees: RbfTree[] = []; + for (const replacedTxExtended of replaced) { + const replacedTx = Common.stripTransaction(replacedTxExtended) as RbfTransaction; + replacedTx.rbf = replacedTxExtended.vin.some((v) => v.sequence < 0xfffffffe); + if (!replacedTx.rbf) { + txFullRbf = true; + } + this.replacedBy.set(replacedTx.txid, newTx.txid); + if (this.treeMap.has(replacedTx.txid)) { + const treeId = this.treeMap.get(replacedTx.txid); + if (treeId) { + const tree = this.rbfTrees.get(treeId); + this.removeTree(treeId); + if (tree) { + tree.interval = newTime - tree?.time; + replacedTrees.push(tree); + treeFullRbf = treeFullRbf || tree.fullRbf || !tree.tx.rbf; + } + } + } else { + const replacedTime = replacedTxExtended.firstSeen || (Date.now() / 1000); + replacedTrees.push({ + tx: replacedTx, + time: replacedTime, + interval: newTime - replacedTime, + fullRbf: !replacedTx.rbf, + replaces: [], + }); + treeFullRbf = treeFullRbf || !replacedTx.rbf; + this.addTx(replacedTx.txid, replacedTxExtended); + } + } + newTx.fullRbf = txFullRbf; + const treeId = replacedTrees[0].tx.txid; + const newTree = { + tx: newTx, + time: newTime, + fullRbf: treeFullRbf, + replaces: replacedTrees + }; + this.addTree(treeId, newTree); + this.updateTreeMap(treeId, newTree); + this.replaces.set(newTx.txid, replacedTrees.map(tree => tree.tx.txid)); + } + + public has(txId: string): boolean { + return this.txs.has(txId); + } + + public anyInSameTree(txId: string, predicate: (tx: RbfTransaction) => boolean): boolean { + const tree = this.getRbfTree(txId); + if (!tree) { + return false; + } + const txs = this.getTransactionsInTree(tree); + for (const tx of txs) { + if (predicate(tx)) { + return true; + } + } + return false; + } + + public getReplacedBy(txId: string): string | undefined { + return this.replacedBy.get(txId); + } + + public getReplaces(txId: string): string[] | undefined { + return this.replaces.get(txId); + } + + public getTx(txId: string): MempoolTransactionExtended | undefined { + return this.txs.get(txId); + } + + public getRbfTree(txId: string): RbfTree | void { + return this.rbfTrees.get(this.treeMap.get(txId) || ''); + } + + // get a paginated list of RbfTrees + // ordered by most recent replacement time + public getRbfTrees(onlyFullRbf: boolean, after?: string): RbfTree[] { + const limit = 25; + const trees: RbfTree[] = []; + const used = new Set(); + const replacements: string[][] = Array.from(this.replacedBy).reverse(); + const afterTree = after ? this.treeMap.get(after) : null; + let ready = !afterTree; + for (let i = 0; i < replacements.length && trees.length <= limit - 1; i++) { + const txid = replacements[i][1]; + const treeId = this.treeMap.get(txid) || ''; + if (treeId === afterTree) { + ready = true; + } else if (ready) { + if (!used.has(treeId)) { + const tree = this.rbfTrees.get(treeId); + used.add(treeId); + if (tree && (!onlyFullRbf || tree.fullRbf)) { + trees.push(tree); + } + } + } + } + return trees; + } + + // get map of rbf trees that have been updated since the last call + public getRbfChanges(): { trees: {[id: string]: RbfTree }, map: { [txid: string]: string }} { + const changes: { trees: {[id: string]: RbfTree }, map: { [txid: string]: string }} = { + trees: {}, + map: {}, + }; + this.dirtyTrees.forEach(id => { + const tree = this.rbfTrees.get(id); + if (tree) { + changes.trees[id] = tree; + this.getTransactionsInTree(tree).forEach(tx => { + changes.map[tx.txid] = id; + }); + } + }); + this.dirtyTrees = new Set(); + return changes; + } + + public mined(txid): void { + if (!this.txs.has(txid)) { + return; + } + const treeId = this.treeMap.get(txid); + if (treeId && this.rbfTrees.has(treeId)) { + const tree = this.rbfTrees.get(treeId); + if (tree) { + this.setTreeMined(tree, txid); + tree.mined = true; + this.dirtyTrees.add(treeId); + this.cacheQueue.push({ op: CacheOp.Change, type: 'tree', txid: treeId }); + } + } + this.evict(txid); + } + + // flag a transaction as removed from the mempool + public evict(txid: string, fast: boolean = false): void { + this.evictionCount++; + if (this.txs.has(txid) && (fast || !this.expiring.has(txid))) { + const expiryTime = fast ? Date.now() + (1000 * 60 * 10) : Date.now() + (1000 * 86400); // 24 hours + this.addExpiration(txid, expiryTime); + } + } + + // is the transaction involved in a full rbf replacement? + public isFullRbf(txid: string): boolean { + const treeId = this.treeMap.get(txid); + if (!treeId) { + return false; + } + const tree = this.rbfTrees.get(treeId); + if (!tree) { + return false; + } + return tree?.fullRbf; + } + + private cleanup(): void { + const now = Date.now(); + for (const txid of this.expiring.keys()) { + if ((this.expiring.get(txid) || 0) < now) { + this.removeExpiration(txid); + this.remove(txid); + } + } + logger.debug(`rbf cache contains ${this.txs.size} txs, ${this.rbfTrees.size} trees, ${this.expiring.size} due to expire (${this.evictionCount} newly expired)`); + this.evictionCount = 0; + } + + // remove a transaction & all previous versions from the cache + private remove(txid): void { + // don't remove a transaction if a newer version remains in the mempool + if (!this.replacedBy.has(txid)) { + const root = this.treeMap.get(txid); + const replaces = this.replaces.get(txid); + this.replaces.delete(txid); + this.treeMap.delete(txid); + this.removeTx(txid); + this.removeExpiration(txid); + if (root === txid) { + this.removeTree(txid); + } + for (const tx of (replaces || [])) { + // recursively remove prior versions from the cache + this.replacedBy.delete(tx); + // if this is the id of a tree, remove that too + if (this.treeMap.get(tx) === tx) { + this.removeTree(tx); + } + this.remove(tx); + } + } + } + + private updateTreeMap(newId: string, tree: RbfTree): void { + this.treeMap.set(tree.tx.txid, newId); + tree.replaces.forEach(subtree => { + this.updateTreeMap(newId, subtree); + }); + } + + private getTransactionsInTree(tree: RbfTree, txs: RbfTransaction[] = []): RbfTransaction[] { + txs.push(tree.tx); + tree.replaces.forEach(subtree => { + this.getTransactionsInTree(subtree, txs); + }); + return txs; + } + + private setTreeMined(tree: RbfTree, txid: string): void { + if (tree.tx.txid === txid) { + tree.tx.mined = true; + } else { + tree.replaces.forEach(subtree => { + this.setTreeMined(subtree, txid); + }); + } + } + + public async updateCache(): Promise { + if (!config.REDIS.ENABLED) { + return; + } + // Update the Redis cache by replaying queued events + for (const e of this.cacheQueue) { + if (e.op === CacheOp.Add || e.op === CacheOp.Change) { + let value = e.value; + switch(e.type) { + case 'tx': { + value = this.txs.get(e.txid); + } break; + case 'tree': { + const tree = this.rbfTrees.get(e.txid); + value = tree ? this.exportTree(tree) : null; + } break; + } + if (value != null) { + await redisCache.$setRbfEntry(e.type, e.txid, value); + } + } else if (e.op === CacheOp.Remove) { + await redisCache.$removeRbfEntry(e.type, e.txid); + } + } + this.cacheQueue = []; + } + + public dump(): any { + const trees = Array.from(this.rbfTrees.values()).map((tree: RbfTree) => { return this.exportTree(tree); }); + + return { + txs: Array.from(this.txs.entries()), + trees, + expiring: Array.from(this.expiring.entries()), + }; + } + + public async load({ txs, trees, expiring, mempool }): Promise { + try { + txs.forEach(txEntry => { + this.txs.set(txEntry.value.txid, txEntry.value); + }); + this.staleCount = 0; + for (const deflatedTree of trees) { + await this.importTree(mempool, deflatedTree.root, deflatedTree.root, deflatedTree, this.txs); + } + expiring.forEach(expiringEntry => { + if (this.txs.has(expiringEntry.key)) { + this.expiring.set(expiringEntry.key, new Date(expiringEntry.value).getTime()); + } + }); + this.staleCount = 0; + await this.checkTrees(); + logger.debug(`loaded ${txs.length} txs, ${trees.length} trees into rbf cache, ${expiring.length} due to expire, ${this.staleCount} were stale`); + this.cleanup(); + + } catch (e) { + logger.err('failed to restore RBF cache: ' + (e instanceof Error ? e.message : e)); + } + } + + exportTree(tree: RbfTree, deflated: any = null) { + if (!deflated) { + deflated = { + root: tree.tx.txid, + }; + } + deflated[tree.tx.txid] = { + tx: tree.tx.txid, + txMined: tree.tx.mined, + time: tree.time, + interval: tree.interval, + mined: tree.mined, + fullRbf: tree.fullRbf, + replaces: tree.replaces.map(child => child.tx.txid), + }; + tree.replaces.forEach(child => { + this.exportTree(child, deflated); + }); + return deflated; + } + + async importTree(mempool, root, txid, deflated, txs: Map, mined: boolean = false): Promise { + const treeInfo = deflated[txid]; + const replaces: RbfTree[] = []; + + // if the root tx is unknown, remove this tree and return early + if (root === txid && !txs.has(txid)) { + this.staleCount++; + this.removeTree(deflated.key); + return; + } + + // recursively reconstruct child trees + for (const childId of treeInfo.replaces) { + const replaced = await this.importTree(mempool, root, childId, deflated, txs, mined); + if (replaced) { + this.replacedBy.set(replaced.tx.txid, txid); + if (mempool[replaced.tx.txid]) { + mempool[replaced.tx.txid].replacement = true; + } + replaces.push(replaced); + if (replaced.mined) { + mined = true; + } + } + } + this.replaces.set(txid, replaces.map(t => t.tx.txid)); + + const tx = txs.get(txid); + if (!tx) { + return; + } + const strippedTx = Common.stripTransaction(tx) as RbfTransaction; + strippedTx.rbf = tx.vin.some((v) => v.sequence < 0xfffffffe); + strippedTx.mined = treeInfo.txMined; + const tree = { + tx: strippedTx, + time: treeInfo.time, + interval: treeInfo.interval, + mined: mined, + fullRbf: treeInfo.fullRbf, + replaces, + }; + this.treeMap.set(txid, root); + if (root === txid) { + this.addTree(root, tree); + } + return tree; + } + + private async checkTrees(): Promise { + const found: { [txid: string]: boolean } = {}; + const txids = Array.from(this.txs.values()).map(tx => tx.txid).filter(txid => { + return !this.expiring.has(txid) && !this.getRbfTree(txid)?.mined; + }); + + const processTxs = (txs: IEsploraApi.Transaction[]): void => { + for (const tx of txs) { + found[tx.txid] = true; + if (tx.status?.confirmed) { + const tree = this.getRbfTree(tx.txid); + if (tree) { + this.setTreeMined(tree, tx.txid); + tree.mined = true; + this.evict(tx.txid, false); + } + } + } + }; + + if (config.MEMPOOL.BACKEND === 'esplora') { + let processedCount = 0; + const sliceLength = Math.ceil(config.ESPLORA.BATCH_QUERY_BASE_SIZE / 40); + for (let i = 0; i < Math.ceil(txids.length / sliceLength); i++) { + const slice = txids.slice(i * sliceLength, (i + 1) * sliceLength); + processedCount += slice.length; + try { + const txs = await bitcoinApi.$getRawTransactions(slice); + processTxs(txs); + logger.debug(`fetched and processed ${processedCount} of ${txids.length} cached rbf transactions (${(processedCount / txids.length * 100).toFixed(2)}%)`); + } catch (err) { + logger.err(`failed to fetch or process ${slice.length} cached rbf transactions`); + } + } + } else { + const txs: IEsploraApi.Transaction[] = []; + for (const txid of txids) { + try { + const tx = await bitcoinApi.$getRawTransaction(txid, true, false); + txs.push(tx); + } catch (err) { + // some 404s are expected, so continue quietly + } + } + processTxs(txs); + } + + for (const txid of txids) { + if (!found[txid]) { + this.evict(txid, false); + } + } + } + + public getLatestRbfSummary(): ReplacementInfo[] { + const rbfList = this.getRbfTrees(false); + return rbfList.slice(0, 6).map(rbfTree => { + let oldFee = 0; + let oldVsize = 0; + for (const replaced of rbfTree.replaces) { + oldFee += replaced.tx.fee; + oldVsize += replaced.tx.vsize; + } + return { + txid: rbfTree.tx.txid, + mined: !!rbfTree.tx.mined, + fullRbf: !!rbfTree.tx.fullRbf, + oldFee, + oldVsize, + newFee: rbfTree.tx.fee, + newVsize: rbfTree.tx.vsize, + }; + }); + } +} + +export default new RbfCache(); diff --git a/backend/src/api/redis-cache.ts b/backend/src/api/redis-cache.ts new file mode 100644 index 0000000000..cbfa2f18b5 --- /dev/null +++ b/backend/src/api/redis-cache.ts @@ -0,0 +1,424 @@ +import { createClient } from 'redis'; +import memPool from './mempool'; +import blocks from './blocks'; +import logger from '../logger'; +import config from '../config'; +import { BlockExtended, BlockSummary, MempoolTransactionExtended } from '../mempool.interfaces'; +import rbfCache from './rbf-cache'; +import transactionUtils from './transaction-utils'; + +enum NetworkDB { + mainnet = 0, + testnet, + signet, + liquid, + liquidtestnet, +} + +class RedisCache { + private client; + private connected = false; + private schemaVersion = 1; + private redisConfig: any; + + private pauseFlush: boolean = false; + private cacheQueue: MempoolTransactionExtended[] = []; + private removeQueue: string[] = []; + private rbfCacheQueue: { type: string, txid: string, value: any }[] = []; + private rbfRemoveQueue: { type: string, txid: string }[] = []; + private txFlushLimit: number = 10000; + private ignoreBlocksCache = false; + + constructor() { + if (config.REDIS.ENABLED) { + this.redisConfig = { + socket: { + path: config.REDIS.UNIX_SOCKET_PATH + }, + database: NetworkDB[config.MEMPOOL.NETWORK], + }; + this.$ensureConnected(); + setInterval(() => { this.$ensureConnected(); }, 10000); + } + } + + private async $ensureConnected(): Promise { + if (!this.connected && config.REDIS.ENABLED) { + try { + this.client = createClient(this.redisConfig); + this.client.on('error', async (e) => { + logger.err(`Error in Redis client: ${e instanceof Error ? e.message : e}`); + this.connected = false; + await this.client.disconnect(); + }); + await this.client.connect().then(async () => { + try { + const version = await this.client.get('schema_version'); + this.connected = true; + if (version !== this.schemaVersion) { + // schema changed + // perform migrations or flush DB if necessary + logger.info(`Redis schema version changed from ${version} to ${this.schemaVersion}`); + await this.client.set('schema_version', this.schemaVersion); + } + logger.info(`Redis client connected`); + return true; + } catch (e) { + this.connected = false; + logger.warn('Failed to connect to Redis'); + return false; + } + }); + await this.$onConnected(); + return true; + } catch (e) { + logger.warn('Error connecting to Redis: ' + (e instanceof Error ? e.message : e)); + return false; + } + } else { + try { + // test connection + await this.client.get('schema_version'); + return true; + } catch (e) { + logger.warn('Lost connection to Redis: ' + (e instanceof Error ? e.message : e)); + logger.warn('Attempting to reconnect in 10 seconds'); + this.connected = false; + return false; + } + } + } + + private async $onConnected(): Promise { + await this.$flushTransactions(); + await this.$removeTransactions([]); + await this.$flushRbfQueues(); + } + + async $updateBlocks(blocks: BlockExtended[]): Promise { + if (!config.REDIS.ENABLED) { + return; + } + if (!this.connected) { + logger.warn(`Failed to update blocks in Redis cache: Redis is not connected`); + return; + } + try { + await this.client.set('blocks', JSON.stringify(blocks)); + logger.debug(`Saved latest blocks to Redis cache`); + } catch (e) { + logger.warn(`Failed to update blocks in Redis cache: ${e instanceof Error ? e.message : e}`); + } + } + + async $updateBlockSummaries(summaries: BlockSummary[]): Promise { + if (!config.REDIS.ENABLED) { + return; + } + if (!this.connected) { + logger.warn(`Failed to update block summaries in Redis cache: Redis is not connected`); + return; + } + try { + await this.client.set('block-summaries', JSON.stringify(summaries)); + logger.debug(`Saved latest block summaries to Redis cache`); + } catch (e) { + logger.warn(`Failed to update block summaries in Redis cache: ${e instanceof Error ? e.message : e}`); + } + } + + async $addTransaction(tx: MempoolTransactionExtended): Promise { + if (!config.REDIS.ENABLED) { + return; + } + this.cacheQueue.push(tx); + if (this.cacheQueue.length >= this.txFlushLimit) { + if (!this.pauseFlush) { + await this.$flushTransactions(); + } + } + } + + async $flushTransactions(): Promise { + if (!config.REDIS.ENABLED) { + return; + } + if (!this.cacheQueue.length) { + return; + } + if (!this.connected) { + logger.warn(`Failed to add ${this.cacheQueue.length} transactions to Redis cache: Redis not connected`); + return; + } + + this.pauseFlush = false; + + const toAdd = this.cacheQueue.slice(0, this.txFlushLimit); + try { + const msetData = toAdd.map(tx => { + const minified: any = structuredClone(tx); + delete minified.hex; + for (const vin of minified.vin) { + delete vin.inner_redeemscript_asm; + delete vin.inner_witnessscript_asm; + delete vin.scriptsig_asm; + } + for (const vout of minified.vout) { + delete vout.scriptpubkey_asm; + } + return [`mempool:tx:${tx.txid}`, JSON.stringify(minified)]; + }); + await this.client.MSET(msetData); + // successful, remove transactions from cache queue + this.cacheQueue = this.cacheQueue.slice(toAdd.length); + logger.debug(`Saved ${toAdd.length} transactions to Redis cache, ${this.cacheQueue.length} left in queue`); + } catch (e) { + logger.warn(`Failed to add ${toAdd.length} transactions to Redis cache: ${e instanceof Error ? e.message : e}`); + this.pauseFlush = true; + } + } + + async $removeTransactions(transactions: string[]): Promise { + if (!config.REDIS.ENABLED) { + return; + } + const toRemove = this.removeQueue.concat(transactions); + this.removeQueue = []; + let failed: string[] = []; + let numRemoved = 0; + if (this.connected) { + const sliceLength = config.REDIS.BATCH_QUERY_BASE_SIZE; + for (let i = 0; i < Math.ceil(toRemove.length / sliceLength); i++) { + const slice = toRemove.slice(i * sliceLength, (i + 1) * sliceLength); + try { + await this.client.unlink(slice.map(txid => `mempool:tx:${txid}`)); + numRemoved+= sliceLength; + logger.debug(`Deleted ${slice.length} transactions from the Redis cache`); + } catch (e) { + logger.warn(`Failed to remove ${slice.length} transactions from Redis cache: ${e instanceof Error ? e.message : e}`); + failed = failed.concat(slice); + } + } + // concat instead of replace, in case more txs have been added in the meantime + this.removeQueue = this.removeQueue.concat(failed); + } else { + this.removeQueue = this.removeQueue.concat(toRemove); + } + } + + async $setRbfEntry(type: string, txid: string, value: any): Promise { + if (!config.REDIS.ENABLED) { + return; + } + if (!this.connected) { + this.rbfCacheQueue.push({ type, txid, value }); + logger.warn(`Failed to set RBF ${type} in Redis cache: Redis is not connected`); + return; + } + try { + await this.client.set(`rbf:${type}:${txid}`, JSON.stringify(value)); + } catch (e) { + logger.warn(`Failed to set RBF ${type} in Redis cache: ${e instanceof Error ? e.message : e}`); + } + } + + async $removeRbfEntry(type: string, txid: string): Promise { + if (!config.REDIS.ENABLED) { + return; + } + if (!this.connected) { + this.rbfRemoveQueue.push({ type, txid }); + logger.warn(`Failed to remove RBF ${type} from Redis cache: Redis is not connected`); + return; + } + try { + await this.client.unlink(`rbf:${type}:${txid}`); + } catch (e) { + logger.warn(`Failed to remove RBF ${type} from Redis cache: ${e instanceof Error ? e.message : e}`); + } + } + + private async $flushRbfQueues(): Promise { + if (!config.REDIS.ENABLED) { + return; + } + if (!this.connected) { + return; + } + try { + const toAdd = this.rbfCacheQueue; + this.rbfCacheQueue = []; + for (const { type, txid, value } of toAdd) { + await this.$setRbfEntry(type, txid, value); + } + logger.debug(`Saved ${toAdd.length} queued RBF entries to the Redis cache`); + const toRemove = this.rbfRemoveQueue; + this.rbfRemoveQueue = []; + for (const { type, txid } of toRemove) { + await this.$removeRbfEntry(type, txid); + } + logger.debug(`Removed ${toRemove.length} queued RBF entries from the Redis cache`); + } catch (e) { + logger.warn(`Failed to flush RBF cache event queues after reconnecting to Redis: ${e instanceof Error ? e.message : e}`); + } + } + + async $getBlocks(): Promise { + if (!config.REDIS.ENABLED) { + return []; + } + if (!this.connected) { + logger.warn(`Failed to retrieve blocks from Redis cache: Redis is not connected`); + return []; + } + try { + const json = await this.client.get('blocks'); + return JSON.parse(json); + } catch (e) { + logger.warn(`Failed to retrieve blocks from Redis cache: ${e instanceof Error ? e.message : e}`); + return []; + } + } + + async $getBlockSummaries(): Promise { + if (!config.REDIS.ENABLED) { + return []; + } + if (!this.connected) { + logger.warn(`Failed to retrieve blocks from Redis cache: Redis is not connected`); + return []; + } + try { + const json = await this.client.get('block-summaries'); + return JSON.parse(json); + } catch (e) { + logger.warn(`Failed to retrieve blocks from Redis cache: ${e instanceof Error ? e.message : e}`); + return []; + } + } + + async $getMempool(): Promise<{ [txid: string]: MempoolTransactionExtended }> { + if (!config.REDIS.ENABLED) { + return {}; + } + if (!this.connected) { + logger.warn(`Failed to retrieve mempool from Redis cache: Redis is not connected`); + return {}; + } + const start = Date.now(); + const mempool = {}; + try { + const mempoolList = await this.scanKeys('mempool:tx:*'); + for (const tx of mempoolList) { + mempool[tx.key] = tx.value; + } + logger.info(`Loaded mempool from Redis cache in ${Date.now() - start} ms`); + return mempool || {}; + } catch (e) { + logger.warn(`Failed to retrieve mempool from Redis cache: ${e instanceof Error ? e.message : e}`); + } + return {}; + } + + async $getRbfEntries(type: string): Promise { + if (!config.REDIS.ENABLED) { + return []; + } + if (!this.connected) { + logger.warn(`Failed to retrieve Rbf ${type}s from Redis cache: Redis is not connected`); + return []; + } + try { + const rbfEntries = await this.scanKeys(`rbf:${type}:*`); + return rbfEntries; + } catch (e) { + logger.warn(`Failed to retrieve Rbf ${type}s from Redis cache: ${e instanceof Error ? e.message : e}`); + return []; + } + } + + async $loadCache(): Promise { + if (!config.REDIS.ENABLED) { + return; + } + logger.info('Restoring mempool and blocks data from Redis cache'); + + // Load mempool + const loadedMempool = await this.$getMempool(); + this.inflateLoadedTxs(loadedMempool); + // Load rbf data + const rbfTxs = await this.$getRbfEntries('tx'); + const rbfTrees = await this.$getRbfEntries('tree'); + const rbfExpirations = await this.$getRbfEntries('exp'); + + // Load & set block data + if (!this.ignoreBlocksCache) { + const loadedBlocks = await this.$getBlocks(); + const loadedBlockSummaries = await this.$getBlockSummaries(); + blocks.setBlocks(loadedBlocks || []); + blocks.setBlockSummaries(loadedBlockSummaries || []); + } + // Set other data + await memPool.$setMempool(loadedMempool); + await rbfCache.load({ + txs: rbfTxs, + trees: rbfTrees.map(loadedTree => { loadedTree.value.key = loadedTree.key; return loadedTree.value; }), + expiring: rbfExpirations, + mempool: memPool.getMempool(), + }); + } + + private inflateLoadedTxs(mempool: { [txid: string]: MempoolTransactionExtended }): void { + for (const tx of Object.values(mempool)) { + for (const vin of tx.vin) { + if (vin.scriptsig) { + vin.scriptsig_asm = transactionUtils.convertScriptSigAsm(vin.scriptsig); + transactionUtils.addInnerScriptsToVin(vin); + } + } + for (const vout of tx.vout) { + if (vout.scriptpubkey) { + vout.scriptpubkey_asm = transactionUtils.convertScriptSigAsm(vout.scriptpubkey); + } + } + } + } + + private async scanKeys(pattern): Promise<{ key: string, value: T }[]> { + logger.info(`loading Redis entries for ${pattern}`); + let keys: string[] = []; + const result: { key: string, value: T }[] = []; + const patternLength = pattern.length - 1; + let count = 0; + const processValues = async (keys): Promise => { + const values = await this.client.MGET(keys); + for (let i = 0; i < values.length; i++) { + if (values[i]) { + result.push({ key: keys[i].slice(patternLength), value: JSON.parse(values[i]) }); + count++; + } + } + logger.info(`loaded ${count} entries from Redis cache`); + }; + for await (const key of this.client.scanIterator({ + MATCH: pattern, + COUNT: 100 + })) { + keys.push(key); + if (keys.length >= 10000) { + await processValues(keys); + keys = []; + } + } + if (keys.length) { + await processValues(keys); + } + return result; + } + + public setIgnoreBlocksCache(): void { + this.ignoreBlocksCache = true; + } +} + +export default new RedisCache(); diff --git a/backend/src/api/services/acceleration.ts b/backend/src/api/services/acceleration.ts new file mode 100644 index 0000000000..7debe71196 --- /dev/null +++ b/backend/src/api/services/acceleration.ts @@ -0,0 +1,82 @@ +import config from '../../config'; +import logger from '../../logger'; +import { BlockExtended, PoolTag } from '../../mempool.interfaces'; +import axios from 'axios'; + +export interface Acceleration { + txid: string, + added: number, + effectiveVsize: number, + effectiveFee: number, + feeDelta: number, + pools: number[], + positions?: { + [pool: number]: { + block: number, + vbytes: number, + }, + }, +}; + +export interface AccelerationHistory { + txid: string, + status: string, + feePaid: number, + added: number, + lastUpdated: number, + baseFee: number, + vsizeFee: number, + effectiveFee: number, + effectiveVsize: number, + feeDelta: number, + blockHash: string, + blockHeight: number, + pools: number[]; +}; + +class AccelerationApi { + public async $fetchAccelerations(): Promise { + if (config.MEMPOOL_SERVICES.ACCELERATIONS) { + try { + const response = await axios.get(`${config.MEMPOOL_SERVICES.API}/accelerator/accelerations`, { responseType: 'json', timeout: 10000 }); + return response.data as Acceleration[]; + } catch (e) { + logger.warn('Failed to fetch current accelerations from the mempool services backend: ' + (e instanceof Error ? e.message : e)); + return null; + } + } else { + return []; + } + } + + public async $fetchAccelerationHistory(page?: number, status?: string): Promise { + if (config.MEMPOOL_SERVICES.ACCELERATIONS) { + try { + const response = await axios.get(`${config.MEMPOOL_SERVICES.API}/accelerator/accelerations/history`, { + responseType: 'json', + timeout: 10000, + params: { + page, + status, + } + }); + return response.data as AccelerationHistory[]; + } catch (e) { + logger.warn('Failed to fetch acceleration history from the mempool services backend: ' + (e instanceof Error ? e.message : e)); + return null; + } + } else { + return []; + } + } + + public isAcceleratedBlock(block: BlockExtended, accelerations: Acceleration[]): boolean { + let anyAccelerated = false; + for (let i = 0; i < accelerations.length && !anyAccelerated; i++) { + anyAccelerated = anyAccelerated || accelerations[i].pools?.includes(block.extras.pool.id); + } + return anyAccelerated; + } +} + +export default new AccelerationApi(); \ No newline at end of file diff --git a/backend/src/api/statistics.ts b/backend/src/api/statistics.ts deleted file mode 100644 index 6e5eb81192..0000000000 --- a/backend/src/api/statistics.ts +++ /dev/null @@ -1,444 +0,0 @@ -import memPool from './mempool'; -import { DB } from '../database'; - -import { Statistic, TransactionExtended, OptimizedStatistic } from '../interfaces'; - -class Statistics { - protected intervalTimer: NodeJS.Timer | undefined; - protected newStatisticsEntryCallback: ((stats: OptimizedStatistic) => void) | undefined; - - public setNewStatisticsEntryCallback(fn: (stats: OptimizedStatistic) => void) { - this.newStatisticsEntryCallback = fn; - } - - constructor() { } - - public startStatistics(): void { - console.log('Starting statistics service'); - - const now = new Date(); - const nextInterval = new Date(now.getFullYear(), now.getMonth(), now.getDate(), now.getHours(), - Math.floor(now.getMinutes() / 1) * 1 + 1, 0, 0); - const difference = nextInterval.getTime() - now.getTime(); - - setTimeout(() => { - this.runStatistics(); - this.intervalTimer = setInterval(() => { - if (!memPool.isInSync()) { - return; - } - this.runStatistics(); - }, 1 * 60 * 1000); - }, difference); - } - - private async runStatistics(): Promise { - const currentMempool = memPool.getMempool(); - const txPerSecond = memPool.getTxPerSecond(); - const vBytesPerSecond = memPool.getVBytesPerSecond(); - - console.log('Running statistics'); - - let memPoolArray: TransactionExtended[] = []; - for (const i in currentMempool) { - if (currentMempool.hasOwnProperty(i)) { - memPoolArray.push(currentMempool[i]); - } - } - // Remove 0 and undefined - memPoolArray = memPoolArray.filter((tx) => tx.feePerVsize); - - if (!memPoolArray.length) { - return; - } - - memPoolArray.sort((a, b) => a.feePerVsize - b.feePerVsize); - const totalWeight = memPoolArray.map((tx) => tx.vsize).reduce((acc, curr) => acc + curr) * 4; - const totalFee = memPoolArray.map((tx) => tx.fee).reduce((acc, curr) => acc + curr); - - const logFees = [1, 2, 3, 4, 5, 6, 8, 10, 12, 15, 20, 30, 40, 50, 60, 70, 80, 90, 100, 125, 150, 175, 200, - 250, 300, 350, 400, 500, 600, 700, 800, 900, 1000, 1200, 1400, 1600, 1800, 2000]; - - const weightVsizeFees: { [feePerWU: number]: number } = {}; - - memPoolArray.forEach((transaction) => { - for (let i = 0; i < logFees.length; i++) { - if ((logFees[i] === 2000 && transaction.feePerVsize >= 2000) || transaction.feePerVsize <= logFees[i]) { - if (weightVsizeFees[logFees[i]]) { - weightVsizeFees[logFees[i]] += transaction.vsize; - } else { - weightVsizeFees[logFees[i]] = transaction.vsize; - } - break; - } - } - }); - - const insertId = await this.$create({ - added: 'NOW()', - unconfirmed_transactions: memPoolArray.length, - tx_per_second: txPerSecond, - vbytes_per_second: Math.round(vBytesPerSecond), - mempool_byte_weight: totalWeight, - total_fee: totalFee, - fee_data: '', - vsize_1: weightVsizeFees['1'] || 0, - vsize_2: weightVsizeFees['2'] || 0, - vsize_3: weightVsizeFees['3'] || 0, - vsize_4: weightVsizeFees['4'] || 0, - vsize_5: weightVsizeFees['5'] || 0, - vsize_6: weightVsizeFees['6'] || 0, - vsize_8: weightVsizeFees['8'] || 0, - vsize_10: weightVsizeFees['10'] || 0, - vsize_12: weightVsizeFees['12'] || 0, - vsize_15: weightVsizeFees['15'] || 0, - vsize_20: weightVsizeFees['20'] || 0, - vsize_30: weightVsizeFees['30'] || 0, - vsize_40: weightVsizeFees['40'] || 0, - vsize_50: weightVsizeFees['50'] || 0, - vsize_60: weightVsizeFees['60'] || 0, - vsize_70: weightVsizeFees['70'] || 0, - vsize_80: weightVsizeFees['80'] || 0, - vsize_90: weightVsizeFees['90'] || 0, - vsize_100: weightVsizeFees['100'] || 0, - vsize_125: weightVsizeFees['125'] || 0, - vsize_150: weightVsizeFees['150'] || 0, - vsize_175: weightVsizeFees['175'] || 0, - vsize_200: weightVsizeFees['200'] || 0, - vsize_250: weightVsizeFees['250'] || 0, - vsize_300: weightVsizeFees['300'] || 0, - vsize_350: weightVsizeFees['350'] || 0, - vsize_400: weightVsizeFees['400'] || 0, - vsize_500: weightVsizeFees['500'] || 0, - vsize_600: weightVsizeFees['600'] || 0, - vsize_700: weightVsizeFees['700'] || 0, - vsize_800: weightVsizeFees['800'] || 0, - vsize_900: weightVsizeFees['900'] || 0, - vsize_1000: weightVsizeFees['1000'] || 0, - vsize_1200: weightVsizeFees['1200'] || 0, - vsize_1400: weightVsizeFees['1400'] || 0, - vsize_1600: weightVsizeFees['1600'] || 0, - vsize_1800: weightVsizeFees['1800'] || 0, - vsize_2000: weightVsizeFees['2000'] || 0, - }); - - if (this.newStatisticsEntryCallback && insertId) { - const newStats = await this.$get(insertId); - if (newStats) { - this.newStatisticsEntryCallback(newStats); - } - } - } - - private async $create(statistics: Statistic): Promise { - try { - const connection = await DB.pool.getConnection(); - const query = `INSERT INTO statistics( - added, - unconfirmed_transactions, - tx_per_second, - vbytes_per_second, - mempool_byte_weight, - fee_data, - total_fee, - vsize_1, - vsize_2, - vsize_3, - vsize_4, - vsize_5, - vsize_6, - vsize_8, - vsize_10, - vsize_12, - vsize_15, - vsize_20, - vsize_30, - vsize_40, - vsize_50, - vsize_60, - vsize_70, - vsize_80, - vsize_90, - vsize_100, - vsize_125, - vsize_150, - vsize_175, - vsize_200, - vsize_250, - vsize_300, - vsize_350, - vsize_400, - vsize_500, - vsize_600, - vsize_700, - vsize_800, - vsize_900, - vsize_1000, - vsize_1200, - vsize_1400, - vsize_1600, - vsize_1800, - vsize_2000 - ) - VALUES (${statistics.added}, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, - ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`; - - const params: (string | number)[] = [ - statistics.unconfirmed_transactions, - statistics.tx_per_second, - statistics.vbytes_per_second, - statistics.mempool_byte_weight, - statistics.fee_data, - statistics.total_fee, - statistics.vsize_1, - statistics.vsize_2, - statistics.vsize_3, - statistics.vsize_4, - statistics.vsize_5, - statistics.vsize_6, - statistics.vsize_8, - statistics.vsize_10, - statistics.vsize_12, - statistics.vsize_15, - statistics.vsize_20, - statistics.vsize_30, - statistics.vsize_40, - statistics.vsize_50, - statistics.vsize_60, - statistics.vsize_70, - statistics.vsize_80, - statistics.vsize_90, - statistics.vsize_100, - statistics.vsize_125, - statistics.vsize_150, - statistics.vsize_175, - statistics.vsize_200, - statistics.vsize_250, - statistics.vsize_300, - statistics.vsize_350, - statistics.vsize_400, - statistics.vsize_500, - statistics.vsize_600, - statistics.vsize_700, - statistics.vsize_800, - statistics.vsize_900, - statistics.vsize_1000, - statistics.vsize_1200, - statistics.vsize_1400, - statistics.vsize_1600, - statistics.vsize_1800, - statistics.vsize_2000, - ]; - const [result]: any = await connection.query(query, params); - connection.release(); - return result.insertId; - } catch (e) { - console.log('$create() error', e); - } - } - - private getQueryForDays(days: number, groupBy: number) { - - return `SELECT id, added, unconfirmed_transactions, - AVG(tx_per_second) AS tx_per_second, - AVG(vbytes_per_second) AS vbytes_per_second, - AVG(vsize_1) AS vsize_1, - AVG(vsize_2) AS vsize_2, - AVG(vsize_3) AS vsize_3, - AVG(vsize_4) AS vsize_4, - AVG(vsize_5) AS vsize_5, - AVG(vsize_6) AS vsize_6, - AVG(vsize_8) AS vsize_8, - AVG(vsize_10) AS vsize_10, - AVG(vsize_12) AS vsize_12, - AVG(vsize_15) AS vsize_15, - AVG(vsize_20) AS vsize_20, - AVG(vsize_30) AS vsize_30, - AVG(vsize_40) AS vsize_40, - AVG(vsize_50) AS vsize_50, - AVG(vsize_60) AS vsize_60, - AVG(vsize_70) AS vsize_70, - AVG(vsize_80) AS vsize_80, - AVG(vsize_90) AS vsize_90, - AVG(vsize_100) AS vsize_100, - AVG(vsize_125) AS vsize_125, - AVG(vsize_150) AS vsize_150, - AVG(vsize_175) AS vsize_175, - AVG(vsize_200) AS vsize_200, - AVG(vsize_250) AS vsize_250, - AVG(vsize_300) AS vsize_300, - AVG(vsize_350) AS vsize_350, - AVG(vsize_400) AS vsize_400, - AVG(vsize_500) AS vsize_500, - AVG(vsize_600) AS vsize_600, - AVG(vsize_700) AS vsize_700, - AVG(vsize_800) AS vsize_800, - AVG(vsize_900) AS vsize_900, - AVG(vsize_1000) AS vsize_1000, - AVG(vsize_1200) AS vsize_1200, - AVG(vsize_1400) AS vsize_1400, - AVG(vsize_1600) AS vsize_1600, - AVG(vsize_1800) AS vsize_1800, - AVG(vsize_2000) AS vsize_2000 FROM statistics GROUP BY UNIX_TIMESTAMP(added) DIV ${groupBy} ORDER BY id DESC LIMIT ${days}`; - } - - public async $get(id: number): Promise { - try { - const connection = await DB.pool.getConnection(); - const query = `SELECT * FROM statistics WHERE id = ?`; - const [rows] = await connection.query(query, [id]); - connection.release(); - if (rows[0]) { - return this.mapStatisticToOptimizedStatistic([rows[0]])[0]; - } - } catch (e) { - console.log('$list2H() error', e); - } - } - - public async $list2H(): Promise { - try { - const connection = await DB.pool.getConnection(); - const query = `SELECT * FROM statistics ORDER BY id DESC LIMIT 120`; - const [rows] = await connection.query(query); - connection.release(); - return this.mapStatisticToOptimizedStatistic(rows); - } catch (e) { - console.log('$list2H() error', e); - return []; - } - } - - public async $list24H(): Promise { - try { - const connection = await DB.pool.getConnection(); - const query = this.getQueryForDays(120, 720); - const [rows] = await connection.query(query); - connection.release(); - return this.mapStatisticToOptimizedStatistic(rows); - } catch (e) { - return []; - } - } - - public async $list1W(): Promise { - try { - const connection = await DB.pool.getConnection(); - const query = this.getQueryForDays(120, 5040); - const [rows] = await connection.query(query); - connection.release(); - return this.mapStatisticToOptimizedStatistic(rows); - } catch (e) { - console.log('$list1W() error', e); - return []; - } - } - - public async $list1M(): Promise { - try { - const connection = await DB.pool.getConnection(); - const query = this.getQueryForDays(120, 20160); - const [rows] = await connection.query(query); - connection.release(); - return this.mapStatisticToOptimizedStatistic(rows); - } catch (e) { - console.log('$list1M() error', e); - return []; - } - } - - public async $list3M(): Promise { - try { - const connection = await DB.pool.getConnection(); - const query = this.getQueryForDays(120, 60480); - const [rows] = await connection.query(query); - connection.release(); - return this.mapStatisticToOptimizedStatistic(rows); - } catch (e) { - console.log('$list3M() error', e); - return []; - } - } - - public async $list6M(): Promise { - try { - const connection = await DB.pool.getConnection(); - const query = this.getQueryForDays(120, 120960); - const [rows] = await connection.query(query); - connection.release(); - return this.mapStatisticToOptimizedStatistic(rows); - } catch (e) { - console.log('$list6M() error', e); - return []; - } - } - - public async $list1Y(): Promise { - try { - const connection = await DB.pool.getConnection(); - const query = this.getQueryForDays(120, 241920); - const [rows] = await connection.query(query); - connection.release(); - return this.mapStatisticToOptimizedStatistic(rows); - } catch (e) { - console.log('$list6M() error', e); - return []; - } - } - private mapStatisticToOptimizedStatistic(statistic: Statistic[]): OptimizedStatistic[] { - return statistic.map((s) => { - return { - id: s.id || 0, - added: s.added, - unconfirmed_transactions: s.unconfirmed_transactions, - tx_per_second: s.tx_per_second, - vbytes_per_second: s.vbytes_per_second, - mempool_byte_weight: s.mempool_byte_weight, - total_fee: s.total_fee, - vsizes: [ - s.vsize_1, - s.vsize_2, - s.vsize_3, - s.vsize_4, - s.vsize_5, - s.vsize_6, - s.vsize_8, - s.vsize_10, - s.vsize_12, - s.vsize_15, - s.vsize_20, - s.vsize_30, - s.vsize_40, - s.vsize_50, - s.vsize_60, - s.vsize_70, - s.vsize_80, - s.vsize_90, - s.vsize_100, - s.vsize_125, - s.vsize_150, - s.vsize_175, - s.vsize_200, - s.vsize_250, - s.vsize_300, - s.vsize_350, - s.vsize_400, - s.vsize_500, - s.vsize_600, - s.vsize_700, - s.vsize_800, - s.vsize_900, - s.vsize_1000, - s.vsize_1200, - s.vsize_1400, - s.vsize_1600, - s.vsize_1800, - s.vsize_2000, - ] - }; - }); - } - -} - -export default new Statistics(); diff --git a/backend/src/api/statistics/statistics-api.ts b/backend/src/api/statistics/statistics-api.ts new file mode 100644 index 0000000000..2d66d69d9a --- /dev/null +++ b/backend/src/api/statistics/statistics-api.ts @@ -0,0 +1,514 @@ +import DB from '../../database'; +import logger from '../../logger'; +import { Statistic, OptimizedStatistic } from '../../mempool.interfaces'; + +class StatisticsApi { + protected queryTimeout = 120000; + + public async $createZeroedStatistic(): Promise { + try { + const query = `INSERT INTO statistics( + added, + unconfirmed_transactions, + tx_per_second, + vbytes_per_second, + mempool_byte_weight, + fee_data, + total_fee, + min_fee, + vsize_1, + vsize_2, + vsize_3, + vsize_4, + vsize_5, + vsize_6, + vsize_8, + vsize_10, + vsize_12, + vsize_15, + vsize_20, + vsize_30, + vsize_40, + vsize_50, + vsize_60, + vsize_70, + vsize_80, + vsize_90, + vsize_100, + vsize_125, + vsize_150, + vsize_175, + vsize_200, + vsize_250, + vsize_300, + vsize_350, + vsize_400, + vsize_500, + vsize_600, + vsize_700, + vsize_800, + vsize_900, + vsize_1000, + vsize_1200, + vsize_1400, + vsize_1600, + vsize_1800, + vsize_2000 + ) + VALUES (NOW(), 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0)`; + const [result]: any = await DB.query(query); + return result.insertId; + } catch (e) { + logger.err('$create() error' + (e instanceof Error ? e.message : e)); + } + } + + public async $create(statistics: Statistic, convertToDatetime = false): Promise { + try { + const query = `INSERT INTO statistics( + added, + unconfirmed_transactions, + tx_per_second, + vbytes_per_second, + mempool_byte_weight, + fee_data, + total_fee, + min_fee, + vsize_1, + vsize_2, + vsize_3, + vsize_4, + vsize_5, + vsize_6, + vsize_8, + vsize_10, + vsize_12, + vsize_15, + vsize_20, + vsize_30, + vsize_40, + vsize_50, + vsize_60, + vsize_70, + vsize_80, + vsize_90, + vsize_100, + vsize_125, + vsize_150, + vsize_175, + vsize_200, + vsize_250, + vsize_300, + vsize_350, + vsize_400, + vsize_500, + vsize_600, + vsize_700, + vsize_800, + vsize_900, + vsize_1000, + vsize_1200, + vsize_1400, + vsize_1600, + vsize_1800, + vsize_2000 + ) + VALUES (${convertToDatetime ? `FROM_UNIXTIME(${statistics.added})` : statistics.added}, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, + ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`; + + const params: (string | number)[] = [ + statistics.unconfirmed_transactions, + statistics.tx_per_second, + statistics.vbytes_per_second, + statistics.mempool_byte_weight, + statistics.fee_data, + statistics.total_fee, + statistics.min_fee, + statistics.vsize_1, + statistics.vsize_2, + statistics.vsize_3, + statistics.vsize_4, + statistics.vsize_5, + statistics.vsize_6, + statistics.vsize_8, + statistics.vsize_10, + statistics.vsize_12, + statistics.vsize_15, + statistics.vsize_20, + statistics.vsize_30, + statistics.vsize_40, + statistics.vsize_50, + statistics.vsize_60, + statistics.vsize_70, + statistics.vsize_80, + statistics.vsize_90, + statistics.vsize_100, + statistics.vsize_125, + statistics.vsize_150, + statistics.vsize_175, + statistics.vsize_200, + statistics.vsize_250, + statistics.vsize_300, + statistics.vsize_350, + statistics.vsize_400, + statistics.vsize_500, + statistics.vsize_600, + statistics.vsize_700, + statistics.vsize_800, + statistics.vsize_900, + statistics.vsize_1000, + statistics.vsize_1200, + statistics.vsize_1400, + statistics.vsize_1600, + statistics.vsize_1800, + statistics.vsize_2000, + ]; + const [result]: any = await DB.query(query, params); + return result.insertId; + } catch (e) { + logger.err('$create() error' + (e instanceof Error ? e.message : e)); + } + } + + private getQueryForDaysAvg(div: number, interval: string) { + return `SELECT + UNIX_TIMESTAMP(added) as added, + CAST(avg(unconfirmed_transactions) as DOUBLE) as unconfirmed_transactions, + CAST(avg(vbytes_per_second) as DOUBLE) as vbytes_per_second, + CAST(avg(min_fee) as DOUBLE) as min_fee, + CAST(avg(vsize_1) as DOUBLE) as vsize_1, + CAST(avg(vsize_2) as DOUBLE) as vsize_2, + CAST(avg(vsize_3) as DOUBLE) as vsize_3, + CAST(avg(vsize_4) as DOUBLE) as vsize_4, + CAST(avg(vsize_5) as DOUBLE) as vsize_5, + CAST(avg(vsize_6) as DOUBLE) as vsize_6, + CAST(avg(vsize_8) as DOUBLE) as vsize_8, + CAST(avg(vsize_10) as DOUBLE) as vsize_10, + CAST(avg(vsize_12) as DOUBLE) as vsize_12, + CAST(avg(vsize_15) as DOUBLE) as vsize_15, + CAST(avg(vsize_20) as DOUBLE) as vsize_20, + CAST(avg(vsize_30) as DOUBLE) as vsize_30, + CAST(avg(vsize_40) as DOUBLE) as vsize_40, + CAST(avg(vsize_50) as DOUBLE) as vsize_50, + CAST(avg(vsize_60) as DOUBLE) as vsize_60, + CAST(avg(vsize_70) as DOUBLE) as vsize_70, + CAST(avg(vsize_80) as DOUBLE) as vsize_80, + CAST(avg(vsize_90) as DOUBLE) as vsize_90, + CAST(avg(vsize_100) as DOUBLE) as vsize_100, + CAST(avg(vsize_125) as DOUBLE) as vsize_125, + CAST(avg(vsize_150) as DOUBLE) as vsize_150, + CAST(avg(vsize_175) as DOUBLE) as vsize_175, + CAST(avg(vsize_200) as DOUBLE) as vsize_200, + CAST(avg(vsize_250) as DOUBLE) as vsize_250, + CAST(avg(vsize_300) as DOUBLE) as vsize_300, + CAST(avg(vsize_350) as DOUBLE) as vsize_350, + CAST(avg(vsize_400) as DOUBLE) as vsize_400, + CAST(avg(vsize_500) as DOUBLE) as vsize_500, + CAST(avg(vsize_600) as DOUBLE) as vsize_600, + CAST(avg(vsize_700) as DOUBLE) as vsize_700, + CAST(avg(vsize_800) as DOUBLE) as vsize_800, + CAST(avg(vsize_900) as DOUBLE) as vsize_900, + CAST(avg(vsize_1000) as DOUBLE) as vsize_1000, + CAST(avg(vsize_1200) as DOUBLE) as vsize_1200, + CAST(avg(vsize_1400) as DOUBLE) as vsize_1400, + CAST(avg(vsize_1600) as DOUBLE) as vsize_1600, + CAST(avg(vsize_1800) as DOUBLE) as vsize_1800, + CAST(avg(vsize_2000) as DOUBLE) as vsize_2000 \ + FROM statistics \ + ${interval === 'all' ? '' : `WHERE added BETWEEN DATE_SUB(NOW(), INTERVAL ${interval}) AND NOW()`} \ + GROUP BY UNIX_TIMESTAMP(added) DIV ${div} \ + ORDER BY statistics.added DESC;`; + } + + private getQueryForDays(div: number, interval: string) { + return `SELECT + UNIX_TIMESTAMP(added) as added, + CAST(avg(unconfirmed_transactions) as DOUBLE) as unconfirmed_transactions, + CAST(avg(vbytes_per_second) as DOUBLE) as vbytes_per_second, + CAST(avg(min_fee) as DOUBLE) as min_fee, + vsize_1, + vsize_2, + vsize_3, + vsize_4, + vsize_5, + vsize_6, + vsize_8, + vsize_10, + vsize_12, + vsize_15, + vsize_20, + vsize_30, + vsize_40, + vsize_50, + vsize_60, + vsize_70, + vsize_80, + vsize_90, + vsize_100, + vsize_125, + vsize_150, + vsize_175, + vsize_200, + vsize_250, + vsize_300, + vsize_350, + vsize_400, + vsize_500, + vsize_600, + vsize_700, + vsize_800, + vsize_900, + vsize_1000, + vsize_1200, + vsize_1400, + vsize_1600, + vsize_1800, + vsize_2000 \ + FROM statistics \ + ${interval === 'all' ? '' : `WHERE added BETWEEN DATE_SUB(NOW(), INTERVAL ${interval}) AND NOW()`} \ + GROUP BY UNIX_TIMESTAMP(added) DIV ${div} \ + ORDER BY statistics.added DESC;`; + } + + public async $get(id: number): Promise { + try { + const query = `SELECT *, UNIX_TIMESTAMP(added) as added FROM statistics WHERE id = ?`; + const [rows] = await DB.query(query, [id]); + if (rows[0]) { + return this.mapStatisticToOptimizedStatistic([rows[0]])[0]; + } + } catch (e) { + logger.err('$list2H() error' + (e instanceof Error ? e.message : e)); + } + } + + public async $list2H(): Promise { + try { + const query = `SELECT *, UNIX_TIMESTAMP(added) as added FROM statistics WHERE added BETWEEN DATE_SUB(NOW(), INTERVAL 2 HOUR) AND NOW() ORDER BY statistics.added DESC`; + const [rows] = await DB.query({ sql: query, timeout: this.queryTimeout }); + return this.mapStatisticToOptimizedStatistic(rows as Statistic[]); + } catch (e) { + logger.err('$list2H() error' + (e instanceof Error ? e.message : e)); + return []; + } + } + + public async $list24H(): Promise { + try { + const query = `SELECT *, UNIX_TIMESTAMP(added) as added FROM statistics WHERE added BETWEEN DATE_SUB(NOW(), INTERVAL 24 HOUR) AND NOW() ORDER BY statistics.added DESC`; + const [rows] = await DB.query({ sql: query, timeout: this.queryTimeout }); + return this.mapStatisticToOptimizedStatistic(rows as Statistic[]); + } catch (e) { + logger.err('$list24h() error' + (e instanceof Error ? e.message : e)); + return []; + } + } + + public async $list1W(): Promise { + try { + const query = this.getQueryForDaysAvg(300, '1 WEEK'); // 5m interval + const [rows] = await DB.query({ sql: query, timeout: this.queryTimeout }); + return this.mapStatisticToOptimizedStatistic(rows as Statistic[]); + } catch (e) { + logger.err('$list1W() error' + (e instanceof Error ? e.message : e)); + return []; + } + } + + public async $list1M(): Promise { + try { + const query = this.getQueryForDaysAvg(1800, '1 MONTH'); // 30m interval + const [rows] = await DB.query({ sql: query, timeout: this.queryTimeout }); + return this.mapStatisticToOptimizedStatistic(rows as Statistic[]); + } catch (e) { + logger.err('$list1M() error' + (e instanceof Error ? e.message : e)); + return []; + } + } + + public async $list3M(): Promise { + try { + const query = this.getQueryForDaysAvg(7200, '3 MONTH'); // 2h interval + const [rows] = await DB.query({ sql: query, timeout: this.queryTimeout }); + return this.mapStatisticToOptimizedStatistic(rows as Statistic[]); + } catch (e) { + logger.err('$list3M() error' + (e instanceof Error ? e.message : e)); + return []; + } + } + + public async $list6M(): Promise { + try { + const query = this.getQueryForDaysAvg(10800, '6 MONTH'); // 3h interval + const [rows] = await DB.query({ sql: query, timeout: this.queryTimeout }); + return this.mapStatisticToOptimizedStatistic(rows as Statistic[]); + } catch (e) { + logger.err('$list6M() error' + (e instanceof Error ? e.message : e)); + return []; + } + } + + public async $list1Y(): Promise { + try { + const query = this.getQueryForDays(28800, '1 YEAR'); // 8h interval + const [rows] = await DB.query({ sql: query, timeout: this.queryTimeout }); + return this.mapStatisticToOptimizedStatistic(rows as Statistic[]); + } catch (e) { + logger.err('$list1Y() error' + (e instanceof Error ? e.message : e)); + return []; + } + } + + public async $list2Y(): Promise { + try { + const query = this.getQueryForDays(28800, '2 YEAR'); // 8h interval + const [rows] = await DB.query({ sql: query, timeout: this.queryTimeout }); + return this.mapStatisticToOptimizedStatistic(rows as Statistic[]); + } catch (e) { + logger.err('$list2Y() error' + (e instanceof Error ? e.message : e)); + return []; + } + } + + public async $list3Y(): Promise { + try { + const query = this.getQueryForDays(43200, '3 YEAR'); // 12h interval + const [rows] = await DB.query({ sql: query, timeout: this.queryTimeout }); + return this.mapStatisticToOptimizedStatistic(rows as Statistic[]); + } catch (e) { + logger.err('$list3Y() error' + (e instanceof Error ? e.message : e)); + return []; + } + } + + public async $list4Y(): Promise { + try { + const query = this.getQueryForDays(43200, '4 YEAR'); // 12h interval + const [rows] = await DB.query({ sql: query, timeout: this.queryTimeout }); + return this.mapStatisticToOptimizedStatistic(rows as Statistic[]); + } catch (e) { + logger.err('$list4Y() error' + (e instanceof Error ? e.message : e)); + return []; + } + } + + public async $listAll(): Promise { + try { + const query = this.getQueryForDays(43200, 'all'); // 12h interval + const [rows] = await DB.query({ sql: query, timeout: this.queryTimeout }); + return this.mapStatisticToOptimizedStatistic(rows as Statistic[]); + } catch (e) { + logger.err('$listAll() error' + (e instanceof Error ? e.message : e)); + return []; + } + } + + private mapStatisticToOptimizedStatistic(statistic: Statistic[]): OptimizedStatistic[] { + return statistic.map((s) => { + return { + added: s.added, + count: s.unconfirmed_transactions, + vbytes_per_second: s.vbytes_per_second, + mempool_byte_weight: s.mempool_byte_weight, + total_fee: s.total_fee, + min_fee: s.min_fee, + vsizes: [ + s.vsize_1, + s.vsize_2, + s.vsize_3, + s.vsize_4, + s.vsize_5, + s.vsize_6, + s.vsize_8, + s.vsize_10, + s.vsize_12, + s.vsize_15, + s.vsize_20, + s.vsize_30, + s.vsize_40, + s.vsize_50, + s.vsize_60, + s.vsize_70, + s.vsize_80, + s.vsize_90, + s.vsize_100, + s.vsize_125, + s.vsize_150, + s.vsize_175, + s.vsize_200, + s.vsize_250, + s.vsize_300, + s.vsize_350, + s.vsize_400, + s.vsize_500, + s.vsize_600, + s.vsize_700, + s.vsize_800, + s.vsize_900, + s.vsize_1000, + s.vsize_1200, + s.vsize_1400, + s.vsize_1600, + s.vsize_1800, + s.vsize_2000, + ] + }; + }); + } + + public mapOptimizedStatisticToStatistic(statistic: OptimizedStatistic[]): Statistic[] { + return statistic.map((s) => { + return { + added: s.added, + unconfirmed_transactions: s.count, + tx_per_second: 0, + vbytes_per_second: s.vbytes_per_second, + mempool_byte_weight: s.mempool_byte_weight || 0, + total_fee: s.total_fee || 0, + min_fee: s.min_fee, + fee_data: '', + vsize_1: s.vsizes[0], + vsize_2: s.vsizes[1], + vsize_3: s.vsizes[2], + vsize_4: s.vsizes[3], + vsize_5: s.vsizes[4], + vsize_6: s.vsizes[5], + vsize_8: s.vsizes[6], + vsize_10: s.vsizes[7], + vsize_12: s.vsizes[8], + vsize_15: s.vsizes[9], + vsize_20: s.vsizes[10], + vsize_30: s.vsizes[11], + vsize_40: s.vsizes[12], + vsize_50: s.vsizes[13], + vsize_60: s.vsizes[14], + vsize_70: s.vsizes[15], + vsize_80: s.vsizes[16], + vsize_90: s.vsizes[17], + vsize_100: s.vsizes[18], + vsize_125: s.vsizes[19], + vsize_150: s.vsizes[20], + vsize_175: s.vsizes[21], + vsize_200: s.vsizes[22], + vsize_250: s.vsizes[23], + vsize_300: s.vsizes[24], + vsize_350: s.vsizes[25], + vsize_400: s.vsizes[26], + vsize_500: s.vsizes[27], + vsize_600: s.vsizes[28], + vsize_700: s.vsizes[29], + vsize_800: s.vsizes[30], + vsize_900: s.vsizes[31], + vsize_1000: s.vsizes[32], + vsize_1200: s.vsizes[33], + vsize_1400: s.vsizes[34], + vsize_1600: s.vsizes[35], + vsize_1800: s.vsizes[36], + vsize_2000: s.vsizes[37], + } + }); + } +} + +export default new StatisticsApi(); diff --git a/backend/src/api/statistics/statistics.routes.ts b/backend/src/api/statistics/statistics.routes.ts new file mode 100644 index 0000000000..31db5198c9 --- /dev/null +++ b/backend/src/api/statistics/statistics.routes.ts @@ -0,0 +1,73 @@ +import { Application, Request, Response } from 'express'; +import config from '../../config'; +import statisticsApi from './statistics-api'; + +class StatisticsRoutes { + public initRoutes(app: Application) { + app + .get(config.MEMPOOL.API_URL_PREFIX + 'statistics/2h', this.$getStatisticsByTime.bind(this, '2h')) + .get(config.MEMPOOL.API_URL_PREFIX + 'statistics/24h', this.$getStatisticsByTime.bind(this, '24h')) + .get(config.MEMPOOL.API_URL_PREFIX + 'statistics/1w', this.$getStatisticsByTime.bind(this, '1w')) + .get(config.MEMPOOL.API_URL_PREFIX + 'statistics/1m', this.$getStatisticsByTime.bind(this, '1m')) + .get(config.MEMPOOL.API_URL_PREFIX + 'statistics/3m', this.$getStatisticsByTime.bind(this, '3m')) + .get(config.MEMPOOL.API_URL_PREFIX + 'statistics/6m', this.$getStatisticsByTime.bind(this, '6m')) + .get(config.MEMPOOL.API_URL_PREFIX + 'statistics/1y', this.$getStatisticsByTime.bind(this, '1y')) + .get(config.MEMPOOL.API_URL_PREFIX + 'statistics/2y', this.$getStatisticsByTime.bind(this, '2y')) + .get(config.MEMPOOL.API_URL_PREFIX + 'statistics/3y', this.$getStatisticsByTime.bind(this, '3y')) + .get(config.MEMPOOL.API_URL_PREFIX + 'statistics/4y', this.$getStatisticsByTime.bind(this, '4y')) + .get(config.MEMPOOL.API_URL_PREFIX + 'statistics/all', this.$getStatisticsByTime.bind(this, 'all')) + ; + } + + private async $getStatisticsByTime(time: '2h' | '24h' | '1w' | '1m' | '3m' | '6m' | '1y' | '2y' | '3y' | '4y' | 'all', req: Request, res: Response) { + res.header('Pragma', 'public'); + res.header('Cache-control', 'public'); + res.setHeader('Expires', new Date(Date.now() + 1000 * 300).toUTCString()); + + try { + let result; + switch (time as string) { + case '24h': + result = await statisticsApi.$list24H(); + res.setHeader('Expires', new Date(Date.now() + 1000 * 60).toUTCString()); + break; + case '1w': + result = await statisticsApi.$list1W(); + break; + case '1m': + result = await statisticsApi.$list1M(); + break; + case '3m': + result = await statisticsApi.$list3M(); + break; + case '6m': + result = await statisticsApi.$list6M(); + break; + case '1y': + result = await statisticsApi.$list1Y(); + break; + case '2y': + result = await statisticsApi.$list2Y(); + break; + case '3y': + result = await statisticsApi.$list3Y(); + break; + case '4y': + result = await statisticsApi.$list4Y(); + break; + case 'all': + result = await statisticsApi.$listAll(); + break; + default: + result = await statisticsApi.$list2H(); + res.setHeader('Expires', new Date(Date.now() + 1000 * 30).toUTCString()); + break; + } + res.json(result); + } catch (e) { + res.status(500).send(e instanceof Error ? e.message : e); + } + } +} + +export default new StatisticsRoutes(); diff --git a/backend/src/api/statistics/statistics.ts b/backend/src/api/statistics/statistics.ts new file mode 100644 index 0000000000..2926a4b173 --- /dev/null +++ b/backend/src/api/statistics/statistics.ts @@ -0,0 +1,164 @@ +import memPool from '../mempool'; +import logger from '../../logger'; +import { TransactionExtended, OptimizedStatistic } from '../../mempool.interfaces'; +import { Common } from '../common'; +import statisticsApi from './statistics-api'; + +class Statistics { + protected intervalTimer: NodeJS.Timer | undefined; + protected lastRun: number = 0; + protected newStatisticsEntryCallback: ((stats: OptimizedStatistic) => void) | undefined; + + public setNewStatisticsEntryCallback(fn: (stats: OptimizedStatistic) => void) { + this.newStatisticsEntryCallback = fn; + } + + public startStatistics(): void { + logger.info('Starting statistics service'); + + const now = new Date(); + const nextInterval = new Date(now.getFullYear(), now.getMonth(), now.getDate(), now.getHours(), + Math.floor(now.getMinutes() / 1) * 1 + 1, 0, 0); + const difference = nextInterval.getTime() - now.getTime(); + + setTimeout(() => { + this.runStatistics(); + this.intervalTimer = setInterval(() => { + this.runStatistics(true); + }, 1 * 60 * 1000); + }, difference); + } + + public async runStatistics(skipIfRecent = false): Promise { + if (!memPool.isInSync()) { + return; + } + + if (skipIfRecent && new Date().getTime() / 1000 - this.lastRun < 30) { + return; + } + + this.lastRun = new Date().getTime() / 1000; + const currentMempool = memPool.getMempool(); + const txPerSecond = memPool.getTxPerSecond(); + const vBytesPerSecond = memPool.getVBytesPerSecond(); + + logger.debug('Running statistics'); + + let memPoolArray: TransactionExtended[] = []; + for (const i in currentMempool) { + if (currentMempool.hasOwnProperty(i)) { + memPoolArray.push(currentMempool[i]); + } + } + // Remove 0 and undefined + memPoolArray = memPoolArray.filter((tx) => tx.effectiveFeePerVsize); + + if (!memPoolArray.length) { + try { + const insertIdZeroed = await statisticsApi.$createZeroedStatistic(); + if (this.newStatisticsEntryCallback && insertIdZeroed) { + const newStats = await statisticsApi.$get(insertIdZeroed); + if (newStats) { + this.newStatisticsEntryCallback(newStats); + } + } + } catch (e) { + logger.err('Unable to insert zeroed statistics. ' + e); + } + return; + } + + memPoolArray.sort((a, b) => a.effectiveFeePerVsize - b.effectiveFeePerVsize); + const totalWeight = memPoolArray.map((tx) => tx.vsize).reduce((acc, curr) => acc + curr) * 4; + const totalFee = memPoolArray.map((tx) => tx.fee).reduce((acc, curr) => acc + curr); + + const logFees = [1, 2, 3, 4, 5, 6, 8, 10, 12, 15, 20, 30, 40, 50, 60, 70, 80, 90, 100, 125, 150, 175, 200, + 250, 300, 350, 400, 500, 600, 700, 800, 900, 1000, 1200, 1400, 1600, 1800, 2000]; + + const weightVsizeFees: { [feePerWU: number]: number } = {}; + const lastItem = logFees.length - 1; + + memPoolArray.forEach((transaction) => { + for (let i = 0; i < logFees.length; i++) { + if ( + (Common.isLiquid() && (i === lastItem || transaction.effectiveFeePerVsize * 10 < logFees[i + 1])) + || + (!Common.isLiquid() && (i === lastItem || transaction.effectiveFeePerVsize < logFees[i + 1])) + ) { + if (weightVsizeFees[logFees[i]]) { + weightVsizeFees[logFees[i]] += transaction.vsize; + } else { + weightVsizeFees[logFees[i]] = transaction.vsize; + } + break; + } + } + }); + + // get minFee and convert to sats/vb + const minFee = memPool.getMempoolInfo().mempoolminfee * 100000; + + try { + const insertId = await statisticsApi.$create({ + added: 'NOW()', + unconfirmed_transactions: memPoolArray.length, + tx_per_second: txPerSecond, + vbytes_per_second: Math.round(vBytesPerSecond), + mempool_byte_weight: totalWeight, + total_fee: totalFee, + fee_data: '', + min_fee: minFee, + vsize_1: weightVsizeFees['1'] || 0, + vsize_2: weightVsizeFees['2'] || 0, + vsize_3: weightVsizeFees['3'] || 0, + vsize_4: weightVsizeFees['4'] || 0, + vsize_5: weightVsizeFees['5'] || 0, + vsize_6: weightVsizeFees['6'] || 0, + vsize_8: weightVsizeFees['8'] || 0, + vsize_10: weightVsizeFees['10'] || 0, + vsize_12: weightVsizeFees['12'] || 0, + vsize_15: weightVsizeFees['15'] || 0, + vsize_20: weightVsizeFees['20'] || 0, + vsize_30: weightVsizeFees['30'] || 0, + vsize_40: weightVsizeFees['40'] || 0, + vsize_50: weightVsizeFees['50'] || 0, + vsize_60: weightVsizeFees['60'] || 0, + vsize_70: weightVsizeFees['70'] || 0, + vsize_80: weightVsizeFees['80'] || 0, + vsize_90: weightVsizeFees['90'] || 0, + vsize_100: weightVsizeFees['100'] || 0, + vsize_125: weightVsizeFees['125'] || 0, + vsize_150: weightVsizeFees['150'] || 0, + vsize_175: weightVsizeFees['175'] || 0, + vsize_200: weightVsizeFees['200'] || 0, + vsize_250: weightVsizeFees['250'] || 0, + vsize_300: weightVsizeFees['300'] || 0, + vsize_350: weightVsizeFees['350'] || 0, + vsize_400: weightVsizeFees['400'] || 0, + vsize_500: weightVsizeFees['500'] || 0, + vsize_600: weightVsizeFees['600'] || 0, + vsize_700: weightVsizeFees['700'] || 0, + vsize_800: weightVsizeFees['800'] || 0, + vsize_900: weightVsizeFees['900'] || 0, + vsize_1000: weightVsizeFees['1000'] || 0, + vsize_1200: weightVsizeFees['1200'] || 0, + vsize_1400: weightVsizeFees['1400'] || 0, + vsize_1600: weightVsizeFees['1600'] || 0, + vsize_1800: weightVsizeFees['1800'] || 0, + vsize_2000: weightVsizeFees['2000'] || 0, + }); + + if (this.newStatisticsEntryCallback && insertId) { + const newStats = await statisticsApi.$get(insertId); + if (newStats) { + this.newStatisticsEntryCallback(newStats); + } + } + } catch (e) { + logger.err('Unable to insert statistics. ' + e); + } + } +} + +export default new Statistics(); diff --git a/backend/src/api/transaction-utils.ts b/backend/src/api/transaction-utils.ts new file mode 100644 index 0000000000..b3077b935e --- /dev/null +++ b/backend/src/api/transaction-utils.ts @@ -0,0 +1,343 @@ +import { TransactionExtended, MempoolTransactionExtended, TransactionMinerInfo } from '../mempool.interfaces'; +import { IEsploraApi } from './bitcoin/esplora-api.interface'; +import { Common } from './common'; +import bitcoinApi, { bitcoinCoreApi } from './bitcoin/bitcoin-api-factory'; +import * as bitcoinjs from 'bitcoinjs-lib'; +import logger from '../logger'; +import config from '../config'; +import pLimit from '../utils/p-limit'; + +class TransactionUtils { + constructor() { } + + public stripCoinbaseTransaction(tx: TransactionExtended): TransactionMinerInfo { + return { + vin: [{ + scriptsig: tx.vin[0].scriptsig || tx.vin[0]['coinbase'] + }], + vout: tx.vout + .map((vout) => ({ + scriptpubkey_address: vout.scriptpubkey_address, + scriptpubkey_asm: vout.scriptpubkey_asm, + value: vout.value + })) + .filter((vout) => vout.value) + }; + } + + // Wrapper for $getTransactionExtended with an automatic retry direct to Core if the first API request fails. + // Propagates any error from the retry request. + public async $getTransactionExtendedRetry(txid: string, addPrevouts = false, lazyPrevouts = false, forceCore = false, addMempoolData = false): Promise { + try { + const result = await this.$getTransactionExtended(txid, addPrevouts, lazyPrevouts, forceCore, addMempoolData); + if (result) { + return result; + } else { + logger.err(`Cannot fetch tx ${txid}. Reason: backend returned null data`); + } + } catch (e) { + logger.err(`Cannot fetch tx ${txid}. Reason: ` + (e instanceof Error ? e.message : e)); + } + // retry direct from Core if first request failed + return this.$getTransactionExtended(txid, addPrevouts, lazyPrevouts, true, addMempoolData); + } + + /** + * @param txId + * @param addPrevouts + * @param lazyPrevouts + * @param forceCore - See https://github.com/mempool/mempool/issues/2904 + */ + public async $getTransactionExtended(txId: string, addPrevouts = false, lazyPrevouts = false, forceCore = false, addMempoolData = false): Promise { + let transaction: IEsploraApi.Transaction; + if (forceCore === true) { + transaction = await bitcoinCoreApi.$getRawTransaction(txId, false, addPrevouts, lazyPrevouts); + } else { + transaction = await bitcoinApi.$getRawTransaction(txId, false, addPrevouts, lazyPrevouts); + } + + if (Common.isLiquid()) { + if (!isFinite(Number(transaction.fee))) { + transaction.fee = Object.values(transaction.fee || {}).reduce((total, output) => total + output, 0); + } + } + + if (addMempoolData || !transaction?.status?.confirmed) { + return this.extendMempoolTransaction(transaction); + } else { + return this.extendTransaction(transaction); + } + } + + public async $getMempoolTransactionExtended(txId: string, addPrevouts = false, lazyPrevouts = false, forceCore = false): Promise { + return (await this.$getTransactionExtended(txId, addPrevouts, lazyPrevouts, forceCore, true)) as MempoolTransactionExtended; + } + + public async $getMempoolTransactionsExtended(txids: string[], addPrevouts = false, lazyPrevouts = false, forceCore = false): Promise { + if (forceCore || config.MEMPOOL.BACKEND !== 'esplora') { + const limiter = pLimit(8); // Run 8 requests at a time + const results = await Promise.allSettled(txids.map( + txid => limiter(() => this.$getMempoolTransactionExtended(txid, addPrevouts, lazyPrevouts, forceCore)) + )); + return results.filter(reply => reply.status === 'fulfilled') + .map(r => (r as PromiseFulfilledResult).value); + } else { + const transactions = await bitcoinApi.$getMempoolTransactions(txids); + return transactions.map(transaction => { + if (Common.isLiquid()) { + if (!isFinite(Number(transaction.fee))) { + transaction.fee = Object.values(transaction.fee || {}).reduce((total, output) => total + output, 0); + } + } + + return this.extendMempoolTransaction(transaction); + }); + } + } + + public extendTransaction(transaction: IEsploraApi.Transaction): TransactionExtended { + // @ts-ignore + if (transaction.vsize) { + // @ts-ignore + return transaction; + } + const feePerVbytes = (transaction.fee || 0) / (transaction.weight / 4); + const transactionExtended: TransactionExtended = Object.assign({ + vsize: transaction.weight / 4, + feePerVsize: feePerVbytes, + effectiveFeePerVsize: feePerVbytes, + }, transaction); + if (!transaction?.status?.confirmed && !transactionExtended.firstSeen) { + transactionExtended.firstSeen = Math.round((Date.now() / 1000)); + } + return transactionExtended; + } + + public extendMempoolTransaction(transaction: IEsploraApi.Transaction): MempoolTransactionExtended { + const vsize = Math.ceil(transaction.weight / 4); + const fractionalVsize = (transaction.weight / 4); + let sigops = Common.isLiquid() ? 0 : (transaction.sigops != null ? transaction.sigops : this.countSigops(transaction)); + // https://github.com/bitcoin/bitcoin/blob/e9262ea32a6e1d364fb7974844fadc36f931f8c6/src/policy/policy.cpp#L295-L298 + const adjustedVsize = Math.max(fractionalVsize, sigops * 5); // adjusted vsize = Max(weight, sigops * bytes_per_sigop) / witness_scale_factor + const feePerVbytes = (transaction.fee || 0) / fractionalVsize; + const adjustedFeePerVsize = (transaction.fee || 0) / adjustedVsize; + const transactionExtended: MempoolTransactionExtended = Object.assign(transaction, { + order: this.txidToOrdering(transaction.txid), + vsize, + adjustedVsize, + sigops, + feePerVsize: feePerVbytes, + adjustedFeePerVsize: adjustedFeePerVsize, + effectiveFeePerVsize: adjustedFeePerVsize, + }); + if (!transactionExtended?.status?.confirmed && !transactionExtended.firstSeen) { + transactionExtended.firstSeen = Math.round((Date.now() / 1000)); + } + return transactionExtended; + } + + public hex2ascii(hex: string) { + let str = ''; + for (let i = 0; i < hex.length; i += 2) { + str += String.fromCharCode(parseInt(hex.substr(i, 2), 16)); + } + return str; + } + + public countScriptSigops(script: string, isRawScript: boolean = false, witness: boolean = false): number { + if (!script?.length) { + return 0; + } + + let sigops = 0; + // count OP_CHECKSIG and OP_CHECKSIGVERIFY + sigops += (script.match(/OP_CHECKSIG/g)?.length || 0); + + // count OP_CHECKMULTISIG and OP_CHECKMULTISIGVERIFY + if (isRawScript) { + // in scriptPubKey or scriptSig, always worth 20 + sigops += 20 * (script.match(/OP_CHECKMULTISIG/g)?.length || 0); + } else { + // in redeem scripts and witnesses, worth N if preceded by OP_N, 20 otherwise + const matches = script.matchAll(/(?:OP_(?:PUSHNUM_)?(\d+))? OP_CHECKMULTISIG/g); + for (const match of matches) { + const n = parseInt(match[1]); + if (Number.isInteger(n)) { + sigops += n; + } else { + sigops += 20; + } + } + } + + return witness ? sigops : (sigops * 4); + } + + public countSigops(transaction: IEsploraApi.Transaction): number { + let sigops = 0; + + for (const input of transaction.vin) { + if (input.scriptsig_asm) { + sigops += this.countScriptSigops(input.scriptsig_asm, true); + } + if (input.prevout) { + switch (true) { + case input.prevout.scriptpubkey_type === 'p2sh' && input.witness?.length === 2 && input.scriptsig && input.scriptsig.startsWith('160014'): + case input.prevout.scriptpubkey_type === 'v0_p2wpkh': + sigops += 1; + break; + + case input.prevout?.scriptpubkey_type === 'p2sh' && input.witness?.length && input.scriptsig && input.scriptsig.startsWith('220020'): + case input.prevout.scriptpubkey_type === 'v0_p2wsh': + if (input.witness?.length) { + sigops += this.countScriptSigops(bitcoinjs.script.toASM(Buffer.from(input.witness[input.witness.length - 1], 'hex')), false, true); + } + break; + + case input.prevout.scriptpubkey_type === 'p2sh': + if (input.inner_redeemscript_asm) { + sigops += this.countScriptSigops(input.inner_redeemscript_asm); + } + break; + } + } + } + + for (const output of transaction.vout) { + if (output.scriptpubkey_asm) { + sigops += this.countScriptSigops(output.scriptpubkey_asm, true); + } + } + + return sigops; + } + + // returns the most significant 4 bytes of the txid as an integer + public txidToOrdering(txid: string): number { + return parseInt( + txid.substr(62, 2) + + txid.substr(60, 2) + + txid.substr(58, 2) + + txid.substr(56, 2), + 16 + ); + } + + public addInnerScriptsToVin(vin: IEsploraApi.Vin): void { + if (!vin.prevout) { + return; + } + + if (vin.prevout.scriptpubkey_type === 'p2sh') { + const redeemScript = vin.scriptsig_asm.split(' ').reverse()[0]; + vin.inner_redeemscript_asm = this.convertScriptSigAsm(redeemScript); + if (vin.witness && vin.witness.length > 2) { + const witnessScript = vin.witness[vin.witness.length - 1]; + vin.inner_witnessscript_asm = this.convertScriptSigAsm(witnessScript); + } + } + + if (vin.prevout.scriptpubkey_type === 'v0_p2wsh' && vin.witness) { + const witnessScript = vin.witness[vin.witness.length - 1]; + vin.inner_witnessscript_asm = this.convertScriptSigAsm(witnessScript); + } + + if (vin.prevout.scriptpubkey_type === 'v1_p2tr' && vin.witness) { + const witnessScript = this.witnessToP2TRScript(vin.witness); + if (witnessScript !== null) { + vin.inner_witnessscript_asm = this.convertScriptSigAsm(witnessScript); + } + } + } + + public convertScriptSigAsm(hex: string): string { + const buf = Buffer.from(hex, 'hex'); + + const b: string[] = []; + + let i = 0; + while (i < buf.length) { + const op = buf[i]; + if (op >= 0x01 && op <= 0x4e) { + i++; + let push: number; + if (op === 0x4c) { + push = buf.readUInt8(i); + b.push('OP_PUSHDATA1'); + i += 1; + } else if (op === 0x4d) { + push = buf.readUInt16LE(i); + b.push('OP_PUSHDATA2'); + i += 2; + } else if (op === 0x4e) { + push = buf.readUInt32LE(i); + b.push('OP_PUSHDATA4'); + i += 4; + } else { + push = op; + b.push('OP_PUSHBYTES_' + push); + } + + const data = buf.slice(i, i + push); + if (data.length !== push) { + break; + } + + b.push(data.toString('hex')); + i += data.length; + } else { + if (op === 0x00) { + b.push('OP_0'); + } else if (op === 0x4f) { + b.push('OP_PUSHNUM_NEG1'); + } else if (op === 0xb1) { + b.push('OP_CLTV'); + } else if (op === 0xb2) { + b.push('OP_CSV'); + } else if (op === 0xba) { + b.push('OP_CHECKSIGADD'); + } else { + const opcode = bitcoinjs.script.toASM([ op ]); + if (opcode && op < 0xfd) { + if (/^OP_(\d+)$/.test(opcode)) { + b.push(opcode.replace(/^OP_(\d+)$/, 'OP_PUSHNUM_$1')); + } else { + b.push(opcode); + } + } else { + b.push('OP_RETURN_' + op); + } + } + i += 1; + } + } + + return b.join(' '); + } + + /** + * This function must only be called when we know the witness we are parsing + * is a taproot witness. + * @param witness An array of hex strings that represents the witness stack of + * the input. + * @returns null if the witness is not a script spend, and the hex string of + * the script item if it is a script spend. + */ + public witnessToP2TRScript(witness: string[]): string | null { + if (witness.length < 2) return null; + // Note: see BIP341 for parsing details of witness stack + + // If there are at least two witness elements, and the first byte of the + // last element is 0x50, this last element is called annex a and + // is removed from the witness stack. + const hasAnnex = witness[witness.length - 1].substring(0, 2) === '50'; + // If there are at least two witness elements left, script path spending is used. + // Call the second-to-last stack element s, the script. + // (Note: this phrasing from BIP341 assumes we've *removed* the annex from the stack) + if (hasAnnex && witness.length < 3) return null; + const positionOfScript = hasAnnex ? witness.length - 3 : witness.length - 2; + return witness[positionOfScript]; + } +} + +export default new TransactionUtils(); diff --git a/backend/src/api/tx-selection-worker.ts b/backend/src/api/tx-selection-worker.ts new file mode 100644 index 0000000000..8ac7328fe2 --- /dev/null +++ b/backend/src/api/tx-selection-worker.ts @@ -0,0 +1,309 @@ +import config from '../config'; +import logger from '../logger'; +import { CompactThreadTransaction, AuditTransaction } from '../mempool.interfaces'; +import { PairingHeap } from '../utils/pairing-heap'; +import { parentPort } from 'worker_threads'; + +let mempool: Map = new Map(); + +if (parentPort) { + parentPort.on('message', (params) => { + if (params.type === 'set') { + mempool = params.mempool; + } else if (params.type === 'update') { + params.added.forEach(tx => { + mempool.set(tx.uid, tx); + }); + params.removed.forEach(uid => { + mempool.delete(uid); + }); + } + + const { blocks, rates, clusters } = makeBlockTemplates(mempool); + + // return the result to main thread. + if (parentPort) { + parentPort.postMessage({ blocks, rates, clusters }); + } + }); +} + +/* +* Build projected mempool blocks using an approximation of the transaction selection algorithm from Bitcoin Core +* (see BlockAssembler in https://github.com/bitcoin/bitcoin/blob/master/src/node/miner.cpp) +*/ +function makeBlockTemplates(mempool: Map) + : { blocks: number[][], rates: Map, clusters: Map } { + const start = Date.now(); + const auditPool: Map = new Map(); + const mempoolArray: AuditTransaction[] = []; + const cpfpClusters: Map = new Map(); + + mempool.forEach(tx => { + tx.dirty = false; + // initializing everything up front helps V8 optimize property access later + auditPool.set(tx.uid, { + uid: tx.uid, + fee: tx.fee, + weight: tx.weight, + feePerVsize: tx.feePerVsize, + effectiveFeePerVsize: tx.feePerVsize, + sigops: tx.sigops, + inputs: tx.inputs || [], + relativesSet: false, + ancestorMap: new Map(), + children: new Set(), + ancestorFee: 0, + ancestorWeight: 0, + ancestorSigops: 0, + score: 0, + used: false, + modified: false, + modifiedNode: null, + }); + mempoolArray.push(auditPool.get(tx.uid) as AuditTransaction); + }); + + // Build relatives graph & calculate ancestor scores + for (const tx of mempoolArray) { + if (!tx.relativesSet) { + setRelatives(tx, auditPool); + } + } + + // Sort by descending ancestor score + mempoolArray.sort((a, b) => { + if (b.score === a.score) { + // tie-break by uid for stability + return a.uid < b.uid ? -1 : 1; + } else { + return (b.score || 0) - (a.score || 0); + } + }); + + // Build blocks by greedily choosing the highest feerate package + // (i.e. the package rooted in the transaction with the best ancestor score) + const blocks: number[][] = []; + let blockWeight = 4000; + let blockSigops = 0; + let transactions: AuditTransaction[] = []; + const modified: PairingHeap = new PairingHeap((a, b): boolean => { + if (a.score === b.score) { + // tie-break by uid for stability + return a.uid > b.uid; + } else { + return (a.score || 0) > (b.score || 0); + } + }); + let overflow: AuditTransaction[] = []; + let failures = 0; + let top = 0; + while ((top < mempoolArray.length || !modified.isEmpty())) { + // skip invalid transactions + while (top < mempoolArray.length && (mempoolArray[top].used || mempoolArray[top].modified)) { + top++; + } + + // Select best next package + let nextTx; + const nextPoolTx = mempoolArray[top]; + const nextModifiedTx = modified.peek(); + if (nextPoolTx && (!nextModifiedTx || (nextPoolTx.score || 0) > (nextModifiedTx.score || 0))) { + nextTx = nextPoolTx; + top++; + } else { + modified.pop(); + if (nextModifiedTx) { + nextTx = nextModifiedTx; + nextTx.modifiedNode = undefined; + } + } + + if (nextTx && !nextTx?.used) { + // Check if the package fits into this block + if (blocks.length >= 7 || ((blockWeight + nextTx.ancestorWeight < config.MEMPOOL.BLOCK_WEIGHT_UNITS) && (blockSigops + nextTx.ancestorSigops <= 80000))) { + const ancestors: AuditTransaction[] = Array.from(nextTx.ancestorMap.values()); + // sort ancestors by dependency graph (equivalent to sorting by ascending ancestor count) + const sortedTxSet = [...ancestors.sort((a, b) => { return (a.ancestorMap.size || 0) - (b.ancestorMap.size || 0); }), nextTx]; + let isCluster = false; + if (sortedTxSet.length > 1) { + cpfpClusters.set(nextTx.uid, sortedTxSet.map(tx => tx.uid)); + isCluster = true; + } + const effectiveFeeRate = Math.min(nextTx.dependencyRate || Infinity, nextTx.ancestorFee / (nextTx.ancestorWeight / 4)); + const used: AuditTransaction[] = []; + while (sortedTxSet.length) { + const ancestor = sortedTxSet.pop(); + const mempoolTx = mempool.get(ancestor.uid); + if (!mempoolTx) { + continue; + } + ancestor.used = true; + ancestor.usedBy = nextTx.uid; + // update original copy of this tx with effective fee rate & relatives data + if (mempoolTx.effectiveFeePerVsize !== effectiveFeeRate) { + mempoolTx.effectiveFeePerVsize = effectiveFeeRate; + mempoolTx.dirty = true; + } + if (mempoolTx.cpfpRoot !== nextTx.uid) { + mempoolTx.cpfpRoot = isCluster ? nextTx.uid : null; + mempoolTx.dirty; + } + mempoolTx.cpfpChecked = true; + transactions.push(ancestor); + blockWeight += ancestor.weight; + used.push(ancestor); + } + + // remove these as valid package ancestors for any descendants remaining in the mempool + if (used.length) { + used.forEach(tx => { + updateDescendants(tx, auditPool, modified, effectiveFeeRate); + }); + } + + failures = 0; + } else { + // hold this package in an overflow list while we check for smaller options + overflow.push(nextTx); + failures++; + } + } + + // this block is full + const exceededPackageTries = failures > 1000 && blockWeight > (config.MEMPOOL.BLOCK_WEIGHT_UNITS - 4000); + const queueEmpty = top >= mempoolArray.length && modified.isEmpty(); + + if ((exceededPackageTries || queueEmpty) && blocks.length < 7) { + // construct this block + if (transactions.length) { + blocks.push(transactions.map(t => t.uid)); + } else { + break; + } + // reset for the next block + transactions = []; + blockWeight = 4000; + + // 'overflow' packages didn't fit in this block, but are valid candidates for the next + for (const overflowTx of overflow.reverse()) { + if (overflowTx.modified) { + overflowTx.modifiedNode = modified.add(overflowTx); + } else { + top--; + mempoolArray[top] = overflowTx; + } + } + overflow = []; + } + } + + if (overflow.length > 0) { + logger.warn('GBT overflow list unexpectedly non-empty after final block constructed'); + } + // add the final unbounded block if it contains any transactions + if (transactions.length > 0) { + blocks.push(transactions.map(t => t.uid)); + } + + // get map of dirty transactions + const rates = new Map(); + for (const tx of mempool.values()) { + if (tx?.dirty) { + rates.set(tx.uid, tx.effectiveFeePerVsize || tx.feePerVsize); + } + } + + const end = Date.now(); + const time = end - start; + logger.debug('Mempool templates calculated in ' + time / 1000 + ' seconds'); + + return { blocks, rates, clusters: cpfpClusters }; +} + +// traverse in-mempool ancestors +// recursion unavoidable, but should be limited to depth < 25 by mempool policy +function setRelatives( + tx: AuditTransaction, + mempool: Map, +): void { + for (const parent of tx.inputs) { + const parentTx = mempool.get(parent); + if (parentTx && !tx.ancestorMap?.has(parent)) { + tx.ancestorMap.set(parent, parentTx); + parentTx.children.add(tx); + // visit each node only once + if (!parentTx.relativesSet) { + setRelatives(parentTx, mempool); + } + parentTx.ancestorMap.forEach((ancestor) => { + tx.ancestorMap.set(ancestor.uid, ancestor); + }); + } + }; + tx.ancestorFee = tx.fee || 0; + tx.ancestorWeight = tx.weight || 0; + tx.ancestorSigops = tx.sigops || 0; + tx.ancestorMap.forEach((ancestor) => { + tx.ancestorFee += ancestor.fee; + tx.ancestorWeight += ancestor.weight; + tx.ancestorSigops += ancestor.sigops; + }); + tx.score = tx.ancestorFee / ((tx.ancestorWeight / 4) || 1); + tx.relativesSet = true; +} + +// iterate over remaining descendants, removing the root as a valid ancestor & updating the ancestor score +// avoids recursion to limit call stack depth +function updateDescendants( + rootTx: AuditTransaction, + mempool: Map, + modified: PairingHeap, + clusterRate: number, +): void { + const descendantSet: Set = new Set(); + // stack of nodes left to visit + const descendants: AuditTransaction[] = []; + let descendantTx; + let tmpScore; + rootTx.children.forEach(childTx => { + if (!descendantSet.has(childTx)) { + descendants.push(childTx); + descendantSet.add(childTx); + } + }); + while (descendants.length) { + descendantTx = descendants.pop(); + if (descendantTx && descendantTx.ancestorMap && descendantTx.ancestorMap.has(rootTx.uid)) { + // remove tx as ancestor + descendantTx.ancestorMap.delete(rootTx.uid); + descendantTx.ancestorFee -= rootTx.fee; + descendantTx.ancestorWeight -= rootTx.weight; + descendantTx.ancestorSigops -= rootTx.sigops; + tmpScore = descendantTx.score; + descendantTx.score = descendantTx.ancestorFee / (descendantTx.ancestorWeight / 4); + descendantTx.dependencyRate = descendantTx.dependencyRate ? Math.min(descendantTx.dependencyRate, clusterRate) : clusterRate; + + if (!descendantTx.modifiedNode) { + descendantTx.modified = true; + descendantTx.modifiedNode = modified.add(descendantTx); + } else { + // rebalance modified heap if score has changed + if (descendantTx.score < tmpScore) { + modified.decreasePriority(descendantTx.modifiedNode); + } else if (descendantTx.score > tmpScore) { + modified.increasePriority(descendantTx.modifiedNode); + } + } + + // add this node's children to the stack + descendantTx.children.forEach(childTx => { + // visit each node only once + if (!descendantSet.has(childTx)) { + descendants.push(childTx); + descendantSet.add(childTx); + } + }); + } + } +} \ No newline at end of file diff --git a/backend/src/api/websocket-handler.ts b/backend/src/api/websocket-handler.ts index a20e075f52..cf2c567633 100644 --- a/backend/src/api/websocket-handler.ts +++ b/backend/src/api/websocket-handler.ts @@ -1,73 +1,310 @@ -const config = require('../../mempool-config.json'); - +import logger from '../logger'; import * as WebSocket from 'ws'; -import { Block, TransactionExtended, WebsocketResponse, MempoolBlock, OptimizedStatistic } from '../interfaces'; +import { + BlockExtended, TransactionExtended, MempoolTransactionExtended, WebsocketResponse, + OptimizedStatistic, ILoadingIndicators, GbtCandidates, TxTrackingInfo, + MempoolBlockDelta, MempoolDelta, MempoolDeltaTxids +} from '../mempool.interfaces'; import blocks from './blocks'; import memPool from './mempool'; import backendInfo from './backend-info'; import mempoolBlocks from './mempool-blocks'; -import fiatConversion from './fiat-conversion'; import { Common } from './common'; +import loadingIndicators from './loading-indicators'; +import config from '../config'; +import transactionUtils from './transaction-utils'; +import rbfCache, { ReplacementInfo } from './rbf-cache'; +import difficultyAdjustment from './difficulty-adjustment'; +import feeApi from './fee-api'; +import BlocksAuditsRepository from '../repositories/BlocksAuditsRepository'; +import BlocksSummariesRepository from '../repositories/BlocksSummariesRepository'; +import Audit from './audit'; +import priceUpdater from '../tasks/price-updater'; +import { ApiPrice } from '../repositories/PricesRepository'; +import accelerationApi from './services/acceleration'; +import mempool from './mempool'; +import statistics from './statistics/statistics'; +import accelerationRepository from '../repositories/AccelerationRepository'; +import bitcoinApi from './bitcoin/bitcoin-api-factory'; + +interface AddressTransactions { + mempool: MempoolTransactionExtended[], + confirmed: MempoolTransactionExtended[], + removed: MempoolTransactionExtended[], +} +import bitcoinSecondClient from './bitcoin/bitcoin-second-client'; +import { calculateMempoolTxCpfp } from './cpfp'; + +// valid 'want' subscriptions +const wantable = [ + 'blocks', + 'mempool-blocks', + 'live-2h-chart', + 'stats', + 'tomahawk', +]; class WebsocketHandler { - private wss: WebSocket.Server | undefined; - private nativeAssetId = '6f0279e9ed041c3d710a9f57d0c02928416460c4b722ae3457a11eec381c526d'; + private webSocketServers: WebSocket.Server[] = []; private extraInitProperties = {}; + private numClients = 0; + private numConnected = 0; + private numDisconnected = 0; + + private socketData: { [key: string]: string } = {}; + private serializedInitData: string = '{}'; + private lastRbfSummary: ReplacementInfo[] | null = null; + private mempoolSequence: number = 0; + constructor() { } - setWebsocketServer(wss: WebSocket.Server) { - this.wss = wss; + addWebsocketServer(wss: WebSocket.Server) { + this.webSocketServers.push(wss); } - setExtraInitProperties(property: string, value: any) { + setExtraInitData(property: string, value: any) { this.extraInitProperties[property] = value; + this.updateSocketDataFields(this.extraInitProperties); + } + + private updateSocketDataFields(data: { [property: string]: any }): void { + for (const property of Object.keys(data)) { + if (data[property] != null) { + this.socketData[property] = JSON.stringify(data[property]); + } else { + delete this.socketData[property]; + } + } + this.serializedInitData = '{' + + Object.keys(this.socketData).map(key => `"${key}": ${this.socketData[key]}`).join(', ') + + '}'; + } + + private updateSocketData(): void { + const _blocks = blocks.getBlocks().slice(-config.MEMPOOL.INITIAL_BLOCKS_AMOUNT); + const da = difficultyAdjustment.getDifficultyAdjustment(); + this.updateSocketDataFields({ + 'backend': config.MEMPOOL.BACKEND, + 'mempoolInfo': memPool.getMempoolInfo(), + 'vBytesPerSecond': memPool.getVBytesPerSecond(), + 'blocks': _blocks, + 'conversions': priceUpdater.getLatestPrices(), + 'mempool-blocks': mempoolBlocks.getMempoolBlocks(), + 'transactions': memPool.getLatestTransactions(), + 'backendInfo': backendInfo.getBackendInfo(), + 'loadingIndicators': loadingIndicators.getLoadingIndicators(), + 'da': da?.previousTime ? da : undefined, + 'fees': feeApi.getRecommendedFee(), + }); + } + + public getSerializedInitData(): string { + return this.serializedInitData; } setupConnectionHandling() { - if (!this.wss) { - throw new Error('WebSocket.Server is not set'); + if (!this.webSocketServers.length) { + throw new Error('No WebSocket.Server have been set'); } - this.wss.on('connection', (client: WebSocket) => { - client.on('message', (message: string) => { + // TODO - Fix indentation after PR is merged + for (const server of this.webSocketServers) { + server.on('connection', (client: WebSocket, req) => { + this.numConnected++; + client['remoteAddress'] = req.headers['x-forwarded-for'] || req.socket?.remoteAddress || 'unknown'; + client.on('error', (e) => { + logger.info(`websocket client error from ${client['remoteAddress']}: ` + (e instanceof Error ? e.message : e)); + client.close(); + }); + client.on('close', () => { + this.numDisconnected++; + }); + client.on('message', async (message: string) => { try { const parsedMessage: WebsocketResponse = JSON.parse(message); const response = {}; - if (parsedMessage.action === 'want') { - client['want-blocks'] = parsedMessage.data.indexOf('blocks') > -1; - client['want-mempool-blocks'] = parsedMessage.data.indexOf('mempool-blocks') > -1; - client['want-live-2h-chart'] = parsedMessage.data.indexOf('live-2h-chart') > -1; - client['want-stats'] = parsedMessage.data.indexOf('stats') > -1; + const wantNow = {}; + if (parsedMessage && parsedMessage.action === 'want' && Array.isArray(parsedMessage.data)) { + for (const sub of wantable) { + const key = `want-${sub}`; + const wants = parsedMessage.data.includes(sub); + if (wants && !client[key]) { + wantNow[key] = true; + } + client[key] = wants; + } + client['wants'] = true; + } + + // send initial data when a client first starts a subscription + if (wantNow['want-blocks'] || (parsedMessage && parsedMessage['refresh-blocks'])) { + response['blocks'] = this.socketData['blocks']; + } + + if (wantNow['want-mempool-blocks']) { + response['mempool-blocks'] = this.socketData['mempool-blocks']; + } + + if (wantNow['want-stats']) { + response['mempoolInfo'] = this.socketData['mempoolInfo']; + response['vBytesPerSecond'] = this.socketData['vBytesPerSecond']; + response['fees'] = this.socketData['fees']; + response['da'] = this.socketData['da']; + } + + if (wantNow['want-tomahawk']) { + response['tomahawk'] = JSON.stringify(bitcoinApi.getHealthStatus()); } if (parsedMessage && parsedMessage['track-tx']) { if (/^[a-fA-F0-9]{64}$/.test(parsedMessage['track-tx'])) { client['track-tx'] = parsedMessage['track-tx']; - // Client is telling the transaction wasn't found but it might have appeared before we had the time to start watching for it + const trackTxid = client['track-tx']; + // Client is telling the transaction wasn't found if (parsedMessage['watch-mempool']) { - const tx = memPool.getMempool()[client['track-tx']]; - if (tx) { - response['tx'] = tx; + const rbfCacheTxid = rbfCache.getReplacedBy(trackTxid); + if (rbfCacheTxid) { + response['txReplaced'] = JSON.stringify({ + txid: rbfCacheTxid, + }); + client['track-tx'] = null; } else { - client['track-mempool-tx'] = parsedMessage['track-tx']; + // It might have appeared before we had the time to start watching for it + const tx = memPool.getMempool()[trackTxid]; + if (tx) { + if (config.MEMPOOL.BACKEND === 'esplora') { + response['tx'] = JSON.stringify(tx); + } else { + // tx.prevout is missing from transactions when in bitcoind mode + try { + const fullTx = await transactionUtils.$getMempoolTransactionExtended(tx.txid, true); + response['tx'] = JSON.stringify(fullTx); + } catch (e) { + logger.debug('Error finding transaction: ' + (e instanceof Error ? e.message : e)); + } + } + } else { + try { + const fullTx = await transactionUtils.$getMempoolTransactionExtended(client['track-tx'], true); + response['tx'] = JSON.stringify(fullTx); + } catch (e) { + logger.debug('Error finding transaction. ' + (e instanceof Error ? e.message : e)); + client['track-mempool-tx'] = parsedMessage['track-tx']; + } + } } } + const tx = memPool.getMempool()[trackTxid]; + if (tx && tx.position) { + const position: { block: number, vsize: number, accelerated?: boolean } = { + ...tx.position + }; + if (tx.acceleration) { + position.accelerated = tx.acceleration; + } + response['txPosition'] = JSON.stringify({ + txid: trackTxid, + position, + accelerationPositions: memPool.getAccelerationPositions(tx.txid), + }); + } } else { client['track-tx'] = null; } } + if (parsedMessage && parsedMessage['track-txs']) { + const txids: string[] = []; + if (Array.isArray(parsedMessage['track-txs'])) { + for (const txid of parsedMessage['track-txs']) { + if (/^[a-fA-F0-9]{64}$/.test(txid)) { + txids.push(txid); + } + } + } + + const txs: { [txid: string]: TxTrackingInfo } = {}; + for (const txid of txids) { + const txInfo: TxTrackingInfo = { + confirmed: true, + }; + const rbfCacheTxid = rbfCache.getReplacedBy(txid); + if (rbfCacheTxid) { + txInfo.replacedBy = rbfCacheTxid; + txInfo.confirmed = false; + } + const tx = memPool.getMempool()[txid]; + if (tx && tx.position) { + txInfo.position = { + ...tx.position + }; + if (tx.acceleration) { + txInfo.accelerated = tx.acceleration; + } + } + if (tx) { + txInfo.confirmed = false; + } + txs[txid] = txInfo; + } + + if (txids.length) { + client['track-txs'] = txids; + } else { + client['track-txs'] = null; + } + + if (Object.keys(txs).length) { + response['tracked-txs'] = JSON.stringify(txs); + } + } + if (parsedMessage && parsedMessage['track-address']) { - if (/^([a-km-zA-HJ-NP-Z1-9]{26,35}|[a-km-zA-HJ-NP-Z1-9]{80}|[a-z]{2,5}1[ac-hj-np-z02-9]{8,87})$/ - .test(parsedMessage['track-address'])) { - client['track-address'] = parsedMessage['track-address']; + const validAddress = this.testAddress(parsedMessage['track-address']); + if (validAddress) { + client['track-address'] = validAddress; } else { client['track-address'] = null; } } + if (parsedMessage && parsedMessage['track-addresses'] && Array.isArray(parsedMessage['track-addresses'])) { + const addressMap: { [address: string]: string } = {}; + for (const address of parsedMessage['track-addresses']) { + const validAddress = this.testAddress(address); + if (validAddress) { + addressMap[address] = validAddress; + } + } + if (Object.keys(addressMap).length > config.MEMPOOL.MAX_TRACKED_ADDRESSES) { + response['track-addresses-error'] = `"too many addresses requested, this connection supports tracking a maximum of ${config.MEMPOOL.MAX_TRACKED_ADDRESSES} addresses"`; + client['track-addresses'] = null; + } else if (Object.keys(addressMap).length > 0) { + client['track-addresses'] = addressMap; + } else { + client['track-addresses'] = null; + } + } + + if (parsedMessage && parsedMessage['track-scriptpubkeys'] && Array.isArray(parsedMessage['track-scriptpubkeys'])) { + const spks: string[] = []; + for (const spk of parsedMessage['track-scriptpubkeys']) { + if (/^[a-fA-F0-9]+$/.test(spk)) { + spks.push(spk.toLowerCase()); + } + } + if (spks.length > config.MEMPOOL.MAX_TRACKED_ADDRESSES) { + response['track-scriptpubkeys-error'] = `"too many scriptpubkeys requested, this connection supports tracking a maximum of ${config.MEMPOOL.MAX_TRACKED_ADDRESSES} scriptpubkeys"`; + client['track-scriptpubkeys'] = null; + } else if (spks.length) { + client['track-scriptpubkeys'] = spks; + } else { + client['track-scriptpubkeys'] = null; + } + } + if (parsedMessage && parsedMessage['track-asset']) { if (/^[a-fA-F0-9]{64}$/.test(parsedMessage['track-asset'])) { client['track-asset'] = parsedMessage['track-asset']; @@ -76,43 +313,164 @@ class WebsocketHandler { } } + if (parsedMessage && parsedMessage['track-mempool-block'] !== undefined) { + if (Number.isInteger(parsedMessage['track-mempool-block']) && parsedMessage['track-mempool-block'] >= 0) { + const index = parsedMessage['track-mempool-block']; + client['track-mempool-block'] = index; + const mBlocksWithTransactions = mempoolBlocks.getMempoolBlocksWithTransactions(); + response['projected-block-transactions'] = JSON.stringify({ + index: index, + sequence: this.mempoolSequence, + blockTransactions: (mBlocksWithTransactions[index]?.transactions || []).map(mempoolBlocks.compressTx), + }); + } else { + client['track-mempool-block'] = null; + } + } + + if (parsedMessage && parsedMessage['track-rbf'] !== undefined) { + if (['all', 'fullRbf'].includes(parsedMessage['track-rbf'])) { + client['track-rbf'] = parsedMessage['track-rbf']; + response['rbfLatest'] = JSON.stringify(rbfCache.getRbfTrees(parsedMessage['track-rbf'] === 'fullRbf')); + } else { + client['track-rbf'] = false; + } + } + + if (parsedMessage && parsedMessage['track-rbf-summary'] != null) { + if (parsedMessage['track-rbf-summary']) { + client['track-rbf-summary'] = true; + if (this.socketData['rbfSummary'] != null) { + response['rbfLatestSummary'] = this.socketData['rbfSummary']; + } + } else { + client['track-rbf-summary'] = false; + } + } + + if (parsedMessage && parsedMessage['track-accelerations'] != null) { + if (parsedMessage['track-accelerations']) { + client['track-accelerations'] = true; + response['accelerations'] = JSON.stringify({ + accelerations: Object.values(memPool.getAccelerations()), + }); + } else { + client['track-accelerations'] = false; + } + } + if (parsedMessage.action === 'init') { - const _blocks = blocks.getBlocks(); - if (!_blocks) { + if (!this.socketData['blocks']?.length || !this.socketData['da'] || !this.socketData['backendInfo'] || !this.socketData['conversions']) { + this.updateSocketData(); + } + if (!this.socketData['blocks']?.length) { return; } - client.send(JSON.stringify({ - 'mempoolInfo': memPool.getMempoolInfo(), - 'vBytesPerSecond': memPool.getVBytesPerSecond(), - 'blocks': _blocks.slice(Math.max(_blocks.length - config.INITIAL_BLOCK_AMOUNT, 0)), - 'conversions': fiatConversion.getTickers()['BTCUSD'], - 'mempool-blocks': mempoolBlocks.getMempoolBlocks(), - 'git-commit': backendInfo.gitCommitHash, - 'hostname': backendInfo.hostname, - ...this.extraInitProperties - })); + client.send(this.serializedInitData); } if (parsedMessage.action === 'ping') { - response['pong'] = true; + response['pong'] = JSON.stringify(true); + } + + if (parsedMessage['track-donation'] && parsedMessage['track-donation'].length === 22) { + client['track-donation'] = parsedMessage['track-donation']; + } + + if (parsedMessage['track-mempool-txids'] === true) { + client['track-mempool-txids'] = true; + } else if (parsedMessage['track-mempool-txids'] === false) { + delete client['track-mempool-txids']; + } + + if (parsedMessage['track-mempool'] === true) { + client['track-mempool'] = true; + } else if (parsedMessage['track-mempool'] === false) { + delete client['track-mempool']; } if (Object.keys(response).length) { - client.send(JSON.stringify(response)); + client.send(this.serializeResponse(response)); } } catch (e) { - console.log(e); + logger.debug(`Error parsing websocket message from ${client['remoteAddress']}: ` + (e instanceof Error ? e.message : e)); + client.close(); } }); }); + } + } + + handleNewDonation(id: string) { + if (!this.webSocketServers.length) { + throw new Error('No WebSocket.Server have been set'); + } + + // TODO - Fix indentation after PR is merged + for (const server of this.webSocketServers) { + server.clients.forEach((client) => { + if (client.readyState !== WebSocket.OPEN) { + return; + } + if (client['track-donation'] === id) { + client.send(JSON.stringify({ donationConfirmed: true })); + } + }); + } + } + + handleLoadingChanged(indicators: ILoadingIndicators) { + if (!this.webSocketServers.length) { + throw new Error('No WebSocket.Server have been set'); + } + + this.updateSocketDataFields({ 'loadingIndicators': indicators }); + + const response = JSON.stringify({ loadingIndicators: indicators }); + // TODO - Fix indentation after PR is merged + for (const server of this.webSocketServers) { + server.clients.forEach((client) => { + if (client.readyState !== WebSocket.OPEN) { + return; + } + client.send(response); + }); + } + } + + handleNewConversionRates(conversionRates: ApiPrice) { + if (!this.webSocketServers.length) { + throw new Error('No WebSocket.Server have been set'); + } + + this.updateSocketDataFields({ 'conversions': conversionRates }); + + const response = JSON.stringify({ conversions: conversionRates }); + // TODO - Fix indentation after PR is merged + for (const server of this.webSocketServers) { + server.clients.forEach((client) => { + if (client.readyState !== WebSocket.OPEN) { + return; + } + client.send(response); + }); + } } handleNewStatistic(stats: OptimizedStatistic) { - if (!this.wss) { - throw new Error('WebSocket.Server is not set'); + if (!this.webSocketServers.length) { + throw new Error('No WebSocket.Server have been set'); } - this.wss.clients.forEach((client: WebSocket) => { + this.printLogs(); + + const response = JSON.stringify({ + 'live-2h-chart': stats + }); + + // TODO - Fix indentation after PR is merged + for (const server of this.webSocketServers) { + server.clients.forEach((client) => { if (client.readyState !== WebSocket.OPEN) { return; } @@ -121,25 +479,193 @@ class WebsocketHandler { return; } - client.send(JSON.stringify({ - 'live-2h-chart': stats - })); + client.send(response); + }); + } + } + + handleReorg(): void { + if (!this.webSocketServers.length) { + throw new Error('No WebSocket.Server have been set'); + } + + const da = difficultyAdjustment.getDifficultyAdjustment(); + + // update init data + this.updateSocketDataFields({ + 'blocks': blocks.getBlocks(), + 'da': da?.previousTime ? da : undefined, + }); + + // TODO - Fix indentation after PR is merged + for (const server of this.webSocketServers) { + server.clients.forEach((client) => { + if (client.readyState !== WebSocket.OPEN) { + return; + } + + const response = {}; + + if (client['want-blocks']) { + response['blocks'] = this.socketData['blocks']; + } + if (client['want-stats']) { + response['da'] = this.socketData['da']; + } + + if (Object.keys(response).length) { + client.send(this.serializeResponse(response)); + } }); + } } - handleMempoolChange(newMempool: { [txid: string]: TransactionExtended }, - newTransactions: TransactionExtended[], deletedTransactions: TransactionExtended[]) { - if (!this.wss) { - throw new Error('WebSocket.Server is not set'); + async $handleMempoolChange(newMempool: { [txid: string]: MempoolTransactionExtended }, mempoolSize: number, + newTransactions: MempoolTransactionExtended[], deletedTransactions: MempoolTransactionExtended[], accelerationDelta: string[], + candidates?: GbtCandidates): Promise { + if (!this.webSocketServers.length) { + throw new Error('No WebSocket.Server have been set'); + } + + this.printLogs(); + + const transactionIds = (memPool.limitGBT && candidates) ? Object.keys(candidates?.txs || {}) : Object.keys(newMempool); + let added = newTransactions; + let removed = deletedTransactions; + if (memPool.limitGBT) { + added = candidates?.added || []; + removed = candidates?.removed || []; + } + + if (config.MEMPOOL.RUST_GBT) { + await mempoolBlocks.$rustUpdateBlockTemplates(transactionIds, newMempool, added, removed, candidates, config.MEMPOOL_SERVICES.ACCELERATIONS); + } else { + await mempoolBlocks.$updateBlockTemplates(transactionIds, newMempool, added, removed, candidates, accelerationDelta, true, config.MEMPOOL_SERVICES.ACCELERATIONS); } - mempoolBlocks.updateMempoolBlocks(newMempool); const mBlocks = mempoolBlocks.getMempoolBlocks(); + const mBlockDeltas = mempoolBlocks.getMempoolBlockDeltas(); const mempoolInfo = memPool.getMempoolInfo(); const vBytesPerSecond = memPool.getVBytesPerSecond(); const rbfTransactions = Common.findRbfTransactions(newTransactions, deletedTransactions); + const da = difficultyAdjustment.getDifficultyAdjustment(); + const accelerations = memPool.getAccelerations(); + memPool.handleRbfTransactions(rbfTransactions); + const rbfChanges = rbfCache.getRbfChanges(); + let rbfReplacements; + let fullRbfReplacements; + let rbfSummary; + if (Object.keys(rbfChanges.trees).length || !this.lastRbfSummary) { + rbfReplacements = rbfCache.getRbfTrees(false); + fullRbfReplacements = rbfCache.getRbfTrees(true); + rbfSummary = rbfCache.getLatestRbfSummary() || []; + this.lastRbfSummary = rbfSummary; + } + + for (const deletedTx of deletedTransactions) { + rbfCache.evict(deletedTx.txid); + } + memPool.removeFromSpendMap(deletedTransactions); + memPool.addToSpendMap(newTransactions); + const recommendedFees = feeApi.getRecommendedFee(); + + const latestTransactions = memPool.getLatestTransactions(); + + if (memPool.isInSync()) { + this.mempoolSequence++; + } + + const replacedTransactions: { replaced: string, by: TransactionExtended }[] = []; + for (const tx of newTransactions) { + if (rbfTransactions[tx.txid]) { + for (const replaced of rbfTransactions[tx.txid]) { + replacedTransactions.push({ replaced: replaced.txid, by: tx }); + } + } + } + const mempoolDeltaTxids: MempoolDeltaTxids = { + sequence: this.mempoolSequence, + added: newTransactions.map(tx => tx.txid), + removed: deletedTransactions.map(tx => tx.txid), + mined: [], + replaced: replacedTransactions.map(replacement => ({ replaced: replacement.replaced, by: replacement.by.txid })), + }; + const mempoolDelta: MempoolDelta = { + sequence: this.mempoolSequence, + added: newTransactions, + removed: deletedTransactions.map(tx => tx.txid), + mined: [], + replaced: replacedTransactions, + }; + + // update init data + const socketDataFields = { + 'mempoolInfo': mempoolInfo, + 'vBytesPerSecond': vBytesPerSecond, + 'mempool-blocks': mBlocks, + 'transactions': latestTransactions, + 'loadingIndicators': loadingIndicators.getLoadingIndicators(), + 'da': da?.previousTime ? da : undefined, + 'fees': recommendedFees, + }; + if (rbfSummary) { + socketDataFields['rbfSummary'] = rbfSummary; + } + this.updateSocketDataFields(socketDataFields); - this.wss.clients.forEach((client: WebSocket) => { + // cache serialized objects to avoid stringify-ing the same thing for every client + const responseCache = { ...this.socketData }; + function getCachedResponse(key: string, data): string { + if (!responseCache[key]) { + responseCache[key] = JSON.stringify(data); + } + return responseCache[key]; + } + + // pre-compute new tracked outspends + const outspendCache: { [txid: string]: { [vout: number]: { vin: number, txid: string } } } = {}; + const trackedTxs = new Set(); + // TODO - Fix indentation after PR is merged + for (const server of this.webSocketServers) { + server.clients.forEach((client) => { + if (client['track-tx']) { + trackedTxs.add(client['track-tx']); + } + if (client['track-txs']) { + for (const txid of client['track-txs']) { + trackedTxs.add(txid); + } + } + }); + } + if (trackedTxs.size > 0) { + for (const tx of newTransactions) { + for (let i = 0; i < tx.vin.length; i++) { + const vin = tx.vin[i]; + if (trackedTxs.has(vin.txid)) { + if (!outspendCache[vin.txid]) { + outspendCache[vin.txid] = { [vin.vout]: { vin: i, txid: tx.txid }}; + } else { + outspendCache[vin.txid][vin.vout] = { vin: i, txid: tx.txid }; + } + } + } + } + } + + // pre-compute address transactions + const addressCache = this.makeAddressCache(newTransactions); + const removedAddressCache = this.makeAddressCache(deletedTransactions); + + // pre-compute acceleration delta + const accelerationUpdate = { + added: accelerationDelta.map(txid => accelerations[txid]).filter(acc => acc != null), + removed: accelerationDelta.filter(txid => !accelerations[txid]), + }; + + // TODO - Fix indentation after PR is merged + for (const server of this.webSocketServers) { + server.clients.forEach(async (client) => { if (client.readyState !== WebSocket.OPEN) { return; } @@ -147,39 +673,96 @@ class WebsocketHandler { const response = {}; if (client['want-stats']) { - response['mempoolInfo'] = mempoolInfo; - response['vBytesPerSecond'] = vBytesPerSecond; + response['mempoolInfo'] = getCachedResponse('mempoolInfo', mempoolInfo); + response['vBytesPerSecond'] = getCachedResponse('vBytesPerSecond', vBytesPerSecond); + response['transactions'] = getCachedResponse('transactions', latestTransactions); + if (da?.previousTime) { + response['da'] = getCachedResponse('da', da); + } + response['fees'] = getCachedResponse('fees', recommendedFees); } if (client['want-mempool-blocks']) { - response['mempool-blocks'] = mBlocks; + response['mempool-blocks'] = getCachedResponse('mempool-blocks', mBlocks); + } + + if (client['want-tomahawk']) { + response['tomahawk'] = getCachedResponse('tomahawk', bitcoinApi.getHealthStatus()); } if (client['track-mempool-tx']) { const tx = newTransactions.find((t) => t.txid === client['track-mempool-tx']); if (tx) { - response['tx'] = tx; + if (config.MEMPOOL.BACKEND !== 'esplora') { + try { + const fullTx = await transactionUtils.$getMempoolTransactionExtended(tx.txid, true); + response['tx'] = JSON.stringify(fullTx); + } catch (e) { + logger.debug('Error finding transaction in mempool: ' + (e instanceof Error ? e.message : e)); + } + } else { + response['tx'] = JSON.stringify(tx); + } client['track-mempool-tx'] = null; } } if (client['track-address']) { - const foundTransactions: TransactionExtended[] = []; + const newTransactions = Array.from(addressCache[client['track-address']]?.values() || []); + const removedTransactions = Array.from(removedAddressCache[client['track-address']]?.values() || []); + // txs may be missing prevouts in non-esplora backends + // so fetch the full transactions now + const fullTransactions = (config.MEMPOOL.BACKEND !== 'esplora') ? await this.getFullTransactions(newTransactions) : newTransactions; - newTransactions.forEach((tx) => { - const someVin = tx.vin.some((vin) => !!vin.prevout && vin.prevout.scriptpubkey_address === client['track-address']); - if (someVin) { - foundTransactions.push(tx); - return; + if (removedTransactions.length) { + response['address-removed-transactions'] = JSON.stringify(removedTransactions); + } + if (fullTransactions.length) { + response['address-transactions'] = JSON.stringify(fullTransactions); + } + } + + if (client['track-addresses']) { + const addressMap: { [address: string]: AddressTransactions } = {}; + for (const [address, key] of Object.entries(client['track-addresses'] || {})) { + const newTransactions = Array.from(addressCache[key as string]?.values() || []); + const removedTransactions = Array.from(removedAddressCache[key as string]?.values() || []); + // txs may be missing prevouts in non-esplora backends + // so fetch the full transactions now + const fullTransactions = (config.MEMPOOL.BACKEND !== 'esplora') ? await this.getFullTransactions(newTransactions) : newTransactions; + if (fullTransactions?.length) { + addressMap[address] = { + mempool: fullTransactions, + confirmed: [], + removed: removedTransactions, + }; } - const someVout = tx.vout.some((vout) => vout.scriptpubkey_address === client['track-address']); - if (someVout) { - foundTransactions.push(tx); + } + + if (Object.keys(addressMap).length > 0) { + response['multi-address-transactions'] = JSON.stringify(addressMap); + } + } + + if (client['track-scriptpubkeys']) { + const spkMap: { [spk: string]: AddressTransactions } = {}; + for (const spk of client['track-scriptpubkeys'] || []) { + const newTransactions = Array.from(addressCache[spk as string]?.values() || []); + const removedTransactions = Array.from(removedAddressCache[spk as string]?.values() || []); + // txs may be missing prevouts in non-esplora backends + // so fetch the full transactions now + const fullTransactions = (config.MEMPOOL.BACKEND !== 'esplora') ? await this.getFullTransactions(newTransactions) : newTransactions; + if (fullTransactions?.length) { + spkMap[spk] = { + mempool: fullTransactions, + confirmed: [], + removed: removedTransactions, + }; } - }); + } - if (foundTransactions.length) { - response['address-transactions'] = foundTransactions; + if (Object.keys(spkMap).length > 0) { + response['multi-scriptpubkey-transactions'] = JSON.stringify(spkMap); } } @@ -187,8 +770,7 @@ class WebsocketHandler { const foundTransactions: TransactionExtended[] = []; newTransactions.forEach((tx) => { - - if (client['track-asset'] === this.nativeAssetId) { + if (client['track-asset'] === Common.nativeAssetId) { if (tx.vin.some((vin) => !!vin.is_pegin)) { foundTransactions.push(tx); return; @@ -208,91 +790,391 @@ class WebsocketHandler { }); if (foundTransactions.length) { - response['address-transactions'] = foundTransactions; + response['address-transactions'] = JSON.stringify(foundTransactions); + } + } + + if (client['track-tx']) { + const trackTxid = client['track-tx']; + const outspends = outspendCache[trackTxid]; + + if (outspends && Object.keys(outspends).length) { + response['utxoSpent'] = JSON.stringify(outspends); + } + + const rbfReplacedBy = rbfChanges.map[client['track-tx']] ? rbfCache.getReplacedBy(client['track-tx']) : false; + if (rbfReplacedBy) { + response['rbfTransaction'] = JSON.stringify({ + txid: rbfReplacedBy, + }); + } + + const rbfChange = rbfChanges.map[client['track-tx']]; + if (rbfChange) { + response['rbfInfo'] = JSON.stringify(rbfChanges.trees[rbfChange]); + } + + const mempoolTx = newMempool[trackTxid]; + if (mempoolTx && mempoolTx.position) { + const positionData = { + txid: trackTxid, + position: { + ...mempoolTx.position, + accelerated: mempoolTx.acceleration || undefined, + acceleratedBy: mempoolTx.acceleratedBy || undefined, + acceleratedAt: mempoolTx.acceleratedAt || undefined, + }, + accelerationPositions: memPool.getAccelerationPositions(mempoolTx.txid), + }; + if (!mempoolTx.cpfpChecked && !mempoolTx.acceleration) { + calculateMempoolTxCpfp(mempoolTx, newMempool); + } + if (mempoolTx.cpfpDirty) { + positionData['cpfp'] = { + ancestors: mempoolTx.ancestors, + bestDescendant: mempoolTx.bestDescendant || null, + descendants: mempoolTx.descendants || null, + effectiveFeePerVsize: mempoolTx.effectiveFeePerVsize || null, + sigops: mempoolTx.sigops, + adjustedVsize: mempoolTx.adjustedVsize, + acceleration: mempoolTx.acceleration, + }; + } + response['txPosition'] = JSON.stringify(positionData); } } - if (client['track-tx'] && rbfTransactions[client['track-tx']]) { - for (const rbfTransaction in rbfTransactions) { - if (client['track-tx'] === rbfTransaction) { - response['rbfTransaction'] = rbfTransactions[rbfTransaction]; - break; + if (client['track-txs']) { + const txids = client['track-txs']; + const txs: { [txid: string]: TxTrackingInfo } = {}; + for (const txid of txids) { + const txInfo: TxTrackingInfo = {}; + const outspends = outspendCache[txid]; + if (outspends && Object.keys(outspends).length) { + txInfo.utxoSpent = outspends; + } + const replacedBy = rbfChanges.map[txid] ? rbfCache.getReplacedBy(txid) : false; + if (replacedBy) { + txInfo.replacedBy = replacedBy; } + const mempoolTx = newMempool[txid]; + if (mempoolTx && mempoolTx.position) { + txInfo.position = { + ...mempoolTx.position, + accelerated: mempoolTx.acceleration || undefined, + acceleratedBy: mempoolTx.acceleratedBy || undefined, + acceleratedAt: mempoolTx.acceleratedAt || undefined, + }; + if (!mempoolTx.cpfpChecked) { + calculateMempoolTxCpfp(mempoolTx, newMempool); + } + if (mempoolTx.cpfpDirty) { + txInfo.cpfp = { + ancestors: mempoolTx.ancestors, + bestDescendant: mempoolTx.bestDescendant || null, + descendants: mempoolTx.descendants || null, + effectiveFeePerVsize: mempoolTx.effectiveFeePerVsize || null, + sigops: mempoolTx.sigops, + adjustedVsize: mempoolTx.adjustedVsize, + }; + } + } + txs[txid] = txInfo; + } + if (Object.keys(txs).length) { + response['tracked-txs'] = JSON.stringify(txs); } } + if (client['track-mempool-block'] >= 0 && memPool.isInSync()) { + const index = client['track-mempool-block']; + if (mBlockDeltas[index]) { + response['projected-block-transactions'] = getCachedResponse(`projected-block-transactions-${index}`, { + index: index, + sequence: this.mempoolSequence, + delta: mBlockDeltas[index], + }); + } + } + + if (client['track-rbf'] === 'all' && rbfReplacements) { + response['rbfLatest'] = getCachedResponse('rbfLatest', rbfReplacements); + } else if (client['track-rbf'] === 'fullRbf' && fullRbfReplacements) { + response['rbfLatest'] = getCachedResponse('fullrbfLatest', fullRbfReplacements); + } + + if (client['track-rbf-summary'] && rbfSummary) { + response['rbfLatestSummary'] = getCachedResponse('rbfLatestSummary', rbfSummary); + } + + if (client['track-mempool-txids']) { + response['mempool-txids'] = getCachedResponse('mempool-txids', mempoolDeltaTxids); + } + + if (client['track-mempool']) { + response['mempool-transactions'] = getCachedResponse('mempool-transactions', mempoolDelta); + } + + if (client['track-accelerations'] && (accelerationUpdate.added.length || accelerationUpdate.removed.length)) { + response['accelerations'] = getCachedResponse('accelerations', accelerationUpdate); + } + if (Object.keys(response).length) { - client.send(JSON.stringify(response)); + client.send(this.serializeResponse(response)); } }); + } } - - handleNewBlock(block: Block, txIds: string[], transactions: TransactionExtended[]) { - if (!this.wss) { - throw new Error('WebSocket.Server is not set'); + + async handleNewBlock(block: BlockExtended, txIds: string[], transactions: MempoolTransactionExtended[]): Promise { + if (!this.webSocketServers.length) { + throw new Error('No WebSocket.Server have been set'); } - // Check how many transactions in the new block matches the latest projected mempool block - // If it's more than 0, recalculate the mempool blocks and send to client in the same update - let mBlocks: undefined | MempoolBlock[]; - let matchRate = 0; - const _mempoolBlocks = mempoolBlocks.getMempoolBlocksWithTransactions(); - if (_mempoolBlocks[0]) { - const matches: string[] = []; - for (const txId of txIds) { - if (_mempoolBlocks[0].transactionIds.indexOf(txId) > -1) { - matches.push(txId); + this.printLogs(); + await statistics.runStatistics(); + + const _memPool = memPool.getMempool(); + const candidateTxs = await memPool.getMempoolCandidates(); + let candidates: GbtCandidates | undefined = (memPool.limitGBT && candidateTxs) ? { txs: candidateTxs, added: [], removed: [] } : undefined; + let transactionIds: string[] = (memPool.limitGBT) ? Object.keys(candidates?.txs || {}) : Object.keys(_memPool); + + const accelerations = Object.values(mempool.getAccelerations()); + await accelerationRepository.$indexAccelerationsForBlock(block, accelerations, transactions); + + const rbfTransactions = Common.findMinedRbfTransactions(transactions, memPool.getSpendMap()); + memPool.handleMinedRbfTransactions(rbfTransactions); + memPool.removeFromSpendMap(transactions); + + if (config.MEMPOOL.AUDIT && memPool.isInSync()) { + let projectedBlocks; + const auditMempool = _memPool; + const isAccelerated = config.MEMPOOL_SERVICES.ACCELERATIONS && accelerationApi.isAcceleratedBlock(block, Object.values(mempool.getAccelerations())); + + if ((config.MEMPOOL_SERVICES.ACCELERATIONS)) { + if (config.MEMPOOL.RUST_GBT) { + const added = memPool.limitGBT ? (candidates?.added || []) : []; + const removed = memPool.limitGBT ? (candidates?.removed || []) : []; + projectedBlocks = await mempoolBlocks.$rustUpdateBlockTemplates(transactionIds, auditMempool, added, removed, candidates, isAccelerated, block.extras.pool.id); + } else { + projectedBlocks = await mempoolBlocks.$makeBlockTemplates(transactionIds, auditMempool, candidates, false, isAccelerated, block.extras.pool.id); } + } else { + projectedBlocks = mempoolBlocks.getMempoolBlocksWithTransactions(); } - matchRate = Math.round((matches.length / (txIds.length - 1)) * 100); - if (matchRate > 0) { - const currentMemPool = memPool.getMempool(); - for (const txId of matches) { - delete currentMemPool[txId]; + if (Common.indexingEnabled()) { + const { censored, added, prioritized, fresh, sigop, fullrbf, accelerated, score, similarity } = Audit.auditBlock(transactions, projectedBlocks, auditMempool); + const matchRate = Math.round(score * 100 * 100) / 100; + + const stripped = projectedBlocks[0]?.transactions ? projectedBlocks[0].transactions : []; + + let totalFees = 0; + let totalWeight = 0; + for (const tx of stripped) { + totalFees += tx.fee; + totalWeight += (tx.vsize * 4); + } + + BlocksSummariesRepository.$saveTemplate({ + height: block.height, + template: { + id: block.id, + transactions: stripped, + }, + version: 1, + }); + + BlocksAuditsRepository.$saveAudit({ + time: block.timestamp, + height: block.height, + hash: block.id, + addedTxs: added, + prioritizedTxs: prioritized, + missingTxs: censored, + freshTxs: fresh, + sigopTxs: sigop, + fullrbfTxs: fullrbf, + acceleratedTxs: accelerated, + matchRate: matchRate, + expectedFees: totalFees, + expectedWeight: totalWeight, + }); + + if (block.extras) { + block.extras.matchRate = matchRate; + block.extras.expectedFees = totalFees; + block.extras.expectedWeight = totalWeight; + block.extras.similarity = similarity; } - mempoolBlocks.updateMempoolBlocks(currentMemPool); - mBlocks = mempoolBlocks.getMempoolBlocks(); } + } else if (block.extras) { + const mBlocks = mempoolBlocks.getMempoolBlocksWithTransactions(); + if (mBlocks?.length && mBlocks[0].transactions) { + block.extras.similarity = Common.getSimilarity(mBlocks[0], transactions); + } + } + + const confirmedTxids: { [txid: string]: boolean } = {}; + + // Update mempool to remove transactions included in the new block + for (const txId of txIds) { + delete _memPool[txId]; + rbfCache.mined(txId); + confirmedTxids[txId] = true; + } + + if (memPool.limitGBT) { + const minFeeMempool = memPool.limitGBT ? await bitcoinSecondClient.getRawMemPool() : null; + const minFeeTip = memPool.limitGBT ? await bitcoinSecondClient.getBlockCount() : -1; + candidates = await memPool.getNextCandidates(minFeeMempool, minFeeTip, transactions); + transactionIds = Object.keys(candidates?.txs || {}); + } else { + candidates = undefined; + transactionIds = Object.keys(memPool.getMempool()); + } + + + if (config.MEMPOOL.RUST_GBT) { + const added = memPool.limitGBT ? (candidates?.added || []) : []; + const removed = memPool.limitGBT ? (candidates?.removed || []) : transactions; + await mempoolBlocks.$rustUpdateBlockTemplates(transactionIds, _memPool, added, removed, candidates, true); + } else { + await mempoolBlocks.$makeBlockTemplates(transactionIds, _memPool, candidates, true, config.MEMPOOL_SERVICES.ACCELERATIONS); + } + const mBlocks = mempoolBlocks.getMempoolBlocks(); + const mBlockDeltas = mempoolBlocks.getMempoolBlockDeltas(); + + const da = difficultyAdjustment.getDifficultyAdjustment(); + const fees = feeApi.getRecommendedFee(); + const mempoolInfo = memPool.getMempoolInfo(); + + // pre-compute address transactions + const addressCache = this.makeAddressCache(transactions); + + // update init data + this.updateSocketDataFields({ + 'mempoolInfo': mempoolInfo, + 'blocks': [...blocks.getBlocks(), block].slice(-config.MEMPOOL.INITIAL_BLOCKS_AMOUNT), + 'mempool-blocks': mBlocks, + 'loadingIndicators': loadingIndicators.getLoadingIndicators(), + 'da': da?.previousTime ? da : undefined, + 'fees': fees, + }); + + const mBlocksWithTransactions = mempoolBlocks.getMempoolBlocksWithTransactions(); + + if (memPool.isInSync()) { + this.mempoolSequence++; } - block.matchRate = matchRate; + const replacedTransactions: { replaced: string, by: TransactionExtended }[] = []; + for (const txid of Object.keys(rbfTransactions)) { + for (const replaced of rbfTransactions[txid].replaced) { + replacedTransactions.push({ replaced: replaced.txid, by: rbfTransactions[txid].replacedBy }); + } + } + const mempoolDeltaTxids: MempoolDeltaTxids = { + sequence: this.mempoolSequence, + added: [], + removed: [], + mined: transactions.map(tx => tx.txid), + replaced: replacedTransactions.map(replacement => ({ replaced: replacement.replaced, by: replacement.by.txid })), + }; + const mempoolDelta: MempoolDelta = { + sequence: this.mempoolSequence, + added: [], + removed: [], + mined: transactions.map(tx => tx.txid), + replaced: replacedTransactions, + }; - this.wss.clients.forEach((client) => { + const responseCache = { ...this.socketData }; + function getCachedResponse(key, data): string { + if (!responseCache[key]) { + responseCache[key] = JSON.stringify(data); + } + return responseCache[key]; + } + + // TODO - Fix indentation after PR is merged + for (const server of this.webSocketServers) { + server.clients.forEach((client) => { if (client.readyState !== WebSocket.OPEN) { return; } - if (!client['want-blocks']) { - return; + const response = {}; + + if (client['want-blocks']) { + response['block'] = getCachedResponse('block', block); } - const response = { - 'block': block, - 'mempoolInfo': memPool.getMempoolInfo(), - }; + if (client['want-stats']) { + response['mempoolInfo'] = getCachedResponse('mempoolInfo', mempoolInfo); + response['vBytesPerSecond'] = getCachedResponse('vBytesPerSecond', memPool.getVBytesPerSecond()); + response['fees'] = getCachedResponse('fees', fees); - if (mBlocks && client['want-mempool-blocks']) { - response['mempool-blocks'] = mBlocks; + if (da?.previousTime) { + response['da'] = getCachedResponse('da', da); + } } - if (client['track-tx'] && txIds.indexOf(client['track-tx']) > -1) { - client['track-tx'] = null; - response['txConfirmed'] = true; + if (mBlocks && client['want-mempool-blocks']) { + response['mempool-blocks'] = getCachedResponse('mempool-blocks', mBlocks); } - if (client['track-address']) { - const foundTransactions: TransactionExtended[] = []; + if (client['want-tomahawk']) { + response['tomahawk'] = getCachedResponse('tomahawk', bitcoinApi.getHealthStatus()); + } - transactions.forEach((tx) => { - if (tx.vin && tx.vin.some((vin) => !!vin.prevout && vin.prevout.scriptpubkey_address === client['track-address'])) { - foundTransactions.push(tx); - return; + if (client['track-tx']) { + const trackTxid = client['track-tx']; + if (trackTxid && confirmedTxids[trackTxid]) { + response['txConfirmed'] = JSON.stringify(trackTxid); + } else { + const mempoolTx = _memPool[trackTxid]; + if (mempoolTx && mempoolTx.position) { + response['txPosition'] = JSON.stringify({ + txid: trackTxid, + position: { + ...mempoolTx.position, + accelerated: mempoolTx.acceleration || undefined, + acceleratedBy: mempoolTx.acceleratedBy || undefined, + acceleratedAt: mempoolTx.acceleratedAt || undefined, + }, + accelerationPositions: memPool.getAccelerationPositions(mempoolTx.txid), + }); } - if (tx.vout && tx.vout.some((vout) => vout.scriptpubkey_address === client['track-address'])) { - foundTransactions.push(tx); + } + } + + if (client['track-txs']) { + const txs: { [txid: string]: TxTrackingInfo } = {}; + for (const txid of client['track-txs']) { + if (confirmedTxids[txid]) { + txs[txid] = { confirmed: true }; + } else { + const mempoolTx = _memPool[txid]; + if (mempoolTx && mempoolTx.position) { + txs[txid] = { + position: { + ...mempoolTx.position, + }, + accelerated: mempoolTx.acceleration || undefined, + acceleratedBy: mempoolTx.acceleratedBy || undefined, + acceleratedAt: mempoolTx.acceleratedAt || undefined, + }; + } } - }); + } + if (Object.keys(txs).length) { + response['tracked-txs'] = JSON.stringify(txs); + } + } + + if (client['track-address']) { + const foundTransactions: TransactionExtended[] = Array.from(addressCache[client['track-address']]?.values() || []); if (foundTransactions.length) { foundTransactions.forEach((tx) => { @@ -304,7 +1186,43 @@ class WebsocketHandler { }; }); - response['block-transactions'] = foundTransactions; + response['block-transactions'] = JSON.stringify(foundTransactions); + } + } + + if (client['track-addresses']) { + const addressMap: { [address: string]: AddressTransactions } = {}; + for (const [address, key] of Object.entries(client['track-addresses'] || {})) { + const fullTransactions = Array.from(addressCache[key as string]?.values() || []); + if (fullTransactions?.length) { + addressMap[address] = { + mempool: [], + confirmed: fullTransactions, + removed: [], + }; + } + } + + if (Object.keys(addressMap).length > 0) { + response['multi-address-transactions'] = JSON.stringify(addressMap); + } + } + + if (client['track-scriptpubkeys']) { + const spkMap: { [spk: string]: AddressTransactions } = {}; + for (const spk of client['track-scriptpubkeys'] || []) { + const fullTransactions = Array.from(addressCache[spk as string]?.values() || []); + if (fullTransactions?.length) { + spkMap[spk] = { + mempool: [], + confirmed: fullTransactions, + removed: [], + }; + } + } + + if (Object.keys(spkMap).length > 0) { + response['multi-scriptpubkey-transactions'] = JSON.stringify(spkMap); } } @@ -312,7 +1230,7 @@ class WebsocketHandler { const foundTransactions: TransactionExtended[] = []; transactions.forEach((tx) => { - if (client['track-asset'] === this.nativeAssetId) { + if (client['track-asset'] === Common.nativeAssetId) { if (tx.vin && tx.vin.some((vin) => !!vin.is_pegin)) { foundTransactions.push(tx); return; @@ -341,12 +1259,159 @@ class WebsocketHandler { }; }); - response['block-transactions'] = foundTransactions; + response['block-transactions'] = JSON.stringify(foundTransactions); + } + } + + if (client['track-mempool-block'] >= 0 && memPool.isInSync()) { + const index = client['track-mempool-block']; + + if (mBlockDeltas && mBlockDeltas[index] && mBlocksWithTransactions[index]?.transactions?.length) { + if (mBlockDeltas[index].added.length > (mBlocksWithTransactions[index]?.transactions.length / 2)) { + response['projected-block-transactions'] = getCachedResponse(`projected-block-transactions-full-${index}`, { + index: index, + sequence: this.mempoolSequence, + blockTransactions: mBlocksWithTransactions[index].transactions.map(mempoolBlocks.compressTx), + }); + } else { + response['projected-block-transactions'] = getCachedResponse(`projected-block-transactions-delta-${index}`, { + index: index, + sequence: this.mempoolSequence, + delta: mBlockDeltas[index], + }); + } } } - client.send(JSON.stringify(response)); + if (client['track-mempool-txids']) { + response['mempool-txids'] = getCachedResponse('mempool-txids', mempoolDeltaTxids); + } + + if (client['track-mempool']) { + response['mempool-transactions'] = getCachedResponse('mempool-transactions', mempoolDelta); + } + + if (Object.keys(response).length) { + client.send(this.serializeResponse(response)); + } }); + } + + await statistics.runStatistics(); + } + + // takes a dictionary of JSON serialized values + // and zips it together into a valid JSON object + private serializeResponse(response): string { + return '{' + + Object.keys(response).filter(key => response[key] != null).map(key => `"${key}": ${response[key]}`).join(', ') + + '}'; + } + + // checks if an address conforms to a valid format + // returns the canonical form: + // - lowercase for bech32(m) + // - lowercase scriptpubkey for P2PK + // or false if invalid + private testAddress(address): string | false { + if (/^([a-km-zA-HJ-NP-Z1-9]{26,35}|[a-km-zA-HJ-NP-Z1-9]{80}|[a-z]{2,5}1[ac-hj-np-z02-9]{8,100}|[A-Z]{2,5}1[AC-HJ-NP-Z02-9]{8,100}|04[a-fA-F0-9]{128}|(02|03)[a-fA-F0-9]{64})$/.test(address)) { + if (/^[A-Z]{2,5}1[AC-HJ-NP-Z02-9]{8,100}|04[a-fA-F0-9]{128}|(02|03)[a-fA-F0-9]{64}$/.test(address)) { + address = address.toLowerCase(); + } + if (/^04[a-fA-F0-9]{128}$/.test(address)) { + return '41' + address + 'ac'; + } else if (/^(02|03)[a-fA-F0-9]{64}$/.test(address)) { + return '21' + address + 'ac'; + } else { + return address; + } + } else { + return false; + } + } + + private makeAddressCache(transactions: MempoolTransactionExtended[]): { [address: string]: Set } { + const addressCache: { [address: string]: Set } = {}; + for (const tx of transactions) { + for (const vin of tx.vin) { + if (vin?.prevout?.scriptpubkey_address) { + if (!addressCache[vin.prevout.scriptpubkey_address]) { + addressCache[vin.prevout.scriptpubkey_address] = new Set(); + } + addressCache[vin.prevout.scriptpubkey_address].add(tx); + } + if (vin?.prevout?.scriptpubkey) { + if (!addressCache[vin.prevout.scriptpubkey]) { + addressCache[vin.prevout.scriptpubkey] = new Set(); + } + addressCache[vin.prevout.scriptpubkey].add(tx); + } + } + for (const vout of tx.vout) { + if (vout?.scriptpubkey_address) { + if (!addressCache[vout?.scriptpubkey_address]) { + addressCache[vout?.scriptpubkey_address] = new Set(); + } + addressCache[vout?.scriptpubkey_address].add(tx); + } + if (vout?.scriptpubkey) { + if (!addressCache[vout.scriptpubkey]) { + addressCache[vout.scriptpubkey] = new Set(); + } + addressCache[vout.scriptpubkey].add(tx); + } + } + } + return addressCache; + } + + private async getFullTransactions(transactions: MempoolTransactionExtended[]): Promise { + for (let i = 0; i < transactions.length; i++) { + try { + transactions[i] = await transactionUtils.$getMempoolTransactionExtended(transactions[i].txid, true); + } catch (e) { + logger.debug('Error finding transaction in mempool: ' + (e instanceof Error ? e.message : e)); + } + } + return transactions; + } + + private printLogs(): void { + if (this.webSocketServers.length) { + let numTxSubs = 0; + let numTxsSubs = 0; + let numProjectedSubs = 0; + let numRbfSubs = 0; + + // TODO - Fix indentation after PR is merged + for (const server of this.webSocketServers) { + server.clients.forEach((client) => { + if (client['track-tx']) { + numTxSubs++; + } + if (client['track-txs']) { + numTxsSubs++; + } + if (client['track-mempool-block'] != null && client['track-mempool-block'] >= 0) { + numProjectedSubs++; + } + if (client['track-rbf']) { + numRbfSubs++; + } + }) + } + + let count = 0; + for (const server of this.webSocketServers) { + count += server.clients?.size || 0; + } + const diff = count - this.numClients; + this.numClients = count; + logger.debug(`${count} websocket clients | ${this.numConnected} connected | ${this.numDisconnected} disconnected | (${diff >= 0 ? '+' : ''}${diff})`); + logger.debug(`websocket subscriptions: track-tx: ${numTxSubs}, track-txs: ${numTxsSubs}, track-mempool-block: ${numProjectedSubs} track-rbf: ${numRbfSubs}`); + this.numConnected = 0; + this.numDisconnected = 0; + } } } diff --git a/backend/src/config.ts b/backend/src/config.ts new file mode 100644 index 0000000000..b0afe7f23c --- /dev/null +++ b/backend/src/config.ts @@ -0,0 +1,378 @@ +const configFromFile = require( + process.env.MEMPOOL_CONFIG_FILE ? process.env.MEMPOOL_CONFIG_FILE : '../mempool-config.json' +); + +interface IConfig { + MEMPOOL: { + ENABLED: boolean; + OFFICIAL: boolean; + NETWORK: 'mainnet' | 'testnet' | 'signet' | 'liquid' | 'liquidtestnet'; + BACKEND: 'esplora' | 'electrum' | 'none'; + HTTP_PORT: number; + UNIX_SOCKET_PATH: string; + SPAWN_CLUSTER_PROCS: number; + API_URL_PREFIX: string; + POLL_RATE_MS: number; + CACHE_DIR: string; + CACHE_ENABLED: boolean; + CLEAR_PROTECTION_MINUTES: number; + RECOMMENDED_FEE_PERCENTILE: number; + BLOCK_WEIGHT_UNITS: number; + INITIAL_BLOCKS_AMOUNT: number; + MEMPOOL_BLOCKS_AMOUNT: number; + INDEXING_BLOCKS_AMOUNT: number; + BLOCKS_SUMMARIES_INDEXING: boolean; + GOGGLES_INDEXING: boolean; + USE_SECOND_NODE_FOR_MINFEE: boolean; + EXTERNAL_ASSETS: string[]; + EXTERNAL_MAX_RETRY: number; + EXTERNAL_RETRY_INTERVAL: number; + USER_AGENT: string; + STDOUT_LOG_MIN_PRIORITY: 'emerg' | 'alert' | 'crit' | 'err' | 'warn' | 'notice' | 'info' | 'debug'; + AUTOMATIC_POOLS_UPDATE: boolean; + POOLS_JSON_URL: string, + POOLS_JSON_TREE_URL: string, + AUDIT: boolean; + RUST_GBT: boolean; + LIMIT_GBT: boolean; + CPFP_INDEXING: boolean; + MAX_BLOCKS_BULK_QUERY: number; + DISK_CACHE_BLOCK_INTERVAL: number; + MAX_PUSH_TX_SIZE_WEIGHT: number; + ALLOW_UNREACHABLE: boolean; + PRICE_UPDATES_PER_HOUR: number; + MAX_TRACKED_ADDRESSES: number; + }; + ESPLORA: { + REST_API_URL: string; + UNIX_SOCKET_PATH: string | void | null; + BATCH_QUERY_BASE_SIZE: number; + RETRY_UNIX_SOCKET_AFTER: number; + REQUEST_TIMEOUT: number; + FALLBACK_TIMEOUT: number; + FALLBACK: string[]; + MAX_BEHIND_TIP: number; + }; + LIGHTNING: { + ENABLED: boolean; + BACKEND: 'lnd' | 'cln' | 'ldk'; + TOPOLOGY_FOLDER: string; + STATS_REFRESH_INTERVAL: number; + GRAPH_REFRESH_INTERVAL: number; + LOGGER_UPDATE_INTERVAL: number; + FORENSICS_INTERVAL: number; + FORENSICS_RATE_LIMIT: number; + }; + LND: { + TLS_CERT_PATH: string; + MACAROON_PATH: string; + REST_API_URL: string; + TIMEOUT: number; + }; + CLIGHTNING: { + SOCKET: string; + }; + ELECTRUM: { + HOST: string; + PORT: number; + TLS_ENABLED: boolean; + }; + CORE_RPC: { + HOST: string; + PORT: number; + USERNAME: string; + PASSWORD: string; + TIMEOUT: number; + COOKIE: boolean; + COOKIE_PATH: string; + }; + SECOND_CORE_RPC: { + HOST: string; + PORT: number; + USERNAME: string; + PASSWORD: string; + TIMEOUT: number; + COOKIE: boolean; + COOKIE_PATH: string; + }; + DATABASE: { + ENABLED: boolean; + HOST: string, + SOCKET: string, + PORT: number; + DATABASE: string; + USERNAME: string; + PASSWORD: string; + TIMEOUT: number; + PID_DIR: string; + POOL_SIZE: number; + }; + SYSLOG: { + ENABLED: boolean; + HOST: string; + PORT: number; + MIN_PRIORITY: 'emerg' | 'alert' | 'crit' | 'err' | 'warn' | 'notice' | 'info' | 'debug'; + FACILITY: string; + }; + STATISTICS: { + ENABLED: boolean; + TX_PER_SECOND_SAMPLE_PERIOD: number; + }; + SOCKS5PROXY: { + ENABLED: boolean; + USE_ONION: boolean; + HOST: string; + PORT: number; + USERNAME: string; + PASSWORD: string; + }; + EXTERNAL_DATA_SERVER: { + MEMPOOL_API: string; + MEMPOOL_ONION: string; + LIQUID_API: string; + LIQUID_ONION: string; + }; + MAXMIND: { + ENABLED: boolean; + GEOLITE2_CITY: string; + GEOLITE2_ASN: string; + GEOIP2_ISP: string; + }, + REPLICATION: { + ENABLED: boolean; + AUDIT: boolean; + AUDIT_START_HEIGHT: number; + STATISTICS: boolean; + STATISTICS_START_TIME: number | string; + SERVERS: string[]; + }, + MEMPOOL_SERVICES: { + API: string; + ACCELERATIONS: boolean; + }, + REDIS: { + ENABLED: boolean; + UNIX_SOCKET_PATH: string; + BATCH_QUERY_BASE_SIZE: number; + }, + FIAT_PRICE: { + ENABLED: boolean; + PAID: boolean; + API_KEY: string; + }, +} + +const defaults: IConfig = { + 'MEMPOOL': { + 'ENABLED': true, + 'OFFICIAL': false, + 'NETWORK': 'mainnet', + 'BACKEND': 'none', + 'HTTP_PORT': 8999, + 'UNIX_SOCKET_PATH': '', + 'SPAWN_CLUSTER_PROCS': 0, + 'API_URL_PREFIX': '/api/v1/', + 'POLL_RATE_MS': 2000, + 'CACHE_DIR': './cache', + 'CACHE_ENABLED': true, + 'CLEAR_PROTECTION_MINUTES': 20, + 'RECOMMENDED_FEE_PERCENTILE': 50, + 'BLOCK_WEIGHT_UNITS': 4000000, + 'INITIAL_BLOCKS_AMOUNT': 8, + 'MEMPOOL_BLOCKS_AMOUNT': 8, + 'INDEXING_BLOCKS_AMOUNT': 11000, // 0 = disable indexing, -1 = index all blocks + 'BLOCKS_SUMMARIES_INDEXING': false, + 'GOGGLES_INDEXING': false, + 'USE_SECOND_NODE_FOR_MINFEE': false, + 'EXTERNAL_ASSETS': [], + 'EXTERNAL_MAX_RETRY': 1, + 'EXTERNAL_RETRY_INTERVAL': 0, + 'USER_AGENT': 'mempool', + 'STDOUT_LOG_MIN_PRIORITY': 'debug', + 'AUTOMATIC_POOLS_UPDATE': false, + 'POOLS_JSON_URL': 'https://raw.githubusercontent.com/mempool/mining-pools/master/pools-v2.json', + 'POOLS_JSON_TREE_URL': 'https://api.github.com/repos/mempool/mining-pools/git/trees/master', + 'AUDIT': false, + 'RUST_GBT': false, + 'LIMIT_GBT': false, + 'CPFP_INDEXING': false, + 'MAX_BLOCKS_BULK_QUERY': 0, + 'DISK_CACHE_BLOCK_INTERVAL': 6, + 'MAX_PUSH_TX_SIZE_WEIGHT': 400000, + 'ALLOW_UNREACHABLE': true, + 'PRICE_UPDATES_PER_HOUR': 1, + 'MAX_TRACKED_ADDRESSES': 1, + }, + 'ESPLORA': { + 'REST_API_URL': 'http://127.0.0.1:3000', + 'UNIX_SOCKET_PATH': null, + 'BATCH_QUERY_BASE_SIZE': 1000, + 'RETRY_UNIX_SOCKET_AFTER': 30000, + 'REQUEST_TIMEOUT': 10000, + 'FALLBACK_TIMEOUT': 5000, + 'FALLBACK': [], + 'MAX_BEHIND_TIP': 2, + }, + 'ELECTRUM': { + 'HOST': '127.0.0.1', + 'PORT': 3306, + 'TLS_ENABLED': true, + }, + 'CORE_RPC': { + 'HOST': '127.0.0.1', + 'PORT': 8332, + 'USERNAME': 'mempool', + 'PASSWORD': 'mempool', + 'TIMEOUT': 60000, + 'COOKIE': false, + 'COOKIE_PATH': '/bitcoin/.cookie' + }, + 'SECOND_CORE_RPC': { + 'HOST': '127.0.0.1', + 'PORT': 8332, + 'USERNAME': 'mempool', + 'PASSWORD': 'mempool', + 'TIMEOUT': 60000, + 'COOKIE': false, + 'COOKIE_PATH': '/bitcoin/.cookie' + }, + 'DATABASE': { + 'ENABLED': true, + 'HOST': '127.0.0.1', + 'SOCKET': '', + 'PORT': 3306, + 'DATABASE': 'mempool', + 'USERNAME': 'mempool', + 'PASSWORD': 'mempool', + 'TIMEOUT': 180000, + 'PID_DIR': '', + 'POOL_SIZE': 100, + }, + 'SYSLOG': { + 'ENABLED': true, + 'HOST': '127.0.0.1', + 'PORT': 514, + 'MIN_PRIORITY': 'info', + 'FACILITY': 'local7' + }, + 'STATISTICS': { + 'ENABLED': true, + 'TX_PER_SECOND_SAMPLE_PERIOD': 150 + }, + 'LIGHTNING': { + 'ENABLED': false, + 'BACKEND': 'lnd', + 'TOPOLOGY_FOLDER': '', + 'STATS_REFRESH_INTERVAL': 600, + 'GRAPH_REFRESH_INTERVAL': 600, + 'LOGGER_UPDATE_INTERVAL': 30, + 'FORENSICS_INTERVAL': 43200, + 'FORENSICS_RATE_LIMIT': 20, + }, + 'LND': { + 'TLS_CERT_PATH': '', + 'MACAROON_PATH': '', + 'REST_API_URL': 'https://localhost:8080', + 'TIMEOUT': 10000, + }, + 'CLIGHTNING': { + 'SOCKET': '', + }, + 'SOCKS5PROXY': { + 'ENABLED': false, + 'USE_ONION': true, + 'HOST': '127.0.0.1', + 'PORT': 9050, + 'USERNAME': '', + 'PASSWORD': '' + }, + 'EXTERNAL_DATA_SERVER': { + 'MEMPOOL_API': 'https://mempool.space/api/v1', + 'MEMPOOL_ONION': 'http://mempoolhqx4isw62xs7abwphsq7ldayuidyx2v2oethdhhj6mlo2r6ad.onion/api/v1', + 'LIQUID_API': 'https://liquid.network/api/v1', + 'LIQUID_ONION': 'http://liquidmom47f6s3m53ebfxn47p76a6tlnxib3wp6deux7wuzotdr6cyd.onion/api/v1' + }, + 'MAXMIND': { + 'ENABLED': false, + 'GEOLITE2_CITY': '/usr/local/share/GeoIP/GeoLite2-City.mmdb', + 'GEOLITE2_ASN': '/usr/local/share/GeoIP/GeoLite2-ASN.mmdb', + 'GEOIP2_ISP': '/usr/local/share/GeoIP/GeoIP2-ISP.mmdb' + }, + 'REPLICATION': { + 'ENABLED': false, + 'AUDIT': false, + 'AUDIT_START_HEIGHT': 774000, + 'STATISTICS': false, + 'STATISTICS_START_TIME': 1481932800, + 'SERVERS': [], + }, + 'MEMPOOL_SERVICES': { + 'API': '', + 'ACCELERATIONS': false, + }, + 'REDIS': { + 'ENABLED': false, + 'UNIX_SOCKET_PATH': '', + 'BATCH_QUERY_BASE_SIZE': 5000, + }, + 'FIAT_PRICE': { + 'ENABLED': true, + 'PAID': false, + 'API_KEY': '', + }, +}; + +class Config implements IConfig { + MEMPOOL: IConfig['MEMPOOL']; + ESPLORA: IConfig['ESPLORA']; + ELECTRUM: IConfig['ELECTRUM']; + CORE_RPC: IConfig['CORE_RPC']; + SECOND_CORE_RPC: IConfig['SECOND_CORE_RPC']; + DATABASE: IConfig['DATABASE']; + SYSLOG: IConfig['SYSLOG']; + STATISTICS: IConfig['STATISTICS']; + LIGHTNING: IConfig['LIGHTNING']; + LND: IConfig['LND']; + CLIGHTNING: IConfig['CLIGHTNING']; + SOCKS5PROXY: IConfig['SOCKS5PROXY']; + EXTERNAL_DATA_SERVER: IConfig['EXTERNAL_DATA_SERVER']; + MAXMIND: IConfig['MAXMIND']; + REPLICATION: IConfig['REPLICATION']; + MEMPOOL_SERVICES: IConfig['MEMPOOL_SERVICES']; + REDIS: IConfig['REDIS']; + FIAT_PRICE: IConfig['FIAT_PRICE']; + + constructor() { + const configs = this.merge(configFromFile, defaults); + this.MEMPOOL = configs.MEMPOOL; + this.ESPLORA = configs.ESPLORA; + this.ELECTRUM = configs.ELECTRUM; + this.CORE_RPC = configs.CORE_RPC; + this.SECOND_CORE_RPC = configs.SECOND_CORE_RPC; + this.DATABASE = configs.DATABASE; + this.SYSLOG = configs.SYSLOG; + this.STATISTICS = configs.STATISTICS; + this.LIGHTNING = configs.LIGHTNING; + this.LND = configs.LND; + this.CLIGHTNING = configs.CLIGHTNING; + this.SOCKS5PROXY = configs.SOCKS5PROXY; + this.EXTERNAL_DATA_SERVER = configs.EXTERNAL_DATA_SERVER; + this.MAXMIND = configs.MAXMIND; + this.REPLICATION = configs.REPLICATION; + this.MEMPOOL_SERVICES = configs.MEMPOOL_SERVICES; + this.REDIS = configs.REDIS; + this.FIAT_PRICE = configs.FIAT_PRICE; + } + + merge = (...objects: object[]): IConfig => { + // @ts-ignore + return objects.reduce((prev, next) => { + Object.keys(prev).forEach(key => { + next[key] = { ...next[key], ...prev[key] }; + }); + return next; + }); + } +} + +export default new Config(); diff --git a/backend/src/database.ts b/backend/src/database.ts index a151ced490..595b88c780 100644 --- a/backend/src/database.ts +++ b/backend/src/database.ts @@ -1,26 +1,180 @@ -const config = require('../mempool-config.json'); -import { createPool } from 'mysql2/promise'; - -export class DB { - static pool = createPool({ - host: config.DB_HOST, - port: config.DB_PORT, - database: config.DB_DATABASE, - user: config.DB_USER, - password: config.DB_PASSWORD, - connectionLimit: 10, +import * as fs from 'fs'; +import path from 'path'; +import config from './config'; +import { createPool, Pool, PoolConnection } from 'mysql2/promise'; +import logger, { LogLevel } from './logger'; +import { FieldPacket, OkPacket, PoolOptions, ResultSetHeader, RowDataPacket } from 'mysql2/typings/mysql'; +import { execSync } from 'child_process'; + + class DB { + constructor() { + if (config.DATABASE.SOCKET !== '') { + this.poolConfig.socketPath = config.DATABASE.SOCKET; + } else { + this.poolConfig.host = config.DATABASE.HOST; + } + } + private pool: Pool | null = null; + private poolConfig: PoolOptions = { + port: config.DATABASE.PORT, + database: config.DATABASE.DATABASE, + user: config.DATABASE.USERNAME, + password: config.DATABASE.PASSWORD, + connectionLimit: config.DATABASE.POOL_SIZE, supportBigNumbers: true, - }); -} + timezone: '+00:00', + }; + + private checkDBFlag() { + if (config.DATABASE.ENABLED === false) { + const stack = new Error().stack; + logger.err(`Trying to use DB feature but config.DATABASE.ENABLED is set to false, please open an issue.\nStack trace: ${stack}}`); + } + } + + public async query(query, params?, errorLogLevel: LogLevel | 'silent' = 'debug', connection?: PoolConnection): Promise<[T, FieldPacket[]]> + { + this.checkDBFlag(); + let hardTimeout; + if (query?.timeout != null) { + hardTimeout = Math.floor(query.timeout * 1.1); + } else { + hardTimeout = config.DATABASE.TIMEOUT; + } + if (hardTimeout > 0) { + return new Promise((resolve, reject) => { + const timer = setTimeout(() => { + reject(new Error(`DB query failed to return, reject or time out within ${hardTimeout / 1000}s - ${query?.sql?.slice(0, 160) || (typeof(query) === 'string' || query instanceof String ? query?.slice(0, 160) : 'unknown query')}`)); + }, hardTimeout); + + // Use a specific connection if provided, otherwise delegate to the pool + const connectionPromise = connection ? Promise.resolve(connection) : this.getPool(); + connectionPromise.then((pool: PoolConnection | Pool) => { + return pool.query(query, params) as Promise<[T, FieldPacket[]]>; + }).then(result => { + resolve(result); + }).catch(error => { + if (errorLogLevel !== 'silent') { + logger[errorLogLevel](`database query "${query?.sql?.slice(0, 160) || (typeof(query) === 'string' || query instanceof String ? query?.slice(0, 160) : 'unknown query')}" failed!`); + } + reject(error); + }).finally(() => { + clearTimeout(timer); + }); + }); + } else { + try { + const pool = await this.getPool(); + return pool.query(query, params); + } catch (e) { + if (errorLogLevel !== 'silent') { + logger[errorLogLevel](`database query "${query?.sql?.slice(0, 160) || (typeof(query) === 'string' || query instanceof String ? query?.slice(0, 160) : 'unknown query')}" failed!`); + } + throw e; + } + } + } + + private async $rollbackAtomic(connection: PoolConnection): Promise { + try { + await connection.rollback(); + await connection.release(); + } catch (e) { + logger.warn('Failed to rollback incomplete db transaction: ' + (e instanceof Error ? e.message : e)); + } + } + + public async $atomicQuery(queries: { query, params }[], errorLogLevel: LogLevel | 'silent' = 'debug'): Promise<[T, FieldPacket[]][]> + { + const pool = await this.getPool(); + const connection = await pool.getConnection(); + try { + await connection.beginTransaction(); + + const results: [T, FieldPacket[]][] = []; + for (const query of queries) { + const result = await this.query(query.query, query.params, errorLogLevel, connection) as [T, FieldPacket[]]; + results.push(result); + } + + await connection.commit(); -export async function checkDbConnection() { - try { - const connection = await DB.pool.getConnection(); - console.log('MySQL connection established.'); - connection.release(); - } catch (e) { - console.log('Could not connect to MySQL.'); - console.log(e); - process.exit(1); + return results; + } catch (e) { + logger.warn('Could not complete db transaction, rolling back: ' + (e instanceof Error ? e.message : e)); + this.$rollbackAtomic(connection); + throw e; + } finally { + connection.release(); + } + } + + public async checkDbConnection() { + this.checkDBFlag(); + try { + await this.query('SELECT ?', [1]); + logger.info('Database connection established.'); + } catch (e) { + logger.err('Could not connect to database: ' + (e instanceof Error ? e.message : e)); + process.exit(1); + } + } + + public getPidLock(): boolean { + const filePath = path.join(config.DATABASE.PID_DIR || __dirname, `/mempool-${config.DATABASE.DATABASE}.pid`); + this.enforcePidLock(filePath); + fs.writeFileSync(filePath, `${process.pid}`); + return true; + } + + private enforcePidLock(filePath: string): void { + if (fs.existsSync(filePath)) { + const pid = parseInt(fs.readFileSync(filePath, 'utf-8')); + if (pid === process.pid) { + logger.warn('PID file already exists for this process'); + return; + } + + let cmd; + try { + cmd = execSync(`ps -p ${pid} -o args=`); + } catch (e) { + logger.warn(`Stale PID file at ${filePath}, but no process running on that PID ${pid}`); + return; + } + + if (cmd && cmd.toString()?.includes('node')) { + const msg = `Another mempool nodejs process is already running on PID ${pid}`; + logger.err(msg); + throw new Error(msg); + } else { + logger.warn(`Stale PID file at ${filePath}, but the PID ${pid} does not belong to a running mempool instance`); + } + } + } + + public releasePidLock(): void { + const filePath = path.join(config.DATABASE.PID_DIR || __dirname, `/mempool-${config.DATABASE.DATABASE}.pid`); + if (fs.existsSync(filePath)) { + const pid = parseInt(fs.readFileSync(filePath, 'utf-8')); + // only release our own pid file + if (pid === process.pid) { + fs.unlinkSync(filePath); + } + } + } + + private async getPool(): Promise { + if (this.pool === null) { + this.pool = createPool(this.poolConfig); + this.pool.on('connection', function (newConnection: PoolConnection) { + newConnection.query(`SET time_zone='+00:00'`); + }); + } + return this.pool; } } + +export default new DB(); diff --git a/backend/src/index.ts b/backend/src/index.ts index 09371d54ab..2a1afc7120 100644 --- a/backend/src/index.ts +++ b/backend/src/index.ts @@ -1,108 +1,381 @@ -const config = require('../mempool-config.json'); -import { Express, Request, Response, NextFunction } from 'express'; -import * as fs from 'fs'; -import * as express from 'express'; -import * as compression from 'compression'; +import express from 'express'; +import { Application, Request, Response, NextFunction } from 'express'; import * as http from 'http'; -import * as https from 'https'; import * as WebSocket from 'ws'; - -import routes from './routes'; +import bitcoinApi from './api/bitcoin/bitcoin-api-factory'; +import cluster from 'cluster'; +import DB from './database'; +import config from './config'; import blocks from './api/blocks'; import memPool from './api/mempool'; import diskCache from './api/disk-cache'; -import statistics from './api/statistics'; +import statistics from './api/statistics/statistics'; import websocketHandler from './api/websocket-handler'; -import fiatConversion from './api/fiat-conversion'; -import bisq from './api/bisq'; +import logger from './logger'; +import backendInfo from './api/backend-info'; +import loadingIndicators from './api/loading-indicators'; +import mempool from './api/mempool'; +import elementsParser from './api/liquid/elements-parser'; +import databaseMigration from './api/database-migration'; +import syncAssets from './sync-assets'; +import icons from './api/liquid/icons'; +import { Common } from './api/common'; +import poolsUpdater from './tasks/pools-updater'; +import indexer from './indexer'; +import nodesRoutes from './api/explorer/nodes.routes'; +import channelsRoutes from './api/explorer/channels.routes'; +import generalLightningRoutes from './api/explorer/general.routes'; +import lightningStatsUpdater from './tasks/lightning/stats-updater.service'; +import networkSyncService from './tasks/lightning/network-sync.service'; +import statisticsRoutes from './api/statistics/statistics.routes'; +import pricesRoutes from './api/prices/prices.routes'; +import miningRoutes from './api/mining/mining-routes'; +import liquidRoutes from './api/liquid/liquid.routes'; +import bitcoinRoutes from './api/bitcoin/bitcoin.routes'; +import fundingTxFetcher from './tasks/lightning/sync-tasks/funding-tx-fetcher'; +import forensicsService from './tasks/lightning/forensics.service'; +import priceUpdater from './tasks/price-updater'; +import chainTips from './api/chain-tips'; +import { AxiosError } from 'axios'; +import v8 from 'v8'; +import { formatBytes, getBytesUnit } from './utils/format'; +import redisCache from './api/redis-cache'; +import accelerationApi from './api/services/acceleration'; +import bitcoinCoreRoutes from './api/bitcoin/bitcoin-core.routes'; +import bitcoinSecondClient from './api/bitcoin/bitcoin-second-client'; +import accelerationRoutes from './api/acceleration/acceleration.routes'; +import aboutRoutes from './api/about.routes'; +import mempoolBlocks from './api/mempool-blocks'; class Server { - wss: WebSocket.Server; - server: https.Server | http.Server; - app: Express; + private wss: WebSocket.Server | undefined; + private wssUnixSocket: WebSocket.Server | undefined; + private server: http.Server | undefined; + private serverUnixSocket: http.Server | undefined; + private app: Application; + private currentBackendRetryInterval = 1; + private backendRetryCount = 0; + + private maxHeapSize: number = 0; + private heapLogInterval: number = 60; + private warnedHeapCritical: boolean = false; + private lastHeapLogTime: number | null = null; constructor() { this.app = express(); + if (!config.MEMPOOL.SPAWN_CLUSTER_PROCS) { + this.startServer(); + return; + } + + if (cluster.isPrimary) { + logger.notice(`Mempool Server (Master) is running on port ${config.MEMPOOL.HTTP_PORT} (${backendInfo.getShortCommitHash()})`); + + const numCPUs = config.MEMPOOL.SPAWN_CLUSTER_PROCS; + for (let i = 0; i < numCPUs; i++) { + const env = { workerId: i }; + const worker = cluster.fork(env); + worker.process['env'] = env; + } + + cluster.on('exit', (worker, code, signal) => { + const workerId = worker.process['env'].workerId; + logger.warn(`Mempool Worker PID #${worker.process.pid} workerId: ${workerId} died. Restarting in 10 seconds... ${signal || code}`); + setTimeout(() => { + const env = { workerId: workerId }; + const newWorker = cluster.fork(env); + newWorker.process['env'] = env; + }, 10000); + }); + } else { + this.startServer(true); + } + } + + async startServer(worker = false): Promise { + logger.notice(`Starting Mempool Server${worker ? ' (worker)' : ''}... (${backendInfo.getShortCommitHash()})`); + + // Register cleanup listeners for exit events + ['exit', 'SIGHUP', 'SIGINT', 'SIGTERM', 'SIGUSR1', 'SIGUSR2'].forEach(event => { + process.on(event, () => { this.onExit(event); }); + }); + process.on('uncaughtException', (error) => { + this.onUnhandledException('uncaughtException', error); + }); + process.on('unhandledRejection', (reason, promise) => { + this.onUnhandledException('unhandledRejection', reason); + }); + + if (config.MEMPOOL.BACKEND === 'esplora') { + bitcoinApi.startHealthChecks(); + } + + if (config.DATABASE.ENABLED) { + DB.getPidLock(); + + await DB.checkDbConnection(); + try { + if (process.env.npm_config_reindex_blocks === 'true') { // Re-index requests + await databaseMigration.$blocksReindexingTruncate(); + } + await databaseMigration.$initializeOrMigrateDatabase(); + } catch (e) { + throw new Error(e instanceof Error ? e.message : 'Error'); + } + } + this.app .use((req: Request, res: Response, next: NextFunction) => { res.setHeader('Access-Control-Allow-Origin', '*'); next(); }) - .use(compression()); + .use(express.urlencoded({ extended: true })) + .use(express.text({ type: ['text/plain', 'application/base64'] })) + .use(express.json()) + ; - if (config.SSL === true) { - const credentials = { - cert: fs.readFileSync(config.SSL_CERT_FILE_PATH), - key: fs.readFileSync(config.SSL_KEY_FILE_PATH), + if (config.DATABASE.ENABLED && config.FIAT_PRICE.ENABLED) { + await priceUpdater.$initializeLatestPriceWithDb(); + } + + this.server = http.createServer(this.app); + this.wss = new WebSocket.Server({ server: this.server }); + if (config.MEMPOOL.UNIX_SOCKET_PATH) { + this.serverUnixSocket = http.createServer(this.app); + this.wssUnixSocket = new WebSocket.Server({ server: this.serverUnixSocket }); + } + + this.setUpWebsocketHandling(); + + await poolsUpdater.updatePoolsJson(); // Needs to be done before loading the disk cache because we sometimes wipe it + await syncAssets.syncAssets$(); + await mempoolBlocks.updatePools$(); + if (config.MEMPOOL.ENABLED) { + if (config.MEMPOOL.CACHE_ENABLED) { + await diskCache.$loadMempoolCache(); + } else if (config.REDIS.ENABLED) { + await redisCache.$loadCache(); + } + } + + if (config.STATISTICS.ENABLED && config.DATABASE.ENABLED && cluster.isPrimary) { + statistics.startStatistics(); + } + + if (Common.isLiquid()) { + const refreshIcons = () => { + try { + icons.loadIcons(); + } catch (e) { + logger.err('Cannot load liquid icons. Ignoring. Reason: ' + (e instanceof Error ? e.message : e)); + } }; - this.server = https.createServer(credentials, this.app); - this.wss = new WebSocket.Server({ server: this.server }); - } else { - this.server = http.createServer(this.app); - this.wss = new WebSocket.Server({ server: this.server }); + // Run once on startup. + refreshIcons(); + // Matches crontab refresh interval for asset db. + setInterval(refreshIcons, 3600_000); + } + + if (config.FIAT_PRICE.ENABLED) { + priceUpdater.$run(); } + await chainTips.updateOrphanedBlocks(); this.setUpHttpApiRoutes(); - this.setUpWebsocketHandling(); - this.runMempoolIntervalFunctions(); - statistics.startStatistics(); - fiatConversion.startService(); - diskCache.loadMempoolCache(); + if (config.MEMPOOL.ENABLED) { + this.runMainUpdateLoop(); + } + + setInterval(() => { this.healthCheck(); }, 2500); - if (config.BISQ_ENABLED) { - bisq.startBisqService(); - bisq.setPriceCallbackFunction((price) => websocketHandler.setExtraInitProperties('bsq-price', price)); + if (config.LIGHTNING.ENABLED) { + this.$runLightningBackend(); } - this.server.listen(config.HTTP_PORT, () => { - console.log(`Server started on port ${config.HTTP_PORT}`); + this.server.listen(config.MEMPOOL.HTTP_PORT, () => { + if (worker) { + logger.info(`Mempool Server worker #${process.pid} started`); + } else { + logger.notice(`Mempool Server is running on port ${config.MEMPOOL.HTTP_PORT}`); + } }); + + if (this.serverUnixSocket) { + this.serverUnixSocket.listen(config.MEMPOOL.UNIX_SOCKET_PATH, () => { + if (worker) { + logger.info(`Mempool Server worker #${process.pid} started`); + } else { + logger.notice(`Mempool Server is listening on ${config.MEMPOOL.UNIX_SOCKET_PATH}`); + } + }); + } + } + + async runMainUpdateLoop(): Promise { + const start = Date.now(); + try { + try { + await memPool.$updateMemPoolInfo(); + } catch (e) { + const msg = `updateMempoolInfo: ${(e instanceof Error ? e.message : e)}`; + if (config.MEMPOOL.USE_SECOND_NODE_FOR_MINFEE) { + logger.warn(msg); + } else { + logger.debug(msg); + } + } + const newMempool = await bitcoinApi.$getRawMempool(); + const minFeeMempool = memPool.limitGBT ? await bitcoinSecondClient.getRawMemPool() : null; + const minFeeTip = memPool.limitGBT ? await bitcoinSecondClient.getBlockCount() : -1; + const newAccelerations = await accelerationApi.$fetchAccelerations(); + const numHandledBlocks = await blocks.$updateBlocks(); + const pollRate = config.MEMPOOL.POLL_RATE_MS * (indexer.indexerIsRunning() ? 10 : 1); + if (numHandledBlocks === 0) { + await memPool.$updateMempool(newMempool, newAccelerations, minFeeMempool, minFeeTip, pollRate); + } + indexer.$run(); + if (config.FIAT_PRICE.ENABLED) { + priceUpdater.$run(); + } + + // rerun immediately if we skipped the mempool update, otherwise wait POLL_RATE_MS + const elapsed = Date.now() - start; + const remainingTime = Math.max(0, pollRate - elapsed); + setTimeout(this.runMainUpdateLoop.bind(this), numHandledBlocks > 0 ? 0 : remainingTime); + this.backendRetryCount = 0; + } catch (e: any) { + this.backendRetryCount++; + let loggerMsg = `Exception in runMainUpdateLoop() (count: ${this.backendRetryCount}). Retrying in ${this.currentBackendRetryInterval} sec.`; + loggerMsg += ` Reason: ${(e instanceof Error ? e.message : e)}.`; + if (e?.stack) { + loggerMsg += ` Stack trace: ${e.stack}`; + } + // When we get a first Exception, only `logger.debug` it and retry after 5 seconds + // From the second Exception, `logger.warn` the Exception and increase the retry delay + if (this.backendRetryCount >= 5) { + logger.warn(loggerMsg); + mempool.setOutOfSync(); + } else { + logger.debug(loggerMsg); + } + if (e instanceof AxiosError) { + logger.debug(`AxiosError: ${e?.message}`); + } + setTimeout(this.runMainUpdateLoop.bind(this), 1000 * this.currentBackendRetryInterval); + } finally { + diskCache.unlock(); + } } - async runMempoolIntervalFunctions() { - await memPool.updateMemPoolInfo(); - await blocks.updateBlocks(); - await memPool.updateMempool(); - setTimeout(this.runMempoolIntervalFunctions.bind(this), config.ELECTRS_POLL_RATE_MS); + async $runLightningBackend(): Promise { + try { + await fundingTxFetcher.$init(); + await networkSyncService.$startService(); + await lightningStatsUpdater.$startService(); + await forensicsService.$startService(); + } catch(e) { + logger.err(`Exception in $runLightningBackend. Restarting in 1 minute. Reason: ${(e instanceof Error ? e.message : e)}`); + await Common.sleep$(1000 * 60); + this.$runLightningBackend(); + }; } - setUpWebsocketHandling() { - websocketHandler.setWebsocketServer(this.wss); + setUpWebsocketHandling(): void { + if (this.wss) { + websocketHandler.addWebsocketServer(this.wss); + } + if (this.wssUnixSocket) { + websocketHandler.addWebsocketServer(this.wssUnixSocket); + } + + if (Common.isLiquid() && config.DATABASE.ENABLED) { + blocks.setNewBlockCallback(async () => { + try { + await elementsParser.$parse(); + await elementsParser.$updateFederationUtxos(); + } catch (e) { + logger.warn('Elements parsing error: ' + (e instanceof Error ? e.message : e)); + } + }); + } websocketHandler.setupConnectionHandling(); - statistics.setNewStatisticsEntryCallback(websocketHandler.handleNewStatistic.bind(websocketHandler)); - blocks.setNewBlockCallback(websocketHandler.handleNewBlock.bind(websocketHandler)); - memPool.setMempoolChangedCallback(websocketHandler.handleMempoolChange.bind(websocketHandler)); + if (config.MEMPOOL.ENABLED) { + statistics.setNewStatisticsEntryCallback(websocketHandler.handleNewStatistic.bind(websocketHandler)); + memPool.setAsyncMempoolChangedCallback(websocketHandler.$handleMempoolChange.bind(websocketHandler)); + blocks.setNewAsyncBlockCallback(websocketHandler.handleNewBlock.bind(websocketHandler)); + } + if (config.FIAT_PRICE.ENABLED) { + priceUpdater.setRatesChangedCallback(websocketHandler.handleNewConversionRates.bind(websocketHandler)); + } + loadingIndicators.setProgressChangedCallback(websocketHandler.handleLoadingChanged.bind(websocketHandler)); + } + + setUpHttpApiRoutes(): void { + bitcoinRoutes.initRoutes(this.app); + bitcoinCoreRoutes.initRoutes(this.app); + pricesRoutes.initRoutes(this.app); + if (config.STATISTICS.ENABLED && config.DATABASE.ENABLED && config.MEMPOOL.ENABLED) { + statisticsRoutes.initRoutes(this.app); + } + if (Common.indexingEnabled() && config.MEMPOOL.ENABLED) { + miningRoutes.initRoutes(this.app); + } + if (Common.isLiquid()) { + liquidRoutes.initRoutes(this.app); + } + if (config.LIGHTNING.ENABLED) { + generalLightningRoutes.initRoutes(this.app); + nodesRoutes.initRoutes(this.app); + channelsRoutes.initRoutes(this.app); + } + if (config.MEMPOOL_SERVICES.ACCELERATIONS) { + accelerationRoutes.initRoutes(this.app); + } + if (!config.MEMPOOL.OFFICIAL) { + aboutRoutes.initRoutes(this.app); + } } - setUpHttpApiRoutes() { - this.app - .get(config.API_ENDPOINT + 'transaction-times', routes.getTransactionTimes) - .get(config.API_ENDPOINT + 'fees/recommended', routes.getRecommendedFees) - .get(config.API_ENDPOINT + 'fees/mempool-blocks', routes.getMempoolBlocks) - .get(config.API_ENDPOINT + 'statistics/2h', routes.get2HStatistics) - .get(config.API_ENDPOINT + 'statistics/24h', routes.get24HStatistics.bind(routes)) - .get(config.API_ENDPOINT + 'statistics/1w', routes.get1WHStatistics.bind(routes)) - .get(config.API_ENDPOINT + 'statistics/1m', routes.get1MStatistics.bind(routes)) - .get(config.API_ENDPOINT + 'statistics/3m', routes.get3MStatistics.bind(routes)) - .get(config.API_ENDPOINT + 'statistics/6m', routes.get6MStatistics.bind(routes)) - .get(config.API_ENDPOINT + 'statistics/1y', routes.get1YStatistics.bind(routes)) - .get(config.API_ENDPOINT + 'backend-info', routes.getBackendInfo) - ; - - if (config.BISQ_ENABLED) { - this.app - .get(config.API_ENDPOINT + 'bisq/stats', routes.getBisqStats) - .get(config.API_ENDPOINT + 'bisq/tx/:txId', routes.getBisqTransaction) - .get(config.API_ENDPOINT + 'bisq/block/:hash', routes.getBisqBlock) - .get(config.API_ENDPOINT + 'bisq/blocks/tip/height', routes.getBisqTip) - .get(config.API_ENDPOINT + 'bisq/blocks/:index/:length', routes.getBisqBlocks) - .get(config.API_ENDPOINT + 'bisq/address/:address', routes.getBisqAddress) - .get(config.API_ENDPOINT + 'bisq/txs/:index/:length', routes.getBisqTransactions) - ; + healthCheck(): void { + const now = Date.now(); + const stats = v8.getHeapStatistics(); + this.maxHeapSize = Math.max(stats.used_heap_size, this.maxHeapSize); + const warnThreshold = 0.8 * stats.heap_size_limit; + + const byteUnits = getBytesUnit(Math.max(this.maxHeapSize, stats.heap_size_limit)); + + if (!this.warnedHeapCritical && this.maxHeapSize > warnThreshold) { + this.warnedHeapCritical = true; + logger.warn(`Used ${(this.maxHeapSize / stats.heap_size_limit * 100).toFixed(2)}% of heap limit (${formatBytes(this.maxHeapSize, byteUnits, true)} / ${formatBytes(stats.heap_size_limit, byteUnits)})!`); + } + if (this.lastHeapLogTime === null || (now - this.lastHeapLogTime) > (this.heapLogInterval * 1000)) { + logger.debug(`Memory usage: ${formatBytes(this.maxHeapSize, byteUnits)} / ${formatBytes(stats.heap_size_limit, byteUnits)}`); + this.warnedHeapCritical = false; + this.maxHeapSize = 0; + this.lastHeapLogTime = now; + } + } + + onExit(exitEvent, code = 0): void { + logger.debug(`onExit for signal: ${exitEvent}`); + if (config.DATABASE.ENABLED) { + DB.releasePidLock(); + } + this.server?.close(); + this.serverUnixSocket?.close(); + this.wss?.close(); + if (this.wssUnixSocket) { + this.wssUnixSocket.close(); } + process.exit(code); + } + + onUnhandledException(type, error): void { + console.error(`${type}:`, error); + this.onExit(type, 1); } } -const server = new Server(); +((): Server => new Server())(); diff --git a/backend/src/indexer.ts b/backend/src/indexer.ts new file mode 100644 index 0000000000..0dd1090b8c --- /dev/null +++ b/backend/src/indexer.ts @@ -0,0 +1,213 @@ +import { Common } from './api/common'; +import blocks from './api/blocks'; +import mempool from './api/mempool'; +import mining from './api/mining/mining'; +import logger from './logger'; +import bitcoinClient from './api/bitcoin/bitcoin-client'; +import priceUpdater from './tasks/price-updater'; +import PricesRepository from './repositories/PricesRepository'; +import config from './config'; +import auditReplicator from './replication/AuditReplication'; +import statisticsReplicator from './replication/StatisticsReplication'; +import AccelerationRepository from './repositories/AccelerationRepository'; + +export interface CoreIndex { + name: string; + synced: boolean; + best_block_height: number; +} + +type TaskName = 'blocksPrices' | 'coinStatsIndex'; + +class Indexer { + private runIndexer = true; + private indexerRunning = false; + private tasksRunning: { [key in TaskName]?: boolean; } = {}; + private tasksScheduled: { [key in TaskName]?: NodeJS.Timeout; } = {}; + private coreIndexes: CoreIndex[] = []; + + public indexerIsRunning(): boolean { + return this.indexerRunning; + } + + /** + * Check which core index is available for indexing + */ + public async checkAvailableCoreIndexes(): Promise { + const updatedCoreIndexes: CoreIndex[] = []; + + const indexes: any = await bitcoinClient.getIndexInfo(); + for (const indexName in indexes) { + const newState = { + name: indexName, + synced: indexes[indexName].synced, + best_block_height: indexes[indexName].best_block_height, + }; + logger.info(`Core index '${indexName}' is ${indexes[indexName].synced ? 'synced' : 'not synced'}. Best block height is ${indexes[indexName].best_block_height}`); + updatedCoreIndexes.push(newState); + + if (indexName === 'coinstatsindex' && newState.synced === true) { + const previousState = this.isCoreIndexReady('coinstatsindex'); + // if (!previousState || previousState.synced === false) { + this.runSingleTask('coinStatsIndex'); + // } + } + } + + this.coreIndexes = updatedCoreIndexes; + } + + /** + * Return the best block height if a core index is available, or 0 if not + * + * @param name + * @returns + */ + public isCoreIndexReady(name: string): CoreIndex | null { + for (const index of this.coreIndexes) { + if (index.name === name && index.synced === true) { + return index; + } + } + return null; + } + + public reindex(): void { + if (Common.indexingEnabled()) { + this.runIndexer = true; + } + } + + /** + * schedules a single task to run in `timeout` ms + * only one task of each type may be scheduled + * + * @param {TaskName} task - the type of task + * @param {number} timeout - delay in ms + * @param {boolean} replace - `true` replaces any already scheduled task (works like a debounce), `false` ignores subsequent requests (works like a throttle) + */ + public scheduleSingleTask(task: TaskName, timeout: number = 10000, replace = false): void { + if (this.tasksScheduled[task]) { + if (!replace) { //throttle + return; + } else { // debounce + clearTimeout(this.tasksScheduled[task]); + } + } + this.tasksScheduled[task] = setTimeout(async () => { + try { + await this.runSingleTask(task); + } catch (e) { + logger.err(`Unexpected error in scheduled task ${task}: ` + (e instanceof Error ? e.message : e)); + } finally { + clearTimeout(this.tasksScheduled[task]); + } + }, timeout); + } + + /** + * Runs a single task immediately + * + * (use `scheduleSingleTask` instead to queue a task to run after some timeout) + */ + public async runSingleTask(task: TaskName): Promise { + if (!Common.indexingEnabled() || this.tasksRunning[task]) { + return; + } + this.tasksRunning[task] = true; + + switch (task) { + case 'blocksPrices': { + if (!['testnet', 'signet'].includes(config.MEMPOOL.NETWORK) && config.FIAT_PRICE.ENABLED) { + let lastestPriceId; + try { + lastestPriceId = await PricesRepository.$getLatestPriceId(); + } catch (e) { + logger.debug('failed to fetch latest price id from db: ' + (e instanceof Error ? e.message : e)); + } if (priceUpdater.historyInserted === false || lastestPriceId === null) { + logger.debug(`Blocks prices indexer is waiting for the price updater to complete`, logger.tags.mining); + this.scheduleSingleTask(task, 10000); + } else { + logger.debug(`Blocks prices indexer will run now`, logger.tags.mining); + await mining.$indexBlockPrices(); + } + } + } break; + + case 'coinStatsIndex': { + logger.debug(`Indexing coinStatsIndex now`); + await mining.$indexCoinStatsIndex(); + } break; + } + + this.tasksRunning[task] = false; + } + + public async $run(): Promise { + if (!Common.indexingEnabled() || this.runIndexer === false || + this.indexerRunning === true || mempool.hasPriority() + ) { + return; + } + + if (config.FIAT_PRICE.ENABLED) { + try { + await priceUpdater.$run(); + } catch (e) { + logger.err(`Running priceUpdater failed. Reason: ` + (e instanceof Error ? e.message : e)); + } + } + + // Do not attempt to index anything unless Bitcoin Core is fully synced + const blockchainInfo = await bitcoinClient.getBlockchainInfo(); + if (blockchainInfo.blocks !== blockchainInfo.headers) { + return; + } + + this.runIndexer = false; + this.indexerRunning = true; + + logger.debug(`Running mining indexer`); + + await this.checkAvailableCoreIndexes(); + + try { + const chainValid = await blocks.$generateBlockDatabase(); + if (chainValid === false) { + // Chain of block hash was invalid, so we need to reindex. Stop here and continue at the next iteration + logger.warn(`The chain of block hash is invalid, re-indexing invalid data in 10 seconds.`, logger.tags.mining); + setTimeout(() => this.reindex(), 10000); + this.indexerRunning = false; + return; + } + + this.runSingleTask('blocksPrices'); + await blocks.$indexCoinbaseAddresses(); + await mining.$indexDifficultyAdjustments(); + await mining.$generateNetworkHashrateHistory(); + await mining.$generatePoolHashrateHistory(); + await blocks.$generateBlocksSummariesDatabase(); + await blocks.$generateCPFPDatabase(); + await blocks.$generateAuditStats(); + await auditReplicator.$sync(); + await statisticsReplicator.$sync(); + await AccelerationRepository.$indexPastAccelerations(); + // do not wait for classify blocks to finish + blocks.$classifyBlocks(); + } catch (e) { + this.indexerRunning = false; + logger.err(`Indexer failed, trying again in 10 seconds. Reason: ` + (e instanceof Error ? e.message : e)); + setTimeout(() => this.reindex(), 10000); + this.indexerRunning = false; + return; + } + + this.indexerRunning = false; + + const runEvery = 1000 * 3600; // 1 hour + logger.debug(`Indexing completed. Next run planned at ${new Date(new Date().getTime() + runEvery).toUTCString()}`); + setTimeout(() => this.reindex(), runEvery); + } +} + +export default new Indexer(); diff --git a/backend/src/interfaces.ts b/backend/src/interfaces.ts deleted file mode 100644 index 9da3cde446..0000000000 --- a/backend/src/interfaces.ts +++ /dev/null @@ -1,324 +0,0 @@ -export interface MempoolInfo { - size: number; - bytes: number; - usage?: number; - maxmempool?: number; - mempoolminfee?: number; - minrelaytxfee?: number; -} - -export interface MempoolBlock { - blockSize: number; - blockVSize: number; - nTx: number; - medianFee: number; - totalFees: number; - feeRange: number[]; -} - -export interface MempoolBlockWithTransactions extends MempoolBlock { - transactionIds: string[]; -} - -export interface Transaction { - txid: string; - version: number; - locktime: number; - fee: number; - size: number; - weight: number; - vin: Vin[]; - vout: Vout[]; - status: Status; -} - -export interface TransactionMinerInfo { - vin: VinStrippedToScriptsig[]; - vout: VoutStrippedToScriptPubkey[]; -} - -interface VinStrippedToScriptsig { - scriptsig: string; -} - -interface VoutStrippedToScriptPubkey { - scriptpubkey_address: string | undefined; - value: number; -} - -export interface TransactionExtended extends Transaction { - vsize: number; - feePerVsize: number; - firstSeen: number; -} - -export interface Vin { - txid: string; - vout: number; - is_coinbase: boolean; - scriptsig: string; - scriptsig_asm: string; - inner_redeemscript_asm?: string; - inner_witnessscript_asm?: string; - sequence: any; - witness?: string[]; - prevout: Vout; - // Elements - is_pegin?: boolean; - issuance?: Issuance; -} - -interface Issuance { - asset_id: string; - is_reissuance: string; - asset_blinding_nonce: string; - asset_entropy: string; - contract_hash: string; - assetamount?: number; - assetamountcommitment?: string; - tokenamount?: number; - tokenamountcommitment?: string; -} - -export interface Vout { - scriptpubkey: string; - scriptpubkey_asm: string; - scriptpubkey_type: string; - scriptpubkey_address: string; - value: number; - // Elements - valuecommitment?: number; - asset?: string; - pegout?: Pegout; -} - -interface Pegout { - genesis_hash: string; - scriptpubkey: string; - scriptpubkey_asm: string; - scriptpubkey_address: string; -} - -export interface Status { - confirmed: boolean; - block_height?: number; - block_hash?: string; - block_time?: number; -} - -export interface Block { - id: string; - height: number; - version: number; - timestamp: number; - bits: number; - nounce: number; - difficulty: number; - merkle_root: string; - tx_count: number; - size: number; - weight: number; - previousblockhash: string; - - // Custom properties - medianFee?: number; - feeRange?: number[]; - reward?: number; - coinbaseTx?: TransactionMinerInfo; - matchRate: number; - stage: number; -} - -export interface Address { - address: string; - chain_stats: ChainStats; - mempool_stats: MempoolStats; -} - -export interface ChainStats { - funded_txo_count: number; - funded_txo_sum: number; - spent_txo_count: number; - spent_txo_sum: number; - tx_count: number; -} - -export interface MempoolStats { - funded_txo_count: number; - funded_txo_sum: number; - spent_txo_count: number; - spent_txo_sum: number; - tx_count: number; -} - -export interface Statistic { - id?: number; - added: string; - unconfirmed_transactions: number; - tx_per_second: number; - vbytes_per_second: number; - total_fee: number; - mempool_byte_weight: number; - fee_data: string; - - vsize_1: number; - vsize_2: number; - vsize_3: number; - vsize_4: number; - vsize_5: number; - vsize_6: number; - vsize_8: number; - vsize_10: number; - vsize_12: number; - vsize_15: number; - vsize_20: number; - vsize_30: number; - vsize_40: number; - vsize_50: number; - vsize_60: number; - vsize_70: number; - vsize_80: number; - vsize_90: number; - vsize_100: number; - vsize_125: number; - vsize_150: number; - vsize_175: number; - vsize_200: number; - vsize_250: number; - vsize_300: number; - vsize_350: number; - vsize_400: number; - vsize_500: number; - vsize_600: number; - vsize_700: number; - vsize_800: number; - vsize_900: number; - vsize_1000: number; - vsize_1200: number; - vsize_1400: number; - vsize_1600: number; - vsize_1800: number; - vsize_2000: number; -} - -export interface OptimizedStatistic { - id: number; - added: string; - unconfirmed_transactions: number; - tx_per_second: number; - vbytes_per_second: number; - total_fee: number; - mempool_byte_weight: number; - vsizes: number[]; -} - -export interface Outspend { - spent: boolean; - txid: string; - vin: number; - status: Status; -} -export interface WebsocketResponse { - action: string; - data: string[]; - 'track-tx': string; - 'track-address': string; - 'watch-mempool': boolean; -} - -export interface VbytesPerSecond { - unixTime: number; - vSize: number; -} - -export interface BisqBlocks { - chainHeight: number; - blocks: BisqBlock[]; -} - -export interface BisqBlock { - height: number; - time: number; - hash: string; - previousBlockHash: string; - txs: BisqTransaction[]; -} - -export interface BisqTransaction { - txVersion: string; - id: string; - blockHeight: number; - blockHash: string; - time: number; - inputs: BisqInput[]; - outputs: BisqOutput[]; - txType: string; - txTypeDisplayString: string; - burntFee: number; - invalidatedBsq: number; - unlockBlockHeight: number; -} - -export interface BisqStats { - minted: number; - burnt: number; - addresses: number; - unspent_txos: number; - spent_txos: number; -} - -interface BisqInput { - spendingTxOutputIndex: number; - spendingTxId: string; - bsqAmount: number; - isVerified: boolean; - address: string; - time: number; -} - -interface BisqOutput { - txVersion: string; - txId: string; - index: number; - bsqAmount: number; - btcAmount: number; - height: number; - isVerified: boolean; - burntFee: number; - invalidatedBsq: number; - address: string; - scriptPubKey: BisqScriptPubKey; - time: any; - txType: string; - txTypeDisplayString: string; - txOutputType: string; - txOutputTypeDisplayString: string; - lockTime: number; - isUnspent: boolean; - spentInfo: SpentInfo; - opReturn?: string; -} - -interface BisqScriptPubKey { - addresses: string[]; - asm: string; - hex: string; - reqSigs: number; - type: string; -} - -interface SpentInfo { - height: number; - inputIndex: number; - txId: string; -} - -export interface BisqTrade { - direction: string; - price: string; - amount: string; - volume: string; - payment_method: string; - trade_id: string; - trade_date: number; -} diff --git a/backend/src/logger.ts b/backend/src/logger.ts new file mode 100644 index 0000000000..bce77c63f2 --- /dev/null +++ b/backend/src/logger.ts @@ -0,0 +1,160 @@ +import config from './config'; +import * as dgram from 'dgram'; + +class Logger { + static priorities = { + emerg: 0, + alert: 1, + crit: 2, + err: 3, + warn: 4, + notice: 5, + info: 6, + debug: 7 + }; + static facilities = { + kern: 0, + user: 1, + mail: 2, + daemon: 3, + auth: 4, + syslog: 5, + lpr: 6, + news: 7, + uucp: 8, + local0: 16, + local1: 17, + local2: 18, + local3: 19, + local4: 20, + local5: 21, + local6: 22, + local7: 23 + }; + + public tags = { + mining: 'Mining', + ln: 'Lightning', + goggles: 'Goggles', + }; + + // @ts-ignore + public emerg: ((msg: string, tag?: string) => void); + // @ts-ignore + public alert: ((msg: string, tag?: string) => void); + // @ts-ignore + public crit: ((msg: string, tag?: string) => void); + // @ts-ignore + public err: ((msg: string, tag?: string) => void); + // @ts-ignore + public warn: ((msg: string, tag?: string) => void); + // @ts-ignore + public notice: ((msg: string, tag?: string) => void); + // @ts-ignore + public info: ((msg: string, tag?: string) => void); + // @ts-ignore + public debug: ((msg: string, tag?: string) => void); + + private name = 'mempool'; + private client: dgram.Socket; + private network: string; + + constructor() { + let prio; + for (prio in Logger.priorities) { + if (true) { + this.addprio(prio); + } + } + this.client = dgram.createSocket('udp4'); + this.network = this.getNetwork(); + } + + public updateNetwork(): void { + this.network = this.getNetwork(); + } + + private addprio(prio): void { + this[prio] = (function(_this) { + return function(msg, tag?: string) { + return _this.msg(prio, msg, tag); + }; + })(this); + } + + private getNetwork(): string { + if (config.LIGHTNING.ENABLED) { + return config.MEMPOOL.NETWORK === 'mainnet' ? 'lightning' : `${config.MEMPOOL.NETWORK}-lightning`; + } + if (config.MEMPOOL.NETWORK && config.MEMPOOL.NETWORK !== 'mainnet') { + return config.MEMPOOL.NETWORK; + } + return ''; + } + + private msg(priority, msg, tag?: string) { + let consolemsg, prionum, syslogmsg; + if (typeof msg === 'string' && msg.length > 0) { + while (msg[msg.length - 1].charCodeAt(0) === 10) { + msg = msg.slice(0, msg.length - 1); + } + } + const network = this.network ? ' <' + this.network + '>' : ''; + prionum = Logger.priorities[priority] || Logger.priorities.info; + consolemsg = `${this.ts()} [${process.pid}] ${priority.toUpperCase()}:${network} ${tag ? '[' + tag + '] ' : ''}${msg}`; + + if (config.SYSLOG.ENABLED && Logger.priorities[priority] <= Logger.priorities[config.SYSLOG.MIN_PRIORITY]) { + syslogmsg = `<${(Logger.facilities[config.SYSLOG.FACILITY] * 8 + prionum)}> ${this.name}[${process.pid}]: ${priority.toUpperCase()}${network} ${tag ? '[' + tag + '] ' : ''}${msg}`; + this.syslog(syslogmsg); + } + if (Logger.priorities[priority] > Logger.priorities[config.MEMPOOL.STDOUT_LOG_MIN_PRIORITY]) { + return; + } + if (priority === 'warning') { + priority = 'warn'; + } + if (priority === 'debug') { + priority = 'info'; + } + if (priority === 'err') { + priority = 'error'; + } + return (console[priority] || console.error)(consolemsg); + } + + private syslog(msg) { + let msgbuf; + msgbuf = Buffer.from(msg); + this.client.send(msgbuf, 0, msgbuf.length, config.SYSLOG.PORT, config.SYSLOG.HOST, function(err, bytes) { + if (err) { + console.log(err); + } + }); + } + + private leadZero(n: number): number | string { + if (n < 10) { + return '0' + n; + } + return n; + } + + private ts() { + let day, dt, hours, minutes, month, months, seconds; + dt = new Date(); + hours = this.leadZero(dt.getHours()); + minutes = this.leadZero(dt.getMinutes()); + seconds = this.leadZero(dt.getSeconds()); + month = dt.getMonth(); + day = dt.getDate(); + if (day < 10) { + day = ' ' + day; + } + months = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec']; + return months[month] + ' ' + day + ' ' + hours + ':' + minutes + ':' + seconds; + } +} + +export type LogLevel = 'emerg' | 'alert' | 'crit' | 'err' | 'warn' | 'notice' | 'info' | 'debug'; + +export default new Logger(); diff --git a/backend/src/mempool.interfaces.ts b/backend/src/mempool.interfaces.ts new file mode 100644 index 0000000000..0ad60f4b96 --- /dev/null +++ b/backend/src/mempool.interfaces.ts @@ -0,0 +1,561 @@ +import { IEsploraApi } from './api/bitcoin/esplora-api.interface'; +import { OrphanedBlock } from './api/chain-tips'; +import { HeapNode } from './utils/pairing-heap'; + +export interface PoolTag { + id: number; + uniqueId: number; + name: string; + link: string; + regexes: string; // JSON array + addresses: string; // JSON array + slug: string; +} + +export interface PoolInfo { + poolId: number; // mysql row id + name: string; + link: string; + blockCount: number; + slug: string; + avgMatchRate: number | null; + avgFeeDelta: number | null; + poolUniqueId: number; +} + +export interface PoolStats extends PoolInfo { + rank: number; + emptyBlocks: number; +} + +export interface BlockAudit { + time: number, + height: number, + hash: string, + missingTxs: string[], + freshTxs: string[], + sigopTxs: string[], + fullrbfTxs: string[], + addedTxs: string[], + prioritizedTxs: string[], + acceleratedTxs: string[], + matchRate: number, + expectedFees?: number, + expectedWeight?: number, + template?: any[]; +} + +export interface TransactionAudit { + seen?: boolean; + expected?: boolean; + added?: boolean; + prioritized?: boolean; + delayed?: number; + accelerated?: boolean; + conflict?: boolean; + coinbase?: boolean; + firstSeen?: number; +} + +export interface AuditScore { + hash: string, + matchRate?: number, + expectedFees?: number + expectedWeight?: number +} + +export interface MempoolBlock { + blockSize: number; + blockVSize: number; + nTx: number; + medianFee: number; + totalFees: number; + feeRange: number[]; +} + +export interface MempoolBlockWithTransactions extends MempoolBlock { + transactionIds: string[]; + transactions: TransactionClassified[]; +} + +export interface MempoolBlockDelta { + added: TransactionCompressed[]; + removed: string[]; + changed: MempoolDeltaChange[]; +} + +export interface MempoolDeltaTxids { + sequence: number, + added: string[]; + removed: string[]; + mined: string[]; + replaced: { replaced: string, by: string }[]; +} + +export interface MempoolDelta { + sequence: number, + added: MempoolTransactionExtended[]; + removed: string[]; + mined: string[]; + replaced: { replaced: string, by: TransactionExtended }[]; +} + +interface VinStrippedToScriptsig { + scriptsig: string; +} + +interface VoutStrippedToScriptPubkey { + scriptpubkey_address: string | undefined; + scriptpubkey_asm: string | undefined; + value: number; +} + +export interface TransactionExtended extends IEsploraApi.Transaction { + vsize: number; + feePerVsize: number; + firstSeen?: number; + effectiveFeePerVsize: number; + ancestors?: Ancestor[]; + descendants?: Ancestor[]; + bestDescendant?: BestDescendant | null; + cpfpChecked?: boolean; + position?: { + block: number, + vsize: number, + }; + acceleration?: boolean; + acceleratedBy?: number[]; + acceleratedAt?: number; + replacement?: boolean; + uid?: number; + flags?: number; +} + +export interface MempoolTransactionExtended extends TransactionExtended { + order: number; + sigops: number; + adjustedVsize: number; + adjustedFeePerVsize: number; + inputs?: number[]; + lastBoosted?: number; + cpfpDirty?: boolean; + cpfpUpdated?: number; +} + +export interface AuditTransaction { + uid: number; + fee: number; + weight: number; + feePerVsize: number; + effectiveFeePerVsize: number; + sigops: number; + inputs: number[]; + relativesSet: boolean; + ancestorMap: Map; + children: Set; + ancestorFee: number; + ancestorWeight: number; + ancestorSigops: number; + score: number; + used: boolean; + modified: boolean; + modifiedNode: HeapNode; + dependencyRate?: number; +} + +export interface CompactThreadTransaction { + uid: number; + fee: number; + weight: number; + sigops: number; + feePerVsize: number; + effectiveFeePerVsize: number; + inputs: number[]; + cpfpRoot?: number; + cpfpChecked?: boolean; + dirty?: boolean; +} + +export interface GbtCandidates { + txs: { [txid: string ]: boolean }, + added: MempoolTransactionExtended[]; + removed: MempoolTransactionExtended[]; +} + +export interface ThreadTransaction { + txid: string; + fee: number; + weight: number; + feePerVsize: number; + effectiveFeePerVsize?: number; + inputs: number[]; + cpfpRoot?: string; + cpfpChecked?: boolean; +} + +export interface Ancestor { + txid: string; + weight: number; + fee: number; +} + +export interface TransactionSet { + fee: number; + weight: number; + score: number; + children?: Set; + available?: boolean; + modified?: boolean; + modifiedNode?: HeapNode; +} + +interface BestDescendant { + txid: string; + weight: number; + fee: number; +} + +export interface CpfpInfo { + ancestors: Ancestor[]; + bestDescendant?: BestDescendant | null; + descendants?: Ancestor[]; + effectiveFeePerVsize?: number; + sigops?: number; + adjustedVsize?: number, + acceleration?: boolean, + fee?: number; +} + +export interface TransactionStripped { + txid: string; + fee: number; + vsize: number; + value: number; + acc?: boolean; + rate?: number; // effective fee rate + time?: number; +} + +export interface TransactionClassified extends TransactionStripped { + flags: number; +} + +// [txid, fee, vsize, value, rate, flags, acceleration?] +export type TransactionCompressed = [string, number, number, number, number, number, number, 1?]; +// [txid, rate, flags, acceleration?] +export type MempoolDeltaChange = [string, number, number, (1|0)]; + +// binary flags for transaction classification +export const TransactionFlags = { + // features + rbf: 0b00000001n, + no_rbf: 0b00000010n, + v1: 0b00000100n, + v2: 0b00001000n, + v3: 0b00010000n, + nonstandard: 0b00100000n, + // address types + p2pk: 0b00000001_00000000n, + p2ms: 0b00000010_00000000n, + p2pkh: 0b00000100_00000000n, + p2sh: 0b00001000_00000000n, + p2wpkh: 0b00010000_00000000n, + p2wsh: 0b00100000_00000000n, + p2tr: 0b01000000_00000000n, + // behavior + cpfp_parent: 0b00000001_00000000_00000000n, + cpfp_child: 0b00000010_00000000_00000000n, + replacement: 0b00000100_00000000_00000000n, + // data + op_return: 0b00000001_00000000_00000000_00000000n, + fake_pubkey: 0b00000010_00000000_00000000_00000000n, + inscription: 0b00000100_00000000_00000000_00000000n, + fake_scripthash: 0b00001000_00000000_00000000_00000000n, + // heuristics + coinjoin: 0b00000001_00000000_00000000_00000000_00000000n, + consolidation: 0b00000010_00000000_00000000_00000000_00000000n, + batch_payout: 0b00000100_00000000_00000000_00000000_00000000n, + // sighash + sighash_all: 0b00000001_00000000_00000000_00000000_00000000_00000000n, + sighash_none: 0b00000010_00000000_00000000_00000000_00000000_00000000n, + sighash_single: 0b00000100_00000000_00000000_00000000_00000000_00000000n, + sighash_default:0b00001000_00000000_00000000_00000000_00000000_00000000n, + sighash_acp: 0b00010000_00000000_00000000_00000000_00000000_00000000n, +}; + +export interface BlockExtension { + totalFees: number; + medianFee: number; // median fee rate + feeRange: number[]; // fee rate percentiles + reward: number; + matchRate: number | null; + expectedFees: number | null; + expectedWeight: number | null; + similarity?: number; + pool: { + id: number; // Note - This is the `unique_id`, not to mix with the auto increment `id` + name: string; + slug: string; + }; + avgFee: number; + avgFeeRate: number; + coinbaseRaw: string; + orphans: OrphanedBlock[] | null; + coinbaseAddress: string | null; + coinbaseAddresses: string[] | null; + coinbaseSignature: string | null; + coinbaseSignatureAscii: string | null; + virtualSize: number; + avgTxSize: number; + totalInputs: number; + totalOutputs: number; + totalOutputAmt: number; + medianFeeAmt: number | null; // median fee in sats + feePercentiles: number[] | null, // fee percentiles in sats + segwitTotalTxs: number; + segwitTotalSize: number; + segwitTotalWeight: number; + header: string; + utxoSetChange: number; + // Requires coinstatsindex, will be set to NULL otherwise + utxoSetSize: number | null; + totalInputAmt: number | null; +} + +/** + * Note: Everything that is added in here will be automatically returned through + * /api/v1/block and /api/v1/blocks APIs + */ +export interface BlockExtended extends IEsploraApi.Block { + extras: BlockExtension; + canonical?: string; +} + +export interface BlockSummary { + id: string; + transactions: TransactionClassified[]; + version?: number; +} + +export interface AuditSummary extends BlockAudit { + timestamp?: number, + size?: number, + weight?: number, + tx_count?: number, + transactions: TransactionClassified[]; + template?: TransactionClassified[]; +} + +export interface BlockPrice { + height: number; + priceId: number; +} + +export interface TransactionMinerInfo { + vin: VinStrippedToScriptsig[]; + vout: VoutStrippedToScriptPubkey[]; +} + +export interface MempoolStats { + funded_txo_count: number; + funded_txo_sum: number; + spent_txo_count: number; + spent_txo_sum: number; + tx_count: number; +} + +export interface EffectiveFeeStats { + medianFee: number; // median effective fee rate + feeRange: number[]; // 2nd, 10th, 25th, 50th, 75th, 90th, 98th percentiles +} + +export interface WorkingEffectiveFeeStats extends EffectiveFeeStats { + minFee: number; + maxFee: number; +} + +export interface CpfpCluster { + root: string, + height: number, + txs: Ancestor[], + effectiveFeePerVsize: number, +} + +export interface CpfpSummary { + transactions: TransactionExtended[]; + clusters: CpfpCluster[]; +} + +export interface Statistic { + id?: number; + added: string; + unconfirmed_transactions: number; + tx_per_second: number; + vbytes_per_second: number; + total_fee: number; + mempool_byte_weight: number; + fee_data: string; + min_fee: number; + + vsize_1: number; + vsize_2: number; + vsize_3: number; + vsize_4: number; + vsize_5: number; + vsize_6: number; + vsize_8: number; + vsize_10: number; + vsize_12: number; + vsize_15: number; + vsize_20: number; + vsize_30: number; + vsize_40: number; + vsize_50: number; + vsize_60: number; + vsize_70: number; + vsize_80: number; + vsize_90: number; + vsize_100: number; + vsize_125: number; + vsize_150: number; + vsize_175: number; + vsize_200: number; + vsize_250: number; + vsize_300: number; + vsize_350: number; + vsize_400: number; + vsize_500: number; + vsize_600: number; + vsize_700: number; + vsize_800: number; + vsize_900: number; + vsize_1000: number; + vsize_1200: number; + vsize_1400: number; + vsize_1600: number; + vsize_1800: number; + vsize_2000: number; +} + +export interface OptimizedStatistic { + added: string; + count: number; + vbytes_per_second: number; + total_fee: number; + mempool_byte_weight: number; + min_fee: number; + vsizes: number[]; +} + +export interface TxTrackingInfo { + replacedBy?: string, + position?: { block: number, vsize: number, accelerated?: boolean, acceleratedBy?: number[], acceleratedAt?: number }, + cpfp?: { + ancestors?: Ancestor[], + bestDescendant?: Ancestor | null, + descendants?: Ancestor[] | null, + effectiveFeePerVsize?: number | null, + sigops: number, + adjustedVsize: number, + }, + utxoSpent?: { [vout: number]: { vin: number, txid: string } }, + accelerated?: boolean, + acceleratedBy?: number[], + acceleratedAt?: number, + confirmed?: boolean +} + +export interface WebsocketResponse { + action: string; + data: string[]; + 'track-tx': string; + 'track-address': string; + 'watch-mempool': boolean; +} + +export interface VbytesPerSecond { + unixTime: number; + vSize: number; +} + +export interface RequiredSpec { [name: string]: RequiredParams; } + +interface RequiredParams { + required: boolean; + types: ('@string' | '@number' | '@boolean' | string)[]; +} + +export interface ILoadingIndicators { [name: string]: number; } + +export interface IBackendInfo { + hostname: string; + gitCommit: string; + version: string; + lightning: boolean; + backend: 'esplora' | 'electrum' | 'none'; +} + +export interface IDifficultyAdjustment { + progressPercent: number; + difficultyChange: number; + estimatedRetargetDate: number; + remainingBlocks: number; + remainingTime: number; + previousRetarget: number; + previousTime: number; + nextRetargetHeight: number; + timeAvg: number; + timeOffset: number; + expectedBlocks: number; +} + +export interface IndexedDifficultyAdjustment { + time: number; // UNIX timestamp + height: number; // Block height + difficulty: number; + adjustment: number; +} + +export interface RewardStats { + totalReward: number; + totalFee: number; + totalTx: number; +} + +export interface ITopNodesPerChannels { + publicKey: string, + alias: string, + channels?: number, + capacity: number, + firstSeen?: number, + updatedAt?: number, + city?: any, + country?: any, +} + +export interface ITopNodesPerCapacity { + publicKey: string, + alias: string, + capacity: number, + channels?: number, + firstSeen?: number, + updatedAt?: number, + city?: any, + country?: any, +} + +export interface INodesRanking { + topByCapacity: ITopNodesPerCapacity[]; + topByChannels: ITopNodesPerChannels[]; +} + +export interface IOldestNodes { + publicKey: string, + alias: string, + firstSeen: number, + channels?: number, + capacity: number, + updatedAt?: number, + city?: any, + country?: any, +} diff --git a/backend/src/replication/AuditReplication.ts b/backend/src/replication/AuditReplication.ts new file mode 100644 index 0000000000..4ea6298397 --- /dev/null +++ b/backend/src/replication/AuditReplication.ts @@ -0,0 +1,137 @@ +import DB from '../database'; +import logger from '../logger'; +import { AuditSummary } from '../mempool.interfaces'; +import blocksAuditsRepository from '../repositories/BlocksAuditsRepository'; +import blocksSummariesRepository from '../repositories/BlocksSummariesRepository'; +import { $sync } from './replicator'; +import config from '../config'; +import { Common } from '../api/common'; +import blocks from '../api/blocks'; + +const BATCH_SIZE = 16; + +/** + * Syncs missing block template and audit data from trusted servers + */ +class AuditReplication { + inProgress: boolean = false; + skip: Set = new Set(); + + public async $sync(): Promise { + if (!config.REPLICATION.ENABLED || !config.REPLICATION.AUDIT) { + // replication not enabled + return; + } + if (this.inProgress) { + logger.info(`AuditReplication sync already in progress`, 'Replication'); + return; + } + this.inProgress = true; + + const missingAudits = await this.$getMissingAuditBlocks(); + + logger.debug(`Fetching missing audit data for ${missingAudits.length} blocks from trusted servers`, 'Replication'); + + let totalSynced = 0; + let totalMissed = 0; + let loggerTimer = Date.now(); + // process missing audits in batches of + for (let i = 0; i < missingAudits.length; i += BATCH_SIZE) { + const slice = missingAudits.slice(i, i + BATCH_SIZE); + const results = await Promise.all(slice.map(hash => this.$syncAudit(hash))); + const synced = results.reduce((total, status) => status ? total + 1 : total, 0); + totalSynced += synced; + totalMissed += (slice.length - synced); + if (Date.now() - loggerTimer > 10000) { + loggerTimer = Date.now(); + logger.info(`Found ${totalSynced} / ${totalSynced + totalMissed} of ${missingAudits.length} missing audits`, 'Replication'); + } + await Common.sleep$(1000); + } + + logger.debug(`Fetched ${totalSynced} audits, ${totalMissed} still missing`, 'Replication'); + + this.inProgress = false; + } + + private async $syncAudit(hash: string): Promise { + if (this.skip.has(hash)) { + // we already know none of our trusted servers have this audit + return false; + } + + let success = false; + // start with a random server so load is uniformly spread + const syncResult = await $sync(`/api/v1/block/${hash}/audit-summary`); + if (syncResult) { + if (syncResult.data?.template?.length) { + await this.$saveAuditData(hash, syncResult.data); + logger.info(`Imported audit data from ${syncResult.server} for block ${syncResult.data.height} (${hash})`); + success = true; + } + if (!syncResult.data && !syncResult.exists) { + this.skip.add(hash); + } + } + + return success; + } + + private async $getMissingAuditBlocks(): Promise { + try { + const startHeight = config.REPLICATION.AUDIT_START_HEIGHT || 0; + const [rows]: any[] = await DB.query(` + SELECT auditable.hash, auditable.height + FROM ( + SELECT hash, height + FROM blocks + WHERE height >= ? + ) AS auditable + LEFT JOIN blocks_audits ON auditable.hash = blocks_audits.hash + WHERE blocks_audits.hash IS NULL + ORDER BY auditable.height DESC + `, [startHeight]); + return rows.map(row => row.hash); + } catch (e: any) { + logger.err(`Cannot fetch missing audit blocks from db. Reason: ` + (e instanceof Error ? e.message : e)); + throw e; + } + } + + private async $saveAuditData(blockHash: string, auditSummary: AuditSummary): Promise { + // save audit & template to DB + await blocksSummariesRepository.$saveTemplate({ + height: auditSummary.height, + template: { + id: blockHash, + transactions: auditSummary.template || [] + }, + version: 1, + }); + await blocksAuditsRepository.$saveAudit({ + hash: blockHash, + height: auditSummary.height, + time: auditSummary.timestamp || auditSummary.time, + missingTxs: auditSummary.missingTxs || [], + addedTxs: auditSummary.addedTxs || [], + prioritizedTxs: auditSummary.prioritizedTxs || [], + freshTxs: auditSummary.freshTxs || [], + sigopTxs: auditSummary.sigopTxs || [], + fullrbfTxs: auditSummary.fullrbfTxs || [], + acceleratedTxs: auditSummary.acceleratedTxs || [], + matchRate: auditSummary.matchRate, + expectedFees: auditSummary.expectedFees, + expectedWeight: auditSummary.expectedWeight, + }); + // add missing data to cached blocks + const cachedBlock = blocks.getBlocks().find(block => block.id === blockHash); + if (cachedBlock) { + cachedBlock.extras.matchRate = auditSummary.matchRate; + cachedBlock.extras.expectedFees = auditSummary.expectedFees || null; + cachedBlock.extras.expectedWeight = auditSummary.expectedWeight || null; + } + } +} + +export default new AuditReplication(); + diff --git a/backend/src/replication/StatisticsReplication.ts b/backend/src/replication/StatisticsReplication.ts new file mode 100644 index 0000000000..49259b4582 --- /dev/null +++ b/backend/src/replication/StatisticsReplication.ts @@ -0,0 +1,237 @@ +import DB from '../database'; +import logger from '../logger'; +import { $sync } from './replicator'; +import config from '../config'; +import { Common } from '../api/common'; +import statistics from '../api/statistics/statistics-api'; + +interface MissingStatistics { + '24h': Set; + '1w': Set; + '1m': Set; + '3m': Set; + '6m': Set; + '2y': Set; + 'all': Set; +} + +const steps = { + '24h': 60, + '1w': 300, + '1m': 1800, + '3m': 7200, + '6m': 10800, + '2y': 28800, + 'all': 43200, +}; + +/** + * Syncs missing statistics data from trusted servers + */ +class StatisticsReplication { + inProgress: boolean = false; + + public async $sync(): Promise { + if (!config.REPLICATION.ENABLED || !config.REPLICATION.STATISTICS || !config.STATISTICS.ENABLED) { + // replication not enabled, or statistics not enabled + return; + } + if (this.inProgress) { + logger.info(`StatisticsReplication sync already in progress`, 'Replication'); + return; + } + this.inProgress = true; + + const missingStatistics = await this.$getMissingStatistics(); + const missingIntervals = Object.keys(missingStatistics).filter(key => missingStatistics[key].size > 0); + const totalMissing = missingIntervals.reduce((total, key) => total + missingStatistics[key].size, 0); + + if (totalMissing === 0) { + this.inProgress = false; + logger.info(`Statistics table is complete, no replication needed`, 'Replication'); + return; + } + + for (const interval of missingIntervals) { + logger.debug(`Missing ${missingStatistics[interval].size} statistics rows in '${interval}' timespan`, 'Replication'); + } + logger.debug(`Fetching ${missingIntervals.join(', ')} statistics endpoints from trusted servers to fill ${totalMissing} rows missing in statistics`, 'Replication'); + + let totalSynced = 0; + let totalMissed = 0; + + for (const interval of missingIntervals) { + const results = await this.$syncStatistics(interval, missingStatistics[interval]); + totalSynced += results.synced; + totalMissed += results.missed; + + logger.info(`Found ${totalSynced} / ${totalSynced + totalMissed} of ${totalMissing} missing statistics rows`, 'Replication'); + await Common.sleep$(3000); + } + + logger.debug(`Synced ${totalSynced} statistics rows, ${totalMissed} still missing`, 'Replication'); + + this.inProgress = false; + } + + private async $syncStatistics(interval: string, missingTimes: Set): Promise { + + let success = false; + let synced = 0; + let missed = new Set(missingTimes); + const syncResult = await $sync(`/api/v1/statistics/${interval}`); + if (syncResult && syncResult.data?.length) { + success = true; + logger.info(`Fetched /api/v1/statistics/${interval} from ${syncResult.server}`); + + for (const stat of syncResult.data) { + const time = this.roundToNearestStep(stat.added, steps[interval]); + if (missingTimes.has(time)) { + try { + await statistics.$create(statistics.mapOptimizedStatisticToStatistic([stat])[0], true); + if (missed.delete(time)) { + synced++; + } + } catch (e: any) { + logger.err(`Failed to insert statistics row at ${stat.added} (${interval}) from ${syncResult.server}. Reason: ` + (e instanceof Error ? e.message : e)); + } + } + } + + } else { + logger.warn(`An error occured when trying to fetch /api/v1/statistics/${interval}`); + } + + return { success, synced, missed: missed.size }; + } + + private async $getMissingStatistics(): Promise { + try { + const now = Math.floor(Date.now() / 1000); + const day = 60 * 60 * 24; + + const startTime = this.getStartTimeFromConfig(); + + const missingStatistics: MissingStatistics = { + '24h': new Set(), + '1w': new Set(), + '1m': new Set(), + '3m': new Set(), + '6m': new Set(), + '2y': new Set(), + 'all': new Set() + }; + + const intervals = [ // [start, end, label ] + [now - day + 600, now - 60, '24h'] , // from 24 hours ago to now = 1 minute granularity + startTime < now - day ? [now - day * 7, now - day, '1w' ] : null, // from 1 week ago to 24 hours ago = 5 minutes granularity + startTime < now - day * 7 ? [now - day * 30, now - day * 7, '1m' ] : null, // from 1 month ago to 1 week ago = 30 minutes granularity + startTime < now - day * 30 ? [now - day * 90, now - day * 30, '3m' ] : null, // from 3 months ago to 1 month ago = 2 hours granularity + startTime < now - day * 90 ? [now - day * 180, now - day * 90, '6m' ] : null, // from 6 months ago to 3 months ago = 3 hours granularity + startTime < now - day * 180 ? [now - day * 365 * 2, now - day * 180, '2y' ] : null, // from 2 years ago to 6 months ago = 8 hours granularity + startTime < now - day * 365 * 2 ? [startTime, now - day * 365 * 2, 'all'] : null, // from start of statistics to 2 years ago = 12 hours granularity + ]; + + for (const interval of intervals) { + if (!interval) { + continue; + } + missingStatistics[interval[2] as string] = await this.$getMissingStatisticsInterval(interval, startTime); + } + + return missingStatistics; + } catch (e: any) { + logger.err(`Cannot fetch missing statistics times from db. Reason: ` + (e instanceof Error ? e.message : e)); + throw e; + } + } + + private async $getMissingStatisticsInterval(interval: any, startTime: number): Promise> { + try { + const start = interval[0]; + const end = interval[1]; + const step = steps[interval[2]]; + + const [rows]: any[] = await DB.query(` + SELECT UNIX_TIMESTAMP(added) as added + FROM statistics + WHERE added >= FROM_UNIXTIME(?) AND added <= FROM_UNIXTIME(?) + GROUP BY UNIX_TIMESTAMP(added) DIV ${step} ORDER BY statistics.added DESC + `, [start, end]); + + const startingTime = Math.max(startTime, start) - Math.max(startTime, start) % step; + + const timeSteps: number[] = []; + for (let time = startingTime; time < end; time += step) { + timeSteps.push(time); + } + + if (timeSteps.length === 0) { + return new Set(); + } + + const roundedTimesAlreadyHere: number[] = Array.from(new Set(rows.map(row => this.roundToNearestStep(row.added, step)))); + + const missingTimes = timeSteps.filter(time => !roundedTimesAlreadyHere.includes(time)).filter((time, i, arr) => { + // Remove outsiders + if (i === 0) { + return arr[i + 1] === time + step + } else if (i === arr.length - 1) { + return arr[i - 1] === time - step; + } + return (arr[i + 1] === time + step) && (arr[i - 1] === time - step) + }); + + // Don't bother fetching if very few rows are missing + if (missingTimes.length < timeSteps.length * 0.01) { + return new Set(); + } + + return new Set(missingTimes); + } catch (e: any) { + logger.err(`Cannot fetch missing statistics times from db. Reason: ` + (e instanceof Error ? e.message : e)); + throw e; + } + } + + private roundToNearestStep(time: number, step: number): number { + const remainder = time % step; + if (remainder < step / 2) { + return time - remainder; + } else { + return time + (step - remainder); + } + } + + private getStartTimeFromConfig(): number { + const now = Math.floor(Date.now() / 1000); + const day = 60 * 60 * 24; + + let startTime: number; + if (typeof(config.REPLICATION.STATISTICS_START_TIME) === 'string' && ['24h', '1w', '1m', '3m', '6m', '2y', 'all'].includes(config.REPLICATION.STATISTICS_START_TIME)) { + if (config.REPLICATION.STATISTICS_START_TIME === 'all') { + startTime = 1481932800; + } else if (config.REPLICATION.STATISTICS_START_TIME === '2y') { + startTime = now - day * 365 * 2; + } else if (config.REPLICATION.STATISTICS_START_TIME === '6m') { + startTime = now - day * 180; + } else if (config.REPLICATION.STATISTICS_START_TIME === '3m') { + startTime = now - day * 90; + } else if (config.REPLICATION.STATISTICS_START_TIME === '1m') { + startTime = now - day * 30; + } else if (config.REPLICATION.STATISTICS_START_TIME === '1w') { + startTime = now - day * 7; + } else { + startTime = now - day; + } + } else { + startTime = Math.max(config.REPLICATION.STATISTICS_START_TIME as number || 1481932800, 1481932800); + } + + return startTime; + } + +} + +export default new StatisticsReplication(); + diff --git a/backend/src/replication/replicator.ts b/backend/src/replication/replicator.ts new file mode 100644 index 0000000000..ac204efcc3 --- /dev/null +++ b/backend/src/replication/replicator.ts @@ -0,0 +1,70 @@ +import config from '../config'; +import backendInfo from '../api/backend-info'; +import axios, { AxiosResponse } from 'axios'; +import { SocksProxyAgent } from 'socks-proxy-agent'; +import * as https from 'https'; + +export async function $sync(path): Promise<{ data?: any, exists: boolean, server?: string }> { + // start with a random server so load is uniformly spread + let allMissing = true; + const offset = Math.floor(Math.random() * config.REPLICATION.SERVERS.length); + for (let i = 0; i < config.REPLICATION.SERVERS.length; i++) { + const server = config.REPLICATION.SERVERS[(i + offset) % config.REPLICATION.SERVERS.length]; + // don't query ourself + if (server === backendInfo.getBackendInfo().hostname) { + continue; + } + + try { + const result = await query(`https://${server}${path}`); + if (result) { + return { data: result, exists: true, server }; + } + } catch (e: any) { + if (e?.response?.status === 404) { + // this server is also missing this data + } else { + // something else went wrong + allMissing = false; + } + } + } + + return { exists: !allMissing }; +} + +export async function query(path): Promise { + type axiosOptions = { + headers: { + 'User-Agent': string + }; + timeout: number; + httpsAgent?: https.Agent; + }; + const axiosOptions: axiosOptions = { + headers: { + 'User-Agent': (config.MEMPOOL.USER_AGENT === 'mempool') ? `mempool/v${backendInfo.getBackendInfo().version}` : `${config.MEMPOOL.USER_AGENT}` + }, + timeout: config.SOCKS5PROXY.ENABLED ? 30000 : 10000 + }; + + if (config.SOCKS5PROXY.ENABLED) { + const socksOptions = { + agentOptions: { + keepAlive: true, + }, + hostname: config.SOCKS5PROXY.HOST, + port: config.SOCKS5PROXY.PORT, + username: config.SOCKS5PROXY.USERNAME || 'circuit0', + password: config.SOCKS5PROXY.PASSWORD, + }; + + axiosOptions.httpsAgent = new SocksProxyAgent(socksOptions); + } + + const data: AxiosResponse = await axios.get(path, axiosOptions); + if (data.statusText === 'error' || !data.data) { + throw new Error(`${data.status}`); + } + return data.data; +} \ No newline at end of file diff --git a/backend/src/repositories/AccelerationRepository.ts b/backend/src/repositories/AccelerationRepository.ts new file mode 100644 index 0000000000..1c3bdad296 --- /dev/null +++ b/backend/src/repositories/AccelerationRepository.ts @@ -0,0 +1,356 @@ +import { AccelerationInfo } from '../api/acceleration/acceleration'; +import { RowDataPacket } from 'mysql2'; +import DB from '../database'; +import logger from '../logger'; +import { IEsploraApi } from '../api/bitcoin/esplora-api.interface'; +import { Common } from '../api/common'; +import config from '../config'; +import blocks from '../api/blocks'; +import accelerationApi, { Acceleration, AccelerationHistory } from '../api/services/acceleration'; +import accelerationCosts from '../api/acceleration/acceleration'; +import bitcoinApi from '../api/bitcoin/bitcoin-api-factory'; +import transactionUtils from '../api/transaction-utils'; +import { BlockExtended, MempoolTransactionExtended } from '../mempool.interfaces'; +import { makeBlockTemplate } from '../api/mini-miner'; + +export interface PublicAcceleration { + txid: string, + height: number, + added: number, + pool: { + id: number, + slug: string, + name: string, + }, + effective_vsize: number, + effective_fee: number, + boost_rate: number, + boost_cost: number, +} + +class AccelerationRepository { + private bidBoostV2Activated = 831580; + + public async $saveAcceleration(acceleration: AccelerationInfo, block: IEsploraApi.Block, pool_id: number, accelerationData: Acceleration[]): Promise { + const accelerationMap: { [txid: string]: Acceleration } = {}; + for (const acc of accelerationData) { + accelerationMap[acc.txid] = acc; + } + try { + await DB.query(` + INSERT INTO accelerations(txid, requested, added, height, pool, effective_vsize, effective_fee, boost_rate, boost_cost) + VALUE (?, FROM_UNIXTIME(?), FROM_UNIXTIME(?), ?, ?, ?, ?, ?, ?) + ON DUPLICATE KEY UPDATE + height = ? + `, [ + acceleration.txSummary.txid, + accelerationMap[acceleration.txSummary.txid].added, + block.timestamp, + block.height, + pool_id, + acceleration.txSummary.effectiveVsize, + acceleration.txSummary.effectiveFee, + acceleration.targetFeeRate, + acceleration.cost, + block.height, + ]); + } catch (e: any) { + logger.err(`Cannot save acceleration (${acceleration.txSummary.txid}) into db. Reason: ` + (e instanceof Error ? e.message : e)); + // We don't throw, not a critical issue if we miss some accelerations + } + } + + public async $getAccelerationInfo(poolSlug: string | null = null, height: number | null = null, interval: string | null = null): Promise { + if (!interval || !['24h', '3d', '1w', '1m'].includes(interval)) { + interval = '1m'; + } + interval = Common.getSqlInterval(interval); + + if (!config.MEMPOOL_SERVICES.ACCELERATIONS || (interval == null && poolSlug == null && height == null)) { + return []; + } + + let query = ` + SELECT *, UNIX_TIMESTAMP(requested) as requested_timestamp, UNIX_TIMESTAMP(added) as block_timestamp FROM accelerations + JOIN pools on pools.unique_id = accelerations.pool + `; + let params: any[] = []; + let hasFilter = false; + + if (interval && height === null) { + query += ` WHERE accelerations.added BETWEEN DATE_SUB(NOW(), INTERVAL ${interval}) AND NOW() `; + hasFilter = true; + } + + if (height != null) { + if (hasFilter) { + query += ` AND accelerations.height = ? `; + } else { + query += ` WHERE accelerations.height = ? `; + } + params.push(height); + } else if (poolSlug != null) { + if (hasFilter) { + query += ` AND pools.slug = ? `; + } else { + query += ` WHERE pools.slug = ? `; + } + params.push(poolSlug); + } + + query += ` ORDER BY accelerations.added DESC `; + + try { + const [rows] = await DB.query(query, params) as RowDataPacket[][]; + if (rows?.length) { + return rows.map(row => ({ + txid: row.txid, + height: row.height, + added: row.requested_timestamp || row.block_timestamp, + pool: { + id: row.id, + slug: row.slug, + name: row.name, + }, + effective_vsize: row.effective_vsize, + effective_fee: row.effective_fee, + boost_rate: row.boost_rate, + boost_cost: row.boost_cost, + })); + } else { + return []; + } + } catch (e) { + logger.err(`Cannot query acceleration info. Reason: ` + (e instanceof Error ? e.message : e)); + throw e; + } + } + + public async $getAccelerationTotals(poolSlug: string | null = null, interval: string | null = null): Promise<{ cost: number, count: number }> { + interval = Common.getSqlInterval(interval); + + if (!config.MEMPOOL_SERVICES.ACCELERATIONS) { + return { cost: 0, count: 0 }; + } + + let query = ` + SELECT SUM(boost_cost) as total_cost, COUNT(txid) as count FROM accelerations + JOIN pools on pools.unique_id = accelerations.pool + `; + let params: any[] = []; + let hasFilter = false; + + if (interval) { + query += ` WHERE accelerations.added BETWEEN DATE_SUB(NOW(), INTERVAL ${interval}) AND NOW() `; + hasFilter = true; + } + if (poolSlug != null) { + if (hasFilter) { + query += ` AND pools.slug = ? `; + } else { + query += ` WHERE pools.slug = ? `; + } + params.push(poolSlug); + } + + try { + const [rows] = await DB.query(query, params) as RowDataPacket[][]; + return { + cost: rows[0]?.total_cost || 0, + count: rows[0]?.count || 0, + }; + } catch (e) { + logger.err(`Cannot query acceleration totals. Reason: ` + (e instanceof Error ? e.message : e)); + throw e; + } + } + + public async $getLastSyncedHeight(): Promise { + try { + const [rows] = await DB.query(` + SELECT * FROM state + WHERE name = 'last_acceleration_block' + `); + if (rows?.['length']) { + return rows[0].number; + } + } catch (e: any) { + logger.err(`Cannot find last acceleration sync height. Reason: ` + (e instanceof Error ? e.message : e)); + } + return 0; + } + + private async $setLastSyncedHeight(height: number): Promise { + try { + await DB.query(` + UPDATE state + SET number = ? + WHERE name = 'last_acceleration_block' + `, [height]); + } catch (e: any) { + logger.err(`Cannot update last acceleration sync height. Reason: ` + (e instanceof Error ? e.message : e)); + } + } + + public async $indexAccelerationsForBlock(block: BlockExtended, accelerations: Acceleration[], transactions: MempoolTransactionExtended[]): Promise { + const blockTxs: { [txid: string]: MempoolTransactionExtended } = {}; + for (const tx of transactions) { + blockTxs[tx.txid] = tx; + } + const successfulAccelerations = accelerations.filter(acc => acc.pools.includes(block.extras.pool.id)); + let boostRate: number | null = null; + for (const acc of successfulAccelerations) { + if (boostRate === null) { + boostRate = accelerationCosts.calculateBoostRate( + accelerations.map(acc => ({ txid: acc.txid, max_bid: acc.feeDelta })), + transactions + ); + } + if (blockTxs[acc.txid]) { + const tx = blockTxs[acc.txid]; + const accelerationInfo = accelerationCosts.getAccelerationInfo(tx, boostRate, transactions); + accelerationInfo.cost = Math.max(0, Math.min(acc.feeDelta, accelerationInfo.cost)); + this.$saveAcceleration(accelerationInfo, block, block.extras.pool.id, successfulAccelerations); + } + } + const lastSyncedHeight = await this.$getLastSyncedHeight(); + // if we've missed any blocks, let the indexer catch up from the last synced height on the next run + if (block.height === lastSyncedHeight + 1) { + await this.$setLastSyncedHeight(block.height); + } + } + + /** + * [INDEXING] Backfill missing acceleration data + */ + async $indexPastAccelerations(): Promise { + if (config.MEMPOOL.NETWORK !== 'mainnet' || !config.MEMPOOL_SERVICES.ACCELERATIONS) { + // acceleration history disabled + return; + } + const lastSyncedHeight = await this.$getLastSyncedHeight(); + const currentHeight = blocks.getCurrentBlockHeight(); + if (currentHeight <= lastSyncedHeight) { + // already in sync + return; + } + + logger.debug(`Fetching accelerations between block ${lastSyncedHeight} and ${currentHeight}`); + + // Fetch accelerations from mempool.space since the last synced block; + const accelerationsByBlock: {[height: number]: AccelerationHistory[]} = {}; + const blockHashes = {}; + let done = false; + let page = 1; + let count = 0; + try { + while (!done) { + // don't DDoS the services backend + Common.sleep$(500 + (Math.random() * 1000)); + const accelerations = await accelerationApi.$fetchAccelerationHistory(page); + page++; + if (!accelerations?.length) { + done = true; + break; + } + for (const acc of accelerations) { + if (acc.status !== 'completed_provisional' && acc.status !== 'completed') { + continue; + } + if (!lastSyncedHeight || acc.blockHeight > lastSyncedHeight) { + if (!accelerationsByBlock[acc.blockHeight]) { + accelerationsByBlock[acc.blockHeight] = []; + blockHashes[acc.blockHeight] = acc.blockHash; + } + accelerationsByBlock[acc.blockHeight].push(acc); + count++; + } else { + done = true; + } + } + } + } catch (e) { + logger.err(`Failed to fetch full acceleration history. Reason: ` + (e instanceof Error ? e.message : e)); + } + + logger.debug(`Indexing ${count} accelerations between block ${lastSyncedHeight} and ${currentHeight}`); + + // process accelerated blocks in order + const heights = Object.keys(accelerationsByBlock).map(key => parseInt(key)).sort((a,b) => a - b); + for (const height of heights) { + const accelerations = accelerationsByBlock[height]; + try { + const block = await blocks.$getBlock(blockHashes[height]) as BlockExtended; + const transactions = (await bitcoinApi.$getTxsForBlock(blockHashes[height])).map(tx => transactionUtils.extendMempoolTransaction(tx)); + + const blockTxs = {}; + for (const tx of transactions) { + blockTxs[tx.txid] = tx; + } + + let boostRate = 0; + // use Bid Boost V2 if active + if (height > this.bidBoostV2Activated) { + boostRate = accelerationCosts.calculateBoostRate( + accelerations.map(acc => ({ txid: acc.txid, max_bid: acc.feeDelta })), + transactions + ); + } else { + // default to Bid Boost V1 (median block fee rate) + const template = makeBlockTemplate( + transactions, + accelerations.map(acc => ({ txid: acc.txid, max_bid: acc.feeDelta })), + 1, + Infinity, + Infinity + ); + const feeStats = Common.calcEffectiveFeeStatistics(template); + boostRate = feeStats.medianFee; + } + const accelerationSummaries = accelerations.map(acc => ({ + ...acc, + pools: acc.pools, + })) + for (const acc of accelerations) { + if (blockTxs[acc.txid] && acc.pools.includes(block.extras.pool.id)) { + const tx = blockTxs[acc.txid]; + const accelerationInfo = accelerationCosts.getAccelerationInfo(tx, boostRate, transactions); + accelerationInfo.cost = Math.max(0, Math.min(acc.feeDelta, accelerationInfo.cost)); + await this.$saveAcceleration(accelerationInfo, block, block.extras.pool.id, accelerationSummaries); + } + } + await this.$setLastSyncedHeight(height); + } catch (e) { + logger.err(`Failed to process accelerations for block ${height}. Reason: ` + (e instanceof Error ? e.message : e)); + return; + } + logger.debug(`Indexed ${accelerations.length} accelerations in block ${height}`); + } + + await this.$setLastSyncedHeight(currentHeight); + + logger.debug(`Indexing accelerations completed`); + } + + /** + * Delete accelerations from the database above blockHeight + */ + public async $deleteAccelerationsFrom(blockHeight: number): Promise { + logger.info(`Delete newer accelerations from height ${blockHeight} from the database`); + try { + const currentSyncedHeight = await this.$getLastSyncedHeight(); + if (currentSyncedHeight >= blockHeight) { + await DB.query(` + UPDATE state + SET number = ? + WHERE name = 'last_acceleration_block' + `, [blockHeight - 1]); + } + await DB.query(`DELETE FROM accelerations where height >= ${blockHeight}`); + } catch (e) { + logger.err('Cannot delete indexed accelerations. Reason: ' + (e instanceof Error ? e.message : e)); + } + } +} + +export default new AccelerationRepository(); diff --git a/backend/src/repositories/BlocksAuditsRepository.ts b/backend/src/repositories/BlocksAuditsRepository.ts new file mode 100644 index 0000000000..1e0d28689f --- /dev/null +++ b/backend/src/repositories/BlocksAuditsRepository.ts @@ -0,0 +1,192 @@ +import blocks from '../api/blocks'; +import DB from '../database'; +import logger from '../logger'; +import { BlockAudit, AuditScore, TransactionAudit } from '../mempool.interfaces'; + +class BlocksAuditRepositories { + public async $saveAudit(audit: BlockAudit): Promise { + try { + await DB.query(`INSERT INTO blocks_audits(time, height, hash, missing_txs, added_txs, prioritized_txs, fresh_txs, sigop_txs, fullrbf_txs, accelerated_txs, match_rate, expected_fees, expected_weight) + VALUE (FROM_UNIXTIME(?), ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)`, [audit.time, audit.height, audit.hash, JSON.stringify(audit.missingTxs), + JSON.stringify(audit.addedTxs), JSON.stringify(audit.prioritizedTxs), JSON.stringify(audit.freshTxs), JSON.stringify(audit.sigopTxs), JSON.stringify(audit.fullrbfTxs), JSON.stringify(audit.acceleratedTxs), audit.matchRate, audit.expectedFees, audit.expectedWeight]); + } catch (e: any) { + if (e.errno === 1062) { // ER_DUP_ENTRY - This scenario is possible upon node backend restart + logger.debug(`Cannot save block audit for block ${audit.hash} because it has already been indexed, ignoring`); + } else { + logger.err(`Cannot save block audit into db. Reason: ` + (e instanceof Error ? e.message : e)); + } + } + } + + public async $setSummary(hash: string, expectedFees: number, expectedWeight: number) { + try { + await DB.query(` + UPDATE blocks_audits SET + expected_fees = ?, + expected_weight = ? + WHERE hash = ? + `, [expectedFees, expectedWeight, hash]); + } catch (e: any) { + logger.err(`Cannot update block audit in db. Reason: ` + (e instanceof Error ? e.message : e)); + } + } + + public async $getBlocksHealthHistory(div: number, interval: string | null): Promise { + try { + let query = `SELECT UNIX_TIMESTAMP(time) as time, height, match_rate FROM blocks_audits`; + + if (interval !== null) { + query += ` WHERE time BETWEEN DATE_SUB(NOW(), INTERVAL ${interval}) AND NOW()`; + } + + query += ` GROUP BY UNIX_TIMESTAMP(time) DIV ${div} ORDER BY height`; + + const [rows] = await DB.query(query); + return rows; + } catch (e: any) { + logger.err(`Cannot fetch blocks health history. Reason: ` + (e instanceof Error ? e.message : e)); + throw e; + } + } + + public async $getBlocksHealthCount(): Promise { + try { + const [rows] = await DB.query(`SELECT count(hash) as count FROM blocks_audits`); + return rows[0].count; + } catch (e: any) { + logger.err(`Cannot fetch blocks health count. Reason: ` + (e instanceof Error ? e.message : e)); + throw e; + } + } + + public async $getBlockAudit(hash: string): Promise { + try { + const [rows]: any[] = await DB.query( + `SELECT blocks_audits.height, blocks_audits.hash as id, UNIX_TIMESTAMP(blocks_audits.time) as timestamp, + template, + missing_txs as missingTxs, + added_txs as addedTxs, + prioritized_txs as prioritizedTxs, + fresh_txs as freshTxs, + sigop_txs as sigopTxs, + fullrbf_txs as fullrbfTxs, + accelerated_txs as acceleratedTxs, + match_rate as matchRate, + expected_fees as expectedFees, + expected_weight as expectedWeight + FROM blocks_audits + JOIN blocks_templates ON blocks_templates.id = blocks_audits.hash + WHERE blocks_audits.hash = ? + `, [hash]); + + if (rows.length) { + rows[0].missingTxs = JSON.parse(rows[0].missingTxs); + rows[0].addedTxs = JSON.parse(rows[0].addedTxs); + rows[0].prioritizedTxs = JSON.parse(rows[0].prioritizedTxs); + rows[0].freshTxs = JSON.parse(rows[0].freshTxs); + rows[0].sigopTxs = JSON.parse(rows[0].sigopTxs); + rows[0].fullrbfTxs = JSON.parse(rows[0].fullrbfTxs); + rows[0].acceleratedTxs = JSON.parse(rows[0].acceleratedTxs); + rows[0].template = JSON.parse(rows[0].template); + + return rows[0]; + } + return null; + } catch (e: any) { + logger.err(`Cannot fetch block audit from db. Reason: ` + (e instanceof Error ? e.message : e)); + throw e; + } + } + + public async $getBlockTxAudit(hash: string, txid: string): Promise { + try { + const blockAudit = await this.$getBlockAudit(hash); + + if (blockAudit) { + const isAdded = blockAudit.addedTxs.includes(txid); + const isPrioritized = blockAudit.prioritizedTxs.includes(txid); + const isAccelerated = blockAudit.acceleratedTxs.includes(txid); + const isConflict = blockAudit.fullrbfTxs.includes(txid); + let isExpected = false; + let firstSeen = undefined; + blockAudit.template?.forEach(tx => { + if (tx.txid === txid) { + isExpected = true; + firstSeen = tx.time; + } + }); + + return { + seen: isExpected || isPrioritized || isAccelerated, + expected: isExpected, + added: isAdded, + prioritized: isPrioritized, + conflict: isConflict, + accelerated: isAccelerated, + firstSeen, + } + } + return null; + } catch (e: any) { + logger.err(`Cannot fetch block transaction audit from db. Reason: ` + (e instanceof Error ? e.message : e)); + throw e; + } + } + + public async $getBlockAuditScore(hash: string): Promise { + try { + const [rows]: any[] = await DB.query( + `SELECT hash, match_rate as matchRate, expected_fees as expectedFees, expected_weight as expectedWeight + FROM blocks_audits + WHERE blocks_audits.hash = ? + `, [hash]); + return rows[0]; + } catch (e: any) { + logger.err(`Cannot fetch block audit from db. Reason: ` + (e instanceof Error ? e.message : e)); + throw e; + } + } + + public async $getBlockAuditScores(maxHeight: number, minHeight: number): Promise { + try { + const [rows]: any[] = await DB.query( + `SELECT hash, match_rate as matchRate, expected_fees as expectedFees, expected_weight as expectedWeight + FROM blocks_audits + WHERE blocks_audits.height BETWEEN ? AND ? + `, [minHeight, maxHeight]); + return rows; + } catch (e: any) { + logger.err(`Cannot fetch block audit from db. Reason: ` + (e instanceof Error ? e.message : e)); + throw e; + } + } + + public async $getBlocksWithoutSummaries(): Promise { + try { + const [fromRows]: any[] = await DB.query(` + SELECT height + FROM blocks_audits + WHERE expected_fees IS NULL + ORDER BY height DESC + LIMIT 1 + `); + if (!fromRows?.length) { + return []; + } + const fromHeight = fromRows[0].height; + const [idRows]: any[] = await DB.query(` + SELECT hash + FROM blocks_audits + WHERE height <= ? + ORDER BY height DESC + `, [fromHeight]); + return idRows.map(row => row.hash); + } catch (e: any) { + logger.err(`Cannot fetch block audit from db. Reason: ` + (e instanceof Error ? e.message : e)); + throw e; + } + } +} + +export default new BlocksAuditRepositories(); + diff --git a/backend/src/repositories/BlocksRepository.ts b/backend/src/repositories/BlocksRepository.ts new file mode 100644 index 0000000000..90100a7674 --- /dev/null +++ b/backend/src/repositories/BlocksRepository.ts @@ -0,0 +1,1131 @@ +import bitcoinApi from '../api/bitcoin/bitcoin-api-factory'; +import { BlockExtended, BlockExtension, BlockPrice, EffectiveFeeStats } from '../mempool.interfaces'; +import DB from '../database'; +import logger from '../logger'; +import { Common } from '../api/common'; +import PoolsRepository from './PoolsRepository'; +import HashratesRepository from './HashratesRepository'; +import { RowDataPacket } from 'mysql2'; +import BlocksSummariesRepository from './BlocksSummariesRepository'; +import DifficultyAdjustmentsRepository from './DifficultyAdjustmentsRepository'; +import bitcoinClient from '../api/bitcoin/bitcoin-client'; +import config from '../config'; +import chainTips from '../api/chain-tips'; +import blocks from '../api/blocks'; +import BlocksAuditsRepository from './BlocksAuditsRepository'; +import transactionUtils from '../api/transaction-utils'; + +interface DatabaseBlock { + id: string; + height: number; + version: number; + timestamp: number; + bits: number; + nonce: number; + difficulty: number; + merkle_root: string; + tx_count: number; + size: number; + weight: number; + previousblockhash: string; + mediantime: number; + totalFees: number; + medianFee: number; + feeRange: string; + reward: number; + poolId: number; + poolName: string; + poolSlug: string; + avgFee: number; + avgFeeRate: number; + coinbaseRaw: string; + coinbaseAddress: string; + coinbaseAddresses: string; + coinbaseSignature: string; + coinbaseSignatureAscii: string; + avgTxSize: number; + totalInputs: number; + totalOutputs: number; + totalOutputAmt: number; + medianFeeAmt: number; + feePercentiles: string; + segwitTotalTxs: number; + segwitTotalSize: number; + segwitTotalWeight: number; + header: string; + utxoSetChange: number; + utxoSetSize: number; + totalInputAmt: number; +} + +const BLOCK_DB_FIELDS = ` + blocks.hash AS id, + blocks.height, + blocks.version, + UNIX_TIMESTAMP(blocks.blockTimestamp) AS timestamp, + blocks.bits, + blocks.nonce, + blocks.difficulty, + blocks.merkle_root, + blocks.tx_count, + blocks.size, + blocks.weight, + blocks.previous_block_hash AS previousblockhash, + UNIX_TIMESTAMP(blocks.median_timestamp) AS mediantime, + blocks.fees AS totalFees, + blocks.median_fee AS medianFee, + blocks.fee_span AS feeRange, + blocks.reward, + pools.unique_id AS poolId, + pools.name AS poolName, + pools.slug AS poolSlug, + blocks.avg_fee AS avgFee, + blocks.avg_fee_rate AS avgFeeRate, + blocks.coinbase_raw AS coinbaseRaw, + blocks.coinbase_address AS coinbaseAddress, + blocks.coinbase_addresses AS coinbaseAddresses, + blocks.coinbase_signature AS coinbaseSignature, + blocks.coinbase_signature_ascii AS coinbaseSignatureAscii, + blocks.avg_tx_size AS avgTxSize, + blocks.total_inputs AS totalInputs, + blocks.total_outputs AS totalOutputs, + blocks.total_output_amt AS totalOutputAmt, + blocks.median_fee_amt AS medianFeeAmt, + blocks.fee_percentiles AS feePercentiles, + blocks.segwit_total_txs AS segwitTotalTxs, + blocks.segwit_total_size AS segwitTotalSize, + blocks.segwit_total_weight AS segwitTotalWeight, + blocks.header, + blocks.utxoset_change AS utxoSetChange, + blocks.utxoset_size AS utxoSetSize, + blocks.total_input_amt AS totalInputAmt +`; + +class BlocksRepository { + /** + * Save indexed block data in the database + */ + public async $saveBlockInDatabase(block: BlockExtended) { + const truncatedCoinbaseSignature = block?.extras?.coinbaseSignature?.substring(0, 500); + const truncatedCoinbaseSignatureAscii = block?.extras?.coinbaseSignatureAscii?.substring(0, 500); + + try { + const query = `INSERT INTO blocks( + height, hash, blockTimestamp, size, + weight, tx_count, coinbase_raw, difficulty, + pool_id, fees, fee_span, median_fee, + reward, version, bits, nonce, + merkle_root, previous_block_hash, avg_fee, avg_fee_rate, + median_timestamp, header, coinbase_address, coinbase_addresses, + coinbase_signature, utxoset_size, utxoset_change, avg_tx_size, + total_inputs, total_outputs, total_input_amt, total_output_amt, + fee_percentiles, segwit_total_txs, segwit_total_size, segwit_total_weight, + median_fee_amt, coinbase_signature_ascii + ) VALUE ( + ?, ?, FROM_UNIXTIME(?), ?, + ?, ?, ?, ?, + ?, ?, ?, ?, + ?, ?, ?, ?, + ?, ?, ?, ?, + FROM_UNIXTIME(?), ?, ?, ?, + ?, ?, ?, ?, + ?, ?, ?, ?, + ?, ?, ?, ?, + ?, ? + )`; + + const poolDbId = await PoolsRepository.$getPoolByUniqueId(block.extras.pool.id); + if (!poolDbId) { + throw Error(`Could not find a mining pool with the unique_id = ${block.extras.pool.id}. This error should never be printed.`); + } + + const params: any[] = [ + block.height, + block.id, + block.timestamp, + block.size, + block.weight, + block.tx_count, + block.extras.coinbaseRaw, + block.difficulty, + poolDbId.id, + block.extras.totalFees, + JSON.stringify(block.extras.feeRange), + block.extras.medianFee, + block.extras.reward, + block.version, + block.bits, + block.nonce, + block.merkle_root, + block.previousblockhash, + block.extras.avgFee, + block.extras.avgFeeRate, + block.mediantime, + block.extras.header, + block.extras.coinbaseAddress, + block.extras.coinbaseAddresses ? JSON.stringify(block.extras.coinbaseAddresses) : null, + truncatedCoinbaseSignature, + block.extras.utxoSetSize, + block.extras.utxoSetChange, + block.extras.avgTxSize, + block.extras.totalInputs, + block.extras.totalOutputs, + block.extras.totalInputAmt, + block.extras.totalOutputAmt, + block.extras.feePercentiles ? JSON.stringify(block.extras.feePercentiles) : null, + block.extras.segwitTotalTxs, + block.extras.segwitTotalSize, + block.extras.segwitTotalWeight, + block.extras.medianFeeAmt, + truncatedCoinbaseSignatureAscii, + ]; + + await DB.query(query, params); + } catch (e: any) { + if (e.errno === 1062) { // ER_DUP_ENTRY - This scenario is possible upon node backend restart + logger.debug(`$saveBlockInDatabase() - Block ${block.height} has already been indexed, ignoring`, logger.tags.mining); + } else { + logger.err('Cannot save indexed block into db. Reason: ' + (e instanceof Error ? e.message : e), logger.tags.mining); + throw e; + } + } + } + + /** + * Save newly indexed data from core coinstatsindex + * + * @param utxoSetSize + * @param totalInputAmt + */ + public async $updateCoinStatsIndexData(blockHash: string, utxoSetSize: number, + totalInputAmt: number + ) : Promise { + try { + const query = ` + UPDATE blocks + SET utxoset_size = ?, total_input_amt = ? + WHERE hash = ? + `; + const params: any[] = [ + utxoSetSize, + totalInputAmt, + blockHash + ]; + await DB.query(query, params); + } catch (e: any) { + logger.err('Cannot update indexed block coinstatsindex. Reason: ' + (e instanceof Error ? e.message : e)); + throw e; + } + } + + /** + * Update missing fee amounts fields + * + * @param blockHash + * @param feeAmtPercentiles + * @param medianFeeAmt + */ + public async $updateFeeAmounts(blockHash: string, feeAmtPercentiles, medianFeeAmt) : Promise { + try { + const query = ` + UPDATE blocks + SET fee_percentiles = ?, median_fee_amt = ? + WHERE hash = ? + `; + const params: any[] = [ + JSON.stringify(feeAmtPercentiles), + medianFeeAmt, + blockHash + ]; + await DB.query(query, params); + } catch (e: any) { + logger.err(`Cannot update fee amounts for block ${blockHash}. Reason: ' + ${e instanceof Error ? e.message : e}`); + throw e; + } + } + + /** + * Get all block height that have not been indexed between [startHeight, endHeight] + */ + public async $getMissingBlocksBetweenHeights(startHeight: number, endHeight: number): Promise { + if (startHeight < endHeight) { + return []; + } + + try { + const [rows]: any[] = await DB.query(` + SELECT height + FROM blocks + WHERE height <= ? AND height >= ? + ORDER BY height DESC; + `, [startHeight, endHeight]); + + const indexedBlockHeights: number[] = []; + rows.forEach((row: any) => { indexedBlockHeights.push(row.height); }); + const seekedBlocks: number[] = Array.from(Array(startHeight - endHeight + 1).keys(), n => n + endHeight).reverse(); + const missingBlocksHeights = seekedBlocks.filter(x => indexedBlockHeights.indexOf(x) === -1); + + return missingBlocksHeights; + } catch (e) { + logger.err('Cannot retrieve blocks list to index. Reason: ' + (e instanceof Error ? e.message : e)); + throw e; + } + } + + /** + * Get empty blocks for one or all pools + */ + public async $countEmptyBlocks(poolId: number | null, interval: string | null = null): Promise { + interval = Common.getSqlInterval(interval); + + const params: any[] = []; + let query = `SELECT count(height) as count, pools.id as poolId + FROM blocks + JOIN pools on pools.id = blocks.pool_id + WHERE tx_count = 1`; + + if (poolId) { + query += ` AND pool_id = ?`; + params.push(poolId); + } + + if (interval) { + query += ` AND blockTimestamp BETWEEN DATE_SUB(NOW(), INTERVAL ${interval}) AND NOW()`; + } + + query += ` GROUP by pools.id`; + + try { + const [rows] = await DB.query(query, params); + return rows; + } catch (e) { + logger.err('Cannot count empty blocks. Reason: ' + (e instanceof Error ? e.message : e)); + throw e; + } + } + + /** + * Return most recent block height + */ + public async $mostRecentBlockHeight(): Promise { + try { + const [row] = await DB.query('SELECT MAX(height) as maxHeight from blocks'); + return row[0]['maxHeight']; + } catch (e) { + logger.err(`Cannot count blocks for this pool (using offset). Reason: ` + (e instanceof Error ? e.message : e)); + throw e; + } + } + + /** + * Get blocks count for a period + */ + public async $blockCount(poolId: number | null, interval: string | null = null): Promise { + interval = Common.getSqlInterval(interval); + + const params: any[] = []; + let query = `SELECT count(height) as blockCount + FROM blocks`; + + if (poolId) { + query += ` WHERE pool_id = ?`; + params.push(poolId); + } + + if (interval) { + if (poolId) { + query += ` AND`; + } else { + query += ` WHERE`; + } + query += ` blockTimestamp BETWEEN DATE_SUB(NOW(), INTERVAL ${interval}) AND NOW()`; + } + + try { + const [rows] = await DB.query(query, params); + return rows[0].blockCount; + } catch (e) { + logger.err(`Cannot count blocks for this pool (using offset). Reason: ` + (e instanceof Error ? e.message : e)); + throw e; + } + } + + /** + * Get blocks count between two dates + * @param poolId + * @param from - The oldest timestamp + * @param to - The newest timestamp + * @returns + */ + public async $blockCountBetweenTimestamp(poolId: number | null, from: number, to: number): Promise { + const params: any[] = []; + let query = `SELECT + count(height) as blockCount, + max(height) as lastBlockHeight + FROM blocks`; + + if (poolId) { + query += ` WHERE pool_id = ?`; + params.push(poolId); + } + + if (poolId) { + query += ` AND`; + } else { + query += ` WHERE`; + } + query += ` blockTimestamp BETWEEN FROM_UNIXTIME('${from}') AND FROM_UNIXTIME('${to}')`; + + try { + const [rows] = await DB.query(query, params); + return rows[0]; + } catch (e) { + logger.err(`Cannot count blocks for this pool (using timestamps). Reason: ` + (e instanceof Error ? e.message : e)); + throw e; + } + } + + /** + * Get blocks count for a period + */ + public async $blockCountBetweenHeight(startHeight: number, endHeight: number): Promise { + const params: any[] = []; + let query = `SELECT count(height) as blockCount + FROM blocks + WHERE height <= ${startHeight} AND height >= ${endHeight}`; + + try { + const [rows] = await DB.query(query, params); + return rows[0].blockCount; + } catch (e) { + logger.err(`Cannot count blocks for this pool (using offset). Reason: ` + (e instanceof Error ? e.message : e)); + throw e; + } + } + + /** + * Get average block health for all blocks for a single pool + */ + public async $getAvgBlockHealthPerPoolId(poolId: number): Promise { + const params: any[] = []; + const query = ` + SELECT AVG(blocks_audits.match_rate) AS avg_match_rate + FROM blocks + JOIN blocks_audits ON blocks.height = blocks_audits.height + WHERE blocks.pool_id = ? + `; + params.push(poolId); + + try { + const [rows] = await DB.query(query, params); + if (!rows[0] || rows[0].avg_match_rate == null) { + return null; + } + return Math.round(rows[0].avg_match_rate * 100) / 100; + } catch (e) { + logger.err(`Cannot get average block health for pool id ${poolId}. Reason: ` + (e instanceof Error ? e.message : e)); + throw e; + } + } + + /** + * Get average block health for all blocks for a single pool + */ + public async $getTotalRewardForPoolId(poolId: number): Promise { + const params: any[] = []; + const query = ` + SELECT sum(reward) as total_reward + FROM blocks + WHERE blocks.pool_id = ? + `; + params.push(poolId); + + try { + const [rows] = await DB.query(query, params); + if (!rows[0] || !rows[0].total_reward) { + return 0; + } + return rows[0].total_reward; + } catch (e) { + logger.err(`Cannot get total reward for pool id ${poolId}. Reason: ` + (e instanceof Error ? e.message : e)); + throw e; + } + } + + /** + * Get the oldest indexed block + */ + public async $oldestBlockTimestamp(): Promise { + const query = `SELECT UNIX_TIMESTAMP(blockTimestamp) as blockTimestamp + FROM blocks + ORDER BY height + LIMIT 1;`; + + try { + const [rows]: any[] = await DB.query(query); + + if (rows.length <= 0) { + return -1; + } + + return rows[0].blockTimestamp; + } catch (e) { + logger.err('Cannot get oldest indexed block timestamp. Reason: ' + (e instanceof Error ? e.message : e)); + throw e; + } + } + + /** + * Get blocks mined by a specific mining pool + */ + public async $getBlocksByPool(slug: string, startHeight?: number): Promise { + const pool = await PoolsRepository.$getPool(slug); + if (!pool) { + throw new Error('This mining pool does not exist'); + } + + const params: any[] = []; + let query = ` + SELECT ${BLOCK_DB_FIELDS} + FROM blocks + JOIN pools ON blocks.pool_id = pools.id + WHERE pool_id = ?`; + params.push(pool.id); + + if (startHeight !== undefined) { + query += ` AND height < ?`; + params.push(startHeight); + } + + query += ` ORDER BY height DESC + LIMIT 10`; + + try { + const [rows]: any[] = await DB.query(query, params); + + const blocks: BlockExtended[] = []; + for (const block of rows) { + blocks.push(await this.formatDbBlockIntoExtendedBlock(block as DatabaseBlock)); + } + + return blocks; + } catch (e) { + logger.err('Cannot get blocks for this pool. Reason: ' + (e instanceof Error ? e.message : e)); + throw e; + } + } + + /** + * Get one block by height + */ + public async $getBlockByHeight(height: number): Promise { + try { + const [rows]: any[] = await DB.query(` + SELECT ${BLOCK_DB_FIELDS} + FROM blocks + JOIN pools ON blocks.pool_id = pools.id + WHERE blocks.height = ?`, + [height] + ); + + if (rows.length <= 0) { + return null; + } + + return await this.formatDbBlockIntoExtendedBlock(rows[0] as DatabaseBlock); + } catch (e) { + logger.err(`Cannot get indexed block ${height}. Reason: ` + (e instanceof Error ? e.message : e)); + throw e; + } + } + + /** + * Return blocks difficulty + */ + public async $getBlocksDifficulty(): Promise { + try { + const [rows]: any[] = await DB.query(`SELECT UNIX_TIMESTAMP(blockTimestamp) as time, height, difficulty, bits FROM blocks ORDER BY height ASC`); + return rows; + } catch (e) { + logger.err('Cannot get blocks difficulty list from the db. Reason: ' + (e instanceof Error ? e.message : e)); + throw e; + } + } + + /** + * Get the first block at or directly after a given timestamp + * @param timestamp number unix time in seconds + * @returns The height and timestamp of a block (timestamp might vary from given timestamp) + */ + public async $getBlockHeightFromTimestamp( + timestamp: number, + ): Promise<{ height: number; hash: string; timestamp: number }> { + try { + // Get first block at or after the given timestamp + const query = `SELECT height, hash, blockTimestamp as timestamp FROM blocks + WHERE blockTimestamp <= FROM_UNIXTIME(?) + ORDER BY blockTimestamp DESC + LIMIT 1`; + const params = [timestamp]; + const [rows]: any[][] = await DB.query(query, params); + if (rows.length === 0) { + throw new Error(`No block was found before timestamp ${timestamp}`); + } + + return rows[0]; + } catch (e) { + logger.err( + 'Cannot get block height from timestamp from the db. Reason: ' + + (e instanceof Error ? e.message : e), + ); + throw e; + } + } + + /** + * Get general block stats + */ + public async $getBlockStats(blockCount: number): Promise { + try { + // We need to use a subquery + const query = ` + SELECT MIN(height) as startBlock, MAX(height) as endBlock, SUM(reward) as totalReward, SUM(fees) as totalFee, SUM(tx_count) as totalTx + FROM + (SELECT height, reward, fees, tx_count FROM blocks + ORDER by height DESC + LIMIT ?) as sub`; + + const [rows]: any = await DB.query(query, [blockCount]); + + return rows[0]; + } catch (e) { + logger.err('Cannot generate reward stats. Reason: ' + (e instanceof Error ? e.message : e)); + throw e; + } + } + + /** + * Check if the chain of block hash is valid and delete data from the stale branch if needed + */ + public async $validateChain(): Promise { + try { + const start = new Date().getTime(); + const [blocks]: any[] = await DB.query(` + SELECT + height, + hash, + previous_block_hash, + UNIX_TIMESTAMP(blockTimestamp) AS timestamp + FROM blocks + ORDER BY height + `); + + let partialMsg = false; + let idx = 1; + while (idx < blocks.length) { + if (blocks[idx].height - 1 !== blocks[idx - 1].height) { + if (partialMsg === false) { + logger.info('Some blocks are not indexed, skipping missing blocks during chain validation'); + partialMsg = true; + } + ++idx; + continue; + } + + if (blocks[idx].previous_block_hash !== blocks[idx - 1].hash) { + logger.warn(`Chain divergence detected at block ${blocks[idx - 1].height}`); + await this.$deleteBlocksFrom(blocks[idx - 1].height); + await HashratesRepository.$deleteHashratesFromTimestamp(blocks[idx - 1].timestamp - 604800); + await DifficultyAdjustmentsRepository.$deleteAdjustementsFromHeight(blocks[idx - 1].height); + return false; + } + ++idx; + } + + logger.debug(`${idx} blocks hash validated in ${new Date().getTime() - start} ms`); + return true; + } catch (e) { + logger.err('Cannot validate chain of block hash. Reason: ' + (e instanceof Error ? e.message : e)); + return true; // Don't do anything if there is a db error + } + } + + /** + * Delete blocks from the database from blockHeight + */ + public async $deleteBlocksFrom(blockHeight: number) { + logger.info(`Delete newer blocks from height ${blockHeight} from the database`, logger.tags.mining); + + try { + await DB.query(`DELETE FROM blocks where height >= ${blockHeight}`); + } catch (e) { + logger.err('Cannot delete indexed blocks. Reason: ' + (e instanceof Error ? e.message : e)); + } + } + + /** + * Get the historical averaged block fees + */ + public async $getHistoricalBlockFees(div: number, interval: string | null, timespan?: {from: number, to: number}): Promise { + try { + let query = `SELECT + CAST(AVG(blocks.height) as INT) as avgHeight, + CAST(AVG(UNIX_TIMESTAMP(blockTimestamp)) as INT) as timestamp, + CAST(AVG(fees) as INT) as avgFees, + prices.USD + FROM blocks + JOIN blocks_prices on blocks_prices.height = blocks.height + JOIN prices on prices.id = blocks_prices.price_id + `; + + if (interval !== null) { + query += ` WHERE blockTimestamp BETWEEN DATE_SUB(NOW(), INTERVAL ${interval}) AND NOW()`; + } else if (timespan) { + query += ` WHERE blockTimestamp BETWEEN FROM_UNIXTIME(${timespan.from}) AND FROM_UNIXTIME(${timespan.to})`; + } + + query += ` GROUP BY UNIX_TIMESTAMP(blockTimestamp) DIV ${div}`; + + const [rows]: any = await DB.query(query); + return rows; + } catch (e) { + logger.err('Cannot generate block fees history. Reason: ' + (e instanceof Error ? e.message : e)); + throw e; + } + } + + /** + * Get the historical averaged block rewards + */ + public async $getHistoricalBlockRewards(div: number, interval: string | null): Promise { + try { + let query = `SELECT + CAST(AVG(blocks.height) as INT) as avgHeight, + CAST(AVG(UNIX_TIMESTAMP(blockTimestamp)) as INT) as timestamp, + CAST(AVG(reward) as INT) as avgRewards, + prices.USD + FROM blocks + JOIN blocks_prices on blocks_prices.height = blocks.height + JOIN prices on prices.id = blocks_prices.price_id + `; + + if (interval !== null) { + query += ` WHERE blockTimestamp BETWEEN DATE_SUB(NOW(), INTERVAL ${interval}) AND NOW()`; + } + + query += ` GROUP BY UNIX_TIMESTAMP(blockTimestamp) DIV ${div}`; + + const [rows]: any = await DB.query(query); + return rows; + } catch (e) { + logger.err('Cannot generate block rewards history. Reason: ' + (e instanceof Error ? e.message : e)); + throw e; + } + } + + /** + * Get the historical averaged block fee rate percentiles + */ + public async $getHistoricalBlockFeeRates(div: number, interval: string | null): Promise { + try { + let query = `SELECT + CAST(AVG(height) as INT) as avgHeight, + CAST(AVG(UNIX_TIMESTAMP(blockTimestamp)) as INT) as timestamp, + CAST(AVG(JSON_EXTRACT(fee_span, '$[0]')) as INT) as avgFee_0, + CAST(AVG(JSON_EXTRACT(fee_span, '$[1]')) as INT) as avgFee_10, + CAST(AVG(JSON_EXTRACT(fee_span, '$[2]')) as INT) as avgFee_25, + CAST(AVG(JSON_EXTRACT(fee_span, '$[3]')) as INT) as avgFee_50, + CAST(AVG(JSON_EXTRACT(fee_span, '$[4]')) as INT) as avgFee_75, + CAST(AVG(JSON_EXTRACT(fee_span, '$[5]')) as INT) as avgFee_90, + CAST(AVG(JSON_EXTRACT(fee_span, '$[6]')) as INT) as avgFee_100 + FROM blocks`; + + if (interval !== null) { + query += ` WHERE blockTimestamp BETWEEN DATE_SUB(NOW(), INTERVAL ${interval}) AND NOW()`; + } + + query += ` GROUP BY UNIX_TIMESTAMP(blockTimestamp) DIV ${div}`; + + const [rows]: any = await DB.query(query); + return rows; + } catch (e) { + logger.err('Cannot generate block fee rates history. Reason: ' + (e instanceof Error ? e.message : e)); + throw e; + } + } + + /** + * Get the historical averaged block sizes + */ + public async $getHistoricalBlockSizes(div: number, interval: string | null): Promise { + try { + let query = `SELECT + CAST(AVG(height) as INT) as avgHeight, + CAST(AVG(UNIX_TIMESTAMP(blockTimestamp)) as INT) as timestamp, + CAST(AVG(size) as INT) as avgSize + FROM blocks`; + + if (interval !== null) { + query += ` WHERE blockTimestamp BETWEEN DATE_SUB(NOW(), INTERVAL ${interval}) AND NOW()`; + } + + query += ` GROUP BY UNIX_TIMESTAMP(blockTimestamp) DIV ${div}`; + + const [rows]: any = await DB.query(query); + return rows; + } catch (e) { + logger.err('Cannot generate block size and weight history. Reason: ' + (e instanceof Error ? e.message : e)); + throw e; + } + } + + /** + * Get the historical averaged block weights + */ + public async $getHistoricalBlockWeights(div: number, interval: string | null): Promise { + try { + let query = `SELECT + CAST(AVG(height) as INT) as avgHeight, + CAST(AVG(UNIX_TIMESTAMP(blockTimestamp)) as INT) as timestamp, + CAST(AVG(weight) as INT) as avgWeight + FROM blocks`; + + if (interval !== null) { + query += ` WHERE blockTimestamp BETWEEN DATE_SUB(NOW(), INTERVAL ${interval}) AND NOW()`; + } + + query += ` GROUP BY UNIX_TIMESTAMP(blockTimestamp) DIV ${div}`; + + const [rows]: any = await DB.query(query); + return rows; + } catch (e) { + logger.err('Cannot generate block size and weight history. Reason: ' + (e instanceof Error ? e.message : e)); + throw e; + } + } + + /** + * Get a list of blocks that have been indexed + */ + public async $getIndexedBlocks(): Promise<{ height: number, hash: string }[]> { + try { + const [rows] = await DB.query(`SELECT height, hash FROM blocks ORDER BY height DESC`) as RowDataPacket[][]; + return rows as { height: number, hash: string }[]; + } catch (e) { + logger.err('Cannot generate block size and weight history. Reason: ' + (e instanceof Error ? e.message : e)); + throw e; + } + } + + /** + * Get a list of blocks that have not had CPFP data indexed + */ + public async $getCPFPUnindexedBlocks(): Promise { + try { + const blockchainInfo = await bitcoinClient.getBlockchainInfo(); + const currentBlockHeight = blockchainInfo.blocks; + let indexingBlockAmount = Math.min(config.MEMPOOL.INDEXING_BLOCKS_AMOUNT, currentBlockHeight); + if (indexingBlockAmount <= -1) { + indexingBlockAmount = currentBlockHeight + 1; + } + const minHeight = Math.max(0, currentBlockHeight - indexingBlockAmount + 1); + + const [rows] = await DB.query(` + SELECT height + FROM compact_cpfp_clusters + WHERE height <= ? AND height >= ? + GROUP BY height + ORDER BY height DESC; + `, [currentBlockHeight, minHeight]) as RowDataPacket[][]; + + const indexedHeights = {}; + rows.forEach((row) => { indexedHeights[row.height] = true; }); + const allHeights: number[] = Array.from(Array(currentBlockHeight - minHeight + 1).keys(), n => n + minHeight).reverse(); + const unindexedHeights = allHeights.filter(x => !indexedHeights[x]); + + return unindexedHeights; + } catch (e) { + logger.err('Cannot fetch CPFP unindexed blocks. Reason: ' + (e instanceof Error ? e.message : e)); + throw e; + } + } + + /** + * Return the oldest block from a consecutive chain of block from the most recent one + */ + public async $getOldestConsecutiveBlock(): Promise { + try { + const [rows]: any = await DB.query(`SELECT height, UNIX_TIMESTAMP(blockTimestamp) as timestamp, difficulty, bits FROM blocks ORDER BY height DESC`); + for (let i = 0; i < rows.length - 1; ++i) { + if (rows[i].height - rows[i + 1].height > 1) { + return rows[i]; + } + } + return rows[rows.length - 1]; + } catch (e) { + logger.err('Cannot generate block size and weight history. Reason: ' + (e instanceof Error ? e.message : e)); + throw e; + } + } + + /** + * Get all blocks which have not be linked to a price yet + */ + public async $getBlocksWithoutPrice(): Promise { + try { + const [rows]: any[] = await DB.query(` + SELECT UNIX_TIMESTAMP(blocks.blockTimestamp) as timestamp, blocks.height + FROM blocks + LEFT JOIN blocks_prices ON blocks.height = blocks_prices.height + WHERE blocks_prices.height IS NULL + ORDER BY blocks.height + `); + return rows; + } catch (e) { + logger.err('Cannot get blocks height and timestamp from the db. Reason: ' + (e instanceof Error ? e.message : e)); + return []; + } + } + + /** + * Save block price by batch + */ + public async $saveBlockPrices(blockPrices: BlockPrice[]): Promise { + try { + let query = `INSERT INTO blocks_prices(height, price_id) VALUES`; + for (const price of blockPrices) { + query += ` (${price.height}, ${price.priceId}),`; + } + query = query.slice(0, -1); + await DB.query(query); + } catch (e: any) { + if (e.errno === 1062) { // ER_DUP_ENTRY - This scenario is possible upon node backend restart + logger.debug(`Cannot save blocks prices for blocks [${blockPrices[0].height} to ${blockPrices[blockPrices.length - 1].height}] because it has already been indexed, ignoring`); + } else { + logger.err(`Cannot save blocks prices for blocks [${blockPrices[0].height} to ${blockPrices[blockPrices.length - 1].height}] into db. Reason: ` + (e instanceof Error ? e.message : e)); + } + } + } + + /** + * Get all indexed blocsk with missing coinstatsindex data + */ + public async $getBlocksMissingCoinStatsIndex(maxHeight: number, minHeight: number): Promise { + try { + const [blocks] = await DB.query(` + SELECT height, hash + FROM blocks + WHERE height >= ${minHeight} AND height <= ${maxHeight} AND + (utxoset_size IS NULL OR total_input_amt IS NULL) + `); + return blocks; + } catch (e) { + logger.err(`Cannot get blocks with missing coinstatsindex. Reason: ` + (e instanceof Error ? e.message : e)); + return []; + } + } + + /** + * Get all indexed blocks with missing coinbase addresses + */ + public async $getBlocksWithoutCoinbaseAddresses(): Promise { + try { + const [blocks] = await DB.query(` + SELECT height, hash, coinbase_addresses + FROM blocks + WHERE coinbase_addresses IS NULL AND + coinbase_address IS NOT NULL + ORDER BY height DESC + `); + return blocks; + } catch (e) { + logger.err(`Cannot get blocks with missing coinbase addresses. Reason: ` + (e instanceof Error ? e.message : e)); + return []; + } + } + + /** + * Save indexed median fee to avoid recomputing it later + * + * @param id + * @param feePercentiles + */ + public async $saveFeePercentilesForBlockId(id: string, feePercentiles: number[]): Promise { + try { + await DB.query(` + UPDATE blocks SET fee_percentiles = ?, median_fee_amt = ? + WHERE hash = ?`, + [JSON.stringify(feePercentiles), feePercentiles[3], id] + ); + } catch (e) { + logger.err(`Cannot update block fee_percentiles. Reason: ` + (e instanceof Error ? e.message : e)); + throw e; + } + } + + /** + * Save indexed effective fee statistics + * + * @param id + * @param feeStats + */ + public async $saveEffectiveFeeStats(id: string, feeStats: EffectiveFeeStats): Promise { + try { + await DB.query(` + UPDATE blocks SET median_fee = ?, fee_span = ? + WHERE hash = ?`, + [feeStats.medianFee, JSON.stringify(feeStats.feeRange), id] + ); + } catch (e) { + logger.err(`Cannot update block fee stats. Reason: ` + (e instanceof Error ? e.message : e)); + throw e; + } + } + + /** + * Save coinbase addresses + * + * @param id + * @param addresses + */ + public async $saveCoinbaseAddresses(id: string, addresses: string[]): Promise { + try { + await DB.query(` + UPDATE blocks SET coinbase_addresses = ? + WHERE hash = ?`, + [JSON.stringify(addresses), id] + ); + } catch (e) { + logger.err(`Cannot update block coinbase addresses. Reason: ` + (e instanceof Error ? e.message : e)); + throw e; + } + } + + /** + * Save pool + * + * @param id + * @param poolId + */ + public async $savePool(id: string, poolId: number): Promise { + try { + await DB.query(` + UPDATE blocks SET pool_id = ? + WHERE hash = ?`, + [poolId, id] + ); + } catch (e) { + logger.err(`Cannot update block pool. Reason: ` + (e instanceof Error ? e.message : e)); + throw e; + } + } + + /** + * Convert a mysql row block into a BlockExtended. Note that you + * must provide the correct field into dbBlk object param + * + * @param dbBlk + */ + private async formatDbBlockIntoExtendedBlock(dbBlk: DatabaseBlock): Promise { + const blk: Partial = {}; + const extras: Partial = {}; + + // IEsploraApi.Block + blk.id = dbBlk.id; + blk.height = dbBlk.height; + blk.version = dbBlk.version; + blk.timestamp = dbBlk.timestamp; + blk.bits = dbBlk.bits; + blk.nonce = dbBlk.nonce; + blk.difficulty = dbBlk.difficulty; + blk.merkle_root = dbBlk.merkle_root; + blk.tx_count = dbBlk.tx_count; + blk.size = dbBlk.size; + blk.weight = dbBlk.weight; + blk.previousblockhash = dbBlk.previousblockhash; + blk.mediantime = dbBlk.mediantime; + + // BlockExtension + extras.totalFees = dbBlk.totalFees; + extras.medianFee = dbBlk.medianFee; + extras.feeRange = JSON.parse(dbBlk.feeRange); + extras.reward = dbBlk.reward; + extras.pool = { + id: dbBlk.poolId, + name: dbBlk.poolName, + slug: dbBlk.poolSlug, + }; + extras.avgFee = dbBlk.avgFee; + extras.avgFeeRate = dbBlk.avgFeeRate; + extras.coinbaseRaw = dbBlk.coinbaseRaw; + extras.coinbaseAddress = dbBlk.coinbaseAddress; + extras.coinbaseAddresses = dbBlk.coinbaseAddresses ? JSON.parse(dbBlk.coinbaseAddresses) : []; + extras.coinbaseSignature = dbBlk.coinbaseSignature; + extras.coinbaseSignatureAscii = dbBlk.coinbaseSignatureAscii; + extras.avgTxSize = dbBlk.avgTxSize; + extras.totalInputs = dbBlk.totalInputs; + extras.totalOutputs = dbBlk.totalOutputs; + extras.totalOutputAmt = dbBlk.totalOutputAmt; + extras.medianFeeAmt = dbBlk.medianFeeAmt; + extras.feePercentiles = JSON.parse(dbBlk.feePercentiles); + extras.segwitTotalTxs = dbBlk.segwitTotalTxs; + extras.segwitTotalSize = dbBlk.segwitTotalSize; + extras.segwitTotalWeight = dbBlk.segwitTotalWeight; + extras.header = dbBlk.header, + extras.utxoSetChange = dbBlk.utxoSetChange; + extras.utxoSetSize = dbBlk.utxoSetSize; + extras.totalInputAmt = dbBlk.totalInputAmt; + extras.virtualSize = dbBlk.weight / 4.0; + + // Re-org can happen after indexing so we need to always get the + // latest state from core + extras.orphans = chainTips.getOrphanedBlocksAtHeight(dbBlk.height); + + // Match rate is not part of the blocks table, but it is part of APIs so we must include it + extras.matchRate = null; + extras.expectedFees = null; + extras.expectedWeight = null; + if (config.MEMPOOL.AUDIT) { + const auditScore = await BlocksAuditsRepository.$getBlockAuditScore(dbBlk.id); + if (auditScore != null) { + extras.matchRate = auditScore.matchRate; + extras.expectedFees = auditScore.expectedFees; + extras.expectedWeight = auditScore.expectedWeight; + } + } + + // If we're missing block summary related field, check if we can populate them on the fly now + // This is for example triggered upon re-org + if (Common.blocksSummariesIndexingEnabled() && + (extras.medianFeeAmt === null || extras.feePercentiles === null)) + { + extras.feePercentiles = await BlocksSummariesRepository.$getFeePercentilesByBlockId(dbBlk.id); + if (extras.feePercentiles === null) { + + let summary; + let summaryVersion = 0; + if (config.MEMPOOL.BACKEND === 'esplora') { + const txs = (await bitcoinApi.$getTxsForBlock(dbBlk.id)).map(tx => transactionUtils.extendTransaction(tx)); + summary = blocks.summarizeBlockTransactions(dbBlk.id, txs); + summaryVersion = 1; + } else { + // Call Core RPC + const block = await bitcoinClient.getBlock(dbBlk.id, 2); + summary = blocks.summarizeBlock(block); + } + + await BlocksSummariesRepository.$saveTransactions(dbBlk.height, dbBlk.id, summary.transactions, summaryVersion); + extras.feePercentiles = await BlocksSummariesRepository.$getFeePercentilesByBlockId(dbBlk.id); + } + if (extras.feePercentiles !== null) { + extras.medianFeeAmt = extras.feePercentiles[3]; + await this.$updateFeeAmounts(dbBlk.id, extras.feePercentiles, extras.medianFeeAmt); + } + } + + blk.extras = extras; + return blk; + } +} + +export default new BlocksRepository(); diff --git a/backend/src/repositories/BlocksSummariesRepository.ts b/backend/src/repositories/BlocksSummariesRepository.ts new file mode 100644 index 0000000000..0268424f2b --- /dev/null +++ b/backend/src/repositories/BlocksSummariesRepository.ts @@ -0,0 +1,198 @@ +import { RowDataPacket } from 'mysql2'; +import DB from '../database'; +import logger from '../logger'; +import { BlockSummary, TransactionClassified } from '../mempool.interfaces'; + +class BlocksSummariesRepository { + public async $getByBlockId(id: string): Promise { + try { + const [summary]: any[] = await DB.query(`SELECT * from blocks_summaries WHERE id = ?`, [id]); + if (summary.length > 0) { + summary[0].transactions = JSON.parse(summary[0].transactions); + return summary[0]; + } + } catch (e) { + logger.err(`Cannot get block summary for block id ${id}. Reason: ` + (e instanceof Error ? e.message : e)); + } + + return undefined; + } + + public async $saveTransactions(blockHeight: number, blockId: string, transactions: TransactionClassified[], version: number): Promise { + try { + const transactionsStr = JSON.stringify(transactions); + await DB.query(` + INSERT INTO blocks_summaries + SET height = ?, transactions = ?, id = ?, version = ? + ON DUPLICATE KEY UPDATE transactions = ?, version = ?`, + [blockHeight, transactionsStr, blockId, version, transactionsStr, version]); + } catch (e: any) { + logger.debug(`Cannot save block summary transactions for ${blockId}. Reason: ${e instanceof Error ? e.message : e}`); + throw e; + } + } + + public async $saveTemplate(params: { height: number, template: BlockSummary, version: number}): Promise { + const blockId = params.template?.id; + try { + const transactions = JSON.stringify(params.template?.transactions || []); + await DB.query(` + INSERT INTO blocks_templates (id, template, version) + VALUE (?, ?, ?) + ON DUPLICATE KEY UPDATE + template = ?, + version = ? + `, [blockId, transactions, params.version, transactions, params.version]); + } catch (e: any) { + if (e.errno === 1062) { // ER_DUP_ENTRY - This scenario is possible upon node backend restart + logger.debug(`Cannot save block template for ${blockId} because it has already been indexed, ignoring`); + } else { + logger.warn(`Cannot save block template for ${blockId}. Reason: ${e instanceof Error ? e.message : e}`); + } + } + } + + public async $getTemplate(id: string): Promise { + try { + const [templates]: any[] = await DB.query(`SELECT * from blocks_templates WHERE id = ?`, [id]); + if (templates.length > 0) { + return { + id: templates[0].id, + transactions: JSON.parse(templates[0].template), + version: templates[0].version, + }; + } + } catch (e) { + logger.err(`Cannot get block template for block id ${id}. Reason: ` + (e instanceof Error ? e.message : e)); + } + return undefined; + } + + public async $getIndexedSummariesId(): Promise { + try { + const [rows] = await DB.query(`SELECT id from blocks_summaries`) as RowDataPacket[][]; + return rows.map(row => row.id); + } catch (e) { + logger.err(`Cannot get block summaries id list. Reason: ` + (e instanceof Error ? e.message : e)); + } + + return []; + } + + public async $getSummariesWithVersion(version: number): Promise<{ height: number, id: string }[]> { + try { + const [rows]: any[] = await DB.query(` + SELECT + height, + id + FROM blocks_summaries + WHERE version = ? + ORDER BY height DESC;`, [version]); + return rows; + } catch (e) { + logger.err(`Cannot get block summaries with version. Reason: ` + (e instanceof Error ? e.message : e)); + } + + return []; + } + + public async $getTemplatesWithVersion(version: number): Promise<{ height: number, id: string }[]> { + try { + const [rows]: any[] = await DB.query(` + SELECT + blocks_summaries.height as height, + blocks_templates.id as id + FROM blocks_templates + JOIN blocks_summaries ON blocks_templates.id = blocks_summaries.id + WHERE blocks_templates.version = ? + ORDER BY height DESC;`, [version]); + return rows; + } catch (e) { + logger.err(`Cannot get block summaries with version. Reason: ` + (e instanceof Error ? e.message : e)); + } + + return []; + } + + public async $getSummariesBelowVersion(version: number): Promise<{ height: number, id: string, version: number }[]> { + try { + const [rows]: any[] = await DB.query(` + SELECT + height, + id, + version + FROM blocks_summaries + WHERE version < ? + ORDER BY height DESC;`, [version]); + return rows; + } catch (e) { + logger.err(`Cannot get block summaries below version. Reason: ` + (e instanceof Error ? e.message : e)); + } + + return []; + } + + public async $getTemplatesBelowVersion(version: number): Promise<{ height: number, id: string, version: number }[]> { + try { + const [rows]: any[] = await DB.query(` + SELECT + blocks_summaries.height as height, + blocks_templates.id as id, + blocks_templates.version as version + FROM blocks_templates + JOIN blocks_summaries ON blocks_templates.id = blocks_summaries.id + WHERE blocks_templates.version < ? + ORDER BY height DESC;`, [version]); + return rows; + } catch (e) { + logger.err(`Cannot get block summaries below version. Reason: ` + (e instanceof Error ? e.message : e)); + } + + return []; + } + + /** + * Get the fee percentiles if the block has already been indexed, [] otherwise + * + * @param id + */ + public async $getFeePercentilesByBlockId(id: string): Promise { + try { + const [rows]: any[] = await DB.query(` + SELECT transactions + FROM blocks_summaries + WHERE id = ?`, + [id] + ); + if (rows === null || rows.length === 0) { + return null; + } + + const transactions = JSON.parse(rows[0].transactions); + if (transactions === null) { + return null; + } + + transactions.shift(); // Ignore coinbase + transactions.sort((a: any, b: any) => a.fee - b.fee); + const fees = transactions.map((t: any) => t.fee); + + return [ + fees[0] ?? 0, // min + fees[Math.max(0, Math.floor(fees.length * 0.1) - 1)] ?? 0, // 10th + fees[Math.max(0, Math.floor(fees.length * 0.25) - 1)] ?? 0, // 25th + fees[Math.max(0, Math.floor(fees.length * 0.5) - 1)] ?? 0, // median + fees[Math.max(0, Math.floor(fees.length * 0.75) - 1)] ?? 0, // 75th + fees[Math.max(0, Math.floor(fees.length * 0.9) - 1)] ?? 0, // 90th + fees[fees.length - 1] ?? 0, // max + ]; + + } catch (e) { + logger.err(`Cannot get block summaries transactions. Reason: ` + (e instanceof Error ? e.message : e)); + return null; + } + } +} + +export default new BlocksSummariesRepository(); + diff --git a/backend/src/repositories/CpfpRepository.ts b/backend/src/repositories/CpfpRepository.ts new file mode 100644 index 0000000000..0242188df4 --- /dev/null +++ b/backend/src/repositories/CpfpRepository.ts @@ -0,0 +1,272 @@ +import { RowDataPacket } from 'mysql2'; +import DB from '../database'; +import logger from '../logger'; +import { Ancestor, CpfpCluster } from '../mempool.interfaces'; +import transactionRepository from '../repositories/TransactionRepository'; + +class CpfpRepository { + public async $batchSaveClusters(clusters: { root: string, height: number, txs: Ancestor[], effectiveFeePerVsize: number }[]): Promise { + try { + const clusterValues: [string, number, Buffer, number][] = []; + const txs: { txid: string, cluster: string }[] = []; + + for (const cluster of clusters) { + if (cluster.txs?.length) { + const roundedEffectiveFee = Math.round(cluster.effectiveFeePerVsize * 100) / 100; + const equalFee = cluster.txs.length > 1 && cluster.txs.reduce((acc, tx) => { + return (acc && Math.round(((tx.fee || 0) / (tx.weight / 4)) * 100) / 100 === roundedEffectiveFee); + }, true); + if (!equalFee) { + clusterValues.push([ + cluster.root, + cluster.height, + Buffer.from(this.pack(cluster.txs)), + cluster.effectiveFeePerVsize + ]); + for (const tx of cluster.txs) { + txs.push({ txid: tx.txid, cluster: cluster.root }); + } + } + } + } + + if (!clusterValues.length) { + return false; + } + + const queries: { query, params }[] = []; + + const maxChunk = 100; + let chunkIndex = 0; + // insert clusters in batches of up to 100 rows + while (chunkIndex < clusterValues.length) { + const chunk = clusterValues.slice(chunkIndex, chunkIndex + maxChunk); + let query = ` + INSERT IGNORE INTO compact_cpfp_clusters(root, height, txs, fee_rate) + VALUES + `; + query += chunk.map(chunk => { + return (' (UNHEX(?), ?, ?, ?)'); + }) + ';'; + const values = chunk.flat(); + queries.push({ + query, + params: values, + }); + chunkIndex += maxChunk; + } + + chunkIndex = 0; + // insert transactions in batches of up to 100 rows + while (chunkIndex < txs.length) { + const chunk = txs.slice(chunkIndex, chunkIndex + maxChunk); + queries.push(transactionRepository.buildBatchSetQuery(chunk)); + chunkIndex += maxChunk; + } + + await DB.$atomicQuery(queries); + + return true; + } catch (e: any) { + logger.err(`Cannot save cpfp clusters into db. Reason: ` + (e instanceof Error ? e.message : e)); + throw e; + } + } + + public async $getCluster(clusterRoot: string): Promise { + const [clusterRows]: any = await DB.query( + ` + SELECT * + FROM compact_cpfp_clusters + WHERE root = UNHEX(?) + `, + [clusterRoot] + ); + const cluster = clusterRows[0]; + if (cluster?.txs) { + cluster.effectiveFeePerVsize = cluster.fee_rate; + cluster.txs = this.unpack(cluster.txs); + return cluster; + } + return; + } + + public async $getClustersAt(height: number): Promise { + const [clusterRows]: any = await DB.query( + ` + SELECT * + FROM compact_cpfp_clusters + WHERE height = ? + `, + [height] + ); + return clusterRows.map(cluster => { + if (cluster?.txs) { + cluster.effectiveFeePerVsize = cluster.fee_rate; + cluster.txs = this.unpack(cluster.txs); + return cluster; + } else { + return null; + } + }).filter(cluster => cluster !== null); + } + + public async $deleteClustersFrom(height: number): Promise { + logger.info(`Delete newer cpfp clusters from height ${height} from the database`); + try { + const [rows] = await DB.query( + ` + SELECT txs, height, root from compact_cpfp_clusters + WHERE height >= ? + `, + [height] + ) as RowDataPacket[][]; + if (rows?.length) { + for (const clusterToDelete of rows) { + const txs = this.unpack(clusterToDelete?.txs); + for (const tx of txs) { + await transactionRepository.$removeTransaction(tx.txid); + } + } + } + await DB.query( + ` + DELETE from compact_cpfp_clusters + WHERE height >= ? + `, + [height] + ); + } catch (e: any) { + logger.err(`Cannot delete cpfp clusters from db. Reason: ` + (e instanceof Error ? e.message : e)); + throw e; + } + } + + public async $deleteClustersAt(height: number): Promise { + logger.info(`Delete cpfp clusters at height ${height} from the database`); + try { + const [rows] = await DB.query( + ` + SELECT txs, height, root from compact_cpfp_clusters + WHERE height = ? + `, + [height] + ) as RowDataPacket[][]; + if (rows?.length) { + for (const clusterToDelete of rows) { + const txs = this.unpack(clusterToDelete?.txs); + for (const tx of txs) { + await transactionRepository.$removeTransaction(tx.txid); + } + } + } + await DB.query( + ` + DELETE from compact_cpfp_clusters + WHERE height = ? + `, + [height] + ); + } catch (e: any) { + logger.err(`Cannot delete cpfp clusters from db. Reason: ` + (e instanceof Error ? e.message : e)); + throw e; + } + } + + // insert a dummy row to mark that we've indexed as far as this block + public async $insertProgressMarker(height: number): Promise { + try { + const [rows]: any = await DB.query( + ` + SELECT root + FROM compact_cpfp_clusters + WHERE height = ? + `, + [height] + ); + if (!rows?.length) { + const rootBuffer = Buffer.alloc(32); + rootBuffer.writeInt32LE(height); + await DB.query( + ` + INSERT INTO compact_cpfp_clusters(root, height, fee_rate) + VALUE (?, ?, ?) + `, + [rootBuffer, height, 0] + ); + } + } catch (e: any) { + logger.err(`Cannot insert cpfp progress marker. Reason: ` + (e instanceof Error ? e.message : e)); + throw e; + } + } + + public pack(txs: Ancestor[]): ArrayBuffer { + const buf = new ArrayBuffer(44 * txs.length); + const view = new DataView(buf); + txs.forEach((tx, i) => { + const offset = i * 44; + for (let x = 0; x < 32; x++) { + // store txid in little-endian + view.setUint8(offset + (31 - x), parseInt(tx.txid.slice(x * 2, (x * 2) + 2), 16)); + } + view.setUint32(offset + 32, tx.weight); + view.setBigUint64(offset + 36, BigInt(Math.round(tx.fee))); + }); + return buf; + } + + public unpack(buf: Buffer): Ancestor[] { + if (!buf) { + return []; + } + + try { + const arrayBuffer = buf.buffer.slice(buf.byteOffset, buf.byteOffset + buf.byteLength); + const txs: Ancestor[] = []; + const view = new DataView(arrayBuffer); + for (let offset = 0; offset < arrayBuffer.byteLength; offset += 44) { + const txid = Array.from(new Uint8Array(arrayBuffer, offset, 32)).reverse().map(b => b.toString(16).padStart(2, '0')).join(''); + const weight = view.getUint32(offset + 32); + const fee = Number(view.getBigUint64(offset + 36)); + txs.push({ + txid, + weight, + fee + }); + } + return txs; + } catch (e) { + logger.warn(`Failed to unpack CPFP cluster. Reason: ` + (e instanceof Error ? e.message : e)); + return []; + } + } + + // returns `true` if two sets of CPFP clusters are deeply identical + public compareClusters(clustersA: CpfpCluster[], clustersB: CpfpCluster[]): boolean { + if (clustersA.length !== clustersB.length) { + return false; + } + + clustersA = clustersA.sort((a,b) => a.root.localeCompare(b.root)); + clustersB = clustersB.sort((a,b) => a.root.localeCompare(b.root)); + + for (let i = 0; i < clustersA.length; i++) { + if (clustersA[i].root !== clustersB[i].root) { + return false; + } + if (clustersA[i].txs.length !== clustersB[i].txs.length) { + return false; + } + for (let j = 0; j < clustersA[i].txs.length; j++) { + if (clustersA[i].txs[j].txid !== clustersB[i].txs[j].txid) { + return false; + } + } + } + + return true; + } +} + +export default new CpfpRepository(); \ No newline at end of file diff --git a/backend/src/repositories/DifficultyAdjustmentsRepository.ts b/backend/src/repositories/DifficultyAdjustmentsRepository.ts new file mode 100644 index 0000000000..0b19cc6405 --- /dev/null +++ b/backend/src/repositories/DifficultyAdjustmentsRepository.ts @@ -0,0 +1,123 @@ +import { Common } from '../api/common'; +import DB from '../database'; +import logger from '../logger'; +import { IndexedDifficultyAdjustment } from '../mempool.interfaces'; + +class DifficultyAdjustmentsRepository { + public async $saveAdjustments(adjustment: IndexedDifficultyAdjustment): Promise { + if (adjustment.height === 1) { + return; + } + + try { + const query = `INSERT INTO difficulty_adjustments(time, height, difficulty, adjustment) VALUE (FROM_UNIXTIME(?), ?, ?, ?)`; + const params: any[] = [ + adjustment.time, + adjustment.height, + adjustment.difficulty, + adjustment.adjustment, + ]; + await DB.query(query, params); + } catch (e: any) { + if (e.errno === 1062) { // ER_DUP_ENTRY - This scenario is possible upon node backend restart + logger.debug(`Cannot save difficulty adjustment at block ${adjustment.height}, already indexed, ignoring`, logger.tags.mining); + } else { + logger.err(`Cannot save difficulty adjustment at block ${adjustment.height}. Reason: ${e instanceof Error ? e.message : e}`, logger.tags.mining); + throw e; + } + } + } + + public async $getAdjustments(interval: string | null, descOrder: boolean = false): Promise { + interval = Common.getSqlInterval(interval); + + let query = `SELECT + CAST(AVG(UNIX_TIMESTAMP(time)) as INT) as time, + CAST(AVG(height) AS INT) as height, + CAST(AVG(difficulty) as DOUBLE) as difficulty, + CAST(AVG(adjustment) as DOUBLE) as adjustment + FROM difficulty_adjustments`; + + if (interval) { + query += ` WHERE time BETWEEN DATE_SUB(NOW(), INTERVAL ${interval}) AND NOW()`; + } + + query += ` GROUP BY UNIX_TIMESTAMP(time) DIV ${86400}`; + + if (descOrder === true) { + query += ` ORDER BY height DESC`; + } else { + query += ` ORDER BY height`; + } + + try { + const [rows] = await DB.query(query); + return rows as IndexedDifficultyAdjustment[]; + } catch (e) { + logger.err(`Cannot get difficulty adjustments from the database. Reason: ` + (e instanceof Error ? e.message : e), logger.tags.mining); + throw e; + } + } + + public async $getRawAdjustments(interval: string | null, descOrder: boolean = false): Promise { + interval = Common.getSqlInterval(interval); + + let query = `SELECT + UNIX_TIMESTAMP(time) as time, + height as height, + difficulty as difficulty, + adjustment as adjustment + FROM difficulty_adjustments`; + + if (interval) { + query += ` WHERE time BETWEEN DATE_SUB(NOW(), INTERVAL ${interval}) AND NOW()`; + } + + if (descOrder === true) { + query += ` ORDER BY height DESC`; + } else { + query += ` ORDER BY height`; + } + + try { + const [rows] = await DB.query(query); + return rows as IndexedDifficultyAdjustment[]; + } catch (e) { + logger.err(`Cannot get difficulty adjustments from the database. Reason: ` + (e instanceof Error ? e.message : e), logger.tags.mining); + throw e; + } + } + + public async $getAdjustmentsHeights(): Promise { + try { + const [rows]: any[] = await DB.query(`SELECT height FROM difficulty_adjustments`); + return rows.map(block => block.height); + } catch (e: any) { + logger.err(`Cannot get difficulty adjustment block heights. Reason: ${e instanceof Error ? e.message : e}`, logger.tags.mining); + throw e; + } + } + + public async $deleteAdjustementsFromHeight(height: number): Promise { + try { + logger.info(`Delete newer difficulty adjustments from height ${height} from the database`, logger.tags.mining); + await DB.query(`DELETE FROM difficulty_adjustments WHERE height >= ?`, [height]); + } catch (e: any) { + logger.err(`Cannot delete difficulty adjustments from the database. Reason: ${e instanceof Error ? e.message : e}`, logger.tags.mining); + throw e; + } + } + + public async $deleteLastAdjustment(): Promise { + try { + logger.info(`Delete last difficulty adjustment from the database`, logger.tags.mining); + await DB.query(`DELETE FROM difficulty_adjustments ORDER BY time LIMIT 1`); + } catch (e: any) { + logger.err(`Cannot delete last difficulty adjustment from the database. Reason: ${e instanceof Error ? e.message : e}`, logger.tags.mining); + throw e; + } + } +} + +export default new DifficultyAdjustmentsRepository(); + diff --git a/backend/src/repositories/HashratesRepository.ts b/backend/src/repositories/HashratesRepository.ts new file mode 100644 index 0000000000..ec44afebe7 --- /dev/null +++ b/backend/src/repositories/HashratesRepository.ts @@ -0,0 +1,236 @@ +import { escape } from 'mysql2'; +import { Common } from '../api/common'; +import mining from '../api/mining/mining'; +import DB from '../database'; +import logger from '../logger'; +import PoolsRepository from './PoolsRepository'; + +class HashratesRepository { + /** + * Save indexed block data in the database + */ + public async $saveHashrates(hashrates: any) { + if (hashrates.length === 0) { + return; + } + + let query = `INSERT INTO + hashrates(hashrate_timestamp, avg_hashrate, pool_id, share, type) VALUES`; + + for (const hashrate of hashrates) { + query += ` (FROM_UNIXTIME(${hashrate.hashrateTimestamp}), ${hashrate.avgHashrate}, ${hashrate.poolId}, ${hashrate.share}, "${hashrate.type}"),`; + } + query = query.slice(0, -1); + + try { + await DB.query(query); + } catch (e: any) { + logger.err('Cannot save indexed hashrate into db. Reason: ' + (e instanceof Error ? e.message : e), logger.tags.mining); + throw e; + } + } + + public async $getRawNetworkDailyHashrate(interval: string | null): Promise { + interval = Common.getSqlInterval(interval); + + let query = `SELECT + UNIX_TIMESTAMP(hashrate_timestamp) as timestamp, + avg_hashrate as avgHashrate + FROM hashrates`; + + if (interval) { + query += ` WHERE hashrate_timestamp BETWEEN DATE_SUB(NOW(), INTERVAL ${interval}) AND NOW() + AND hashrates.type = 'daily'`; + } else { + query += ` WHERE hashrates.type = 'daily'`; + } + + query += ` ORDER by hashrate_timestamp`; + + try { + const [rows]: any[] = await DB.query(query); + return rows; + } catch (e) { + logger.err('Cannot fetch network hashrate history. Reason: ' + (e instanceof Error ? e.message : e), logger.tags.mining); + throw e; + } + } + + public async $getNetworkDailyHashrate(interval: string | null): Promise { + interval = Common.getSqlInterval(interval); + + let query = `SELECT + CAST(AVG(UNIX_TIMESTAMP(hashrate_timestamp)) as INT) as timestamp, + CAST(AVG(avg_hashrate) as DOUBLE) as avgHashrate + FROM hashrates`; + + if (interval) { + query += ` WHERE hashrate_timestamp BETWEEN DATE_SUB(NOW(), INTERVAL ${interval}) AND NOW() + AND hashrates.type = 'daily'`; + } else { + query += ` WHERE hashrates.type = 'daily'`; + } + + query += ` GROUP BY UNIX_TIMESTAMP(hashrate_timestamp) DIV ${86400}`; + query += ` ORDER by hashrate_timestamp`; + + try { + const [rows]: any[] = await DB.query(query); + return rows; + } catch (e) { + logger.err('Cannot fetch network hashrate history. Reason: ' + (e instanceof Error ? e.message : e), logger.tags.mining); + throw e; + } + } + + public async $getWeeklyHashrateTimestamps(): Promise { + const query = `SELECT UNIX_TIMESTAMP(hashrate_timestamp) as timestamp + FROM hashrates + WHERE type = 'weekly' + GROUP BY hashrate_timestamp`; + + try { + const [rows]: any[] = await DB.query(query); + return rows.map(row => row.timestamp); + } catch (e) { + logger.err('Cannot retreive indexed weekly hashrate timestamps. Reason: ' + (e instanceof Error ? e.message : e), logger.tags.mining); + throw e; + } + } + + /** + * Returns the current biggest pool hashrate history + */ + public async $getPoolsWeeklyHashrate(interval: string | null): Promise { + interval = Common.getSqlInterval(interval); + + const topPoolsId = (await PoolsRepository.$getPoolsInfo('1w')).map((pool) => pool.poolId); + if (topPoolsId.length === 0) { + return []; + } + + let query = `SELECT UNIX_TIMESTAMP(hashrate_timestamp) as timestamp, avg_hashrate as avgHashrate, share, pools.name as poolName + FROM hashrates + JOIN pools on pools.id = pool_id`; + + if (interval) { + query += ` WHERE hashrate_timestamp BETWEEN DATE_SUB(NOW(), INTERVAL ${interval}) AND NOW() + AND hashrates.type = 'weekly' + AND pool_id IN (${topPoolsId})`; + } else { + query += ` WHERE hashrates.type = 'weekly' + AND pool_id IN (${topPoolsId})`; + } + + query += ` ORDER by hashrate_timestamp, FIELD(pool_id, ${topPoolsId})`; + + try { + const [rows]: any[] = await DB.query(query); + return rows; + } catch (e) { + logger.err('Cannot fetch weekly pools hashrate history. Reason: ' + (e instanceof Error ? e.message : e), logger.tags.mining); + throw e; + } + } + + /** + * Returns a pool hashrate history + */ + public async $getPoolWeeklyHashrate(slug: string): Promise { + const pool = await PoolsRepository.$getPool(slug); + if (!pool) { + throw new Error('This mining pool does not exist'); + } + + // Find hashrate boundaries + let query = `SELECT MIN(hashrate_timestamp) as firstTimestamp, MAX(hashrate_timestamp) as lastTimestamp + FROM hashrates + JOIN pools on pools.id = pool_id + WHERE hashrates.type = 'weekly' AND pool_id = ? AND avg_hashrate != 0 + ORDER by hashrate_timestamp LIMIT 1`; + + let boundaries = { + firstTimestamp: '1970-01-01', + lastTimestamp: '9999-01-01' + }; + + try { + const [rows]: any[] = await DB.query(query, [pool.id]); + boundaries = rows[0]; + } catch (e) { + logger.err('Cannot fetch hashrate start/end timestamps for this pool. Reason: ' + (e instanceof Error ? e.message : e), logger.tags.mining); + } + + // Get hashrates entries between boundaries + query = `SELECT UNIX_TIMESTAMP(hashrate_timestamp) as timestamp, avg_hashrate as avgHashrate, share, pools.name as poolName + FROM hashrates + JOIN pools on pools.id = pool_id + WHERE hashrates.type = 'weekly' AND hashrate_timestamp BETWEEN ? AND ? + AND pool_id = ? + ORDER by hashrate_timestamp`; + + try { + const [rows]: any[] = await DB.query(query, [boundaries.firstTimestamp, boundaries.lastTimestamp, pool.id]); + return rows; + } catch (e) { + logger.err('Cannot fetch pool hashrate history for this pool. Reason: ' + (e instanceof Error ? e.message : e), logger.tags.mining); + throw e; + } + } + + /** + * Get latest run timestamp + */ + public async $getLatestRun(key: string): Promise { + const query = `SELECT number FROM state WHERE name = ?`; + + try { + const [rows]: any[] = await DB.query(query, [key]); + + if (rows.length === 0) { + return 0; + } + return rows[0]['number']; + } catch (e) { + logger.err(`Cannot retrieve last indexing run for ${key}. Reason: ` + (e instanceof Error ? e.message : e), logger.tags.mining); + throw e; + } + } + + /** + * Delete most recent data points for re-indexing + */ + public async $deleteLastEntries() { + logger.info(`Delete latest hashrates data points from the database`, logger.tags.mining); + + try { + const [rows]: any[] = await DB.query(`SELECT MAX(hashrate_timestamp) as timestamp FROM hashrates GROUP BY type`); + for (const row of rows) { + await DB.query(`DELETE FROM hashrates WHERE hashrate_timestamp = ?`, [row.timestamp]); + } + // Re-run the hashrate indexing to fill up missing data + mining.lastHashrateIndexingDate = null; + mining.lastWeeklyHashrateIndexingDate = null; + } catch (e) { + logger.err('Cannot delete latest hashrates data points. Reason: ' + (e instanceof Error ? e.message : e), logger.tags.mining); + } + } + + /** + * Delete hashrates from the database from timestamp + */ + public async $deleteHashratesFromTimestamp(timestamp: number) { + logger.info(`Delete newer hashrates from timestamp ${new Date(timestamp * 1000).toUTCString()} from the database`, logger.tags.mining); + + try { + await DB.query(`DELETE FROM hashrates WHERE hashrate_timestamp >= FROM_UNIXTIME(?)`, [timestamp]); + // Re-run the hashrate indexing to fill up missing data + mining.lastHashrateIndexingDate = null; + mining.lastWeeklyHashrateIndexingDate = null; + } catch (e) { + logger.err('Cannot delete latest hashrates data points. Reason: ' + (e instanceof Error ? e.message : e), logger.tags.mining); + } + } +} + +export default new HashratesRepository(); diff --git a/backend/src/repositories/NodeRecordsRepository.ts b/backend/src/repositories/NodeRecordsRepository.ts new file mode 100644 index 0000000000..cf676e35e2 --- /dev/null +++ b/backend/src/repositories/NodeRecordsRepository.ts @@ -0,0 +1,67 @@ +import { ResultSetHeader, RowDataPacket } from 'mysql2'; +import DB from '../database'; +import logger from '../logger'; + +export interface NodeRecord { + publicKey: string; // node public key + type: number; // TLV extension record type + payload: string; // base64 record payload +} + +class NodesRecordsRepository { + public async $saveRecord(record: NodeRecord): Promise { + try { + const payloadBytes = Buffer.from(record.payload, 'base64'); + await DB.query(` + INSERT INTO nodes_records(public_key, type, payload) + VALUE (?, ?, ?) + ON DUPLICATE KEY UPDATE + payload = ? + `, [record.publicKey, record.type, payloadBytes, payloadBytes]); + } catch (e: any) { + if (e.errno !== 1062) { // ER_DUP_ENTRY - Not an issue, just ignore this + logger.err(`Cannot save node record (${[record.publicKey, record.type, record.payload]}) into db. Reason: ` + (e instanceof Error ? e.message : e)); + // We don't throw, not a critical issue if we miss some nodes records + } + } + } + + public async $getRecordTypes(publicKey: string): Promise { + try { + const query = ` + SELECT type FROM nodes_records + WHERE public_key = ? + `; + const [rows] = await DB.query(query, [publicKey]); + return rows.map(row => row['type']); + } catch (e) { + logger.err(`Cannot retrieve custom records for ${publicKey} from db. Reason: ` + (e instanceof Error ? e.message : e)); + return []; + } + } + + public async $deleteUnusedRecords(publicKey: string, recordTypes: number[]): Promise { + try { + let query; + if (recordTypes.length) { + query = ` + DELETE FROM nodes_records + WHERE public_key = ? + AND type NOT IN (${recordTypes.map(type => `${type}`).join(',')}) + `; + } else { + query = ` + DELETE FROM nodes_records + WHERE public_key = ? + `; + } + const [result] = await DB.query(query, [publicKey]); + return result.affectedRows; + } catch (e) { + logger.err(`Cannot delete unused custom records for ${publicKey} from db. Reason: ` + (e instanceof Error ? e.message : e)); + return 0; + } + } +} + +export default new NodesRecordsRepository(); diff --git a/backend/src/repositories/NodesSocketsRepository.ts b/backend/src/repositories/NodesSocketsRepository.ts new file mode 100644 index 0000000000..e85126de42 --- /dev/null +++ b/backend/src/repositories/NodesSocketsRepository.ts @@ -0,0 +1,45 @@ +import { ResultSetHeader } from 'mysql2'; +import DB from '../database'; +import logger from '../logger'; + +export interface NodeSocket { + publicKey: string; + network: string | null; + addr: string; +} + +class NodesSocketsRepository { + public async $saveSocket(socket: NodeSocket): Promise { + try { + await DB.query(` + INSERT INTO nodes_sockets(public_key, socket, type) + VALUE (?, ?, ?) + `, [socket.publicKey, socket.addr, socket.network], 'silent'); + } catch (e: any) { + if (e.errno !== 1062) { // ER_DUP_ENTRY - Not an issue, just ignore this + logger.err(`Cannot save node socket (${[socket.publicKey, socket.addr, socket.network]}) into db. Reason: ` + (e instanceof Error ? e.message : e)); + // We don't throw, not a critical issue if we miss some nodes sockets + } + } + } + + public async $deleteUnusedSockets(publicKey: string, addresses: string[]): Promise { + if (addresses.length === 0) { + return 0; + } + try { + const query = ` + DELETE FROM nodes_sockets + WHERE public_key = ? + AND socket NOT IN (${addresses.map(id => `"${id}"`).join(',')}) + `; + const [result] = await DB.query(query, [publicKey]); + return result.affectedRows; + } catch (e) { + logger.err(`Cannot delete unused sockets for ${publicKey} from db. Reason: ` + (e instanceof Error ? e.message : e)); + return 0; + } + } +} + +export default new NodesSocketsRepository(); diff --git a/backend/src/repositories/PoolsRepository.ts b/backend/src/repositories/PoolsRepository.ts new file mode 100644 index 0000000000..eda792bb3e --- /dev/null +++ b/backend/src/repositories/PoolsRepository.ts @@ -0,0 +1,227 @@ +import { Common } from '../api/common'; +import poolsParser from '../api/pools-parser'; +import config from '../config'; +import DB from '../database'; +import logger from '../logger'; +import { PoolInfo, PoolTag } from '../mempool.interfaces'; + +class PoolsRepository { + /** + * Get all pools tagging info + */ + public async $getPools(): Promise { + const [rows] = await DB.query('SELECT id, unique_id as uniqueId, name, addresses, regexes, slug FROM pools'); + return rows; + } + + /** + * Get unknown pool tagging info + */ + public async $getUnknownPool(): Promise { + let [rows]: any[] = await DB.query('SELECT id, unique_id as uniqueId, name, slug FROM pools where name = "Unknown"'); + if (rows && rows.length === 0 && config.DATABASE.ENABLED) { + await poolsParser.$insertUnknownPool(); + [rows] = await DB.query('SELECT id, unique_id as uniqueId, name, slug FROM pools where name = "Unknown"'); + } + return rows[0]; + } + + /** + * Get basic pool info and block count + */ + public async $getPoolsInfo(interval: string | null = null): Promise { + interval = Common.getSqlInterval(interval); + + let query = ` + SELECT + COUNT(blocks.height) As blockCount, + pool_id AS poolId, + pools.name AS name, + pools.link AS link, + slug, + AVG(blocks_audits.match_rate) AS avgMatchRate, + AVG((CAST(blocks.fees as SIGNED) - CAST(blocks_audits.expected_fees as SIGNED)) / NULLIF(CAST(blocks_audits.expected_fees as SIGNED), 0)) AS avgFeeDelta, + unique_id as poolUniqueId + FROM blocks + JOIN pools on pools.id = pool_id + LEFT JOIN blocks_audits ON blocks_audits.height = blocks.height + `; + + if (interval) { + query += ` WHERE blocks.blockTimestamp BETWEEN DATE_SUB(NOW(), INTERVAL ${interval}) AND NOW()`; + } + + query += ` GROUP BY pool_id + ORDER BY COUNT(blocks.height) DESC`; + + try { + const [rows] = await DB.query(query); + return rows; + } catch (e) { + logger.err(`Cannot generate pools stats. Reason: ` + (e instanceof Error ? e.message : e)); + throw e; + } + } + + /** + * Get basic pool info and block count between two timestamp + */ + public async $getPoolsInfoBetween(from: number, to: number): Promise { + const query = `SELECT COUNT(height) as blockCount, pools.id as poolId, pools.name as poolName + FROM pools + LEFT JOIN blocks on pools.id = blocks.pool_id AND blocks.blockTimestamp BETWEEN FROM_UNIXTIME(?) AND FROM_UNIXTIME(?) + GROUP BY pools.id`; + + try { + const [rows] = await DB.query(query, [from, to]); + return rows; + } catch (e) { + logger.err('Cannot generate pools blocks count. Reason: ' + (e instanceof Error ? e.message : e)); + throw e; + } + } + + /** + * Get a mining pool info + */ + public async $getPool(slug: string, parse: boolean = true): Promise { + const query = ` + SELECT * + FROM pools + WHERE pools.slug = ?`; + + try { + const [rows]: any[] = await DB.query(query, [slug]); + + if (rows.length < 1) { + return null; + } + + if (parse) { + rows[0].regexes = JSON.parse(rows[0].regexes); + } + if (['testnet', 'signet'].includes(config.MEMPOOL.NETWORK)) { + rows[0].addresses = []; // pools-v2.json only contains mainnet addresses + } else if (parse) { + rows[0].addresses = JSON.parse(rows[0].addresses); + } + + return rows[0]; + } catch (e) { + logger.err('Cannot get pool from db. Reason: ' + (e instanceof Error ? e.message : e)); + throw e; + } + } + + /** + * Get a mining pool info by its unique id + */ + public async $getPoolByUniqueId(id: number, parse: boolean = true): Promise { + const query = ` + SELECT * + FROM pools + WHERE pools.unique_id = ?`; + + try { + const [rows]: any[] = await DB.query(query, [id]); + + if (rows.length < 1) { + return null; + } + + if (parse) { + rows[0].regexes = JSON.parse(rows[0].regexes); + } + if (['testnet', 'signet'].includes(config.MEMPOOL.NETWORK)) { + rows[0].addresses = []; // pools.json only contains mainnet addresses + } else if (parse) { + rows[0].addresses = JSON.parse(rows[0].addresses); + } + + return rows[0]; + } catch (e) { + logger.err('Cannot get pool from db. Reason: ' + (e instanceof Error ? e.message : e)); + throw e; + } + } + + /** + * Insert a new mining pool in the database + * + * @param pool + */ + public async $insertNewMiningPool(pool: any, slug: string): Promise { + try { + await DB.query(` + INSERT INTO pools + SET name = ?, link = ?, addresses = ?, regexes = ?, slug = ?, unique_id = ?`, + [pool.name, pool.link, JSON.stringify(pool.addresses), JSON.stringify(pool.regexes), slug, pool.id] + ); + } catch (e: any) { + logger.err(`Cannot insert new mining pool into db. Reason: ` + (e instanceof Error ? e.message : e)); + } + } + + /** + * Rename an existing mining pool + * + * @param dbId + * @param newSlug + * @param newName + */ + public async $renameMiningPool(dbId: number, newSlug: string, newName: string): Promise { + try { + await DB.query(` + UPDATE pools + SET slug = ?, name = ? + WHERE id = ?`, + [newSlug, newName, dbId] + ); + } catch (e: any) { + logger.err(`Cannot rename mining pool id ${dbId}. Reason: ` + (e instanceof Error ? e.message : e)); + } + } + + /** + * Update an exisiting mining pool link + * + * @param dbId + * @param newLink + */ + public async $updateMiningPoolLink(dbId: number, newLink: string): Promise { + try { + await DB.query(` + UPDATE pools + SET link = ? + WHERE id = ?`, + [newLink, dbId] + ); + } catch (e: any) { + logger.err(`Cannot update link for mining pool id ${dbId}. Reason: ` + (e instanceof Error ? e.message : e)); + } + + } + + /** + * Update an existing mining pool addresses or coinbase tags + * + * @param dbId + * @param addresses + * @param regexes + */ + public async $updateMiningPoolTags(dbId: number, addresses: string, regexes: string): Promise { + try { + await DB.query(` + UPDATE pools + SET addresses = ?, regexes = ? + WHERE id = ?`, + [JSON.stringify(addresses), JSON.stringify(regexes), dbId] + ); + } catch (e: any) { + logger.err(`Cannot update mining pool id ${dbId}. Reason: ` + (e instanceof Error ? e.message : e)); + } + } + +} + +export default new PoolsRepository(); diff --git a/backend/src/repositories/PricesRepository.ts b/backend/src/repositories/PricesRepository.ts new file mode 100644 index 0000000000..13392f0cf4 --- /dev/null +++ b/backend/src/repositories/PricesRepository.ts @@ -0,0 +1,519 @@ +import DB from '../database'; +import logger from '../logger'; +import config from '../config'; +import priceUpdater from '../tasks/price-updater'; + +export interface ApiPrice { + time?: number, + USD: number, + EUR: number, + GBP: number, + CAD: number, + CHF: number, + AUD: number, + JPY: number, + BGN: number, + BRL: number, + CNY: number, + CZK: number, + DKK: number, + HKD: number, + HRK: number, + HUF: number, + IDR: number, + ILS: number, + INR: number, + ISK: number, + KRW: number, + MXN: number, + MYR: number, + NOK: number, + NZD: number, + PHP: number, + PLN: number, + RON: number, + RUB: number, + SEK: number, + SGD: number, + THB: number, + TRY: number, + ZAR: number, +} + +const ApiPriceFields = config.FIAT_PRICE.API_KEY ? + ` + UNIX_TIMESTAMP(time) as time, + USD, + EUR, + GBP, + CAD, + CHF, + AUD, + JPY, + BGN, + BRL, + CNY, + CZK, + DKK, + HKD, + HRK, + HUF, + IDR, + ILS, + INR, + ISK, + KRW, + MXN, + MYR, + NOK, + NZD, + PHP, + PLN, + RON, + RUB, + SEK, + SGD, + THB, + TRY, + ZAR + `: + ` + UNIX_TIMESTAMP(time) as time, + USD, + EUR, + GBP, + CAD, + CHF, + AUD, + JPY + `; + +export interface ExchangeRates { + USDEUR: number, + USDGBP: number, + USDCAD: number, + USDCHF: number, + USDAUD: number, + USDJPY: number, + USDBGN?: number, + USDBRL?: number, + USDCNY?: number, + USDCZK?: number, + USDDKK?: number, + USDHKD?: number, + USDHRK?: number, + USDHUF?: number, + USDIDR?: number, + USDILS?: number, + USDINR?: number, + USDISK?: number, + USDKRW?: number, + USDMXN?: number, + USDMYR?: number, + USDNOK?: number, + USDNZD?: number, + USDPHP?: number, + USDPLN?: number, + USDRON?: number, + USDRUB?: number, + USDSEK?: number, + USDSGD?: number, + USDTHB?: number, + USDTRY?: number, + USDZAR?: number, +} + +export interface Conversion { + prices: ApiPrice[], + exchangeRates: ExchangeRates; +} + +export const MAX_PRICES = { + USD: 100000000, + EUR: 100000000, + GBP: 100000000, + CAD: 100000000, + CHF: 100000000, + AUD: 100000000, + JPY: 10000000000, + BGN: 1000000000, + BRL: 1000000000, + CNY: 1000000000, + CZK: 10000000000, + DKK: 1000000000, + HKD: 1000000000, + HRK: 1000000000, + HUF: 10000000000, + IDR: 100000000000, + ILS: 1000000000, + INR: 10000000000, + ISK: 10000000000, + KRW: 100000000000, + MXN: 1000000000, + MYR: 1000000000, + NOK: 1000000000, + NZD: 1000000000, + PHP: 10000000000, + PLN: 1000000000, + RON: 1000000000, + RUB: 10000000000, + SEK: 1000000000, + SGD: 100000000, + THB: 10000000000, + TRY: 10000000000, + ZAR: 10000000000, +}; + +class PricesRepository { + public async $savePrices(time: number, prices: ApiPrice): Promise { + if (prices.USD === -1) { + // Some historical price entries have no USD prices, so we just ignore them to avoid future UX issues + // As of today there are only 4 (on 2013-09-05, 2013-0909, 2013-09-12 and 2013-09-26) so that's fine + return; + } + + // Sanity check + for (const currency of Object.keys(prices)) { + if (prices[currency] < -1 || prices[currency] > MAX_PRICES[currency]) { // We use -1 to mark a "missing data, so it's a valid entry" + logger.info(`Ignore BTC${currency} price of ${prices[currency]}`); + prices[currency] = 0; + } + } + + try { + if (!config.FIAT_PRICE.API_KEY) { // Store only the 7 main currencies + await DB.query(` + INSERT INTO prices(time, USD, EUR, GBP, CAD, CHF, AUD, JPY) + VALUE (FROM_UNIXTIME(?), ?, ?, ?, ?, ?, ?, ? )`, + [time, prices.USD, prices.EUR, prices.GBP, prices.CAD, prices.CHF, prices.AUD, prices.JPY] + ); + } else { // Store all 7 main currencies + all the currencies obtained with the external API + await DB.query(` + INSERT INTO prices(time, USD, EUR, GBP, CAD, CHF, AUD, JPY, BGN, BRL, CNY, CZK, DKK, HKD, HRK, HUF, IDR, ILS, INR, ISK, KRW, MXN, MYR, NOK, NZD, PHP, PLN, RON, RUB, SEK, SGD, THB, TRY, ZAR) + VALUE (FROM_UNIXTIME(?), ?, ?, ?, ?, ?, ?, ?, ? , ?, ?, ?, ?, ?, ?, ?, ? , ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ? , ? )`, + [time, prices.USD, prices.EUR, prices.GBP, prices.CAD, prices.CHF, prices.AUD, prices.JPY, prices.BGN, prices.BRL, prices.CNY, prices.CZK, prices.DKK, + prices.HKD, prices.HRK, prices.HUF, prices.IDR, prices.ILS, prices.INR, prices.ISK, prices.KRW, prices.MXN, prices.MYR, prices.NOK, prices.NZD, + prices.PHP, prices.PLN, prices.RON, prices.RUB, prices.SEK, prices.SGD, prices.THB, prices.TRY, prices.ZAR] + ); + } + } catch (e) { + logger.err(`Cannot save exchange rate into db. Reason: ` + (e instanceof Error ? e.message : e)); + throw e; + } + } + + public async $saveAdditionalCurrencyPrices(time: number, prices: ApiPrice, legacyCurrencies: string[]): Promise { + try { + await DB.query(` + UPDATE prices + SET BGN = ?, BRL = ?, CNY = ?, CZK = ?, DKK = ?, HKD = ?, HRK = ?, HUF = ?, IDR = ?, ILS = ?, INR = ?, ISK = ?, KRW = ?, MXN = ?, MYR = ?, NOK = ?, NZD = ?, PHP = ?, PLN = ?, RON = ?, RUB = ?, SEK = ?, SGD = ?, THB = ?, TRY = ?, ZAR = ? + WHERE UNIX_TIMESTAMP(time) = ?`, + [prices.BGN, prices.BRL, prices.CNY, prices.CZK, prices.DKK, prices.HKD, prices.HRK, prices.HUF, prices.IDR, prices.ILS, prices.INR, prices.ISK, prices.KRW, prices.MXN, prices.MYR, prices.NOK, prices.NZD, prices.PHP, prices.PLN, prices.RON, prices.RUB, prices.SEK, prices.SGD, prices.THB, prices.TRY, prices.ZAR, time] + ); + for (const currency of legacyCurrencies) { + await DB.query(` + UPDATE prices + SET ${currency} = ? + WHERE UNIX_TIMESTAMP(time) = ?`, + [prices[currency], time] + ); + } + } catch (e) { + logger.err(`Cannot update exchange rate into db. Reason: ` + (e instanceof Error ? e.message : e)); + throw e; + } + } + + public async $getOldestPriceTime(): Promise { + const [oldestRow] = await DB.query(` + SELECT UNIX_TIMESTAMP(time) AS time + FROM prices + ORDER BY time + LIMIT 1 + `); + return oldestRow[0] ? oldestRow[0].time : 0; + } + + public async $getLatestPriceId(): Promise { + const [oldestRow] = await DB.query(` + SELECT id + FROM prices + ORDER BY time DESC + LIMIT 1` + ); + return oldestRow[0] ? oldestRow[0].id : null; + } + + public async $getLatestPriceTime(): Promise { + const [oldestRow] = await DB.query(` + SELECT UNIX_TIMESTAMP(time) AS time + FROM prices + ORDER BY time DESC + LIMIT 1` + ); + return oldestRow[0] ? oldestRow[0].time : 0; + } + + public async $getPricesTimes(): Promise { + const [times] = await DB.query(` + SELECT UNIX_TIMESTAMP(time) AS time + FROM prices + WHERE USD != -1 + ORDER BY time + `); + if (!Array.isArray(times)) { + return []; + } + return times.map(time => time.time); + } + + public async $getPricesTimesWithMissingFields(): Promise<{time: number, USD: number, eur_missing: boolean, gbp_missing: boolean, cad_missing: boolean, chf_missing: boolean, aud_missing: boolean, jpy_missing: boolean}[]> { + const [times] = await DB.query(` + SELECT UNIX_TIMESTAMP(time) AS time, + USD, + CASE WHEN EUR = -1 THEN TRUE ELSE FALSE END AS eur_missing, + CASE WHEN GBP = -1 THEN TRUE ELSE FALSE END AS gbp_missing, + CASE WHEN CAD = -1 THEN TRUE ELSE FALSE END AS cad_missing, + CASE WHEN CHF = -1 THEN TRUE ELSE FALSE END AS chf_missing, + CASE WHEN AUD = -1 THEN TRUE ELSE FALSE END AS aud_missing, + CASE WHEN JPY = -1 THEN TRUE ELSE FALSE END AS jpy_missing + FROM prices + WHERE USD != -1 + AND -1 IN (EUR, GBP, CAD, CHF, AUD, JPY, BGN, BRL, CNY, CZK, DKK, HKD, HRK, HUF, IDR, ILS, INR, ISK, KRW, + MXN, MYR, NOK, NZD, PHP, PLN, RON, RUB, SEK, SGD, THB, TRY, ZAR) + ORDER BY time DESC + `); + if (!Array.isArray(times)) { + return []; + } + return times as {time: number, USD: number, eur_missing: boolean, gbp_missing: boolean, cad_missing: boolean, chf_missing: boolean, aud_missing: boolean, jpy_missing: boolean}[]; + } + + public async $getPricesTimesAndId(): Promise<{time: number, id: number, USD: number}[]> { + const [times] = await DB.query(` + SELECT + UNIX_TIMESTAMP(time) AS time, + id, + USD + FROM prices + ORDER BY time + `); + return times as {time: number, id: number, USD: number}[]; + } + + public async $getLatestConversionRates(): Promise { + const [rates] = await DB.query(` + SELECT ${ApiPriceFields} + FROM prices + ORDER BY time DESC + LIMIT 1` + ); + + if (!Array.isArray(rates) || rates.length === 0) { + return priceUpdater.getEmptyPricesObj(); + } + return rates[0] as ApiPrice; + } + + public async $getNearestHistoricalPrice(timestamp: number | undefined, currency?: string): Promise { + try { + const [rates] = await DB.query(` + SELECT ${ApiPriceFields} + FROM prices + WHERE UNIX_TIMESTAMP(time) < ? + ORDER BY time DESC + LIMIT 1`, + [timestamp] + ); + if (!Array.isArray(rates)) { + throw Error(`Cannot get single historical price from the database`); + } + + const [latestPrices] = await DB.query(` + SELECT ${ApiPriceFields} + FROM prices + ORDER BY time DESC + LIMIT 1 + `); + if (!Array.isArray(latestPrices)) { + throw Error(`Cannot get single historical price from the database`); + } + + // Compute fiat exchange rates + let latestPrice = latestPrices[0] as ApiPrice; + if (!latestPrice || latestPrice.USD === -1) { + latestPrice = priceUpdater.getEmptyPricesObj(); + } + + const computeFx = (usd: number, other: number): number => usd <= 0.05 ? 0 : Math.round(Math.max(other, 0) / usd * 100) / 100; + + const exchangeRates: ExchangeRates = config.FIAT_PRICE.API_KEY ? + { + USDEUR: computeFx(latestPrice.USD, latestPrice.EUR), + USDGBP: computeFx(latestPrice.USD, latestPrice.GBP), + USDCAD: computeFx(latestPrice.USD, latestPrice.CAD), + USDCHF: computeFx(latestPrice.USD, latestPrice.CHF), + USDAUD: computeFx(latestPrice.USD, latestPrice.AUD), + USDJPY: computeFx(latestPrice.USD, latestPrice.JPY), + USDBGN: computeFx(latestPrice.USD, latestPrice.BGN), + USDBRL: computeFx(latestPrice.USD, latestPrice.BRL), + USDCNY: computeFx(latestPrice.USD, latestPrice.CNY), + USDCZK: computeFx(latestPrice.USD, latestPrice.CZK), + USDDKK: computeFx(latestPrice.USD, latestPrice.DKK), + USDHKD: computeFx(latestPrice.USD, latestPrice.HKD), + USDHRK: computeFx(latestPrice.USD, latestPrice.HRK), + USDHUF: computeFx(latestPrice.USD, latestPrice.HUF), + USDIDR: computeFx(latestPrice.USD, latestPrice.IDR), + USDILS: computeFx(latestPrice.USD, latestPrice.ILS), + USDINR: computeFx(latestPrice.USD, latestPrice.INR), + USDISK: computeFx(latestPrice.USD, latestPrice.ISK), + USDKRW: computeFx(latestPrice.USD, latestPrice.KRW), + USDMXN: computeFx(latestPrice.USD, latestPrice.MXN), + USDMYR: computeFx(latestPrice.USD, latestPrice.MYR), + USDNOK: computeFx(latestPrice.USD, latestPrice.NOK), + USDNZD: computeFx(latestPrice.USD, latestPrice.NZD), + USDPHP: computeFx(latestPrice.USD, latestPrice.PHP), + USDPLN: computeFx(latestPrice.USD, latestPrice.PLN), + USDRON: computeFx(latestPrice.USD, latestPrice.RON), + USDRUB: computeFx(latestPrice.USD, latestPrice.RUB), + USDSEK: computeFx(latestPrice.USD, latestPrice.SEK), + USDSGD: computeFx(latestPrice.USD, latestPrice.SGD), + USDTHB: computeFx(latestPrice.USD, latestPrice.THB), + USDTRY: computeFx(latestPrice.USD, latestPrice.TRY), + USDZAR: computeFx(latestPrice.USD, latestPrice.ZAR), + } : { + USDEUR: computeFx(latestPrice.USD, latestPrice.EUR), + USDGBP: computeFx(latestPrice.USD, latestPrice.GBP), + USDCAD: computeFx(latestPrice.USD, latestPrice.CAD), + USDCHF: computeFx(latestPrice.USD, latestPrice.CHF), + USDAUD: computeFx(latestPrice.USD, latestPrice.AUD), + USDJPY: computeFx(latestPrice.USD, latestPrice.JPY), + }; + + if (currency) { + if (!latestPrice[currency]) { + return null; + } + const filteredRates = rates.map((rate: any) => { + return { + time: rate.time, + [currency]: rate[currency], + ['USD']: rate['USD'] + }; + }); + if (filteredRates.length === 0) { // No price data before 2010-07-19: add a fake entry + filteredRates.push({ + time: 1279497600, + [currency]: 0, + ['USD']: 0 + }); + } + return { + prices: filteredRates as ApiPrice[], + exchangeRates: exchangeRates + }; + } + + return { + prices: rates as ApiPrice[], + exchangeRates: exchangeRates + }; + } catch (e) { + logger.err(`Cannot fetch single historical prices from the db. Reason ${e instanceof Error ? e.message : e}`); + return null; + } + } + + public async $getHistoricalPrices(currency?: string): Promise { + try { + const [rates] = await DB.query(` + SELECT ${ApiPriceFields} + FROM prices + ORDER BY time DESC + `); + if (!Array.isArray(rates)) { + throw Error(`Cannot get average historical price from the database`); + } + + // Compute fiat exchange rates + let latestPrice = rates[0] as ApiPrice; + if (latestPrice.USD === -1) { + latestPrice = priceUpdater.getEmptyPricesObj(); + } + + const computeFx = (usd: number, other: number): number => + usd <= 0 ? 0 : Math.round(Math.max(other, 0) / usd * 100) / 100; + + const exchangeRates: ExchangeRates = config.FIAT_PRICE.API_KEY ? + { + USDEUR: computeFx(latestPrice.USD, latestPrice.EUR), + USDGBP: computeFx(latestPrice.USD, latestPrice.GBP), + USDCAD: computeFx(latestPrice.USD, latestPrice.CAD), + USDCHF: computeFx(latestPrice.USD, latestPrice.CHF), + USDAUD: computeFx(latestPrice.USD, latestPrice.AUD), + USDJPY: computeFx(latestPrice.USD, latestPrice.JPY), + USDBGN: computeFx(latestPrice.USD, latestPrice.BGN), + USDBRL: computeFx(latestPrice.USD, latestPrice.BRL), + USDCNY: computeFx(latestPrice.USD, latestPrice.CNY), + USDCZK: computeFx(latestPrice.USD, latestPrice.CZK), + USDDKK: computeFx(latestPrice.USD, latestPrice.DKK), + USDHKD: computeFx(latestPrice.USD, latestPrice.HKD), + USDHRK: computeFx(latestPrice.USD, latestPrice.HRK), + USDHUF: computeFx(latestPrice.USD, latestPrice.HUF), + USDIDR: computeFx(latestPrice.USD, latestPrice.IDR), + USDILS: computeFx(latestPrice.USD, latestPrice.ILS), + USDINR: computeFx(latestPrice.USD, latestPrice.INR), + USDISK: computeFx(latestPrice.USD, latestPrice.ISK), + USDKRW: computeFx(latestPrice.USD, latestPrice.KRW), + USDMXN: computeFx(latestPrice.USD, latestPrice.MXN), + USDMYR: computeFx(latestPrice.USD, latestPrice.MYR), + USDNOK: computeFx(latestPrice.USD, latestPrice.NOK), + USDNZD: computeFx(latestPrice.USD, latestPrice.NZD), + USDPHP: computeFx(latestPrice.USD, latestPrice.PHP), + USDPLN: computeFx(latestPrice.USD, latestPrice.PLN), + USDRON: computeFx(latestPrice.USD, latestPrice.RON), + USDRUB: computeFx(latestPrice.USD, latestPrice.RUB), + USDSEK: computeFx(latestPrice.USD, latestPrice.SEK), + USDSGD: computeFx(latestPrice.USD, latestPrice.SGD), + USDTHB: computeFx(latestPrice.USD, latestPrice.THB), + USDTRY: computeFx(latestPrice.USD, latestPrice.TRY), + USDZAR: computeFx(latestPrice.USD, latestPrice.ZAR), + } : { + USDEUR: computeFx(latestPrice.USD, latestPrice.EUR), + USDGBP: computeFx(latestPrice.USD, latestPrice.GBP), + USDCAD: computeFx(latestPrice.USD, latestPrice.CAD), + USDCHF: computeFx(latestPrice.USD, latestPrice.CHF), + USDAUD: computeFx(latestPrice.USD, latestPrice.AUD), + USDJPY: computeFx(latestPrice.USD, latestPrice.JPY), + }; + + if (currency) { + if (!latestPrice[currency]) { + return null; + } + const filteredRates = rates.map((rate: any) => { + return { + time: rate.time, + [currency]: rate[currency], + ['USD']: rate['USD'] + }; + }); + return { + prices: filteredRates as ApiPrice[], + exchangeRates: exchangeRates + }; + } + + return { + prices: rates as ApiPrice[], + exchangeRates: exchangeRates + }; + } catch (e) { + logger.err(`Cannot fetch historical prices from the db. Reason ${e instanceof Error ? e.message : e}`); + return null; + } + } +} + +export default new PricesRepository(); + diff --git a/backend/src/repositories/TransactionRepository.ts b/backend/src/repositories/TransactionRepository.ts new file mode 100644 index 0000000000..b5067f790e --- /dev/null +++ b/backend/src/repositories/TransactionRepository.ts @@ -0,0 +1,122 @@ +import DB from '../database'; +import logger from '../logger'; +import { Ancestor, CpfpInfo } from '../mempool.interfaces'; +import cpfpRepository from './CpfpRepository'; + +class TransactionRepository { + public async $setCluster(txid: string, clusterRoot: string): Promise { + try { + await DB.query( + ` + INSERT INTO compact_transactions + ( + txid, + cluster + ) + VALUE (UNHEX(?), UNHEX(?)) + ON DUPLICATE KEY UPDATE + cluster = UNHEX(?) + ;`, + [txid, clusterRoot, clusterRoot] + ); + } catch (e: any) { + logger.err(`Cannot save transaction cpfp cluster into db. Reason: ` + (e instanceof Error ? e.message : e)); + throw e; + } + } + + public buildBatchSetQuery(txs: { txid: string, cluster: string }[]): { query, params } { + let query = ` + INSERT IGNORE INTO compact_transactions + ( + txid, + cluster + ) + VALUES + `; + query += txs.map(tx => { + return (' (UNHEX(?), UNHEX(?))'); + }) + ';'; + const values = txs.map(tx => [tx.txid, tx.cluster]).flat(); + return { + query, + params: values, + }; + } + + public async $batchSetCluster(txs): Promise { + try { + const query = this.buildBatchSetQuery(txs); + await DB.query( + query.query, + query.params, + ); + } catch (e: any) { + logger.err(`Cannot save cpfp transactions into db. Reason: ` + (e instanceof Error ? e.message : e)); + throw e; + } + } + + public async $getCpfpInfo(txid: string): Promise { + try { + const [txRows]: any = await DB.query( + ` + SELECT HEX(txid) as id, HEX(cluster) as root + FROM compact_transactions + WHERE txid = UNHEX(?) + `, + [txid] + ); + if (txRows.length && txRows[0].root != null) { + const txid = txRows[0].id.toLowerCase(); + const clusterId = txRows[0].root.toLowerCase(); + const cluster = await cpfpRepository.$getCluster(clusterId); + if (cluster) { + return this.convertCpfp(txid, cluster); + } + } + } catch (e) { + logger.err('Cannot get transaction cpfp info from db. Reason: ' + (e instanceof Error ? e.message : e)); + throw e; + } + } + + public async $removeTransaction(txid: string): Promise { + try { + await DB.query( + ` + DELETE FROM compact_transactions + WHERE txid = UNHEX(?) + `, + [txid] + ); + } catch (e) { + logger.warn('Cannot delete transaction cpfp info from db. Reason: ' + (e instanceof Error ? e.message : e)); + throw e; + } + } + + private convertCpfp(txid, cluster): CpfpInfo { + const descendants: Ancestor[] = []; + const ancestors: Ancestor[] = []; + let matched = false; + + for (const tx of (cluster?.txs || [])) { + if (tx.txid === txid) { + matched = true; + } else if (!matched) { + descendants.push(tx); + } else { + ancestors.push(tx); + } + } + return { + descendants, + ancestors, + effectiveFeePerVsize: cluster.effectiveFeePerVsize, + }; + } +} + +export default new TransactionRepository(); + diff --git a/backend/src/routes.ts b/backend/src/routes.ts deleted file mode 100644 index ddb625f042..0000000000 --- a/backend/src/routes.ts +++ /dev/null @@ -1,145 +0,0 @@ -import { Request, Response } from 'express'; -import statistics from './api/statistics'; -import feeApi from './api/fee-api'; -import backendInfo from './api/backend-info'; -import mempoolBlocks from './api/mempool-blocks'; -import mempool from './api/mempool'; -import bisq from './api/bisq'; - -class Routes { - private cache = {}; - - constructor() { - this.createCache(); - setInterval(this.createCache.bind(this), 600000); - } - - private async createCache() { - this.cache['24h'] = await statistics.$list24H(); - this.cache['1w'] = await statistics.$list1W(); - this.cache['1m'] = await statistics.$list1M(); - this.cache['3m'] = await statistics.$list3M(); - this.cache['6m'] = await statistics.$list6M(); - this.cache['1y'] = await statistics.$list1Y(); - console.log('Statistics cache created'); - } - - public async get2HStatistics(req: Request, res: Response) { - const result = await statistics.$list2H(); - res.json(result); - } - - public get24HStatistics(req: Request, res: Response) { - res.json(this.cache['24h']); - } - - public get1WHStatistics(req: Request, res: Response) { - res.json(this.cache['1w']); - } - - public get1MStatistics(req: Request, res: Response) { - res.json(this.cache['1m']); - } - - public get3MStatistics(req: Request, res: Response) { - res.json(this.cache['3m']); - } - - public get6MStatistics(req: Request, res: Response) { - res.json(this.cache['6m']); - } - - public get1YStatistics(req: Request, res: Response) { - res.json(this.cache['1y']); - } - - public async getRecommendedFees(req: Request, res: Response) { - const result = feeApi.getRecommendedFee(); - res.json(result); - } - - public getMempoolBlocks(req: Request, res: Response) { - try { - const result = mempoolBlocks.getMempoolBlocks(); - res.json(result); - } catch (e) { - res.status(500).send(e.message); - } - } - - public getTransactionTimes(req: Request, res: Response) { - if (!Array.isArray(req.query.txId)) { - res.status(500).send('Not an array'); - return; - } - const txIds: string[] = []; - for (const _txId in req.query.txId) { - if (typeof req.query.txId[_txId] === 'string') { - txIds.push(req.query.txId[_txId].toString()); - } - } - - const times = mempool.getFirstSeenForTransactions(txIds); - res.json(times); - } - - public getBackendInfo(req: Request, res: Response) { - res.json(backendInfo.getBackendInfo()); - } - - public getBisqStats(req: Request, res: Response) { - const result = bisq.getStats(); - res.json(result); - } - - public getBisqTip(req: Request, res: Response) { - const result = bisq.getLatestBlockHeight(); - res.type('text/plain'); - res.send(result.toString()); - } - - public getBisqTransaction(req: Request, res: Response) { - const result = bisq.getTransaction(req.params.txId); - if (result) { - res.json(result); - } else { - res.status(404).send('Bisq transaction not found'); - } - } - - public getBisqTransactions(req: Request, res: Response) { - const index = parseInt(req.params.index, 10) || 0; - const length = parseInt(req.params.length, 10) > 100 ? 100 : parseInt(req.params.length, 10) || 25; - const [transactions, count] = bisq.getTransactions(index, length); - res.header('X-Total-Count', count.toString()); - res.json(transactions); - } - - public getBisqBlock(req: Request, res: Response) { - const result = bisq.getBlock(req.params.hash); - if (result) { - res.json(result); - } else { - res.status(404).send('Bisq block not found'); - } - } - - public getBisqBlocks(req: Request, res: Response) { - const index = parseInt(req.params.index, 10) || 0; - const length = parseInt(req.params.length, 10) > 100 ? 100 : parseInt(req.params.length, 10) || 25; - const [transactions, count] = bisq.getBlocks(index, length); - res.header('X-Total-Count', count.toString()); - res.json(transactions); - } - - public getBisqAddress(req: Request, res: Response) { - const result = bisq.getAddress(req.params.address.substr(1)); - if (result) { - res.json(result); - } else { - res.status(404).send('Bisq address not found'); - } - } -} - -export default new Routes(); diff --git a/backend/src/rpc-api/commands.ts b/backend/src/rpc-api/commands.ts new file mode 100644 index 0000000000..85675230b5 --- /dev/null +++ b/backend/src/rpc-api/commands.ts @@ -0,0 +1,96 @@ +module.exports = { + addMultiSigAddress: 'addmultisigaddress', + addNode: 'addnode', // bitcoind v0.8.0+ + backupWallet: 'backupwallet', + createMultiSig: 'createmultisig', + createRawTransaction: 'createrawtransaction', // bitcoind v0.7.0+ + decodeRawTransaction: 'decoderawtransaction', // bitcoind v0.7.0+ + decodeScript: 'decodescript', + dumpPrivKey: 'dumpprivkey', + dumpWallet: 'dumpwallet', // bitcoind v0.9.0+ + encryptWallet: 'encryptwallet', + estimateFee: 'estimatefee', // bitcoind v0.10.0x + estimatePriority: 'estimatepriority', // bitcoind v0.10.0+ + estimateSmartFee: 'estimatesmartfee', + generate: 'generate', // bitcoind v0.11.0+ + getAccount: 'getaccount', + getAccountAddress: 'getaccountaddress', + getAddedNodeInfo: 'getaddednodeinfo', // bitcoind v0.8.0+ + getAddressesByAccount: 'getaddressesbyaccount', + getBalance: 'getbalance', + getBestBlockHash: 'getbestblockhash', // bitcoind v0.9.0+ + getBlock: 'getblock', + getBlockStats: 'getblockstats', + getBlockFilter: 'getblockfilter', + getBlockchainInfo: 'getblockchaininfo', // bitcoind v0.9.2+ + getBlockCount: 'getblockcount', + getBlockHash: 'getblockhash', + getBlockHeader: 'getblockheader', + getBlockTemplate: 'getblocktemplate', // bitcoind v0.7.0+ + getChainTips: 'getchaintips', // bitcoind v0.10.0+ + getChainTxStats: 'getchaintxstats', + getConnectionCount: 'getconnectioncount', + getDifficulty: 'getdifficulty', + getGenerate: 'getgenerate', + getInfo: 'getinfo', + getMempoolAncestors: 'getmempoolancestors', + getMempoolDescendants: 'getmempooldescendants', + getMempoolEntry: 'getmempoolentry', + getMempoolInfo: 'getmempoolinfo', // bitcoind v0.10+ + getMiningInfo: 'getmininginfo', + getNetTotals: 'getnettotals', + getNetworkInfo: 'getnetworkinfo', // bitcoind v0.9.2+ + getNetworkHashPs: 'getnetworkhashps', // bitcoind v0.9.0+ + getNewAddress: 'getnewaddress', + getPeerInfo: 'getpeerinfo', // bitcoind v0.7.0+ + getRawChangeAddress: 'getrawchangeaddress', // bitcoin v0.9+ + getRawMemPool: 'getrawmempool', // bitcoind v0.7.0+ + getRawTransaction: 'getrawtransaction', // bitcoind v0.7.0+ + getReceivedByAccount: 'getreceivedbyaccount', + getReceivedByAddress: 'getreceivedbyaddress', + getTransaction: 'gettransaction', + getTxOut: 'gettxout', // bitcoind v0.7.0+ + getTxOutProof: 'gettxoutproof', // bitcoind v0.11.0+ + getTxOutSetInfo: 'gettxoutsetinfo', // bitcoind v0.7.0+ + getUnconfirmedBalance: 'getunconfirmedbalance', // bitcoind v0.9.0+ + getWalletInfo: 'getwalletinfo', // bitcoind v0.9.2+ + help: 'help', + importAddress: 'importaddress', // bitcoind v0.10.0+ + importPrivKey: 'importprivkey', + importWallet: 'importwallet', // bitcoind v0.9.0+ + keypoolRefill: 'keypoolrefill', + keyPoolRefill: 'keypoolrefill', + listAccounts: 'listaccounts', + listAddressGroupings: 'listaddressgroupings', // bitcoind v0.7.0+ + listLockUnspent: 'listlockunspent', // bitcoind v0.8.0+ + listReceivedByAccount: 'listreceivedbyaccount', + listReceivedByAddress: 'listreceivedbyaddress', + listSinceBlock: 'listsinceblock', + listTransactions: 'listtransactions', + listUnspent: 'listunspent', // bitcoind v0.7.0+ + lockUnspent: 'lockunspent', // bitcoind v0.8.0+ + move: 'move', + ping: 'ping', // bitcoind v0.9.0+ + prioritiseTransaction: 'prioritisetransaction', // bitcoind v0.10.0+ + sendFrom: 'sendfrom', + sendMany: 'sendmany', + sendRawTransaction: 'sendrawtransaction', // bitcoind v0.7.0+ + sendToAddress: 'sendtoaddress', + setAccount: 'setaccount', + setGenerate: 'setgenerate', + setTxFee: 'settxfee', + signMessage: 'signmessage', + signRawTransaction: 'signrawtransaction', // bitcoind v0.7.0+ + stop: 'stop', + submitBlock: 'submitblock', // bitcoind v0.7.0+ + validateAddress: 'validateaddress', + verifyChain: 'verifychain', // bitcoind v0.9.0+ + verifyMessage: 'verifymessage', + verifyTxOutProof: 'verifytxoutproof', // bitcoind v0.11.0+ + walletLock: 'walletlock', + walletPassphrase: 'walletpassphrase', + walletPassphraseChange: 'walletpassphrasechange', + getTxoutSetinfo: 'gettxoutsetinfo', + getIndexInfo: 'getindexinfo', + testMempoolAccept: 'testmempoolaccept', +}; diff --git a/backend/src/rpc-api/index.ts b/backend/src/rpc-api/index.ts new file mode 100644 index 0000000000..131e1a0485 --- /dev/null +++ b/backend/src/rpc-api/index.ts @@ -0,0 +1,61 @@ +var commands = require('./commands') +var rpc = require('./jsonrpc') + +// ===----------------------------------------------------------------------===// +// JsonRPC +// ===----------------------------------------------------------------------===// +function Client (opts) { + // @ts-ignore + this.rpc = new rpc.JsonRPC(opts) +} + +// ===----------------------------------------------------------------------===// +// cmd +// ===----------------------------------------------------------------------===// +Client.prototype.cmd = function () { + var args = [].slice.call(arguments) + var cmd = args.shift() + + callRpc(cmd, args, this.rpc) +} + +// ===----------------------------------------------------------------------===// +// callRpc +// ===----------------------------------------------------------------------===// +function callRpc (cmd, args, rpc) { + var fn = args[args.length - 1] + + // If the last argument is a callback, pop it from the args list + if (typeof fn === 'function') { + args.pop() + } else { + fn = function () {} + } + + return rpc.call(cmd, args, function () { + var args = [].slice.call(arguments) + // @ts-ignore + args.unshift(null) + // @ts-ignore + fn.apply(this, args) + }, function (err) { + fn(err) + }) +} + +// ===----------------------------------------------------------------------===// +// Initialize wrappers +// ===----------------------------------------------------------------------===// +(function () { + for (var protoFn in commands) { + (function (protoFn) { + Client.prototype[protoFn] = function () { + var args = [].slice.call(arguments) + return callRpc(commands[protoFn], args, this.rpc) + } + })(protoFn) + } +})() + +// Export! +module.exports.Client = Client; diff --git a/backend/src/rpc-api/jsonrpc.ts b/backend/src/rpc-api/jsonrpc.ts new file mode 100644 index 0000000000..0bcbdc16cf --- /dev/null +++ b/backend/src/rpc-api/jsonrpc.ts @@ -0,0 +1,177 @@ +var http = require('http') +var https = require('https') +import { readFileSync } from 'fs'; + +var JsonRPC = function (opts) { + // @ts-ignore + this.opts = opts || {} + // @ts-ignore + this.http = this.opts.ssl ? https : http +} + +JsonRPC.prototype.call = function (method, params) { + return new Promise((resolve, reject) => { + var time = Date.now() + var requestJSON + + if (Array.isArray(method)) { + // multiple rpc batch call + requestJSON = [] + method.forEach(function (batchCall, i) { + requestJSON.push({ + id: time + '-' + i, + method: batchCall.method, + params: batchCall.params + }) + }) + } else { + // single rpc call + requestJSON = { + id: time, + method: method, + params: params + } + } + + // First we encode the request into JSON + requestJSON = JSON.stringify(requestJSON) + + // prepare request options + var requestOptions = { + host: this.opts.host || 'localhost', + port: this.opts.port || 8332, + method: 'POST', + path: '/', + headers: { + 'Host': this.opts.host || 'localhost', + 'Content-Length': requestJSON.length + }, + agent: false, + rejectUnauthorized: this.opts.ssl && this.opts.sslStrict !== false + } + + if (this.opts.ssl && this.opts.sslCa) { + // @ts-ignore + requestOptions.ca = this.opts.sslCa + } + + // use HTTP auth if user and password set + if (this.opts.cookie) { + if (!this.cachedCookie) { + this.cachedCookie = readFileSync(this.opts.cookie).toString(); + } + // @ts-ignore + requestOptions.auth = this.cachedCookie; + } else if (this.opts.user && this.opts.pass) { + // @ts-ignore + requestOptions.auth = this.opts.user + ':' + this.opts.pass + } + + // Now we'll make a request to the server + var cbCalled = false + var request = this.http.request(requestOptions) + + // start request timeout timer + var reqTimeout = setTimeout(function () { + if (cbCalled) return + cbCalled = true + request.abort() + var err = new Error('ETIMEDOUT') + // @ts-ignore + err.code = 'ETIMEDOUT' + reject(err) + }, this.opts.timeout || 30000) + + // set additional timeout on socket in case of remote freeze after sending headers + request.setTimeout(this.opts.timeout || 30000, function () { + if (cbCalled) return + cbCalled = true + request.abort() + var err = new Error('ESOCKETTIMEDOUT') + // @ts-ignore + err.code = 'ESOCKETTIMEDOUT' + reject(err) + }) + + request.on('error', function (err) { + if (cbCalled) return + cbCalled = true + clearTimeout(reqTimeout) + reject(err) + }) + + request.on('response', (response) => { + clearTimeout(reqTimeout) + + // We need to buffer the response chunks in a nonblocking way. + var buffer = '' + response.on('data', function (chunk) { + buffer = buffer + chunk + }) + // When all the responses are finished, we decode the JSON and + // depending on whether it's got a result or an error, we call + // emitSuccess or emitError on the promise. + response.on('end', () => { + var err + + if (cbCalled) return + cbCalled = true + + try { + var decoded = JSON.parse(buffer) + } catch (e) { + // if we authenticated using a cookie and it failed, read the cookie file again + if ( + response.statusCode === 401 /* Unauthorized */ && + this.opts.cookie + ) { + this.cachedCookie = undefined; + } + + if (response.statusCode !== 200) { + err = new Error('Invalid params, response status code: ' + response.statusCode) + err.code = -32602 + reject(err) + } else { + err = new Error('Problem parsing JSON response from server') + err.code = -32603 + reject(err) + } + return + } + + if (!Array.isArray(decoded)) { + decoded = [decoded] + } + + // iterate over each response, normally there will be just one + // unless a batch rpc call response is being processed + decoded.forEach(function (decodedResponse, i) { + if (decodedResponse.hasOwnProperty('error') && decodedResponse.error != null) { + if (reject) { + err = new Error(decodedResponse.error.message || '') + if (decodedResponse.error.code) { + err.code = decodedResponse.error.code + } + reject(err) + } + } else if (decodedResponse.hasOwnProperty('result')) { + // @ts-ignore + resolve(decodedResponse.result, response.headers) + } else { + if (reject) { + err = new Error(decodedResponse.error.message || '') + if (decodedResponse.error.code) { + err.code = decodedResponse.error.code + } + reject(err) + } + } + }) + }) + }) + request.end(requestJSON); + }); +} + +module.exports.JsonRPC = JsonRPC diff --git a/backend/src/sync-assets.ts b/backend/src/sync-assets.ts new file mode 100644 index 0000000000..f4cc1f2660 --- /dev/null +++ b/backend/src/sync-assets.ts @@ -0,0 +1,85 @@ +import axios, { AxiosResponse } from 'axios'; +import * as fs from 'fs'; +import config from './config'; +import backendInfo from './api/backend-info'; +import logger from './logger'; +import { SocksProxyAgent } from 'socks-proxy-agent'; + +const PATH = './'; + +class SyncAssets { + constructor() { } + + public async syncAssets$() { + for (const url of config.MEMPOOL.EXTERNAL_ASSETS) { + try { + await this.downloadFile$(url); + } catch (e) { + throw new Error(`Failed to download external asset. ` + (e instanceof Error ? e.message : e)); + } + } + } + + private async downloadFile$(url: string) { + return new Promise((resolve, reject) => { + const fileName = url.split('/').slice(-1)[0]; + + try { + if (config.SOCKS5PROXY.ENABLED) { + const socksOptions: any = { + agentOptions: { + keepAlive: true, + }, + hostname: config.SOCKS5PROXY.HOST, + port: config.SOCKS5PROXY.PORT + }; + + if (config.SOCKS5PROXY.USERNAME && config.SOCKS5PROXY.PASSWORD) { + socksOptions.username = config.SOCKS5PROXY.USERNAME; + socksOptions.password = config.SOCKS5PROXY.PASSWORD; + } + + const agent = new SocksProxyAgent(socksOptions); + + logger.info(`Downloading external asset ${fileName} over the Tor network...`); + return axios.get(url, { + headers: { + 'User-Agent': (config.MEMPOOL.USER_AGENT === 'mempool') ? `mempool/v${backendInfo.getBackendInfo().version}` : `${config.MEMPOOL.USER_AGENT}` + }, + httpAgent: agent, + httpsAgent: agent, + responseType: 'stream', + timeout: 30000 + }).then(function (response) { + const writer = fs.createWriteStream(PATH + fileName); + writer.on('finish', () => { + logger.info(`External asset ${fileName} saved to ${PATH + fileName}`); + resolve(0); + }); + response.data.pipe(writer); + }); + } else { + logger.info(`Downloading external asset ${fileName} over clearnet...`); + return axios.get(url, { + headers: { + 'User-Agent': (config.MEMPOOL.USER_AGENT === 'mempool') ? `mempool/v${backendInfo.getBackendInfo().version}` : `${config.MEMPOOL.USER_AGENT}` + }, + responseType: 'stream', + timeout: 30000 + }).then(function (response) { + const writer = fs.createWriteStream(PATH + fileName); + writer.on('finish', () => { + logger.info(`External asset ${fileName} saved to ${PATH + fileName}`); + resolve(0); + }); + response.data.pipe(writer); + }); + } + } catch (e: any) { + reject(e); + } + }); + } +} + +export default new SyncAssets(); diff --git a/backend/src/tasks/lightning/forensics.service.ts b/backend/src/tasks/lightning/forensics.service.ts new file mode 100644 index 0000000000..aa88f5bb4a --- /dev/null +++ b/backend/src/tasks/lightning/forensics.service.ts @@ -0,0 +1,526 @@ +import DB from '../../database'; +import logger from '../../logger'; +import channelsApi from '../../api/explorer/channels.api'; +import bitcoinApi from '../../api/bitcoin/bitcoin-api-factory'; +import config from '../../config'; +import { IEsploraApi } from '../../api/bitcoin/esplora-api.interface'; +import { Common } from '../../api/common'; +import { ILightningApi } from '../../api/lightning/lightning-api.interface'; + +const tempCacheSize = 10000; + +class ForensicsService { + loggerTimer = 0; + closedChannelsScanBlock = 0; + txCache: { [txid: string]: IEsploraApi.Transaction } = {}; + tempCached: string[] = []; + + public async $startService(): Promise { + logger.info('Starting lightning network forensics service'); + + this.loggerTimer = new Date().getTime() / 1000; + + await this.$runTasks(); + } + + private async $runTasks(): Promise { + try { + logger.debug(`Running forensics scans`); + + if (config.MEMPOOL.BACKEND === 'esplora') { + await this.$runClosedChannelsForensics(false); + await this.$runOpenedChannelsForensics(); + } + + } catch (e) { + logger.err('ForensicsService.$runTasks() error: ' + (e instanceof Error ? e.message : e)); + } + + setTimeout(() => { this.$runTasks(); }, 1000 * config.LIGHTNING.FORENSICS_INTERVAL); + } + + /* + 1. Mutually closed + 2. Forced closed + 3. Forced closed with penalty + + ┌────────────────────────────────────┐ ┌────────────────────────────┐ + │ outputs contain revocation script? ├──yes──► force close w/ penalty = 3 │ + └──────────────┬─────────────────────┘ └────────────────────────────┘ + no + ┌──────────────▼──────────────────────────┐ + │ outputs contain other lightning script? ├──┐ + └──────────────┬──────────────────────────┘ │ + no yes + ┌──────────────▼─────────────┐ │ + │ sequence starts with 0x80 │ ┌────────▼────────┐ + │ and ├──────► force close = 2 │ + │ locktime starts with 0x20? │ └─────────────────┘ + └──────────────┬─────────────┘ + no + ┌─────────▼────────┐ + │ mutual close = 1 │ + └──────────────────┘ + */ + + public async $runClosedChannelsForensics(onlyNewChannels: boolean = false): Promise { + // Only Esplora backend can retrieve spent transaction outputs + if (config.MEMPOOL.BACKEND !== 'esplora') { + return; + } + + try { + logger.debug(`Started running closed channel forensics...`); + let allChannels; + if (onlyNewChannels) { + allChannels = await channelsApi.$getClosedChannelsWithoutReason(); + } else { + allChannels = await channelsApi.$getUnresolvedClosedChannels(); + } + + let progress = 0; + const sliceLength = Math.ceil(config.ESPLORA.BATCH_QUERY_BASE_SIZE / 10); + // process batches of 1000 channels + for (let i = 0; i < Math.ceil(allChannels.length / sliceLength); i++) { + const channels = allChannels.slice(i * sliceLength, (i + 1) * sliceLength); + + let allOutspends: IEsploraApi.Outspend[][] = []; + const forceClosedChannels: { channel: any, cachedSpends: string[] }[] = []; + + // fetch outspends in bulk + try { + const outspendTxids = channels.map(channel => channel.closing_transaction_id); + allOutspends = await bitcoinApi.$getBatchedOutspendsInternal(outspendTxids); + logger.info(`Fetched outspends for ${allOutspends.length} txs from esplora for LN forensics`); + await Common.sleep$(config.LIGHTNING.FORENSICS_RATE_LIMIT); + } catch (e) { + logger.err(`Failed to call ${config.ESPLORA.REST_API_URL + '/internal/txs/outspends/by-txid'}. Reason ${e instanceof Error ? e.message : e}`); + } + // fetch spending transactions in bulk and load into txCache + const newSpendingTxids: { [txid: string]: boolean } = {}; + for (const outspends of allOutspends) { + for (const outspend of outspends) { + if (outspend.spent && outspend.txid) { + newSpendingTxids[outspend.txid] = true; + } + } + } + const allOutspendTxs = await this.fetchTransactions( + allOutspends.flatMap(outspends => + outspends + .filter(outspend => outspend.spent && outspend.txid) + .map(outspend => outspend.txid) + ) + ); + logger.info(`Fetched ${allOutspendTxs.length} out-spending txs from esplora for LN forensics`); + + // process each outspend + for (const [index, channel] of channels.entries()) { + let reason = 0; + const cached: string[] = []; + try { + const outspends = allOutspends[index]; + if (!outspends || !outspends.length) { + // outspends are missing + continue; + } + const lightningScriptReasons: number[] = []; + for (const outspend of outspends) { + if (outspend.spent && outspend.txid) { + const spendingTx = this.txCache[outspend.txid]; + if (!spendingTx) { + continue; + } + cached.push(spendingTx.txid); + const lightningScript = this.findLightningScript(spendingTx.vin[outspend.vin || 0]); + lightningScriptReasons.push(lightningScript); + } + } + const filteredReasons = lightningScriptReasons.filter((r) => r !== 1); + if (filteredReasons.length) { + if (filteredReasons.some((r) => r === 2 || r === 4)) { + // Force closed with penalty + reason = 3; + } else { + // Force closed without penalty + reason = 2; + await DB.query(`UPDATE channels SET closing_resolved = ? WHERE id = ?`, [true, channel.id]); + } + await DB.query(`UPDATE channels SET closing_reason = ? WHERE id = ?`, [reason, channel.id]); + // clean up cached transactions + cached.forEach(txid => { + delete this.txCache[txid]; + }); + } else { + forceClosedChannels.push({ channel, cachedSpends: cached }); + } + } catch (e) { + logger.err(`$runClosedChannelsForensics() failed for channel ${channel.short_id}. Reason: ${e instanceof Error ? e.message : e}`); + } + } + + // fetch force-closing transactions in bulk + const closingTxs = await this.fetchTransactions(forceClosedChannels.map(x => x.channel.closing_transaction_id)); + logger.info(`Fetched ${closingTxs.length} closing txs from esplora for LN forensics`); + + // process channels with no lightning script reasons + for (const { channel, cachedSpends } of forceClosedChannels) { + const closingTx = this.txCache[channel.closing_transaction_id]; + if (!closingTx) { + // no channel close transaction found yet + continue; + } + /* + We can detect a commitment transaction (force close) by reading Sequence and Locktime + https://github.com/lightning/bolts/blob/master/03-transactions.md#commitment-transaction + */ + const sequenceHex: string = closingTx.vin[0].sequence.toString(16); + const locktimeHex: string = closingTx.locktime.toString(16); + let reason; + if (sequenceHex.substring(0, 2) === '80' && locktimeHex.substring(0, 2) === '20') { + // Force closed, but we can't be sure if it's a penalty or not + reason = 2; + } else { + // Mutually closed + reason = 1; + // clean up cached transactions + delete this.txCache[closingTx.txid]; + for (const txid of cachedSpends) { + delete this.txCache[txid]; + } + } + await DB.query(`UPDATE channels SET closing_reason = ? WHERE id = ?`, [reason, channel.id]); + } + + progress += channels.length; + const elapsedSeconds = Math.round((new Date().getTime() / 1000) - this.loggerTimer); + if (elapsedSeconds > 10) { + logger.debug(`Updating channel closed channel forensics ${progress}/${allChannels.length}`); + this.loggerTimer = new Date().getTime() / 1000; + } + } + logger.debug(`Closed channels forensics scan complete.`); + } catch (e) { + logger.err('$runClosedChannelsForensics() error: ' + (e instanceof Error ? e.message : e)); + } + } + + private findLightningScript(vin: IEsploraApi.Vin): number { + const topElement = vin.witness?.length > 2 ? vin.witness[vin.witness.length - 2] : null; + if (/^OP_IF OP_PUSHBYTES_33 \w{66} OP_ELSE OP_PUSH(NUM_\d+|BYTES_(1 \w{2}|2 \w{4})) OP_CSV OP_DROP OP_PUSHBYTES_33 \w{66} OP_ENDIF OP_CHECKSIG$/.test(vin.inner_witnessscript_asm)) { + // https://github.com/lightning/bolts/blob/master/03-transactions.md#commitment-transaction-outputs + if (topElement === '01') { + // top element is '01' to get in the revocation path + // 'Revoked Lightning Force Close'; + // Penalty force closed + return 2; + } else { + // top element is '', this is a delayed to_local output + // 'Lightning Force Close'; + return 3; + } + } else if ( + /^OP_DUP OP_HASH160 OP_PUSHBYTES_20 \w{40} OP_EQUAL OP_IF OP_CHECKSIG OP_ELSE OP_PUSHBYTES_33 \w{66} OP_SWAP OP_SIZE OP_PUSHBYTES_1 20 OP_EQUAL OP_NOTIF OP_DROP OP_PUSHNUM_2 OP_SWAP OP_PUSHBYTES_33 \w{66} OP_PUSHNUM_2 OP_CHECKMULTISIG OP_ELSE OP_HASH160 OP_PUSHBYTES_20 \w{40} OP_EQUALVERIFY OP_CHECKSIG OP_ENDIF (OP_PUSHNUM_1 OP_CSV OP_DROP |)OP_ENDIF$/.test(vin.inner_witnessscript_asm) || + /^OP_DUP OP_HASH160 OP_PUSHBYTES_20 \w{40} OP_EQUAL OP_IF OP_CHECKSIG OP_ELSE OP_PUSHBYTES_33 \w{66} OP_SWAP OP_SIZE OP_PUSHBYTES_1 20 OP_EQUAL OP_IF OP_HASH160 OP_PUSHBYTES_20 \w{40} OP_EQUALVERIFY OP_PUSHNUM_2 OP_SWAP OP_PUSHBYTES_33 \w{66} OP_PUSHNUM_2 OP_CHECKMULTISIG OP_ELSE OP_DROP OP_PUSHBYTES_3 \w{6} OP_CLTV OP_DROP OP_CHECKSIG OP_ENDIF (OP_PUSHNUM_1 OP_CSV OP_DROP |)OP_ENDIF$/.test(vin.inner_witnessscript_asm) + ) { + // https://github.com/lightning/bolts/blob/master/03-transactions.md#offered-htlc-outputs + // https://github.com/lightning/bolts/blob/master/03-transactions.md#received-htlc-outputs + if (topElement?.length === 66) { + // top element is a public key + // 'Revoked Lightning HTLC'; Penalty force closed + return 4; + } else if (topElement) { + // top element is a preimage + // 'Lightning HTLC'; + return 5; + } else { + // top element is '' to get in the expiry of the script + // 'Expired Lightning HTLC'; + return 6; + } + } else if (/^OP_PUSHBYTES_33 \w{66} OP_CHECKSIG OP_IFDUP OP_NOTIF OP_PUSHNUM_16 OP_CSV OP_ENDIF$/.test(vin.inner_witnessscript_asm)) { + // https://github.com/lightning/bolts/blob/master/03-transactions.md#to_local_anchor-and-to_remote_anchor-output-option_anchors + if (topElement) { + // top element is a signature + // 'Lightning Anchor'; + return 7; + } else { + // top element is '', it has been swept after 16 blocks + // 'Swept Lightning Anchor'; + return 8; + } + } + return 1; + } + + // If a channel open tx spends funds from a another channel transaction, + // we can attribute that output to a specific counterparty + private async $runOpenedChannelsForensics(): Promise { + const runTimer = Date.now(); + let progress = 0; + + try { + logger.debug(`Started running open channel forensics...`); + const channels = await channelsApi.$getChannelsWithoutSourceChecked(); + + // preload open channel transactions + await this.fetchTransactions(channels.map(channel => channel.transaction_id), true); + + for (const openChannel of channels) { + const openTx = this.txCache[openChannel.transaction_id]; + if (!openTx) { + continue; + } + for (const input of openTx.vin) { + const closeChannel = await channelsApi.$getChannelByClosingId(input.txid); + if (closeChannel) { + // this input directly spends a channel close output + await this.$attributeChannelBalances(closeChannel, openChannel, input); + } else { + const prevOpenChannels = await channelsApi.$getChannelsByOpeningId(input.txid); + if (prevOpenChannels?.length) { + // this input spends a channel open change output + for (const prevOpenChannel of prevOpenChannels) { + await this.$attributeChannelBalances(prevOpenChannel, openChannel, input, null, null, true); + } + } else { + // check if this input spends any swept channel close outputs + await this.$attributeSweptChannelCloses(openChannel, input); + } + } + } + // calculate how much of the total input value is attributable to the channel open output + openChannel.funding_ratio = openTx.vout[openChannel.transaction_vout].value / ((openTx.vout.reduce((sum, v) => sum + v.value, 0) || 1) + openTx.fee); + // save changes to the opening channel, and mark it as checked + if (openTx?.vin?.length === 1) { + openChannel.single_funded = true; + } + if (openChannel.node1_funding_balance || openChannel.node2_funding_balance || openChannel.node1_closing_balance || openChannel.node2_closing_balance || openChannel.closed_by) { + await channelsApi.$updateOpeningInfo(openChannel); + } + await channelsApi.$markChannelSourceChecked(openChannel.id); + + ++progress; + const elapsedSeconds = Math.round((new Date().getTime() / 1000) - this.loggerTimer); + if (elapsedSeconds > 10) { + logger.debug(`Updating opened channel forensics ${progress}/${channels?.length}`); + this.loggerTimer = new Date().getTime() / 1000; + this.truncateTempCache(); + } + if (Date.now() - runTimer > (config.LIGHTNING.FORENSICS_INTERVAL * 1000)) { + break; + } + } + + logger.debug(`Open channels forensics scan complete.`); + } catch (e) { + logger.err('$runOpenedChannelsForensics() error: ' + (e instanceof Error ? e.message : e)); + } finally { + this.clearTempCache(); + } + } + + // Check if a channel open tx input spends the result of a swept channel close output + private async $attributeSweptChannelCloses(openChannel: ILightningApi.Channel, input: IEsploraApi.Vin): Promise { + const sweepTx = await this.fetchTransaction(input.txid, true); + if (!sweepTx) { + logger.err(`couldn't find input transaction for channel forensics ${openChannel.channel_id} ${input.txid}`); + return; + } + const openContribution = sweepTx.vout[input.vout].value; + for (const sweepInput of sweepTx.vin) { + const lnScriptType = this.findLightningScript(sweepInput); + if (lnScriptType > 1) { + const closeChannel = await channelsApi.$getChannelByClosingId(sweepInput.txid); + if (closeChannel) { + const initiator = (lnScriptType === 2 || lnScriptType === 4) ? 'remote' : (lnScriptType === 3 ? 'local' : null); + await this.$attributeChannelBalances(closeChannel, openChannel, sweepInput, openContribution, initiator); + } + } + } + } + + private async $attributeChannelBalances( + prevChannel, openChannel, input: IEsploraApi.Vin, openContribution: number | null = null, + initiator: 'remote' | 'local' | null = null, linkedOpenings: boolean = false + ): Promise { + // figure out which node controls the input/output + let openSide; + let prevLocal; + let prevRemote; + let matched = false; + let ambiguous = false; // if counterparties are the same in both channels, we can't tell them apart + if (openChannel.node1_public_key === prevChannel.node1_public_key) { + openSide = 1; + prevLocal = 1; + prevRemote = 2; + matched = true; + } else if (openChannel.node1_public_key === prevChannel.node2_public_key) { + openSide = 1; + prevLocal = 2; + prevRemote = 1; + matched = true; + } + if (openChannel.node2_public_key === prevChannel.node1_public_key) { + openSide = 2; + prevLocal = 1; + prevRemote = 2; + if (matched) { + ambiguous = true; + } + matched = true; + } else if (openChannel.node2_public_key === prevChannel.node2_public_key) { + openSide = 2; + prevLocal = 2; + prevRemote = 1; + if (matched) { + ambiguous = true; + } + matched = true; + } + + if (matched && !ambiguous) { + // fetch closing channel transaction and perform forensics on the outputs + const prevChannelTx = await this.fetchTransaction(input.txid, true); + let outspends: IEsploraApi.Outspend[] | undefined; + try { + outspends = await bitcoinApi.$getOutspends(input.txid); + await Common.sleep$(config.LIGHTNING.FORENSICS_RATE_LIMIT); + } catch (e) { + logger.err(`Failed to call ${config.ESPLORA.REST_API_URL + '/tx/' + input.txid + '/outspends'}. Reason ${e instanceof Error ? e.message : e}`); + } + if (!outspends || !prevChannelTx) { + return; + } + if (!linkedOpenings) { + if (!prevChannel.outputs || !prevChannel.outputs.length) { + prevChannel.outputs = prevChannelTx.vout.map(vout => { + return { + type: 0, + value: vout.value, + }; + }); + } + + // preload outspend transactions + await this.fetchTransactions(outspends.filter(o => o.spent && o.txid).map(o => o.txid), true); + + for (let i = 0; i < outspends?.length; i++) { + const outspend = outspends[i]; + const output = prevChannel.outputs[i]; + if (outspend.spent && outspend.txid) { + const spendingTx = this.txCache[outspend.txid]; + if (spendingTx) { + output.type = this.findLightningScript(spendingTx.vin[outspend.vin || 0]); + } + } else { + output.type = 0; + } + } + + // attribute outputs to each counterparty, and sum up total known balances + prevChannel.outputs[input.vout].node = prevLocal; + const isPenalty = prevChannel.outputs.filter((out) => out.type === 2 || out.type === 4)?.length > 0; + const normalOutput = [1,3].includes(prevChannel.outputs[input.vout].type); + const mutualClose = ((prevChannel.status === 2 || prevChannel.status === 'closed') && prevChannel.closing_reason === 1); + let localClosingBalance = 0; + let remoteClosingBalance = 0; + for (const output of prevChannel.outputs) { + if (isPenalty) { + // penalty close, so local node takes everything + localClosingBalance += output.value; + } else if (output.node) { + // this output determinstically linked to one of the counterparties + if (output.node === prevLocal) { + localClosingBalance += output.value; + } else { + remoteClosingBalance += output.value; + } + } else if (normalOutput && (output.type === 1 || output.type === 3 || (mutualClose && prevChannel.outputs.length === 2))) { + // local node had one main output, therefore remote node takes the other + remoteClosingBalance += output.value; + } + } + prevChannel[`node${prevLocal}_closing_balance`] = localClosingBalance; + prevChannel[`node${prevRemote}_closing_balance`] = remoteClosingBalance; + prevChannel.closing_fee = prevChannelTx.fee; + + if (initiator && !linkedOpenings) { + const initiatorSide = initiator === 'remote' ? prevRemote : prevLocal; + prevChannel.closed_by = prevChannel[`node${initiatorSide}_public_key`]; + } + + // save changes to the closing channel + await channelsApi.$updateClosingInfo(prevChannel); + } else { + if (prevChannelTx.vin.length <= 1) { + prevChannel[`node${prevLocal}_funding_balance`] = prevChannel.capacity; + prevChannel.single_funded = true; + prevChannel.funding_ratio = 1; + // save changes to the closing channel + await channelsApi.$updateOpeningInfo(prevChannel); + } + } + openChannel[`node${openSide}_funding_balance`] = openChannel[`node${openSide}_funding_balance`] + (openContribution || prevChannelTx?.vout[input.vout]?.value || 0); + } + } + + async fetchTransaction(txid: string, temp: boolean = false): Promise { + let tx = this.txCache[txid]; + if (!tx) { + try { + tx = await bitcoinApi.$getRawTransaction(txid); + this.txCache[txid] = tx; + if (temp) { + this.tempCached.push(txid); + } + await Common.sleep$(config.LIGHTNING.FORENSICS_RATE_LIMIT); + } catch (e) { + logger.err(`Failed to call ${config.ESPLORA.REST_API_URL + '/tx/' + txid}. Reason ${e instanceof Error ? e.message : e}`); + return null; + } + } + return tx; + } + + // fetches a batch of transactions and adds them to the txCache + // the returned list of txs does *not* preserve ordering or number + async fetchTransactions(txids, temp: boolean = false): Promise<(IEsploraApi.Transaction | null)[]> { + // deduplicate txids + const uniqueTxids = [...new Set(txids)]; + // filter out any transactions we already have in the cache + const needToFetch: string[] = uniqueTxids.filter(txid => !this.txCache[txid]); + try { + const txs = await bitcoinApi.$getRawTransactions(needToFetch); + for (const tx of txs) { + this.txCache[tx.txid] = tx; + if (temp) { + this.tempCached.push(tx.txid); + } + } + await Common.sleep$(config.LIGHTNING.FORENSICS_RATE_LIMIT); + } catch (e) { + logger.err(`Failed to call ${config.ESPLORA.REST_API_URL + '/txs'}. Reason ${e instanceof Error ? e.message : e}`); + return []; + } + return txids.map(txid => this.txCache[txid]); + } + + clearTempCache(): void { + for (const txid of this.tempCached) { + delete this.txCache[txid]; + } + this.tempCached = []; + } + + truncateTempCache(): void { + if (this.tempCached.length > tempCacheSize) { + const removed = this.tempCached.splice(0, this.tempCached.length - tempCacheSize); + for (const txid of removed) { + delete this.txCache[txid]; + } + } + } +} + +export default new ForensicsService(); diff --git a/backend/src/tasks/lightning/network-sync.service.ts b/backend/src/tasks/lightning/network-sync.service.ts new file mode 100644 index 0000000000..7d6a40571c --- /dev/null +++ b/backend/src/tasks/lightning/network-sync.service.ts @@ -0,0 +1,329 @@ +import DB from '../../database'; +import logger from '../../logger'; +import channelsApi from '../../api/explorer/channels.api'; +import bitcoinApi from '../../api/bitcoin/bitcoin-api-factory'; +import config from '../../config'; +import { ILightningApi } from '../../api/lightning/lightning-api.interface'; +import { $lookupNodeLocation } from './sync-tasks/node-locations'; +import lightningApi from '../../api/lightning/lightning-api-factory'; +import nodesApi from '../../api/explorer/nodes.api'; +import { ResultSetHeader } from 'mysql2'; +import fundingTxFetcher from './sync-tasks/funding-tx-fetcher'; +import NodesSocketsRepository from '../../repositories/NodesSocketsRepository'; +import { Common } from '../../api/common'; +import blocks from '../../api/blocks'; +import NodeRecordsRepository from '../../repositories/NodeRecordsRepository'; +import forensicsService from './forensics.service'; + +class NetworkSyncService { + loggerTimer = 0; + closedChannelsScanBlock = 0; + + constructor() {} + + public async $startService(): Promise { + logger.info(`Starting lightning network sync service`, logger.tags.ln); + + this.loggerTimer = new Date().getTime() / 1000; + + await this.$runTasks(); + } + + private async $runTasks(): Promise { + const taskStartTime = Date.now(); + try { + logger.debug(`Updating nodes and channels`, logger.tags.ln); + + const networkGraph = await lightningApi.$getNetworkGraph(); + if (networkGraph.nodes.length === 0 || networkGraph.edges.length === 0) { + logger.info(`LN Network graph is empty, retrying in 10 seconds`, logger.tags.ln); + setTimeout(() => { this.$runTasks(); }, 10000); + return; + } + + await this.$updateNodesList(networkGraph.nodes); + await this.$updateChannelsList(networkGraph.edges); + await this.$deactivateChannelsWithoutActiveNodes(); + await this.$lookUpCreationDateFromChain(); + await this.$updateNodeFirstSeen(); + await this.$scanForClosedChannels(); + + if (config.MEMPOOL.BACKEND === 'esplora') { + // run forensics on new channels only + await forensicsService.$runClosedChannelsForensics(true); + } + + } catch (e) { + logger.err(`$runTasks() error: ${e instanceof Error ? e.message : e}`, logger.tags.ln); + } + + setTimeout(() => { this.$runTasks(); }, Math.max(1, (1000 * config.LIGHTNING.GRAPH_REFRESH_INTERVAL) - (Date.now() - taskStartTime))); + } + + /** + * Update the `nodes` table to reflect the current network graph state + */ + private async $updateNodesList(nodes: ILightningApi.Node[]): Promise { + let progress = 0; + + let deletedSockets = 0; + let deletedRecords = 0; + const graphNodesPubkeys: string[] = []; + for (const node of nodes) { + const latestUpdated = await channelsApi.$getLatestChannelUpdateForNode(node.pub_key); + node.last_update = Math.max(node.last_update ?? 0, latestUpdated); + + await nodesApi.$saveNode(node); + graphNodesPubkeys.push(node.pub_key); + ++progress; + + const elapsedSeconds = Math.round((new Date().getTime() / 1000) - this.loggerTimer); + if (elapsedSeconds > config.LIGHTNING.LOGGER_UPDATE_INTERVAL) { + logger.debug(`Updating node ${progress}/${nodes.length}`, logger.tags.ln); + this.loggerTimer = new Date().getTime() / 1000; + } + + const addresses: string[] = []; + for (const socket of node.addresses) { + await NodesSocketsRepository.$saveSocket(Common.formatSocket(node.pub_key, socket)); + addresses.push(socket.addr); + } + deletedSockets += await NodesSocketsRepository.$deleteUnusedSockets(node.pub_key, addresses); + + const oldRecordTypes = await NodeRecordsRepository.$getRecordTypes(node.pub_key); + const customRecordTypes: number[] = []; + for (const [type, payload] of Object.entries(node.custom_records || {})) { + const numericalType = parseInt(type); + await NodeRecordsRepository.$saveRecord({ + publicKey: node.pub_key, + type: numericalType, + payload, + }); + customRecordTypes.push(numericalType); + } + if (oldRecordTypes.reduce((changed, type) => changed || customRecordTypes.indexOf(type) === -1, false)) { + deletedRecords += await NodeRecordsRepository.$deleteUnusedRecords(node.pub_key, customRecordTypes); + } + } + logger.debug(`${progress} nodes updated. ${deletedSockets} sockets deleted. ${deletedRecords} custom records deleted.`); + + // If a channel if not present in the graph, mark it as inactive + await nodesApi.$setNodesInactive(graphNodesPubkeys); + + if (config.MAXMIND.ENABLED) { + $lookupNodeLocation(); + } + } + + /** + * Update the `channels` table to reflect the current network graph state + */ + private async $updateChannelsList(channels: ILightningApi.Channel[]): Promise { + try { + const [closedChannelsRaw]: any[] = await DB.query(`SELECT id FROM channels WHERE status = 2`); + const closedChannels = {}; + for (const closedChannel of closedChannelsRaw) { + closedChannels[closedChannel.id] = true; + } + + let progress = 0; + + const graphChannelsIds: string[] = []; + for (const channel of channels) { + if (!closedChannels[channel.channel_id]) { + await channelsApi.$saveChannel(channel); + } + graphChannelsIds.push(channel.channel_id); + ++progress; + + const elapsedSeconds = Math.round((new Date().getTime() / 1000) - this.loggerTimer); + if (elapsedSeconds > config.LIGHTNING.LOGGER_UPDATE_INTERVAL) { + logger.debug(`Updating channel ${progress}/${channels.length}`, logger.tags.ln); + this.loggerTimer = new Date().getTime() / 1000; + } + } + + logger.debug(`${progress} channels updated`, logger.tags.ln); + + // If a channel if not present in the graph, mark it as inactive + await channelsApi.$setChannelsInactive(graphChannelsIds); + } catch (e) { + logger.err(` Cannot update channel list. Reason: ${(e instanceof Error ? e.message : e)}`, logger.tags.ln); + } + } + + // This method look up the creation date of the earliest channel of the node + // and update the node to that date in order to get the earliest first seen date + private async $updateNodeFirstSeen(): Promise { + let progress = 0; + let updated = 0; + + try { + const [nodes]: any[] = await DB.query(` + SELECT nodes.public_key, UNIX_TIMESTAMP(nodes.first_seen) AS first_seen, + ( + SELECT MIN(UNIX_TIMESTAMP(created)) + FROM channels + WHERE channels.node1_public_key = nodes.public_key + ) AS created1, + ( + SELECT MIN(UNIX_TIMESTAMP(created)) + FROM channels + WHERE channels.node2_public_key = nodes.public_key + ) AS created2 + FROM nodes + `); + + for (const node of nodes) { + const lowest = Math.min( + node.created1 ?? Number.MAX_SAFE_INTEGER, + node.created2 ?? Number.MAX_SAFE_INTEGER, + node.first_seen ?? Number.MAX_SAFE_INTEGER + ); + if (lowest < node.first_seen) { + const query = `UPDATE nodes SET first_seen = FROM_UNIXTIME(?) WHERE public_key = ?`; + const params = [lowest, node.public_key]; + ++updated; + await DB.query(query, params); + } + ++progress; + const elapsedSeconds = Math.round((new Date().getTime() / 1000) - this.loggerTimer); + if (elapsedSeconds > config.LIGHTNING.LOGGER_UPDATE_INTERVAL) { + logger.debug(`Updating node first seen date ${progress}/${nodes.length}`, logger.tags.ln); + this.loggerTimer = new Date().getTime() / 1000; + } + } + if (updated > 0) { + logger.debug(`Updated ${updated} node first seen dates`, logger.tags.ln); + } + } catch (e) { + logger.err(`$updateNodeFirstSeen() error: ${e instanceof Error ? e.message : e}`, logger.tags.ln); + } + } + + private async $lookUpCreationDateFromChain(): Promise { + let progress = 0; + + logger.debug(`Running channel creation date lookup`, logger.tags.ln); + try { + const channels = await channelsApi.$getChannelsWithoutCreatedDate(); + for (const channel of channels) { + const transaction = await fundingTxFetcher.$fetchChannelOpenTx(channel.short_id); + if (!transaction) { + continue; + } + await DB.query(` + UPDATE channels SET created = FROM_UNIXTIME(?) WHERE channels.id = ?`, + [transaction.timestamp, channel.id] + ); + ++progress; + const elapsedSeconds = Math.round((new Date().getTime() / 1000) - this.loggerTimer); + if (elapsedSeconds > config.LIGHTNING.LOGGER_UPDATE_INTERVAL) { + logger.debug(`Updating channel creation date ${progress}/${channels.length}`, logger.tags.ln); + this.loggerTimer = new Date().getTime() / 1000; + } + } + + if (channels.length > 0) { + logger.debug(`Updated ${channels.length} channels' creation date`, logger.tags.ln); + } + } catch (e) { + logger.err(`$lookUpCreationDateFromChain() error: ${e instanceof Error ? e.message : e}`, logger.tags.ln); + } + } + + /** + * If a channel does not have any active node linked to it, then also + * mark that channel as inactive + */ + private async $deactivateChannelsWithoutActiveNodes(): Promise { + logger.debug(`Find channels which nodes are offline`, logger.tags.ln); + + try { + const result = await DB.query(` + UPDATE channels + SET status = 0 + WHERE channels.status = 1 + AND ( + ( + SELECT COUNT(*) + FROM nodes + WHERE nodes.public_key = channels.node1_public_key + AND nodes.status = 1 + ) = 0 + OR ( + SELECT COUNT(*) + FROM nodes + WHERE nodes.public_key = channels.node2_public_key + AND nodes.status = 1 + ) = 0) + `); + + if (result[0].changedRows ?? 0 > 0) { + logger.debug(`Marked ${result[0].changedRows} channels as inactive because they are not linked to any active node`, logger.tags.ln); + } + } catch (e) { + logger.err(`$deactivateChannelsWithoutActiveNodes() error: ${e instanceof Error ? e.message : e}`, logger.tags.ln); + } + } + + private async $scanForClosedChannels(): Promise { + let currentBlockHeight = blocks.getCurrentBlockHeight(); + if (config.MEMPOOL.ENABLED === false) { // https://github.com/mempool/mempool/issues/3582 + currentBlockHeight = await bitcoinApi.$getBlockHeightTip(); + } + if (this.closedChannelsScanBlock === currentBlockHeight) { + logger.debug(`We've already scan closed channels for this block, skipping.`); + return; + } + + let progress = 0; + + try { + let log = `Starting closed channels scan`; + if (this.closedChannelsScanBlock > 0) { + log += `. Last scan was at block ${this.closedChannelsScanBlock}`; + } else { + log += ` for the first time`; + } + logger.debug(`${log}`, logger.tags.ln); + + const allChannels = await channelsApi.$getChannelsByStatus([0, 1]); + + const sliceLength = Math.ceil(config.ESPLORA.BATCH_QUERY_BASE_SIZE / 2); + // process batches of 5000 channels + for (let i = 0; i < Math.ceil(allChannels.length / sliceLength); i++) { + const channels = allChannels.slice(i * sliceLength, (i + 1) * sliceLength); + const outspends = await bitcoinApi.$getOutSpendsByOutpoint(channels.map(channel => { + return { txid: channel.transaction_id, vout: channel.transaction_vout }; + })); + + for (const [index, channel] of channels.entries()) { + const spendingTx = outspends[index]; + if (spendingTx.spent === true && spendingTx.status?.confirmed === true) { + // logger.debug(`Marking channel: ${channel.id} as closed.`, logger.tags.ln); + await DB.query(`UPDATE channels SET status = 2, closing_date = FROM_UNIXTIME(?) WHERE id = ?`, + [spendingTx.status.block_time, channel.id]); + if (spendingTx.txid && !channel.closing_transaction_id) { + await DB.query(`UPDATE channels SET closing_transaction_id = ? WHERE id = ?`, [spendingTx.txid, channel.id]); + } + } + } + + progress += channels.length; + const elapsedSeconds = Math.round((new Date().getTime() / 1000) - this.loggerTimer); + if (elapsedSeconds > config.LIGHTNING.LOGGER_UPDATE_INTERVAL) { + logger.debug(`Checking if channel has been closed ${progress}/${allChannels.length}`, logger.tags.ln); + this.loggerTimer = new Date().getTime() / 1000; + } + } + + this.closedChannelsScanBlock = currentBlockHeight; + logger.debug(`Closed channels scan completed at block ${this.closedChannelsScanBlock}`, logger.tags.ln); + } catch (e) { + logger.err(`$scanForClosedChannels() error: ${e instanceof Error ? e.message : e}`, logger.tags.ln); + } + } +} + +export default new NetworkSyncService(); diff --git a/backend/src/tasks/lightning/stats-updater.service.ts b/backend/src/tasks/lightning/stats-updater.service.ts new file mode 100644 index 0000000000..5d0ac3cfcb --- /dev/null +++ b/backend/src/tasks/lightning/stats-updater.service.ts @@ -0,0 +1,37 @@ +import logger from '../../logger'; +import lightningApi from '../../api/lightning/lightning-api-factory'; +import LightningStatsImporter from './sync-tasks/stats-importer'; +import config from '../../config'; +import { Common } from '../../api/common'; + +class LightningStatsUpdater { + public async $startService(): Promise { + logger.info(`Starting Lightning Stats service`, logger.tags.ln); + + await this.$runTasks(); + LightningStatsImporter.$run(); + } + + private async $runTasks(): Promise { + await this.$logStatsDaily(); + + setTimeout(() => { this.$runTasks(); }, 1000 * config.LIGHTNING.STATS_REFRESH_INTERVAL); + } + + /** + * Update the latest entry for each node every config.LIGHTNING.STATS_REFRESH_INTERVAL seconds + */ + private async $logStatsDaily(): Promise { + try { + const date = new Date(); + Common.setDateMidnight(date); + const networkGraph = await lightningApi.$getNetworkGraph(); + await LightningStatsImporter.computeNetworkStats(date.getTime() / 1000, networkGraph); + logger.debug(`Updated latest network stats`, logger.tags.ln); + } catch (e) { + logger.err(`Exception in $logStatsDaily. Reason: ${(e instanceof Error ? e.message : e)}`); + } + } +} + +export default new LightningStatsUpdater(); diff --git a/backend/src/tasks/lightning/sync-tasks/funding-tx-fetcher.ts b/backend/src/tasks/lightning/sync-tasks/funding-tx-fetcher.ts new file mode 100644 index 0000000000..ada2a89b21 --- /dev/null +++ b/backend/src/tasks/lightning/sync-tasks/funding-tx-fetcher.ts @@ -0,0 +1,122 @@ +import { existsSync, promises } from 'fs'; +import bitcoinClient from '../../../api/bitcoin/bitcoin-client'; +import { Common } from '../../../api/common'; +import config from '../../../config'; +import logger from '../../../logger'; + +const fsPromises = promises; + +const BLOCKS_CACHE_MAX_SIZE = 100; +const CACHE_FILE_NAME = config.MEMPOOL.CACHE_DIR + '/ln-funding-txs-cache.json'; + +class FundingTxFetcher { + private running = false; + private blocksCache = {}; + private channelNewlyProcessed = 0; + public fundingTxCache = {}; + + async $init(): Promise { + // Load funding tx disk cache + if (Object.keys(this.fundingTxCache).length === 0 && existsSync(CACHE_FILE_NAME)) { + try { + this.fundingTxCache = JSON.parse(await fsPromises.readFile(CACHE_FILE_NAME, 'utf-8')); + } catch (e) { + logger.err(`Unable to parse channels funding txs disk cache. Starting from scratch`, logger.tags.ln); + this.fundingTxCache = {}; + } + logger.debug(`Imported ${Object.keys(this.fundingTxCache).length} funding tx amount from the disk cache`, logger.tags.ln); + } + } + + async $fetchChannelsFundingTxs(channelIds: string[]): Promise { + if (this.running) { + return; + } + this.running = true; + + const globalTimer = new Date().getTime() / 1000; + let cacheTimer = new Date().getTime() / 1000; + let loggerTimer = new Date().getTime() / 1000; + let channelProcessed = 0; + this.channelNewlyProcessed = 0; + for (const channelId of channelIds) { + await this.$fetchChannelOpenTx(channelId); + ++channelProcessed; + + let elapsedSeconds = Math.round((new Date().getTime() / 1000) - loggerTimer); + if (elapsedSeconds > config.LIGHTNING.LOGGER_UPDATE_INTERVAL) { + elapsedSeconds = Math.round((new Date().getTime() / 1000) - globalTimer); + logger.info(`Indexing channels funding tx ${channelProcessed + 1} of ${channelIds.length} ` + + `(${Math.floor(channelProcessed / channelIds.length * 10000) / 100}%) | ` + + `elapsed: ${elapsedSeconds} seconds`, + logger.tags.ln + ); + loggerTimer = new Date().getTime() / 1000; + } + + elapsedSeconds = Math.round((new Date().getTime() / 1000) - cacheTimer); + if (elapsedSeconds > 60) { + logger.debug(`Saving ${Object.keys(this.fundingTxCache).length} funding txs cache into disk`, logger.tags.ln); + fsPromises.writeFile(CACHE_FILE_NAME, JSON.stringify(this.fundingTxCache)); + cacheTimer = new Date().getTime() / 1000; + } + } + + if (this.channelNewlyProcessed > 0) { + logger.info(`Indexed ${this.channelNewlyProcessed} additional channels funding tx`, logger.tags.ln); + logger.debug(`Saving ${Object.keys(this.fundingTxCache).length} funding txs cache into disk`, logger.tags.ln); + fsPromises.writeFile(CACHE_FILE_NAME, JSON.stringify(this.fundingTxCache)); + } + + this.running = false; + } + + public async $fetchChannelOpenTx(channelId: string): Promise<{timestamp: number, txid: string, value: number} | null> { + channelId = Common.channelIntegerIdToShortId(channelId); + + if (this.fundingTxCache[channelId]) { + return this.fundingTxCache[channelId]; + } + + const parts = channelId.split('x'); + const blockHeight = parts[0]; + const txIdx = parts[1]; + const outputIdx = parts[2]; + + let block = this.blocksCache[blockHeight]; + // Fetch it from core + if (!block) { + const blockHash = await bitcoinClient.getBlockHash(parseInt(blockHeight, 10)); + block = await bitcoinClient.getBlock(blockHash, 1); + } + this.blocksCache[block.height] = block; + + const blocksCacheHashes = Object.keys(this.blocksCache).sort((a, b) => parseInt(b) - parseInt(a)).reverse(); + if (blocksCacheHashes.length > BLOCKS_CACHE_MAX_SIZE) { + for (let i = 0; i < 10; ++i) { + delete this.blocksCache[blocksCacheHashes[i]]; + } + } + + const txid = block.tx[txIdx]; + const rawTx = await bitcoinClient.getRawTransaction(txid); + const tx = await bitcoinClient.decodeRawTransaction(rawTx); + + if (!tx || !tx.vout || tx.vout.length < parseInt(outputIdx, 10) + 1 || tx.vout[outputIdx].value === undefined) { + logger.err(`Cannot find blockchain funding tx for channel id ${channelId}. Possible reasons are: bitcoin backend timeout or the channel shortId is not valid`); + return null; + } + + this.fundingTxCache[channelId] = { + timestamp: block.time, + txid: txid, + value: tx.vout[outputIdx].value, + }; + + ++this.channelNewlyProcessed; + + return this.fundingTxCache[channelId]; + } +} + +export default new FundingTxFetcher; diff --git a/backend/src/tasks/lightning/sync-tasks/node-locations.ts b/backend/src/tasks/lightning/sync-tasks/node-locations.ts new file mode 100644 index 0000000000..17974275ca --- /dev/null +++ b/backend/src/tasks/lightning/sync-tasks/node-locations.ts @@ -0,0 +1,169 @@ +import * as net from 'net'; +import maxmind, { CityResponse, AsnResponse, IspResponse } from 'maxmind'; +import nodesApi from '../../../api/explorer/nodes.api'; +import config from '../../../config'; +import DB from '../../../database'; +import logger from '../../../logger'; +import { ResultSetHeader } from 'mysql2'; +import * as IPCheck from '../../../utils/ipcheck.js'; +import { Reader } from 'mmdb-lib'; + +export async function $lookupNodeLocation(): Promise { + let loggerTimer = new Date().getTime() / 1000; + let progress = 0; + let nodesUpdated = 0; + let geoNamesInserted = 0; + + logger.debug(`Running node location updater using Maxmind`, logger.tags.ln); + try { + const nodes = await nodesApi.$getAllNodes(); + const lookupCity = await maxmind.open(config.MAXMIND.GEOLITE2_CITY); + const lookupAsn = await maxmind.open(config.MAXMIND.GEOLITE2_ASN); + let lookupIsp: Reader | null = null; + try { + lookupIsp = await maxmind.open(config.MAXMIND.GEOIP2_ISP); + } catch (e) { } + + for (const node of nodes) { + const sockets: string[] = node.sockets.split(','); + for (const socket of sockets) { + const ip = socket.substring(0, socket.lastIndexOf(':')).replace('[', '').replace(']', ''); + const hasClearnet = [4, 6].includes(net.isIP(ip)); + + if (hasClearnet && ip !== '127.0.1.1' && ip !== '127.0.0.1') { + const city = lookupCity.get(ip); + const asn = lookupAsn.get(ip); + let isp: IspResponse | null = null; + if (lookupIsp) { + isp = lookupIsp.get(ip); + } + + let asOverwrite: any | undefined; + if (asn && (IPCheck.match(ip, '170.75.160.0/20') || IPCheck.match(ip, '172.81.176.0/21'))) { + asOverwrite = { + asn: 394745, + name: 'Lunanode', + }; + } + else if (asn && (IPCheck.match(ip, '50.7.0.0/16') || IPCheck.match(ip, '66.90.64.0/18'))) { + asOverwrite = { + asn: 30058, + name: 'FDCservers.net', + }; + } + else if (asn && asn.autonomous_system_number === 174) { + asOverwrite = { + asn: 174, + name: 'Cogent Communications', + }; + } + + if (city && (asn || isp)) { + const query = ` + UPDATE nodes SET + as_number = ?, + city_id = ?, + country_id = ?, + subdivision_id = ?, + longitude = ?, + latitude = ?, + accuracy_radius = ? + WHERE public_key = ? + `; + + const params = [ + asOverwrite?.asn ?? isp?.autonomous_system_number ?? asn?.autonomous_system_number, + city.city?.geoname_id, + city.country?.geoname_id, + city.subdivisions ? city.subdivisions[0].geoname_id : null, + city.location?.longitude, + city.location?.latitude, + city.location?.accuracy_radius, + node.public_key + ]; + let result = await DB.query(query, params); + if (result[0].changedRows ?? 0 > 0) { + ++nodesUpdated; + } + + // Store Continent + if (city.continent?.geoname_id) { + result = await DB.query( + `INSERT IGNORE INTO geo_names (id, type, names) VALUES (?, 'continent', ?)`, + [city.continent?.geoname_id, JSON.stringify(city.continent?.names)]); + if (result[0].changedRows ?? 0 > 0) { + ++geoNamesInserted; + } + } + + // Store Country + if (city.country?.geoname_id) { + result = await DB.query( + `INSERT IGNORE INTO geo_names (id, type, names) VALUES (?, 'country', ?)`, + [city.country?.geoname_id, JSON.stringify(city.country?.names)]); + if (result[0].changedRows ?? 0 > 0) { + ++geoNamesInserted; + } + } + + // Store Country ISO code + if (city.country?.iso_code) { + result = await DB.query( + `INSERT IGNORE INTO geo_names (id, type, names) VALUES (?, 'country_iso_code', ?)`, + [city.country?.geoname_id, city.country?.iso_code]); + if (result[0].changedRows ?? 0 > 0) { + ++geoNamesInserted; + } + } + + // Store Division + if (city.subdivisions && city.subdivisions[0]) { + result = await DB.query( + `INSERT IGNORE INTO geo_names (id, type, names) VALUES (?, 'division', ?)`, + [city.subdivisions[0].geoname_id, JSON.stringify(city.subdivisions[0]?.names)]); + if (result[0].changedRows ?? 0 > 0) { + ++geoNamesInserted; + } + } + + // Store City + if (city.city?.geoname_id) { + result = await DB.query( + `INSERT IGNORE INTO geo_names (id, type, names) VALUES (?, 'city', ?)`, + [city.city?.geoname_id, JSON.stringify(city.city?.names)]); + if (result[0].changedRows ?? 0 > 0) { + ++geoNamesInserted; + } + } + + // Store AS name + if (isp?.autonomous_system_organization ?? asn?.autonomous_system_organization) { + result = await DB.query( + `INSERT IGNORE INTO geo_names (id, type, names) VALUES (?, 'as_organization', ?)`, + [ + asOverwrite?.asn ?? isp?.autonomous_system_number ?? asn?.autonomous_system_number, + JSON.stringify(asOverwrite?.name ?? isp?.isp ?? asn?.autonomous_system_organization) + ]); + if (result[0].changedRows ?? 0 > 0) { + ++geoNamesInserted; + } + } + } + + ++progress; + const elapsedSeconds = Math.round((new Date().getTime() / 1000) - loggerTimer); + if (elapsedSeconds > config.LIGHTNING.LOGGER_UPDATE_INTERVAL) { + logger.debug(`Updating node location data ${progress}/${nodes.length}`); + loggerTimer = new Date().getTime() / 1000; + } + } + } + } + + if (nodesUpdated > 0) { + logger.debug(`${nodesUpdated} nodes maxmind data updated, ${geoNamesInserted} geo names inserted`, logger.tags.ln); + } + } catch (e) { + logger.err('$lookupNodeLocation() error: ' + (e instanceof Error ? e.message : e)); + } +} diff --git a/backend/src/tasks/lightning/sync-tasks/stats-importer.ts b/backend/src/tasks/lightning/sync-tasks/stats-importer.ts new file mode 100644 index 0000000000..14ad82d7e8 --- /dev/null +++ b/backend/src/tasks/lightning/sync-tasks/stats-importer.ts @@ -0,0 +1,550 @@ +import DB from '../../../database'; +import { promises } from 'fs'; +import logger from '../../../logger'; +import fundingTxFetcher from './funding-tx-fetcher'; +import config from '../../../config'; +import { ILightningApi } from '../../../api/lightning/lightning-api.interface'; +import { isIP } from 'net'; +import { Common } from '../../../api/common'; +import channelsApi from '../../../api/explorer/channels.api'; +import nodesApi from '../../../api/explorer/nodes.api'; + +const fsPromises = promises; + +class LightningStatsImporter { + topologiesFolder = config.LIGHTNING.TOPOLOGY_FOLDER; + + async $run(): Promise { + try { + const [channels]: any[] = await DB.query('SELECT short_id from channels;'); + logger.info(`Caching funding txs for currently existing channels`, logger.tags.ln); + await fundingTxFetcher.$fetchChannelsFundingTxs(channels.map(channel => channel.short_id)); + + if (config.MEMPOOL.NETWORK !== 'mainnet' || config.DATABASE.ENABLED === false) { + return; + } + + await this.$importHistoricalLightningStats(); + await this.$cleanupIncorrectSnapshot(); + } catch (e) { + logger.err(`Exception in LightningStatsImporter::$run(). ${e}`); + } + } + + /** + * Generate LN network stats for one day + */ + public async computeNetworkStats(timestamp: number, + networkGraph: ILightningApi.NetworkGraph, isHistorical: boolean = false): Promise { + // Node counts and network shares + let clearnetNodes = 0; + let torNodes = 0; + let clearnetTorNodes = 0; + let unannouncedNodes = 0; + + const [nodesInDbRaw]: any[] = await DB.query(`SELECT public_key FROM nodes`); + const nodesInDb = {}; + for (const node of nodesInDbRaw) { + nodesInDb[node.public_key] = node; + } + + for (const node of networkGraph.nodes) { + // If we don't know about this node, insert it in db + if (isHistorical === true && !nodesInDb[node.pub_key]) { + await nodesApi.$saveNode({ + last_update: node.last_update, + pub_key: node.pub_key, + alias: node.alias, + addresses: node.addresses, + color: node.color, + features: node.features, + }); + nodesInDb[node.pub_key] = node; + } else { + await nodesApi.$updateNodeSockets(node.pub_key, node.addresses); + } + + let hasOnion = false; + let hasClearnet = false; + let isUnnanounced = true; + + for (const socket of (node.addresses ?? [])) { + if (!socket.network?.length && !socket.addr?.length) { + continue; + } + hasOnion = hasOnion || ['torv2', 'torv3'].includes(socket.network) || socket.addr.indexOf('onion') !== -1 || socket.addr.indexOf('torv2') !== -1 || socket.addr.indexOf('torv3') !== -1; + hasClearnet = hasClearnet || ['ipv4', 'ipv6'].includes(socket.network) || [4, 6].includes(isIP(socket.addr.split(':')[0])) || socket.addr.indexOf('ipv4') !== -1 || socket.addr.indexOf('ipv6') !== -1;; + } + if (hasOnion && hasClearnet) { + clearnetTorNodes++; + isUnnanounced = false; + } else if (hasOnion) { + torNodes++; + isUnnanounced = false; + } else if (hasClearnet) { + clearnetNodes++; + isUnnanounced = false; + } + if (isUnnanounced) { + unannouncedNodes++; + } + } + + // Channels and node historical stats + const nodeStats = {}; + let capacity = 0; + let avgFeeRate = 0; + let avgBaseFee = 0; + const capacities: number[] = []; + const feeRates: number[] = []; + const baseFees: number[] = []; + const alreadyCountedChannels = {}; + + const [channelsInDbRaw]: any[] = await DB.query(`SELECT short_id FROM channels`); + const channelsInDb = {}; + for (const channel of channelsInDbRaw) { + channelsInDb[channel.short_id] = channel; + } + + for (const channel of networkGraph.edges) { + const short_id = Common.channelIntegerIdToShortId(channel.channel_id); + + const tx = await fundingTxFetcher.$fetchChannelOpenTx(short_id); + if (!tx) { + logger.err(`Unable to fetch funding tx for channel ${short_id}. Capacity and creation date is unknown. Skipping channel.`, logger.tags.ln); + continue; + } + + // If we don't know about this channel, insert it in db + if (isHistorical === true && !channelsInDb[short_id]) { + await channelsApi.$saveChannel({ + channel_id: short_id, + chan_point: `${tx.txid}:${short_id.split('x')[2]}`, + last_update: channel.last_update, + node1_pub: channel.node1_pub, + node2_pub: channel.node2_pub, + capacity: (tx.value * 100000000).toString(), + node1_policy: null, + node2_policy: null, + }, 0); + channelsInDb[channel.channel_id] = channel; + } + + if (!nodeStats[channel.node1_pub]) { + nodeStats[channel.node1_pub] = { + capacity: 0, + channels: 0, + }; + } + if (!nodeStats[channel.node2_pub]) { + nodeStats[channel.node2_pub] = { + capacity: 0, + channels: 0, + }; + } + + if (!alreadyCountedChannels[short_id]) { + capacity += Math.round(tx.value * 100000000); + capacities.push(Math.round(tx.value * 100000000)); + alreadyCountedChannels[short_id] = true; + + nodeStats[channel.node1_pub].capacity += Math.round(tx.value * 100000000); + nodeStats[channel.node1_pub].channels++; + nodeStats[channel.node2_pub].capacity += Math.round(tx.value * 100000000); + nodeStats[channel.node2_pub].channels++; + } + + if (isHistorical === false) { // Coming from the node + for (const policy of [channel.node1_policy, channel.node2_policy]) { + if (policy && parseInt(policy.fee_rate_milli_msat, 10) < 5000) { + avgFeeRate += parseInt(policy.fee_rate_milli_msat, 10); + feeRates.push(parseInt(policy.fee_rate_milli_msat, 10)); + } + if (policy && parseInt(policy.fee_base_msat, 10) < 5000) { + avgBaseFee += parseInt(policy.fee_base_msat, 10); + baseFees.push(parseInt(policy.fee_base_msat, 10)); + } + } + } else { + // @ts-ignore + if (channel.node1_policy.fee_rate_milli_msat < 5000) { + // @ts-ignore + avgFeeRate += parseInt(channel.node1_policy.fee_rate_milli_msat, 10); + // @ts-ignore + feeRates.push(parseInt(channel.node1_policy.fee_rate_milli_msat), 10); + } + // @ts-ignore + if (channel.node1_policy.fee_base_msat < 5000) { + // @ts-ignore + avgBaseFee += parseInt(channel.node1_policy.fee_base_msat, 10); + // @ts-ignore + baseFees.push(parseInt(channel.node1_policy.fee_base_msat), 10); + } + } + } + + let medCapacity = 0; + let medFeeRate = 0; + let medBaseFee = 0; + let avgCapacity = 0; + + avgFeeRate /= Math.max(networkGraph.edges.length, 1); + avgBaseFee /= Math.max(networkGraph.edges.length, 1); + + if (capacities.length > 0) { + medCapacity = capacities.sort((a, b) => b - a)[Math.round(capacities.length / 2 - 1)]; + avgCapacity = Math.round(capacity / Math.max(capacities.length, 1)); + } + if (feeRates.length > 0) { + medFeeRate = feeRates.sort((a, b) => b - a)[Math.round(feeRates.length / 2 - 1)]; + } + if (baseFees.length > 0) { + medBaseFee = baseFees.sort((a, b) => b - a)[Math.round(baseFees.length / 2 - 1)]; + } + + let query = `INSERT INTO lightning_stats( + added, + channel_count, + node_count, + total_capacity, + tor_nodes, + clearnet_nodes, + unannounced_nodes, + clearnet_tor_nodes, + avg_capacity, + avg_fee_rate, + avg_base_fee_mtokens, + med_capacity, + med_fee_rate, + med_base_fee_mtokens + ) + VALUES (FROM_UNIXTIME(?), ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?) + ON DUPLICATE KEY UPDATE + added = FROM_UNIXTIME(?), + channel_count = ?, + node_count = ?, + total_capacity = ?, + tor_nodes = ?, + clearnet_nodes = ?, + unannounced_nodes = ?, + clearnet_tor_nodes = ?, + avg_capacity = ?, + avg_fee_rate = ?, + avg_base_fee_mtokens = ?, + med_capacity = ?, + med_fee_rate = ?, + med_base_fee_mtokens = ? + `; + + await DB.query(query, [ + timestamp, + capacities.length, + networkGraph.nodes.length, + capacity, + torNodes, + clearnetNodes, + unannouncedNodes, + clearnetTorNodes, + avgCapacity, + avgFeeRate, + avgBaseFee, + medCapacity, + medFeeRate, + medBaseFee, + timestamp, + capacities.length, + networkGraph.nodes.length, + capacity, + torNodes, + clearnetNodes, + unannouncedNodes, + clearnetTorNodes, + avgCapacity, + avgFeeRate, + avgBaseFee, + medCapacity, + medFeeRate, + medBaseFee, + ]); + + for (const public_key of Object.keys(nodeStats)) { + query = `INSERT INTO node_stats( + public_key, + added, + capacity, + channels + ) + VALUES (?, FROM_UNIXTIME(?), ?, ?) + ON DUPLICATE KEY UPDATE + added = FROM_UNIXTIME(?), + capacity = ?, + channels = ? + `; + + await DB.query(query, [ + public_key, + timestamp, + nodeStats[public_key].capacity, + nodeStats[public_key].channels, + timestamp, + nodeStats[public_key].capacity, + nodeStats[public_key].channels, + ]); + + if (!isHistorical) { + await DB.query( + `UPDATE nodes SET capacity = ?, channels = ? WHERE public_key = ?`, + [ + nodeStats[public_key].capacity, + nodeStats[public_key].channels, + public_key, + ] + ); + } + } + + return { + added: timestamp, + node_count: networkGraph.nodes.length + }; + } + + /** + * Import topology files LN historical data into the database + */ + async $importHistoricalLightningStats(): Promise { + if (!config.LIGHTNING.TOPOLOGY_FOLDER) { + logger.info(`Lightning topology folder is not set. Not importing historical LN stats`); + return; + } + + logger.debug('Run the historical importer'); + try { + let fileList: string[] = []; + try { + fileList = await fsPromises.readdir(this.topologiesFolder); + } catch (e) { + logger.err(`Unable to open topology folder at ${this.topologiesFolder}`, logger.tags.ln); + throw e; + } + // Insert history from the most recent to the oldest + // This also put the .json cached files first + fileList.sort().reverse(); + + const [rows]: any[] = await DB.query(` + SELECT UNIX_TIMESTAMP(added) AS added + FROM lightning_stats + ORDER BY added DESC + `); + const existingStatsTimestamps = {}; + for (const row of rows) { + existingStatsTimestamps[row.added] = row; + } + + // For logging purpose + let processed = 10; + let totalProcessed = 0; + let logStarted = false; + + for (const filename of fileList) { + processed++; + + const timestamp = parseInt(filename.split('_')[1], 10); + + // Stats exist already, don't calculate/insert them + if (existingStatsTimestamps[timestamp] !== undefined) { + totalProcessed++; + continue; + } + + if (filename.indexOf('topology_') === -1) { + totalProcessed++; + continue; + } + + logger.debug(`Reading ${this.topologiesFolder}/${filename}`, logger.tags.ln); + let fileContent = ''; + try { + fileContent = await fsPromises.readFile(`${this.topologiesFolder}/${filename}`, 'utf8'); + } catch (e: any) { + if (e.errno == -1) { // EISDIR - Ignore directorie + totalProcessed++; + continue; + } + logger.err(`Unable to open ${this.topologiesFolder}/${filename}`, logger.tags.ln); + totalProcessed++; + continue; + } + + let graph; + try { + graph = JSON.parse(fileContent); + graph = await this.cleanupTopology(graph); + } catch (e) { + logger.debug(`Invalid topology file ${this.topologiesFolder}/${filename}, cannot parse the content. Reason: ${e instanceof Error ? e.message : e}`, logger.tags.ln); + totalProcessed++; + continue; + } + + if (this.isIncorrectSnapshot(timestamp, graph)) { + logger.debug(`Ignoring ${this.topologiesFolder}/${filename}, because we defined it as an incorrect snapshot`); + ++totalProcessed; + continue; + } + + if (!logStarted) { + logger.info(`Founds a topology file that we did not import. Importing historical lightning stats now.`, logger.tags.ln); + logStarted = true; + } + + const datestr = `${new Date(timestamp * 1000).toUTCString()} (${timestamp})`; + logger.debug(`${datestr}: Found ${graph.nodes.length} nodes and ${graph.edges.length} channels`, logger.tags.ln); + + totalProcessed++; + + if (processed > 10) { + logger.info(`Generating LN network stats for ${datestr}. Processed ${totalProcessed}/${fileList.length} files`, logger.tags.ln); + processed = 0; + } else { + logger.debug(`Generating LN network stats for ${datestr}. Processed ${totalProcessed}/${fileList.length} files`, logger.tags.ln); + } + await fundingTxFetcher.$fetchChannelsFundingTxs(graph.edges.map(channel => channel.channel_id.slice(0, -2))); + const stat = await this.computeNetworkStats(timestamp, graph, true); + + existingStatsTimestamps[timestamp] = stat; + } + + if (totalProcessed > 0) { + logger.info(`Lightning network stats historical import completed`, logger.tags.ln); + } + } catch (e) { + logger.err(`Lightning network stats historical failed. Reason: ${e instanceof Error ? e.message : e}`, logger.tags.ln); + } + } + + cleanupTopology(graph): ILightningApi.NetworkGraph { + const newGraph = { + nodes: [], + edges: [], + }; + + for (const node of graph.nodes) { + const addressesParts = (node.addresses ?? '').split(','); + const addresses: any[] = []; + for (const address of addressesParts) { + const formatted = Common.findSocketNetwork(address); + addresses.push({ + network: formatted.network, + addr: formatted.url + }); + } + + let rgb = node.rgb_color ?? '#000000'; + if (rgb.indexOf('#') === -1) { + rgb = `#${rgb}`; + } + newGraph.nodes.push({ + last_update: node.timestamp ?? 0, + pub_key: node.id ?? null, + alias: node.alias ?? node.id.slice(0, 20), + addresses: addresses, + color: rgb, + features: {}, + }); + } + + for (const adjacency of graph.adjacency) { + if (adjacency.length === 0) { + continue; + } else { + for (const edge of adjacency) { + newGraph.edges.push({ + channel_id: edge.scid, + chan_point: '', + last_update: edge.timestamp, + node1_pub: edge.source ?? null, + node2_pub: edge.destination ?? null, + capacity: '0', // Will be fetch later + node1_policy: { + time_lock_delta: edge.cltv_expiry_delta, + min_htlc: edge.htlc_minimim_msat, + fee_base_msat: edge.fee_base_msat, + fee_rate_milli_msat: edge.fee_proportional_millionths, + max_htlc_msat: edge.htlc_maximum_msat, + last_update: edge.timestamp, + disabled: false, + }, + node2_policy: null, + }); + } + } + } + + return newGraph; + } + + private isIncorrectSnapshot(timestamp, graph): boolean { + if (timestamp >= 1549065600 /* 2019-02-02 */ && timestamp <= 1550620800 /* 2019-02-20 */ && graph.nodes.length < 2600) { + return true; + } + if (timestamp >= 1552953600 /* 2019-03-19 */ && timestamp <= 1556323200 /* 2019-05-27 */ && graph.nodes.length < 4000) { + return true; + } + if (timestamp >= 1557446400 /* 2019-05-10 */ && timestamp <= 1560470400 /* 2019-06-14 */ && graph.nodes.length < 4000) { + return true; + } + if (timestamp >= 1561680000 /* 2019-06-28 */ && timestamp <= 1563148800 /* 2019-07-15 */ && graph.nodes.length < 4000) { + return true; + } + if (timestamp >= 1571270400 /* 2019-11-17 */ && timestamp <= 1580601600 /* 2020-02-02 */ && graph.nodes.length < 4500) { + return true; + } + if (timestamp >= 1591142400 /* 2020-06-03 */ && timestamp <= 1592006400 /* 2020-06-13 */ && graph.nodes.length < 5500) { + return true; + } + if (timestamp >= 1632787200 /* 2021-09-28 */ && timestamp <= 1633564800 /* 2021-10-07 */ && graph.nodes.length < 13000) { + return true; + } + if (timestamp >= 1634256000 /* 2021-10-15 */ && timestamp <= 1645401600 /* 2022-02-21 */ && graph.nodes.length < 17000) { + return true; + } + if (timestamp >= 1654992000 /* 2022-06-12 */ && timestamp <= 1661472000 /* 2022-08-26 */ && graph.nodes.length < 14000) { + return true; + } + + return false; + } + + private async $cleanupIncorrectSnapshot(): Promise { + // We do not run this one automatically because those stats are not supposed to be inserted in the first + // place, but I write them here to remind us we manually run those queries + + // DELETE FROM lightning_stats + // WHERE ( + // UNIX_TIMESTAMP(added) >= 1549065600 AND UNIX_TIMESTAMP(added) <= 1550620800 AND node_count < 2600 OR + // UNIX_TIMESTAMP(added) >= 1552953600 AND UNIX_TIMESTAMP(added) <= 1556323200 AND node_count < 4000 OR + // UNIX_TIMESTAMP(added) >= 1557446400 AND UNIX_TIMESTAMP(added) <= 1560470400 AND node_count < 4000 OR + // UNIX_TIMESTAMP(added) >= 1561680000 AND UNIX_TIMESTAMP(added) <= 1563148800 AND node_count < 4000 OR + // UNIX_TIMESTAMP(added) >= 1571270400 AND UNIX_TIMESTAMP(added) <= 1580601600 AND node_count < 4500 OR + // UNIX_TIMESTAMP(added) >= 1591142400 AND UNIX_TIMESTAMP(added) <= 1592006400 AND node_count < 5500 OR + // UNIX_TIMESTAMP(added) >= 1632787200 AND UNIX_TIMESTAMP(added) <= 1633564800 AND node_count < 13000 OR + // UNIX_TIMESTAMP(added) >= 1634256000 AND UNIX_TIMESTAMP(added) <= 1645401600 AND node_count < 17000 OR + // UNIX_TIMESTAMP(added) >= 1654992000 AND UNIX_TIMESTAMP(added) <= 1661472000 AND node_count < 14000 + // ) + + // DELETE FROM node_stats + // WHERE ( + // UNIX_TIMESTAMP(added) >= 1549065600 AND UNIX_TIMESTAMP(added) <= 1550620800 OR + // UNIX_TIMESTAMP(added) >= 1552953600 AND UNIX_TIMESTAMP(added) <= 1556323200 OR + // UNIX_TIMESTAMP(added) >= 1557446400 AND UNIX_TIMESTAMP(added) <= 1560470400 OR + // UNIX_TIMESTAMP(added) >= 1561680000 AND UNIX_TIMESTAMP(added) <= 1563148800 OR + // UNIX_TIMESTAMP(added) >= 1571270400 AND UNIX_TIMESTAMP(added) <= 1580601600 OR + // UNIX_TIMESTAMP(added) >= 1591142400 AND UNIX_TIMESTAMP(added) <= 1592006400 OR + // UNIX_TIMESTAMP(added) >= 1632787200 AND UNIX_TIMESTAMP(added) <= 1633564800 OR + // UNIX_TIMESTAMP(added) >= 1634256000 AND UNIX_TIMESTAMP(added) <= 1645401600 OR + // UNIX_TIMESTAMP(added) >= 1654992000 AND UNIX_TIMESTAMP(added) <= 1661472000 + // ) + } +} + +export default new LightningStatsImporter; diff --git a/backend/src/tasks/pools-updater.ts b/backend/src/tasks/pools-updater.ts new file mode 100644 index 0000000000..a3a3265c62 --- /dev/null +++ b/backend/src/tasks/pools-updater.ts @@ -0,0 +1,198 @@ +import axios, { AxiosResponse } from 'axios'; +import poolsParser from '../api/pools-parser'; +import config from '../config'; +import DB from '../database'; +import backendInfo from '../api/backend-info'; +import logger from '../logger'; +import { SocksProxyAgent } from 'socks-proxy-agent'; +import * as https from 'https'; + +/** + * Maintain the most recent version of pools-v2.json + */ +class PoolsUpdater { + lastRun: number = 0; + currentSha: string | null = null; + poolsUrl: string = config.MEMPOOL.POOLS_JSON_URL; + treeUrl: string = config.MEMPOOL.POOLS_JSON_TREE_URL; + + public async updatePoolsJson(): Promise { + if (['mainnet', 'testnet', 'signet'].includes(config.MEMPOOL.NETWORK) === false || + config.MEMPOOL.ENABLED === false + ) { + return; + } + + const oneWeek = 604800; + const oneDay = 86400; + + const now = new Date().getTime() / 1000; + if (now - this.lastRun < oneWeek) { // Execute the PoolsUpdate only once a week, or upon restart + return; + } + + this.lastRun = now; + + try { + const githubSha = await this.fetchPoolsSha(); // Fetch pools-v2.json sha from github + if (githubSha === null) { + return; + } + + if (config.DATABASE.ENABLED === true) { + this.currentSha = await this.getShaFromDb(); + } + + logger.debug(`pools-v2.json sha | Current: ${this.currentSha} | Github: ${githubSha}`); + if (this.currentSha !== null && this.currentSha === githubSha) { + return; + } + + // See backend README for more details about the mining pools update process + if (this.currentSha !== null && // If we don't have any mining pool, download it at least once + config.MEMPOOL.AUTOMATIC_POOLS_UPDATE !== true && // Automatic pools update is disabled + !process.env.npm_config_update_pools // We're not manually updating mining pool + ) { + logger.warn(`Updated mining pools data is available (${githubSha}) but AUTOMATIC_POOLS_UPDATE is disabled`); + logger.info(`You can update your mining pools using the --update-pools command flag. You may want to clear your nginx cache as well if applicable`); + return; + } + + const network = config.SOCKS5PROXY.ENABLED ? 'tor' : 'clearnet'; + if (this.currentSha === null) { + logger.info(`Downloading pools-v2.json for the first time from ${this.poolsUrl} over ${network}`, logger.tags.mining); + } else { + logger.warn(`pools-v2.json is outdated, fetching latest from ${this.poolsUrl} over ${network}`, logger.tags.mining); + } + const poolsJson = await this.query(this.poolsUrl); + if (poolsJson === undefined) { + return; + } + poolsParser.setMiningPools(poolsJson); + + if (config.DATABASE.ENABLED === false) { // Don't run db operations + logger.info(`Mining pools-v2.json (${githubSha}) import completed (no database)`); + return; + } + + try { + await DB.query('START TRANSACTION;'); + await poolsParser.migratePoolsJson(); + await this.updateDBSha(githubSha); + await DB.query('COMMIT;'); + } catch (e) { + logger.err(`Could not migrate mining pools, rolling back. Exception: ${JSON.stringify(e)}`, logger.tags.mining); + await DB.query('ROLLBACK;'); + } + logger.info(`Mining pools-v2.json (${githubSha}) import completed`); + + } catch (e) { + this.lastRun = now - (oneWeek - oneDay); // Try again in 24h instead of waiting next week + logger.err(`PoolsUpdater failed. Will try again in 24h. Exception: ${JSON.stringify(e)}`, logger.tags.mining); + } + } + + /** + * Fetch our latest pools-v2.json sha from the db + */ + private async updateDBSha(githubSha: string): Promise { + this.currentSha = githubSha; + if (config.DATABASE.ENABLED === true) { + try { + await DB.query('DELETE FROM state where name="pools_json_sha"'); + await DB.query(`INSERT INTO state VALUES('pools_json_sha', NULL, '${githubSha}')`); + } catch (e) { + logger.err('Cannot save github pools-v2.json sha into the db. Reason: ' + (e instanceof Error ? e.message : e), logger.tags.mining); + } + } + } + + /** + * Fetch our latest pools-v2.json sha from the db + */ + private async getShaFromDb(): Promise { + try { + const [rows]: any[] = await DB.query('SELECT string FROM state WHERE name="pools_json_sha"'); + return (rows.length > 0 ? rows[0].string : null); + } catch (e) { + logger.err('Cannot fetch pools-v2.json sha from db. Reason: ' + (e instanceof Error ? e.message : e), logger.tags.mining); + return null; + } + } + + /** + * Fetch our latest pools-v2.json sha from github + */ + private async fetchPoolsSha(): Promise { + const response = await this.query(this.treeUrl); + + if (response !== undefined) { + for (const file of response['tree']) { + if (file['path'] === 'pools-v2.json') { + return file['sha']; + } + } + } + + logger.err(`Cannot find "pools-v2.json" in git tree (${this.treeUrl})`, logger.tags.mining); + return null; + } + + /** + * Http request wrapper + */ + private async query(path): Promise { + type axiosOptions = { + headers: { + 'User-Agent': string + }; + timeout: number; + httpsAgent?: https.Agent; + }; + const setDelay = (secs: number = 1): Promise => new Promise(resolve => setTimeout(() => resolve(), secs * 1000)); + const axiosOptions: axiosOptions = { + headers: { + 'User-Agent': (config.MEMPOOL.USER_AGENT === 'mempool') ? `mempool/v${backendInfo.getBackendInfo().version}` : `${config.MEMPOOL.USER_AGENT}` + }, + timeout: config.SOCKS5PROXY.ENABLED ? 30000 : 10000 + }; + let retry = 0; + + while (retry < config.MEMPOOL.EXTERNAL_MAX_RETRY) { + try { + if (config.SOCKS5PROXY.ENABLED) { + const socksOptions: any = { + agentOptions: { + keepAlive: true, + }, + hostname: config.SOCKS5PROXY.HOST, + port: config.SOCKS5PROXY.PORT + }; + + if (config.SOCKS5PROXY.USERNAME && config.SOCKS5PROXY.PASSWORD) { + socksOptions.username = config.SOCKS5PROXY.USERNAME; + socksOptions.password = config.SOCKS5PROXY.PASSWORD; + } else { + // Retry with different tor circuits https://stackoverflow.com/a/64960234 + socksOptions.username = `circuit${retry}`; + } + + axiosOptions.httpsAgent = new SocksProxyAgent(socksOptions); + } + + const data: AxiosResponse = await axios.get(path, axiosOptions); + if (data.statusText === 'error' || !data.data) { + throw new Error(`Could not fetch data from ${path}, Error: ${data.status}`); + } + return data.data; + } catch (e) { + logger.err('Could not connect to Github. Reason: ' + (e instanceof Error ? e.message : e)); + retry++; + } + await setDelay(config.MEMPOOL.EXTERNAL_RETRY_INTERVAL); + } + return undefined; + } +} + +export default new PoolsUpdater(); diff --git a/backend/src/tasks/price-feeds/bitfinex-api.ts b/backend/src/tasks/price-feeds/bitfinex-api.ts new file mode 100644 index 0000000000..30b70e9eb6 --- /dev/null +++ b/backend/src/tasks/price-feeds/bitfinex-api.ts @@ -0,0 +1,44 @@ +import { query } from '../../utils/axios-query'; +import priceUpdater, { PriceFeed, PriceHistory } from '../price-updater'; + +class BitfinexApi implements PriceFeed { + public name: string = 'Bitfinex'; + public currencies: string[] = ['USD', 'EUR', 'GPB', 'JPY']; + + public url: string = 'https://api.bitfinex.com/v1/pubticker/BTC'; + public urlHist: string = 'https://api-pub.bitfinex.com/v2/candles/trade:{GRANULARITY}:tBTC{CURRENCY}/hist'; + + public async $fetchPrice(currency): Promise { + const response = await query(this.url + currency); + if (response && response['last_price']) { + return parseInt(response['last_price'], 10); + } else { + return -1; + } + } + + public async $fetchRecentPrice(currencies: string[], type: 'hour' | 'day'): Promise { + const priceHistory: PriceHistory = {}; + + for (const currency of currencies) { + if (this.currencies.includes(currency) === false) { + continue; + } + + const response = await query(this.urlHist.replace('{GRANULARITY}', type === 'hour' ? '1h' : '1D').replace('{CURRENCY}', currency)); + const pricesRaw = response ? response : []; + + for (const price of pricesRaw as any[]) { + const time = Math.round(price[0] / 1000); + if (priceHistory[time] === undefined) { + priceHistory[time] = priceUpdater.getEmptyPricesObj(); + } + priceHistory[time][currency] = price[2]; + } + } + + return priceHistory; + } +} + +export default BitfinexApi; diff --git a/backend/src/tasks/price-feeds/bitflyer-api.ts b/backend/src/tasks/price-feeds/bitflyer-api.ts new file mode 100644 index 0000000000..72b2e6adf9 --- /dev/null +++ b/backend/src/tasks/price-feeds/bitflyer-api.ts @@ -0,0 +1,28 @@ +import { query } from '../../utils/axios-query'; +import { PriceFeed, PriceHistory } from '../price-updater'; + +class BitflyerApi implements PriceFeed { + public name: string = 'Bitflyer'; + public currencies: string[] = ['USD', 'EUR', 'JPY']; + + public url: string = 'https://api.bitflyer.com/v1/ticker?product_code=BTC_'; + public urlHist: string = ''; + + constructor() { + } + + public async $fetchPrice(currency): Promise { + const response = await query(this.url + currency); + if (response && response['ltp']) { + return parseInt(response['ltp'], 10); + } else { + return -1; + } + } + + public async $fetchRecentPrice(currencies: string[], type: 'hour' | 'day'): Promise { + return []; + } +} + +export default BitflyerApi; diff --git a/backend/src/tasks/price-feeds/coinbase-api.ts b/backend/src/tasks/price-feeds/coinbase-api.ts new file mode 100644 index 0000000000..d2c6d063ac --- /dev/null +++ b/backend/src/tasks/price-feeds/coinbase-api.ts @@ -0,0 +1,46 @@ +import { query } from '../../utils/axios-query'; +import priceUpdater, { PriceFeed, PriceHistory } from '../price-updater'; + +class CoinbaseApi implements PriceFeed { + public name: string = 'Coinbase'; + public currencies: string[] = ['USD', 'EUR', 'GBP']; + + public url: string = 'https://api.coinbase.com/v2/prices/BTC-{CURRENCY}/spot'; + public urlHist: string = 'https://api.exchange.coinbase.com/products/BTC-{CURRENCY}/candles?granularity={GRANULARITY}'; + + constructor() { + } + + public async $fetchPrice(currency): Promise { + const response = await query(this.url.replace('{CURRENCY}', currency)); + if (response && response['data'] && response['data']['amount']) { + return parseInt(response['data']['amount'], 10); + } else { + return -1; + } + } + + public async $fetchRecentPrice(currencies: string[], type: 'hour' | 'day'): Promise { + const priceHistory: PriceHistory = {}; + + for (const currency of currencies) { + if (this.currencies.includes(currency) === false) { + continue; + } + + const response = await query(this.urlHist.replace('{GRANULARITY}', type === 'hour' ? '3600' : '86400').replace('{CURRENCY}', currency)); + const pricesRaw = response ? response : []; + + for (const price of pricesRaw as any[]) { + if (priceHistory[price[0]] === undefined) { + priceHistory[price[0]] = priceUpdater.getEmptyPricesObj(); + } + priceHistory[price[0]][currency] = price[4]; + } + } + + return priceHistory; + } +} + +export default CoinbaseApi; diff --git a/backend/src/tasks/price-feeds/free-currency-api.ts b/backend/src/tasks/price-feeds/free-currency-api.ts new file mode 100644 index 0000000000..48e511aa86 --- /dev/null +++ b/backend/src/tasks/price-feeds/free-currency-api.ts @@ -0,0 +1,100 @@ +import config from '../../config'; +import { query } from '../../utils/axios-query'; +import { ConversionFeed, ConversionRates } from '../price-updater'; + +const emptyRates = { + AUD: -1, + BGN: -1, + BRL: -1, + CAD: -1, + CHF: -1, + CNY: -1, + CZK: -1, + DKK: -1, + EUR: -1, + GBP: -1, + HKD: -1, + HRK: -1, + HUF: -1, + IDR: -1, + ILS: -1, + INR: -1, + ISK: -1, + JPY: -1, + KRW: -1, + MXN: -1, + MYR: -1, + NOK: -1, + NZD: -1, + PHP: -1, + PLN: -1, + RON: -1, + RUB: -1, + SEK: -1, + SGD: -1, + THB: -1, + TRY: -1, + USD: -1, + ZAR: -1, +}; + +type PaidCurrencyData = { + [key: string]: { + code: string; + value: number; + } +}; + +type FreeCurrencyData = { + [key: string]: number; +}; + +class FreeCurrencyApi implements ConversionFeed { + private API_KEY = config.FIAT_PRICE.API_KEY; + private PAID = config.FIAT_PRICE.PAID; + private API_URL_PREFIX: string = this.PAID ? `https://api.currencyapi.com/v3/` : `https://api.freecurrencyapi.com/v1/`; + + constructor() { } + + public async $getQuota(): Promise { + const response = await query(`${this.API_URL_PREFIX}status?apikey=${this.API_KEY}`); + if (response && response['quotas']) { + return response['quotas']; + } + return null; + } + + public async $fetchLatestConversionRates(): Promise { + const response = await query(`${this.API_URL_PREFIX}latest?apikey=${this.API_KEY}`); + if (response && response['data']) { + if (this.PAID) { + response['data'] = this.convertData(response['data']); + } + return response['data']; + } + return emptyRates; + } + + public async $fetchConversionRates(date: string): Promise { + const response = await query(`${this.API_URL_PREFIX}historical?date=${date}&apikey=${this.API_KEY}`, true); + if (response && response['data'] && (response['data'][date] || this.PAID)) { + if (this.PAID) { + response['data'] = this.convertData(response['data']); + response['data'][response['meta'].last_updated_at.substr(0, 10)] = response['data']; + } + return response['data'][date]; + } + return emptyRates; + } + + private convertData(data: PaidCurrencyData): FreeCurrencyData { + const simplifiedData: FreeCurrencyData = {}; + for (const key in data) { + simplifiedData[key] = data[key].value; + } + return simplifiedData; + } + +} + +export default FreeCurrencyApi; diff --git a/backend/src/tasks/price-feeds/gemini-api.ts b/backend/src/tasks/price-feeds/gemini-api.ts new file mode 100644 index 0000000000..fc86dc0a3e --- /dev/null +++ b/backend/src/tasks/price-feeds/gemini-api.ts @@ -0,0 +1,47 @@ +import { query } from '../../utils/axios-query'; +import priceUpdater, { PriceFeed, PriceHistory } from '../price-updater'; + +class GeminiApi implements PriceFeed { + public name: string = 'Gemini'; + public currencies: string[] = ['USD', 'EUR', 'GBP', 'SGD']; + + public url: string = 'https://api.gemini.com/v1/pubticker/BTC'; + public urlHist: string = 'https://api.gemini.com/v2/candles/BTC{CURRENCY}/{GRANULARITY}'; + + constructor() { + } + + public async $fetchPrice(currency): Promise { + const response = await query(this.url + currency); + if (response && response['last']) { + return parseInt(response['last'], 10); + } else { + return -1; + } + } + + public async $fetchRecentPrice(currencies: string[], type: 'hour' | 'day'): Promise { + const priceHistory: PriceHistory = {}; + + for (const currency of currencies) { + if (this.currencies.includes(currency) === false) { + continue; + } + + const response = await query(this.urlHist.replace('{GRANULARITY}', type === 'hour' ? '1hr' : '1day').replace('{CURRENCY}', currency)); + const pricesRaw = response ? response : []; + + for (const price of pricesRaw as any[]) { + const time = Math.round(price[0] / 1000); + if (priceHistory[time] === undefined) { + priceHistory[time] = priceUpdater.getEmptyPricesObj(); + } + priceHistory[time][currency] = price[4]; + } + } + + return priceHistory; + } +} + +export default GeminiApi; diff --git a/backend/src/tasks/price-feeds/kraken-api.ts b/backend/src/tasks/price-feeds/kraken-api.ts new file mode 100644 index 0000000000..ebc784c6ff --- /dev/null +++ b/backend/src/tasks/price-feeds/kraken-api.ts @@ -0,0 +1,106 @@ +import logger from '../../logger'; +import PricesRepository from '../../repositories/PricesRepository'; +import { query } from '../../utils/axios-query'; +import priceUpdater, { PriceFeed, PriceHistory } from '../price-updater'; + +class KrakenApi implements PriceFeed { + public name: string = 'Kraken'; + public currencies: string[] = ['USD', 'EUR', 'GBP', 'CAD', 'CHF', 'AUD', 'JPY']; + + public url: string = 'https://api.kraken.com/0/public/Ticker?pair=XBT'; + public urlHist: string = 'https://api.kraken.com/0/public/OHLC?interval={GRANULARITY}&pair=XBT'; + + constructor() { + } + + private getTicker(currency) { + let ticker = `XXBTZ${currency}`; + if (['CHF', 'AUD'].includes(currency)) { + ticker = `XBT${currency}`; + } + return ticker; + } + + public async $fetchPrice(currency): Promise { + const response = await query(this.url + currency); + const ticker = this.getTicker(currency); + if (response && response['result'] && response['result'][ticker] && + response['result'][ticker]['c'] && response['result'][ticker]['c'].length > 0 + ) { + return parseInt(response['result'][ticker]['c'][0], 10); + } else { + return -1; + } + } + + public async $fetchRecentPrice(currencies: string[], type: 'hour' | 'day'): Promise { + const priceHistory: PriceHistory = {}; + + for (const currency of currencies) { + if (this.currencies.includes(currency) === false) { + continue; + } + + const response = await query(this.urlHist.replace('{GRANULARITY}', '60') + currency); + const pricesRaw = response ? response['result'][this.getTicker(currency)] : []; + + for (const price of pricesRaw) { + if (priceHistory[price[0]] === undefined) { + priceHistory[price[0]] = priceUpdater.getEmptyPricesObj(); + } + priceHistory[price[0]][currency] = price[4]; + } + } + + return priceHistory; + } + + /** + * Fetch weekly price and save it into the database + */ + public async $insertHistoricalPrice(): Promise { + const existingPriceTimes = await PricesRepository.$getPricesTimes(); + + // EUR weekly price history goes back to timestamp 1378339200 (September 5, 2013) + // USD weekly price history goes back to timestamp 1380758400 (October 3, 2013) + // GBP weekly price history goes back to timestamp 1415232000 (November 6, 2014) + // JPY weekly price history goes back to timestamp 1415232000 (November 6, 2014) + // CAD weekly price history goes back to timestamp 1436400000 (July 9, 2015) + // CHF weekly price history goes back to timestamp 1575504000 (December 5, 2019) + // AUD weekly price history goes back to timestamp 1591833600 (June 11, 2020) + + let priceHistory: any = {}; // map: timestamp -> Prices + + for (const currency of this.currencies) { + const response = await query(this.urlHist.replace('{GRANULARITY}', '10080') + currency); + const priceHistoryRaw = response ? response['result'][this.getTicker(currency)] : []; + + for (const price of priceHistoryRaw) { + if (existingPriceTimes.includes(parseInt(price[0]))) { + continue; + } + + // prices[0] = kraken price timestamp + // prices[4] = closing price + if (priceHistory[price[0]] === undefined) { + priceHistory[price[0]] = priceUpdater.getEmptyPricesObj(); + } + priceHistory[price[0]][currency] = price[4]; + } + } + + for (const time in priceHistory) { + if (priceHistory[time].USD === -1) { + delete priceHistory[time]; + continue; + } + await PricesRepository.$savePrices(parseInt(time, 10), priceHistory[time]); + } + + if (Object.keys(priceHistory).length > 0) { + logger.info(`Inserted ${Object.keys(priceHistory).length} Kraken EUR, USD, GBP, JPY, CAD, CHF and AUD weekly price history into db`, logger.tags.mining); + } + } +} + +export default KrakenApi; diff --git a/backend/src/tasks/price-feeds/mtgox-weekly.json b/backend/src/tasks/price-feeds/mtgox-weekly.json new file mode 100644 index 0000000000..84e077ce06 --- /dev/null +++ b/backend/src/tasks/price-feeds/mtgox-weekly.json @@ -0,0 +1,762 @@ +[ + { + "ct": 1279497600, + "c": "0.08584" + }, + { + "ct": 1280102400, + "c": "0.0505" + }, + { + "ct": 1280707200, + "c": "0.0611" + }, + { + "ct": 1281312000, + "c": "0.0609" + }, + { + "ct": 1281916800, + "c": "0.06529" + }, + { + "ct": 1282521600, + "c": "0.066" + }, + { + "ct": 1283126400, + "c": "0.064" + }, + { + "ct": 1283731200, + "c": "0.06165" + }, + { + "ct": 1284336000, + "c": "0.0615" + }, + { + "ct": 1284940800, + "c": "0.0627" + }, + { + "ct": 1285545600, + "c": "0.0622" + }, + { + "ct": 1286150400, + "c": "0.06111" + }, + { + "ct": 1286755200, + "c": "0.0965" + }, + { + "ct": 1287360000, + "c": "0.102" + }, + { + "ct": 1287964800, + "c": "0.11501" + }, + { + "ct": 1288569600, + "c": "0.1925" + }, + { + "ct": 1289174400, + "c": "0.34" + }, + { + "ct": 1289779200, + "c": "0.27904" + }, + { + "ct": 1290384000, + "c": "0.27675" + }, + { + "ct": 1290988800, + "c": "0.27" + }, + { + "ct": 1291593600, + "c": "0.19" + }, + { + "ct": 1292198400, + "c": "0.2189" + }, + { + "ct": 1292803200, + "c": "0.2401" + }, + { + "ct": 1293408000, + "c": "0.263" + }, + { + "ct": 1294012800, + "c": "0.29997" + }, + { + "ct": 1294617600, + "c": "0.323" + }, + { + "ct": 1295222400, + "c": "0.38679" + }, + { + "ct": 1295827200, + "c": "0.4424" + }, + { + "ct": 1296432000, + "c": "0.4799" + }, + { + "ct": 1297036800, + "c": "0.8968" + }, + { + "ct": 1297641600, + "c": "1.05" + }, + { + "ct": 1298246400, + "c": "0.865" + }, + { + "ct": 1298851200, + "c": "0.89" + }, + { + "ct": 1299456000, + "c": "0.8999" + }, + { + "ct": 1300060800, + "c": "0.89249" + }, + { + "ct": 1300665600, + "c": "0.75218" + }, + { + "ct": 1301270400, + "c": "0.82754" + }, + { + "ct": 1301875200, + "c": "0.779" + }, + { + "ct": 1302480000, + "c": "0.7369" + }, + { + "ct": 1303084800, + "c": "1.1123" + }, + { + "ct": 1303689600, + "c": "1.6311" + }, + { + "ct": 1304294400, + "c": "3.03311" + }, + { + "ct": 1304899200, + "c": "3.8659" + }, + { + "ct": 1305504000, + "c": "6.98701" + }, + { + "ct": 1306108800, + "c": "6.6901" + }, + { + "ct": 1306713600, + "c": "8.4" + }, + { + "ct": 1307318400, + "c": "16.7" + }, + { + "ct": 1307923200, + "c": "18.5464" + }, + { + "ct": 1308528000, + "c": "17.51" + }, + { + "ct": 1309132800, + "c": "16.45001" + }, + { + "ct": 1309737600, + "c": "15.44049" + }, + { + "ct": 1310342400, + "c": "14.879" + }, + { + "ct": 1310947200, + "c": "13.16" + }, + { + "ct": 1311552000, + "c": "13.98001" + }, + { + "ct": 1312156800, + "c": "13.35" + }, + { + "ct": 1312761600, + "c": "7.9" + }, + { + "ct": 1313366400, + "c": "10.7957" + }, + { + "ct": 1313971200, + "c": "11.31125" + }, + { + "ct": 1314576000, + "c": "9.07011" + }, + { + "ct": 1315180800, + "c": "8.17798" + }, + { + "ct": 1315785600, + "c": "5.86436" + }, + { + "ct": 1316390400, + "c": "5.2" + }, + { + "ct": 1316995200, + "c": "5.33" + }, + { + "ct": 1317600000, + "c": "5.02701" + }, + { + "ct": 1318204800, + "c": "4.10288" + }, + { + "ct": 1318809600, + "c": "3.5574" + }, + { + "ct": 1319414400, + "c": "3.12657" + }, + { + "ct": 1320019200, + "c": "3.27" + }, + { + "ct": 1320624000, + "c": "2.95959" + }, + { + "ct": 1321228800, + "c": "2.99626" + }, + { + "ct": 1321833600, + "c": "2.2" + }, + { + "ct": 1322438400, + "c": "2.47991" + }, + { + "ct": 1323043200, + "c": "2.82809" + }, + { + "ct": 1323648000, + "c": "3.2511" + }, + { + "ct": 1324252800, + "c": "3.193" + }, + { + "ct": 1324857600, + "c": "4.225" + }, + { + "ct": 1325462400, + "c": "5.26766" + }, + { + "ct": 1326067200, + "c": "7.11358" + }, + { + "ct": 1326672000, + "c": "7.00177" + }, + { + "ct": 1327276800, + "c": "6.3097" + }, + { + "ct": 1327881600, + "c": "5.38191" + }, + { + "ct": 1328486400, + "c": "5.68881" + }, + { + "ct": 1329091200, + "c": "5.51468" + }, + { + "ct": 1329696000, + "c": "4.38669" + }, + { + "ct": 1330300800, + "c": "4.922" + }, + { + "ct": 1330905600, + "c": "4.8201" + }, + { + "ct": 1331510400, + "c": "4.90901" + }, + { + "ct": 1332115200, + "c": "5.27943" + }, + { + "ct": 1332720000, + "c": "4.55001" + }, + { + "ct": 1333324800, + "c": "4.81922" + }, + { + "ct": 1333929600, + "c": "4.79253" + }, + { + "ct": 1334534400, + "c": "4.96892" + }, + { + "ct": 1335139200, + "c": "5.20352" + }, + { + "ct": 1335744000, + "c": "4.90441" + }, + { + "ct": 1336348800, + "c": "5.04991" + }, + { + "ct": 1336953600, + "c": "4.92996" + }, + { + "ct": 1337558400, + "c": "5.09002" + }, + { + "ct": 1338163200, + "c": "5.13896" + }, + { + "ct": 1338768000, + "c": "5.2051" + }, + { + "ct": 1339372800, + "c": "5.46829" + }, + { + "ct": 1339977600, + "c": "6.16382" + }, + { + "ct": 1340582400, + "c": "6.35002" + }, + { + "ct": 1341187200, + "c": "6.62898" + }, + { + "ct": 1341792000, + "c": "6.79898" + }, + { + "ct": 1342396800, + "c": "7.62101" + }, + { + "ct": 1343001600, + "c": "8.4096" + }, + { + "ct": 1343606400, + "c": "8.71027" + }, + { + "ct": 1344211200, + "c": "10.86998" + }, + { + "ct": 1344816000, + "c": "11.6239" + }, + { + "ct": 1345420800, + "c": "7.98" + }, + { + "ct": 1346025600, + "c": "10.61" + }, + { + "ct": 1346630400, + "c": "10.2041" + }, + { + "ct": 1347235200, + "c": "11.02" + }, + { + "ct": 1347840000, + "c": "11.87" + }, + { + "ct": 1348444800, + "c": "12.19331" + }, + { + "ct": 1349049600, + "c": "12.4" + }, + { + "ct": 1349654400, + "c": "11.8034" + }, + { + "ct": 1350259200, + "c": "11.7389" + }, + { + "ct": 1350864000, + "c": "11.63107" + }, + { + "ct": 1351468800, + "c": "10.69998" + }, + { + "ct": 1352073600, + "c": "10.80011" + }, + { + "ct": 1352678400, + "c": "10.84692" + }, + { + "ct": 1353283200, + "c": "11.65961" + }, + { + "ct": 1353888000, + "c": "12.4821" + }, + { + "ct": 1354492800, + "c": "12.50003" + }, + { + "ct": 1355097600, + "c": "13.388" + }, + { + "ct": 1355702400, + "c": "13.30002" + }, + { + "ct": 1356307200, + "c": "13.31202" + }, + { + "ct": 1356912000, + "c": "13.45001" + }, + { + "ct": 1357516800, + "c": "13.5199" + }, + { + "ct": 1358121600, + "c": "14.11601" + }, + { + "ct": 1358726400, + "c": "15.7" + }, + { + "ct": 1359331200, + "c": "17.95" + }, + { + "ct": 1359936000, + "c": "20.59" + }, + { + "ct": 1360540800, + "c": "23.96975" + }, + { + "ct": 1361145600, + "c": "26.8146" + }, + { + "ct": 1361750400, + "c": "29.88999" + }, + { + "ct": 1362355200, + "c": "34.49999" + }, + { + "ct": 1362960000, + "c": "46" + }, + { + "ct": 1363564800, + "c": "47.4" + }, + { + "ct": 1364169600, + "c": "71.93" + }, + { + "ct": 1364774400, + "c": "93.03001" + }, + { + "ct": 1365379200, + "c": "162.30102" + }, + { + "ct": 1365984000, + "c": "89.99999" + }, + { + "ct": 1366588800, + "c": "119.2" + }, + { + "ct": 1367193600, + "c": "134.44444" + }, + { + "ct": 1367798400, + "c": "115.98" + }, + { + "ct": 1368403200, + "c": "114.82002" + }, + { + "ct": 1369008000, + "c": "122.49999" + }, + { + "ct": 1369612800, + "c": "133.5" + }, + { + "ct": 1370217600, + "c": "122.5" + }, + { + "ct": 1370822400, + "c": "100.43743" + }, + { + "ct": 1371427200, + "c": "99.9" + }, + { + "ct": 1372032000, + "c": "107.90001" + }, + { + "ct": 1372636800, + "c": "97.51" + }, + { + "ct": 1373241600, + "c": "76.5" + }, + { + "ct": 1373846400, + "c": "94.41986" + }, + { + "ct": 1374451200, + "c": "91.998" + }, + { + "ct": 1375056000, + "c": "98.78008" + }, + { + "ct": 1375660800, + "c": "105.12" + }, + { + "ct": 1376265600, + "c": "105" + }, + { + "ct": 1376870400, + "c": "113.38" + }, + { + "ct": 1377475200, + "c": "122.11102" + }, + { + "ct": 1378080000, + "c": "146.01003" + }, + { + "ct": 1378684800, + "c": "126.31501" + }, + { + "ct": 1379289600, + "c": "138.3002" + }, + { + "ct": 1379894400, + "c": "134.00001" + }, + { + "ct": 1380499200, + "c": "143.88402" + }, + { + "ct": 1381104000, + "c": "137.8" + }, + { + "ct": 1381708800, + "c": "147.53" + }, + { + "ct": 1382313600, + "c": "186.1" + }, + { + "ct": 1382918400, + "c": "207.0001" + }, + { + "ct": 1383523200, + "c": "224.01001" + }, + { + "ct": 1384128000, + "c": "336.33101" + }, + { + "ct": 1384732800, + "c": "528" + }, + { + "ct": 1385337600, + "c": "795" + }, + { + "ct": 1385942400, + "c": "1004.42392" + }, + { + "ct": 1386547200, + "c": "804.5" + }, + { + "ct": 1387152000, + "c": "919.985" + }, + { + "ct": 1387756800, + "c": "639.48" + }, + { + "ct": 1388361600, + "c": "786.98" + }, + { + "ct": 1388966400, + "c": "1015" + }, + { + "ct": 1389571200, + "c": "940" + }, + { + "ct": 1390176000, + "c": "954.995" + }, + { + "ct": 1390780800, + "c": "1007.98999" + }, + { + "ct": 1391385600, + "c": "954" + }, + { + "ct": 1391990400, + "c": "659.49776" + }, + { + "ct": 1392595200, + "c": "299.702" + }, + { + "ct": 1393200000, + "c": "310.00001" + }, + { + "ct": 1393804800, + "c": "135" + } +] diff --git a/backend/src/tasks/price-updater.ts b/backend/src/tasks/price-updater.ts new file mode 100644 index 0000000000..467669a6f6 --- /dev/null +++ b/backend/src/tasks/price-updater.ts @@ -0,0 +1,489 @@ +import * as fs from 'fs'; +import path from 'path'; +import config from '../config'; +import logger from '../logger'; +import PricesRepository, { ApiPrice, MAX_PRICES } from '../repositories/PricesRepository'; +import BitfinexApi from './price-feeds/bitfinex-api'; +import BitflyerApi from './price-feeds/bitflyer-api'; +import CoinbaseApi from './price-feeds/coinbase-api'; +import GeminiApi from './price-feeds/gemini-api'; +import KrakenApi from './price-feeds/kraken-api'; +import FreeCurrencyApi from './price-feeds/free-currency-api'; + +export interface PriceFeed { + name: string; + url: string; + urlHist: string; + currencies: string[]; + + $fetchPrice(currency): Promise; + $fetchRecentPrice(currencies: string[], type: string): Promise; +} + +export interface PriceHistory { + [timestamp: number]: ApiPrice; +} + +export interface ConversionFeed { + $getQuota(): Promise; + $fetchLatestConversionRates(): Promise; + $fetchConversionRates(date: string): Promise; +} + +export interface ConversionRates { + [currency: string]: number +} + +function getMedian(arr: number[]): number { + const sortedArr = arr.slice().sort((a, b) => a - b); + const mid = Math.floor(sortedArr.length / 2); + return sortedArr.length % 2 !== 0 + ? sortedArr[mid] + : (sortedArr[mid - 1] + sortedArr[mid]) / 2; +} + +class PriceUpdater { + public historyInserted = false; + private additionalCurrenciesHistoryInserted = false; + private additionalCurrenciesHistoryRunning = false; + private lastFailedHistoricalRun = 0; + private timeBetweenUpdatesMs = 360_0000 / config.MEMPOOL.PRICE_UPDATES_PER_HOUR; + private cyclePosition = -1; + private firstRun = true; + private lastTime = -1; + private lastHistoricalRun = 0; + private running = false; + private feeds: PriceFeed[] = []; + private currencies: string[] = ['USD', 'EUR', 'GBP', 'CAD', 'CHF', 'AUD', 'JPY']; + private latestPrices: ApiPrice; + private currencyConversionFeed: ConversionFeed | undefined; + private newCurrencies: string[] = ['BGN', 'BRL', 'CNY', 'CZK', 'DKK', 'HKD', 'HRK', 'HUF', 'IDR', 'ILS', 'INR', 'ISK', 'KRW', 'MXN', 'MYR', 'NOK', 'NZD', 'PHP', 'PLN', 'RON', 'RUB', 'SEK', 'SGD', 'THB', 'TRY', 'ZAR']; + private lastTimeConversionsRatesFetched: number = 0; + private latestConversionsRatesFromFeed: ConversionRates = { USD: -1 }; + private ratesChangedCallback: ((rates: ApiPrice) => void) | undefined; + + constructor() { + this.latestPrices = this.getEmptyPricesObj(); + + this.feeds.push(new BitflyerApi()); // Does not have historical endpoint + this.feeds.push(new KrakenApi()); + this.feeds.push(new CoinbaseApi()); + this.feeds.push(new BitfinexApi()); + this.feeds.push(new GeminiApi()); + + this.currencyConversionFeed = new FreeCurrencyApi(); + this.setCyclePosition(); + } + + public getLatestPrices(): ApiPrice { + return this.latestPrices; + } + + public getEmptyPricesObj(): ApiPrice { + return { + time: 0, + USD: -1, + EUR: -1, + GBP: -1, + CAD: -1, + CHF: -1, + AUD: -1, + JPY: -1, + BGN: -1, + BRL: -1, + CNY: -1, + CZK: -1, + DKK: -1, + HKD: -1, + HRK: -1, + HUF: -1, + IDR: -1, + ILS: -1, + INR: -1, + ISK: -1, + KRW: -1, + MXN: -1, + MYR: -1, + NOK: -1, + NZD: -1, + PHP: -1, + PLN: -1, + RON: -1, + RUB: -1, + SEK: -1, + SGD: -1, + THB: -1, + TRY: -1, + ZAR: -1, + }; + } + + public setRatesChangedCallback(fn: (rates: ApiPrice) => void): void { + this.ratesChangedCallback = fn; + } + + /** + * We execute this function before the websocket initialization since + * the websocket init is not done asyncronously + */ + public async $initializeLatestPriceWithDb(): Promise { + this.latestPrices = await PricesRepository.$getLatestConversionRates(); + } + + public async $run(): Promise { + if (config.MEMPOOL.NETWORK === 'signet' || config.MEMPOOL.NETWORK === 'testnet') { + // Coins have no value on testnet/signet, so we want to always show 0 + return; + } + + if (this.running === true) { + return; + } + this.running = true; + + if ((Math.round(new Date().getTime() / 1000) - this.lastHistoricalRun) > 3600 * 24) { + // Once a day, look for missing prices (could happen due to network connectivity issues) + this.historyInserted = false; + this.additionalCurrenciesHistoryInserted = false; + } + + if (this.lastFailedHistoricalRun > 0 && (Math.round(new Date().getTime() / 1000) - this.lastFailedHistoricalRun) > 60) { + // If the last attempt to insert missing prices failed, we try again after 60 seconds + this.additionalCurrenciesHistoryInserted = false; + } + + if (config.FIAT_PRICE.API_KEY && this.currencyConversionFeed && (Math.round(new Date().getTime() / 1000) - this.lastTimeConversionsRatesFetched) > 3600 * 24) { + // Once a day, fetch conversion rates from api: we don't need more granularity for fiat currencies and have a limited number of requests + try { + this.latestConversionsRatesFromFeed = await this.currencyConversionFeed.$fetchLatestConversionRates(); + this.lastTimeConversionsRatesFetched = Math.round(new Date().getTime() / 1000); + logger.debug(`Fetched currencies conversion rates from conversions API: ${JSON.stringify(this.latestConversionsRatesFromFeed)}`); + } catch (e) { + logger.err(`Cannot fetch conversion rates from conversions API. Reason: ${(e instanceof Error ? e.message : e)}`); + } + } + + try { + await this.$updatePrice(); + if (this.historyInserted === false && config.DATABASE.ENABLED === true) { + await this.$insertHistoricalPrices(); + } + if (this.additionalCurrenciesHistoryInserted === false && config.DATABASE.ENABLED === true && config.FIAT_PRICE.API_KEY && !this.additionalCurrenciesHistoryRunning) { + await this.$insertMissingAdditionalPrices(); + } + + } catch (e: any) { + logger.err(`Cannot save BTC prices in db. Reason: ${e instanceof Error ? e.message : e}`, logger.tags.mining); + } + + this.running = false; + } + + private getMillisecondsSinceBeginningOfHour(): number { + const now = new Date(); + const beginningOfHour = new Date(now); + beginningOfHour.setMinutes(0, 0, 0); + return now.getTime() - beginningOfHour.getTime(); + } + + private setCyclePosition(): void { + const millisecondsSinceBeginningOfHour = this.getMillisecondsSinceBeginningOfHour(); + for (let i = 0; i < config.MEMPOOL.PRICE_UPDATES_PER_HOUR; i++) { + if (this.timeBetweenUpdatesMs * i > millisecondsSinceBeginningOfHour) { + this.cyclePosition = i; + return; + } + } + this.cyclePosition = config.MEMPOOL.PRICE_UPDATES_PER_HOUR; + } + + /** + * Fetch last BTC price from exchanges, average them, and save it in the database once every hour + */ + private async $updatePrice(): Promise { + let forceUpdate = false; + if (this.firstRun === true && config.DATABASE.ENABLED === true) { + const lastUpdate = await PricesRepository.$getLatestPriceTime(); + if (new Date().getTime() / 1000 - lastUpdate > this.timeBetweenUpdatesMs / 1000) { + forceUpdate = true; + } + this.firstRun = false; + } + + const millisecondsSinceBeginningOfHour = this.getMillisecondsSinceBeginningOfHour(); + + // Reset the cycle on new hour + if (this.lastTime > millisecondsSinceBeginningOfHour) { + this.cyclePosition = 0; + } + this.lastTime = millisecondsSinceBeginningOfHour; + if (millisecondsSinceBeginningOfHour < this.timeBetweenUpdatesMs * this.cyclePosition && !forceUpdate && this.cyclePosition !== 0) { + return; + } + + for (const currency of this.currencies) { + let prices: number[] = []; + + for (const feed of this.feeds) { + // Fetch prices from API which supports `currency` + if (feed.currencies.includes(currency)) { + try { + const price = await feed.$fetchPrice(currency); + if (price > -1 && price < MAX_PRICES[currency]) { + prices.push(price); + } + logger.debug(`${feed.name} BTC/${currency} price: ${price}`, logger.tags.mining); + } catch (e) { + logger.debug(`Could not fetch BTC/${currency} price at ${feed.name}. Reason: ${(e instanceof Error ? e.message : e)}`, logger.tags.mining); + } + } + } + if (prices.length === 1) { + logger.debug(`Only ${prices.length} feed available for BTC/${currency} price`, logger.tags.mining); + } + + // Compute average price, non weighted + prices = prices.filter(price => price > 0); + if (prices.length === 0) { + this.latestPrices[currency] = -1; + } else { + this.latestPrices[currency] = Math.round(getMedian(prices)); + } + } + + if (config.FIAT_PRICE.API_KEY && this.latestPrices.USD > 0 && Object.keys(this.latestConversionsRatesFromFeed).length > 0) { + for (const conversionCurrency of this.newCurrencies) { + if (this.latestConversionsRatesFromFeed[conversionCurrency] > 0 && this.latestPrices.USD * this.latestConversionsRatesFromFeed[conversionCurrency] < MAX_PRICES[conversionCurrency]) { + this.latestPrices[conversionCurrency] = Math.round(this.latestPrices.USD * this.latestConversionsRatesFromFeed[conversionCurrency]); + } + } + } + + if (config.DATABASE.ENABLED === true && this.cyclePosition === 0) { + // Save everything in db + try { + const p = 60 * 60 * 1000; // milliseconds in an hour + const nowRounded = new Date(Math.round(new Date().getTime() / p) * p); // https://stackoverflow.com/a/28037042 + await PricesRepository.$savePrices(nowRounded.getTime() / 1000, this.latestPrices); + } catch (e) { + logger.err(`Cannot save latest prices into db. Trying again in 5 minutes. Reason: ${(e instanceof Error ? e.message : e)}`); + } + } + + this.latestPrices.time = Math.round(new Date().getTime() / 1000); + logger.info(`Latest BTC fiat averaged price: ${JSON.stringify(this.latestPrices)}`); + + if (this.ratesChangedCallback) { + this.ratesChangedCallback(this.latestPrices); + } + + if (!forceUpdate) { + this.cyclePosition++; + } + + if (this.latestPrices.USD === -1) { + this.latestPrices = await PricesRepository.$getLatestConversionRates(); + } + } + + /** + * Called once by the database migration to initialize historical prices data (weekly) + * We use MtGox weekly price from July 19, 2010 to September 30, 2013 + * We use Kraken weekly price from October 3, 2013 up to last month + * We use Kraken hourly price for the past month + */ + private async $insertHistoricalPrices(): Promise { + const existingPriceTimes = await PricesRepository.$getPricesTimes(); + + // Insert MtGox weekly prices + const pricesJson: any[] = JSON.parse(fs.readFileSync(path.join(__dirname, 'mtgox-weekly.json')).toString()); + const prices = this.getEmptyPricesObj(); + let insertedCount: number = 0; + for (const price of pricesJson) { + if (existingPriceTimes.includes(price['ct'])) { + continue; + } + + // From 1380758400 we will use Kraken price as it follows closely MtGox, but was not affected as much + // by the MtGox exchange collapse a few months later + if (price['ct'] > 1380758400) { + break; + } + prices.USD = price['c']; + await PricesRepository.$savePrices(price['ct'], prices); + ++insertedCount; + } + if (insertedCount > 0) { + logger.notice(`Inserted ${insertedCount} MtGox USD weekly price history into db`, logger.tags.mining); + } else { + logger.debug(`Inserted ${insertedCount} MtGox USD weekly price history into db`, logger.tags.mining); + } + + // Insert Kraken weekly prices + await new KrakenApi().$insertHistoricalPrice(); + + // Insert missing recent hourly prices + await this.$insertMissingRecentPrices('day'); + await this.$insertMissingRecentPrices('hour'); + + this.historyInserted = true; + this.lastHistoricalRun = Math.round(new Date().getTime() / 1000); + } + + /** + * Find missing hourly prices and insert them in the database + * It has a limited backward range and it depends on which API are available + */ + private async $insertMissingRecentPrices(type: 'hour' | 'day'): Promise { + const existingPriceTimes = await PricesRepository.$getPricesTimes(); + + logger.debug(`Fetching ${type === 'day' ? 'dai' : 'hour'}ly price history from exchanges and saving missing ones into the database`, logger.tags.mining); + + const historicalPrices: PriceHistory[] = []; + + // Fetch all historical hourly prices + for (const feed of this.feeds) { + try { + historicalPrices.push(await feed.$fetchRecentPrice(this.currencies, type)); + } catch (e) { + logger.err(`Cannot fetch hourly historical price from ${feed.name}. Ignoring this feed. Reason: ${e instanceof Error ? e.message : e}`, logger.tags.mining); + } + } + + // Group them by timestamp and currency, for example + // grouped[123456789]['USD'] = [1, 2, 3, 4]; + const grouped = {}; + for (const historicalEntry of historicalPrices) { + for (const time in historicalEntry) { + if (existingPriceTimes.includes(parseInt(time, 10))) { + continue; + } + + if (grouped[time] === undefined) { + grouped[time] = { + USD: [], EUR: [], GBP: [], CAD: [], CHF: [], AUD: [], JPY: [] + }; + } + + for (const currency of this.currencies) { + const price = historicalEntry[time][currency]; + if (price > -1 && price < MAX_PRICES[currency]) { + grouped[time][currency].push(typeof price === 'string' ? parseInt(price, 10) : price); + } + } + } + } + + // Average prices and insert everything into the db + let totalInserted = 0; + for (const time in grouped) { + const prices: ApiPrice = this.getEmptyPricesObj(); + for (const currency in grouped[time]) { + if (grouped[time][currency].length === 0) { + continue; + } + prices[currency] = Math.round(getMedian(grouped[time][currency])); + } + await PricesRepository.$savePrices(parseInt(time, 10), prices); + ++totalInserted; + } + + if (totalInserted > 0) { + logger.notice(`Inserted ${totalInserted} ${type === 'day' ? 'dai' : 'hour'}ly historical prices into the db`, logger.tags.mining); + } else { + logger.debug(`Inserted ${totalInserted} ${type === 'day' ? 'dai' : 'hour'}ly historical prices into the db`, logger.tags.mining); + } + } + + /** + * Find missing prices for additional currencies and insert them in the database + * We calculate the additional prices from the USD price and the conversion rates + */ + private async $insertMissingAdditionalPrices(): Promise { + this.lastFailedHistoricalRun = 0; + const priceTimesToFill = await PricesRepository.$getPricesTimesWithMissingFields(); + if (priceTimesToFill.length === 0) { + return; + } + try { + const remainingQuota = await this.currencyConversionFeed?.$getQuota(); + if (remainingQuota['month']['remaining'] < 500) { // We need some calls left for the daily updates + logger.debug(`Not enough conversions API credit to insert missing prices in ${priceTimesToFill.length} rows (${remainingQuota['month']['remaining']} calls left).`, logger.tags.mining); + this.additionalCurrenciesHistoryInserted = true; // Do not try again until next day + return; + } + } catch (e) { + logger.err(`Cannot fetch conversions API credit, insertion of missing prices aborted. Reason: ${(e instanceof Error ? e.message : e)}`); + return; + } + + this.additionalCurrenciesHistoryRunning = true; + logger.debug(`Inserting missing historical conversion rates using conversions API to fill ${priceTimesToFill.length} rows`, logger.tags.mining); + + let conversionRates: { [timestamp: number]: ConversionRates } = {}; + let totalInserted = 0; + + for (let i = 0; i < priceTimesToFill.length; i++) { + const priceTime = priceTimesToFill[i]; + const missingLegacyCurrencies = this.getMissingLegacyCurrencies(priceTime); // In the case a legacy currency (EUR, GBP, CAD, CHF, AUD, JPY) + const year = new Date(priceTime.time * 1000).getFullYear(); // is missing, we use the same process as for the new currencies + const month = new Date(priceTime.time * 1000).getMonth(); + const yearMonthTimestamp = new Date(year, month, 1).getTime() / 1000; + if (conversionRates[yearMonthTimestamp] === undefined) { + try { + if (year === new Date().getFullYear() && month === new Date().getMonth()) { // For rows in the current month, we use the latest conversion rates + conversionRates[yearMonthTimestamp] = this.latestConversionsRatesFromFeed; + } else { + conversionRates[yearMonthTimestamp] = await this.currencyConversionFeed?.$fetchConversionRates(`${year}-${month + 1 < 10 ? `0${month + 1}` : `${month + 1}`}-15`) || { USD: -1 }; + } + + if (conversionRates[yearMonthTimestamp]['USD'] < 0) { + throw new Error('Incorrect USD conversion rate'); + } + } catch (e) { + if ((e instanceof Error ? e.message : '').includes('429')) { // Continue 60 seconds later if and only if error is 429 + this.lastFailedHistoricalRun = Math.round(new Date().getTime() / 1000); + logger.info(`Got a 429 error from conversions API. This is expected to happen a few times during the initial historical price insertion, process will resume in 60 seconds.`, logger.tags.mining); + } else { + logger.err(`Cannot fetch conversion rates from conversions API for ${year}-${month + 1 < 10 ? `0${month + 1}` : `${month + 1}`}-01, trying again next day. Error: ${(e instanceof Error ? e.message : e)}`, logger.tags.mining); + } + break; + } + } + + const prices: ApiPrice = this.getEmptyPricesObj(); + + let willInsert = false; + for (const conversionCurrency of this.newCurrencies.concat(missingLegacyCurrencies)) { + if (conversionRates[yearMonthTimestamp][conversionCurrency] > 0 && priceTime.USD * conversionRates[yearMonthTimestamp][conversionCurrency] < MAX_PRICES[conversionCurrency]) { + prices[conversionCurrency] = year >= 2013 ? Math.round(priceTime.USD * conversionRates[yearMonthTimestamp][conversionCurrency]) : Math.round(priceTime.USD * conversionRates[yearMonthTimestamp][conversionCurrency] * 100) / 100; + willInsert = true; + } else { + prices[conversionCurrency] = 0; + } + } + + if (willInsert) { + await PricesRepository.$saveAdditionalCurrencyPrices(priceTime.time, prices, missingLegacyCurrencies); + ++totalInserted; + } + } + + logger.debug(`Inserted ${totalInserted} missing additional currency prices into the db`, logger.tags.mining); + this.additionalCurrenciesHistoryInserted = true; + this.additionalCurrenciesHistoryRunning = false; + } + + // Helper function to get legacy missing currencies in a row (EUR, GBP, CAD, CHF, AUD, JPY) + private getMissingLegacyCurrencies(priceTime: any): string[] { + const missingCurrencies: string[] = []; + ['eur', 'gbp', 'cad', 'chf', 'aud', 'jpy'].forEach(currency => { + if (priceTime[`${currency}_missing`]) { + missingCurrencies.push(currency.toUpperCase()); + } + }); + return missingCurrencies; + } +} + +export default new PriceUpdater(); diff --git a/backend/src/utils/axios-query.ts b/backend/src/utils/axios-query.ts new file mode 100644 index 0000000000..e641d3ce98 --- /dev/null +++ b/backend/src/utils/axios-query.ts @@ -0,0 +1,70 @@ +import axios, { AxiosResponse } from 'axios'; +import { SocksProxyAgent } from 'socks-proxy-agent'; +import backendInfo from '../api/backend-info'; +import config from '../config'; +import logger from '../logger'; +import * as https from 'https'; + +export async function query(path, throwOnFail: boolean = false): Promise { + type axiosOptions = { + headers: { + 'User-Agent': string + }; + timeout: number; + httpsAgent?: https.Agent; + }; + const setDelay = (secs: number = 1): Promise => new Promise(resolve => setTimeout(() => resolve(), secs * 1000)); + const axiosOptions: axiosOptions = { + headers: { + 'User-Agent': (config.MEMPOOL.USER_AGENT === 'mempool') ? `mempool/v${backendInfo.getBackendInfo().version}` : `${config.MEMPOOL.USER_AGENT}` + }, + timeout: config.SOCKS5PROXY.ENABLED ? 30000 : 10000 + }; + let retry = 0; + let lastError: any = null; + + while (retry < config.MEMPOOL.EXTERNAL_MAX_RETRY) { + try { + if (config.SOCKS5PROXY.ENABLED) { + const socksOptions: any = { + agentOptions: { + keepAlive: true, + }, + hostname: config.SOCKS5PROXY.HOST, + port: config.SOCKS5PROXY.PORT + }; + + if (config.SOCKS5PROXY.USERNAME && config.SOCKS5PROXY.PASSWORD) { + socksOptions.username = config.SOCKS5PROXY.USERNAME; + socksOptions.password = config.SOCKS5PROXY.PASSWORD; + } else { + // Retry with different tor circuits https://stackoverflow.com/a/64960234 + socksOptions.username = `circuit${retry}`; + } + + axiosOptions.httpsAgent = new SocksProxyAgent(socksOptions); + } + + const data: AxiosResponse = await axios.get(path, axiosOptions); + if (data.statusText === 'error' || !data.data) { + throw new Error(`Could not fetch data from ${path}, Error: ${data.status}`); + } + return data.data; + } catch (e) { + lastError = e; + logger.warn(`Could not connect to ${path} (Attempt ${retry + 1}/${config.MEMPOOL.EXTERNAL_MAX_RETRY}). Reason: ` + (e instanceof Error ? e.message : e)); + retry++; + } + if (retry < config.MEMPOOL.EXTERNAL_MAX_RETRY) { + await setDelay(config.MEMPOOL.EXTERNAL_RETRY_INTERVAL); + } + } + + logger.err(`Could not connect to ${path}. All ${config.MEMPOOL.EXTERNAL_MAX_RETRY} attempts failed`); + + if (throwOnFail && lastError) { + throw lastError; + } + + return undefined; +} diff --git a/backend/src/utils/bitcoin-script.ts b/backend/src/utils/bitcoin-script.ts new file mode 100644 index 0000000000..3414e82691 --- /dev/null +++ b/backend/src/utils/bitcoin-script.ts @@ -0,0 +1,203 @@ +const opcodes = { + OP_FALSE: 0, + OP_0: 0, + OP_PUSHDATA1: 76, + OP_PUSHDATA2: 77, + OP_PUSHDATA4: 78, + OP_1NEGATE: 79, + OP_PUSHNUM_NEG1: 79, + OP_RESERVED: 80, + OP_TRUE: 81, + OP_1: 81, + OP_2: 82, + OP_3: 83, + OP_4: 84, + OP_5: 85, + OP_6: 86, + OP_7: 87, + OP_8: 88, + OP_9: 89, + OP_10: 90, + OP_11: 91, + OP_12: 92, + OP_13: 93, + OP_14: 94, + OP_15: 95, + OP_16: 96, + OP_PUSHNUM_1: 81, + OP_PUSHNUM_2: 82, + OP_PUSHNUM_3: 83, + OP_PUSHNUM_4: 84, + OP_PUSHNUM_5: 85, + OP_PUSHNUM_6: 86, + OP_PUSHNUM_7: 87, + OP_PUSHNUM_8: 88, + OP_PUSHNUM_9: 89, + OP_PUSHNUM_10: 90, + OP_PUSHNUM_11: 91, + OP_PUSHNUM_12: 92, + OP_PUSHNUM_13: 93, + OP_PUSHNUM_14: 94, + OP_PUSHNUM_15: 95, + OP_PUSHNUM_16: 96, + OP_NOP: 97, + OP_VER: 98, + OP_IF: 99, + OP_NOTIF: 100, + OP_VERIF: 101, + OP_VERNOTIF: 102, + OP_ELSE: 103, + OP_ENDIF: 104, + OP_VERIFY: 105, + OP_RETURN: 106, + OP_TOALTSTACK: 107, + OP_FROMALTSTACK: 108, + OP_2DROP: 109, + OP_2DUP: 110, + OP_3DUP: 111, + OP_2OVER: 112, + OP_2ROT: 113, + OP_2SWAP: 114, + OP_IFDUP: 115, + OP_DEPTH: 116, + OP_DROP: 117, + OP_DUP: 118, + OP_NIP: 119, + OP_OVER: 120, + OP_PICK: 121, + OP_ROLL: 122, + OP_ROT: 123, + OP_SWAP: 124, + OP_TUCK: 125, + OP_CAT: 126, + OP_SUBSTR: 127, + OP_LEFT: 128, + OP_RIGHT: 129, + OP_SIZE: 130, + OP_INVERT: 131, + OP_AND: 132, + OP_OR: 133, + OP_XOR: 134, + OP_EQUAL: 135, + OP_EQUALVERIFY: 136, + OP_RESERVED1: 137, + OP_RESERVED2: 138, + OP_1ADD: 139, + OP_1SUB: 140, + OP_2MUL: 141, + OP_2DIV: 142, + OP_NEGATE: 143, + OP_ABS: 144, + OP_NOT: 145, + OP_0NOTEQUAL: 146, + OP_ADD: 147, + OP_SUB: 148, + OP_MUL: 149, + OP_DIV: 150, + OP_MOD: 151, + OP_LSHIFT: 152, + OP_RSHIFT: 153, + OP_BOOLAND: 154, + OP_BOOLOR: 155, + OP_NUMEQUAL: 156, + OP_NUMEQUALVERIFY: 157, + OP_NUMNOTEQUAL: 158, + OP_LESSTHAN: 159, + OP_GREATERTHAN: 160, + OP_LESSTHANOREQUAL: 161, + OP_GREATERTHANOREQUAL: 162, + OP_MIN: 163, + OP_MAX: 164, + OP_WITHIN: 165, + OP_RIPEMD160: 166, + OP_SHA1: 167, + OP_SHA256: 168, + OP_HASH160: 169, + OP_HASH256: 170, + OP_CODESEPARATOR: 171, + OP_CHECKSIG: 172, + OP_CHECKSIGVERIFY: 173, + OP_CHECKMULTISIG: 174, + OP_CHECKMULTISIGVERIFY: 175, + OP_NOP1: 176, + OP_NOP2: 177, + OP_CHECKLOCKTIMEVERIFY: 177, + OP_CLTV: 177, + OP_NOP3: 178, + OP_CHECKSEQUENCEVERIFY: 178, + OP_CSV: 178, + OP_NOP4: 179, + OP_NOP5: 180, + OP_NOP6: 181, + OP_NOP7: 182, + OP_NOP8: 183, + OP_NOP9: 184, + OP_NOP10: 185, + OP_CHECKSIGADD: 186, + OP_PUBKEYHASH: 253, + OP_PUBKEY: 254, + OP_INVALIDOPCODE: 255, +}; +// add unused opcodes +for (let i = 187; i <= 255; i++) { + opcodes[`OP_RETURN_${i}`] = i; +} + +export { opcodes }; + +/** extracts m and n from a multisig script (asm), returns nothing if it is not a multisig script */ +export function parseMultisigScript(script: string): void | { m: number, n: number } { + if (!script) { + return; + } + const ops = script.split(' '); + if (ops.length < 3 || ops.pop() !== 'OP_CHECKMULTISIG') { + return; + } + const opN = ops.pop(); + if (!opN) { + return; + } + if (!opN.startsWith('OP_PUSHNUM_')) { + return; + } + const n = parseInt(opN.match(/[0-9]+/)?.[0] || '', 10); + if (ops.length < n * 2 + 1) { + return; + } + // pop n public keys + for (let i = 0; i < n; i++) { + if (!/^0((2|3)\w{64}|4\w{128})$/.test(ops.pop() || '')) { + return; + } + if (!/^OP_PUSHBYTES_(33|65)$/.test(ops.pop() || '')) { + return; + } + } + const opM = ops.pop(); + if (!opM) { + return; + } + if (!opM.startsWith('OP_PUSHNUM_')) { + return; + } + const m = parseInt(opM.match(/[0-9]+/)?.[0] || '', 10); + + if (ops.length) { + return; + } + + return { m, n }; +} + +export function getVarIntLength(n: number): number { + if (n < 0xfd) { + return 1; + } else if (n <= 0xffff) { + return 3; + } else if (n <= 0xffffffff) { + return 5; + } else { + return 9; + } +} \ No newline at end of file diff --git a/backend/src/utils/clone.ts b/backend/src/utils/clone.ts new file mode 100644 index 0000000000..38e36096f3 --- /dev/null +++ b/backend/src/utils/clone.ts @@ -0,0 +1,14 @@ +// simple recursive deep clone for literal-type objects +// does not preserve Dates, Maps, Sets etc +// does not support recursive objects +// properties deeper than maxDepth will be shallow cloned +export function deepClone(obj: any, maxDepth: number = 50, depth: number = 0): any { + let cloned = obj; + if (depth < maxDepth && typeof obj === 'object') { + cloned = Array.isArray(obj) ? [] : {}; + for (const key in obj) { + cloned[key] = deepClone(obj[key], maxDepth, depth + 1); + } + } + return cloned; +} \ No newline at end of file diff --git a/backend/src/utils/format.ts b/backend/src/utils/format.ts new file mode 100644 index 0000000000..63dc07ae4f --- /dev/null +++ b/backend/src/utils/format.ts @@ -0,0 +1,95 @@ +const byteUnits = ['B', 'kB', 'MB', 'GB', 'TB']; + +export function getBytesUnit(bytes: number): string { + if (isNaN(bytes) || !isFinite(bytes)) { + return 'B'; + } + + let unitIndex = 0; + while (unitIndex < byteUnits.length && bytes > 1024) { + unitIndex++; + bytes /= 1024; + } + + return byteUnits[unitIndex]; +} + +export function formatBytes(bytes: number, toUnit: string, skipUnit = false): string { + if (isNaN(bytes) || !isFinite(bytes)) { + return `${bytes}`; + } + + let unitIndex = 0; + while (unitIndex < byteUnits.length && (toUnit && byteUnits[unitIndex] !== toUnit || (!toUnit && bytes > 1024))) { + unitIndex++; + bytes /= 1024; + } + + return `${bytes.toFixed(2)}${skipUnit ? '' : ' ' + byteUnits[unitIndex]}`; +} + +// https://stackoverflow.com/a/64235212 +export function hex2bin(hex: string): string { + if (!hex) { + return ''; + } + + hex = hex.replace('0x', '').toLowerCase(); + let out = ''; + + for (const c of hex) { + switch (c) { + case '0': out += '0000'; break; + case '1': out += '0001'; break; + case '2': out += '0010'; break; + case '3': out += '0011'; break; + case '4': out += '0100'; break; + case '5': out += '0101'; break; + case '6': out += '0110'; break; + case '7': out += '0111'; break; + case '8': out += '1000'; break; + case '9': out += '1001'; break; + case 'a': out += '1010'; break; + case 'b': out += '1011'; break; + case 'c': out += '1100'; break; + case 'd': out += '1101'; break; + case 'e': out += '1110'; break; + case 'f': out += '1111'; break; + default: return ''; + } + } + return out; +} + +export function bin2hex(bin: string): string { + if (!bin) { + return ''; + } + + let out = ''; + + for (let i = 0; i < bin.length; i += 4) { + const c = bin.substring(i, i + 4); + switch (c) { + case '0000': out += '0'; break; + case '0001': out += '1'; break; + case '0010': out += '2'; break; + case '0011': out += '3'; break; + case '0100': out += '4'; break; + case '0101': out += '5'; break; + case '0110': out += '6'; break; + case '0111': out += '7'; break; + case '1000': out += '8'; break; + case '1001': out += '9'; break; + case '1010': out += 'a'; break; + case '1011': out += 'b'; break; + case '1100': out += 'c'; break; + case '1101': out += 'd'; break; + case '1110': out += 'e'; break; + case '1111': out += 'f'; break; + default: return ''; + } + } + + return out; +} \ No newline at end of file diff --git a/backend/src/utils/ipcheck.js b/backend/src/utils/ipcheck.js new file mode 100644 index 0000000000..06d4a6f155 --- /dev/null +++ b/backend/src/utils/ipcheck.js @@ -0,0 +1,119 @@ +var net = require('net'); + +var IPCheck = module.exports = function(input) { + var self = this; + + if (!(self instanceof IPCheck)) { + return new IPCheck(input); + } + + self.input = input; + self.parse(); +}; + +IPCheck.prototype.parse = function() { + var self = this; + + if (!self.input || typeof self.input !== 'string') return self.valid = false; + + var ip; + + var pos = self.input.lastIndexOf('/'); + if (pos !== -1) { + ip = self.input.substring(0, pos); + self.mask = +self.input.substring(pos + 1); + } else { + ip = self.input; + self.mask = null; + } + + self.ipv = net.isIP(ip); + self.valid = !!self.ipv && !isNaN(self.mask); + + if (!self.valid) return; + + // default mask = 32 for ipv4 and 128 for ipv6 + if (self.mask === null) self.mask = self.ipv === 4 ? 32 : 128; + + if (self.ipv === 4) { + // difference between ipv4 and ipv6 masks + self.mask += 96; + } + + if (self.mask < 0 || self.mask > 128) { + self.valid = false; + return; + } + + self.address = [ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 ]; + + if(self.ipv === 4){ + self.parseIPv4(ip); + }else{ + self.parseIPv6(ip); + } +}; + +IPCheck.prototype.parseIPv4 = function(ip) { + var self = this; + + // ipv4 addresses live under ::ffff:0:0 + self.address[10] = self.address[11] = 0xff; + + var octets = ip.split('.'); + for (var i = 0; i < 4; i++) { + self.address[i + 12] = parseInt(octets[i], 10); + } +}; + + +var V6_TRANSITIONAL = /:(\d+\.\d+\.\d+\.\d+)$/; + +IPCheck.prototype.parseIPv6 = function(ip) { + var self = this; + + var transitionalMatch = V6_TRANSITIONAL.exec(ip); + if(transitionalMatch){ + self.parseIPv4(transitionalMatch[1]); + return; + } + + var bits = ip.split(':'); + if (bits.length < 8) { + ip = ip.replace('::', Array(11 - bits.length).join(':')); + bits = ip.split(':'); + } + + var j = 0; + for (var i = 0; i < bits.length; i += 1) { + var x = bits[i] ? parseInt(bits[i], 16) : 0; + self.address[j++] = x >> 8; + self.address[j++] = x & 0xff; + } +}; + +IPCheck.prototype.match = function(cidr) { + var self = this; + + if (!(cidr instanceof IPCheck)) cidr = new IPCheck(cidr); + if (!self.valid || !cidr.valid) return false; + + var mask = cidr.mask; + var i = 0; + + while (mask >= 8) { + if (self.address[i] !== cidr.address[i]) return false; + + i++; + mask -= 8; + } + + var shift = 8 - mask; + return (self.address[i] >>> shift) === (cidr.address[i] >>> shift); +}; + + +IPCheck.match = function(ip, cidr) { + ip = ip instanceof IPCheck ? ip : new IPCheck(ip); + return ip.match(cidr); +}; diff --git a/backend/src/utils/p-limit.ts b/backend/src/utils/p-limit.ts new file mode 100644 index 0000000000..20cead411a --- /dev/null +++ b/backend/src/utils/p-limit.ts @@ -0,0 +1,179 @@ +/* +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. +*/ + +/* +How it works: +`this._head` is an instance of `Node` which keeps track of its current value and nests +another instance of `Node` that keeps the value that comes after it. When a value is +provided to `.enqueue()`, the code needs to iterate through `this._head`, going deeper +and deeper to find the last value. However, iterating through every single item is slow. +This problem is solved by saving a reference to the last value as `this._tail` so that +it can reference it to add a new value. +*/ + +class Node { + value; + next; + + constructor(value) { + this.value = value; + } +} + +class Queue { + private _head; + private _tail; + private _size; + + constructor() { + this.clear(); + } + + enqueue(value) { + const node = new Node(value); + + if (this._head) { + this._tail.next = node; + this._tail = node; + } else { + this._head = node; + this._tail = node; + } + + this._size++; + } + + dequeue() { + const current = this._head; + if (!current) { + return; + } + + this._head = this._head.next; + this._size--; + return current.value; + } + + clear() { + this._head = undefined; + this._tail = undefined; + this._size = 0; + } + + get size() { + return this._size; + } + + *[Symbol.iterator]() { + let current = this._head; + + while (current) { + yield current.value; + current = current.next; + } + } +} + +interface LimitFunction { + readonly activeCount: number; + readonly pendingCount: number; + clearQueue: () => void; + ( + fn: (...args: Arguments) => PromiseLike | ReturnType, + ...args: Arguments + ): Promise; +} + +export default function pLimit(concurrency: number): LimitFunction { + if ( + !( + (Number.isInteger(concurrency) || + concurrency === Number.POSITIVE_INFINITY) && + concurrency > 0 + ) + ) { + throw new TypeError('Expected `concurrency` to be a number from 1 and up'); + } + + const queue = new Queue(); + let activeCount = 0; + + const next = () => { + activeCount--; + + if (queue.size > 0) { + queue.dequeue()(); + } + }; + + const run = async (fn, resolve, args) => { + activeCount++; + + const result = (async () => fn(...args))(); + + resolve(result); + + try { + await result; + } catch {} + + next(); + }; + + const enqueue = (fn, resolve, args) => { + queue.enqueue(run.bind(undefined, fn, resolve, args)); + + (async () => { + // This function needs to wait until the next microtask before comparing + // `activeCount` to `concurrency`, because `activeCount` is updated asynchronously + // when the run function is dequeued and called. The comparison in the if-statement + // needs to happen asynchronously as well to get an up-to-date value for `activeCount`. + await Promise.resolve(); + + if (activeCount < concurrency && queue.size > 0) { + queue.dequeue()(); + } + })(); + }; + + const generator = (fn, ...args) => + new Promise((resolve) => { + enqueue(fn, resolve, args); + }); + + Object.defineProperties(generator, { + activeCount: { + get: () => activeCount, + }, + pendingCount: { + get: () => queue.size, + }, + clearQueue: { + value: () => { + queue.clear(); + }, + }, + }); + + return generator as any; +} diff --git a/backend/src/utils/pairing-heap.ts b/backend/src/utils/pairing-heap.ts new file mode 100644 index 0000000000..876e056c44 --- /dev/null +++ b/backend/src/utils/pairing-heap.ts @@ -0,0 +1,174 @@ +export type HeapNode = { + element: T + child?: HeapNode + next?: HeapNode + prev?: HeapNode +} | null | undefined; + +// minimal pairing heap priority queue implementation +export class PairingHeap { + private root: HeapNode = null; + private comparator: (a: T, b: T) => boolean; + + // comparator function should return 'true' if a is higher priority than b + constructor(comparator: (a: T, b: T) => boolean) { + this.comparator = comparator; + } + + isEmpty(): boolean { + return !this.root; + } + + add(element: T): HeapNode { + const node: HeapNode = { + element + }; + + this.root = this.meld(this.root, node); + + return node; + } + + // returns the top priority element without modifying the queue + peek(): T | void { + return this.root?.element; + } + + // removes and returns the top priority element + pop(): T | void { + let element; + if (this.root) { + const node = this.root; + element = node.element; + this.root = this.mergePairs(node.child); + } + return element; + } + + deleteNode(node: HeapNode): void { + if (!node) { + return; + } + + if (node === this.root) { + this.root = this.mergePairs(node.child); + } + else { + if (node.prev) { + if (node.prev.child === node) { + node.prev.child = node.next; + } + else { + node.prev.next = node.next; + } + } + if (node.next) { + node.next.prev = node.prev; + } + this.root = this.meld(this.root, this.mergePairs(node.child)); + } + + node.child = null; + node.prev = null; + node.next = null; + } + + // fix the heap after increasing the priority of a given node + increasePriority(node: HeapNode): void { + // already the top priority element + if (!node || node === this.root) { + return; + } + // extract from siblings + if (node.prev) { + if (node.prev?.child === node) { + if (this.comparator(node.prev.element, node.element)) { + // already in a valid position + return; + } + node.prev.child = node.next; + } + else { + node.prev.next = node.next; + } + } + if (node.next) { + node.next.prev = node.prev; + } + + this.root = this.meld(this.root, node); + } + + decreasePriority(node: HeapNode): void { + this.deleteNode(node); + this.root = this.meld(this.root, node); + } + + meld(a: HeapNode, b: HeapNode): HeapNode { + if (!a) { + return b; + } + if (!b || a === b) { + return a; + } + + let parent: HeapNode = b; + let child: HeapNode = a; + if (this.comparator(a.element, b.element)) { + parent = a; + child = b; + } + + child.next = parent.child; + if (parent.child) { + parent.child.prev = child; + } + child.prev = parent; + parent.child = child; + + parent.next = null; + parent.prev = null; + + return parent; + } + + mergePairs(node: HeapNode): HeapNode { + if (!node) { + return null; + } + + let current: HeapNode = node; + let next: HeapNode; + let nextCurrent: HeapNode; + let pairs: HeapNode; + let melded: HeapNode; + while (current) { + next = current.next; + if (next) { + nextCurrent = next.next; + melded = this.meld(current, next); + if (melded) { + melded.prev = pairs; + } + pairs = melded; + } + else { + nextCurrent = null; + current.prev = pairs; + pairs = current; + break; + } + current = nextCurrent; + } + + melded = null; + let prev: HeapNode; + while (pairs) { + prev = pairs.prev; + melded = this.meld(melded, pairs); + pairs = prev; + } + + return melded; + } +} \ No newline at end of file diff --git a/backend/src/utils/secp256k1.ts b/backend/src/utils/secp256k1.ts new file mode 100644 index 0000000000..9e0f6dc3ba --- /dev/null +++ b/backend/src/utils/secp256k1.ts @@ -0,0 +1,77 @@ +function powMod(x: bigint, power: number, modulo: bigint): bigint { + for (let i = 0; i < power; i++) { + x = (x * x) % modulo; + } + return x; +} + +function sqrtMod(x: bigint, P: bigint): bigint { + const b2 = (x * x * x) % P; + const b3 = (b2 * b2 * x) % P; + const b6 = (powMod(b3, 3, P) * b3) % P; + const b9 = (powMod(b6, 3, P) * b3) % P; + const b11 = (powMod(b9, 2, P) * b2) % P; + const b22 = (powMod(b11, 11, P) * b11) % P; + const b44 = (powMod(b22, 22, P) * b22) % P; + const b88 = (powMod(b44, 44, P) * b44) % P; + const b176 = (powMod(b88, 88, P) * b88) % P; + const b220 = (powMod(b176, 44, P) * b44) % P; + const b223 = (powMod(b220, 3, P) * b3) % P; + const t1 = (powMod(b223, 23, P) * b22) % P; + const t2 = (powMod(t1, 6, P) * b2) % P; + const root = powMod(t2, 2, P); + return root; +} + +const curveP = BigInt(`0xFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFEFFFFFC2F`); + +/** + * This function tells whether the point given is a DER encoded point on the ECDSA curve. + * @param {string} pointHex The point as a hex string (*must not* include a '0x' prefix) + * @returns {boolean} true if the point is on the SECP256K1 curve + */ +export function isPoint(pointHex: string): boolean { + if (!pointHex?.length) { + return false; + } + if ( + !( + // is uncompressed + ( + (pointHex.length === 130 && pointHex.startsWith('04')) || + // OR is compressed + (pointHex.length === 66 && + (pointHex.startsWith('02') || pointHex.startsWith('03'))) + ) + ) + ) { + return false; + } + + // Function modified slightly from noble-curves + + + // Now we know that pointHex is a 33 or 65 byte hex string. + const isCompressed = pointHex.length === 66; + + const x = BigInt(`0x${pointHex.slice(2, 66)}`); + if (x >= curveP) { + return false; + } + + if (!isCompressed) { + const y = BigInt(`0x${pointHex.slice(66, 130)}`); + if (y >= curveP) { + return false; + } + // Just check y^2 = x^3 + 7 (secp256k1 curve) + return (y * y) % curveP === (x * x * x + 7n) % curveP; + } else { + // Get unaltered y^2 (no mod p) + const ySquared = (x * x * x + 7n) % curveP; + // Try to sqrt it, it will round down if not perfect root + const y = sqrtMod(ySquared, curveP); + // If we square and it's equal, then it was a perfect root and valid point. + return (y * y) % curveP === ySquared; + } +} \ No newline at end of file diff --git a/backend/testSetup.ts b/backend/testSetup.ts new file mode 100644 index 0000000000..ca51bbbe60 --- /dev/null +++ b/backend/testSetup.ts @@ -0,0 +1,5 @@ +jest.mock('./mempool-config.json', () => ({}), { virtual: true }); +jest.mock('./src/logger.ts', () => ({}), { virtual: true }); +jest.mock('./src/api/rbf-cache.ts', () => ({}), { virtual: true }); +jest.mock('./src/api/mempool.ts', () => ({}), { virtual: true }); +jest.mock('./src/api/memory-cache.ts', () => ({}), { virtual: true }); diff --git a/backend/tsconfig.build.json b/backend/tsconfig.build.json new file mode 100644 index 0000000000..e3d61b71c5 --- /dev/null +++ b/backend/tsconfig.build.json @@ -0,0 +1,8 @@ +{ + "extends": "./tsconfig", + "exclude": ["**/*.test.*", "**/__mocks__/*", "**/__tests__/*"], + "compilerOptions": { + "types": ["node"] + }, + +} diff --git a/backend/tsconfig.json b/backend/tsconfig.json index 9b3cb6248a..bfab64081a 100644 --- a/backend/tsconfig.json +++ b/backend/tsconfig.json @@ -1,15 +1,21 @@ { "compilerOptions": { "module": "commonjs", - "target": "es2015", + "target": "esnext", + "types": ["node", "jest"], + "lib": ["es2019", "dom"], "strict": true, + "skipLibCheck": true, "noImplicitAny": false, "sourceMap": false, "outDir": "dist", "moduleResolution": "node", "typeRoots": [ "node_modules/@types" - ] + ], + "allowSyntheticDefaultImports": true, + "esModuleInterop": true, + "allowJs": true, }, "include": [ "src/**/*.ts" @@ -17,4 +23,4 @@ "exclude": [ "dist/**" ] -} \ No newline at end of file +} diff --git a/backend/tslint.json b/backend/tslint.json deleted file mode 100644 index 65ac58f4bb..0000000000 --- a/backend/tslint.json +++ /dev/null @@ -1,137 +0,0 @@ -{ - "rules": { - "arrow-return-shorthand": true, - "callable-types": true, - "class-name": true, - "comment-format": [ - true, - "check-space" - ], - "curly": true, - "deprecation": { - "severity": "warn" - }, - "eofline": true, - "forin": true, - "import-blacklist": [ - true, - "rxjs", - "rxjs/Rx" - ], - "import-spacing": true, - "indent": [ - true, - "spaces" - ], - "interface-over-type-literal": true, - "label-position": true, - "max-line-length": [ - true, - 140 - ], - "member-access": false, - "member-ordering": [ - true, - { - "order": [ - "static-field", - "instance-field", - "static-method", - "instance-method" - ] - } - ], - "no-arg": true, - "no-bitwise": true, - "no-console": [ - true, - "debug", - "info", - "time", - "timeEnd", - "trace" - ], - "no-construct": true, - "no-debugger": true, - "no-duplicate-super": true, - "no-empty": false, - "no-empty-interface": true, - "no-eval": true, - "no-inferrable-types": false, - "no-misused-new": true, - "no-non-null-assertion": true, - "no-shadowed-variable": true, - "no-string-literal": false, - "no-string-throw": true, - "no-switch-case-fall-through": true, - "no-trailing-whitespace": true, - "no-unnecessary-initializer": true, - "no-unused-expression": true, - "no-use-before-declare": true, - "no-var-keyword": true, - "object-literal-sort-keys": false, - "one-line": [ - true, - "check-open-brace", - "check-catch", - "check-else", - "check-whitespace" - ], - "prefer-const": true, - "quotemark": [ - true, - "single" - ], - "radix": true, - "semicolon": [ - true, - "always" - ], - "triple-equals": [ - true, - "allow-null-check" - ], - "typedef-whitespace": [ - true, - { - "call-signature": "nospace", - "index-signature": "nospace", - "parameter": "nospace", - "property-declaration": "nospace", - "variable-declaration": "nospace" - } - ], - "unified-signatures": true, - "variable-name": false, - "whitespace": [ - true, - "check-branch", - "check-decl", - "check-operator", - "check-separator", - "check-type" - ], - "directive-selector": [ - true, - "attribute", - "app", - "camelCase" - ], - "component-selector": [ - true, - "element", - "app", - "kebab-case" - ], - "no-output-on-prefix": true, - "use-input-property-decorator": true, - "use-output-property-decorator": true, - "use-host-property-decorator": true, - "no-input-rename": true, - "no-output-rename": true, - "use-life-cycle-interface": true, - "use-pipe-transform-interface": true, - "component-class-suffix": true, - "directive-class-suffix": true - } -} diff --git a/backend/yarn.lock b/backend/yarn.lock deleted file mode 100644 index ce75ffd749..0000000000 --- a/backend/yarn.lock +++ /dev/null @@ -1,1135 +0,0 @@ -# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY. -# yarn lockfile v1 - - -"@babel/code-frame@^7.0.0": - version "7.5.5" - resolved "https://registry.yarnpkg.com/@babel/code-frame/-/code-frame-7.5.5.tgz#bc0782f6d69f7b7d49531219699b988f669a8f9d" - integrity sha512-27d4lZoomVyo51VegxI20xZPuSHusqbQag/ztrBC7wegWoQ1nLREPVSKSW8byhTlzTKyNE4ifaTA6lCp7JjpFw== - dependencies: - "@babel/highlight" "^7.0.0" - -"@babel/highlight@^7.0.0": - version "7.5.0" - resolved "https://registry.yarnpkg.com/@babel/highlight/-/highlight-7.5.0.tgz#56d11312bd9248fa619591d02472be6e8cb32540" - integrity sha512-7dV4eu9gBxoM0dAnj/BCFDW9LFU0zvTrkq0ugM7pnHEgguOEeOz1so2ZghEdzviYzQEED0r4EAgpsBChKy1TRQ== - dependencies: - chalk "^2.0.0" - esutils "^2.0.2" - js-tokens "^4.0.0" - -"@types/body-parser@*": - version "1.17.1" - resolved "https://registry.yarnpkg.com/@types/body-parser/-/body-parser-1.17.1.tgz#18fcf61768fb5c30ccc508c21d6fd2e8b3bf7897" - integrity sha512-RoX2EZjMiFMjZh9lmYrwgoP9RTpAjSHiJxdp4oidAQVO02T7HER3xj9UKue5534ULWeqVEkujhWcyvUce+d68w== - dependencies: - "@types/connect" "*" - "@types/node" "*" - -"@types/caseless@*": - version "0.12.2" - resolved "https://registry.yarnpkg.com/@types/caseless/-/caseless-0.12.2.tgz#f65d3d6389e01eeb458bd54dc8f52b95a9463bc8" - integrity sha512-6ckxMjBBD8URvjB6J3NcnuAn5Pkl7t3TizAg+xdlzzQGSPSmBcXf8KoIH0ua/i+tio+ZRUHEXp0HEmvaR4kt0w== - -"@types/compression@^1.0.1": - version "1.0.1" - resolved "https://registry.yarnpkg.com/@types/compression/-/compression-1.0.1.tgz#f3682a6b3ce2dbd4aece48547153ebc592281fa7" - integrity sha512-GuoIYzD70h+4JUqUabsm31FGqvpCYHGKcLtor7nQ/YvUyNX0o9SJZ9boFI5HjFfbOda5Oe/XOvNK6FES8Y/79w== - dependencies: - "@types/express" "*" - -"@types/connect@*": - version "3.4.32" - resolved "https://registry.yarnpkg.com/@types/connect/-/connect-3.4.32.tgz#aa0e9616b9435ccad02bc52b5b454ffc2c70ba28" - integrity sha512-4r8qa0quOvh7lGD0pre62CAb1oni1OO6ecJLGCezTmhQ8Fz50Arx9RUszryR8KlgK6avuSXvviL6yWyViQABOg== - dependencies: - "@types/node" "*" - -"@types/express-serve-static-core@*": - version "4.17.0" - resolved "https://registry.yarnpkg.com/@types/express-serve-static-core/-/express-serve-static-core-4.17.0.tgz#e80c25903df5800e926402b7e8267a675c54a281" - integrity sha512-Xnub7w57uvcBqFdIGoRg1KhNOeEj0vB6ykUM7uFWyxvbdE89GFyqgmUcanAriMr4YOxNFZBAWkfcWIb4WBPt3g== - dependencies: - "@types/node" "*" - "@types/range-parser" "*" - -"@types/express@*", "@types/express@^4.17.2": - version "4.17.2" - resolved "https://registry.yarnpkg.com/@types/express/-/express-4.17.2.tgz#a0fb7a23d8855bac31bc01d5a58cadd9b2173e6c" - integrity sha512-5mHFNyavtLoJmnusB8OKJ5bshSzw+qkMIBAobLrIM48HJvunFva9mOa6aBwh64lBFyNwBbs0xiEFuj4eU/NjCA== - dependencies: - "@types/body-parser" "*" - "@types/express-serve-static-core" "*" - "@types/serve-static" "*" - -"@types/mime@*": - version "2.0.1" - resolved "https://registry.yarnpkg.com/@types/mime/-/mime-2.0.1.tgz#dc488842312a7f075149312905b5e3c0b054c79d" - integrity sha512-FwI9gX75FgVBJ7ywgnq/P7tw+/o1GUbtP0KzbtusLigAOgIgNISRK0ZPl4qertvXSIE8YbsVJueQ90cDt9YYyw== - -"@types/node@*": - version "12.12.17" - resolved "https://registry.yarnpkg.com/@types/node/-/node-12.12.17.tgz#191b71e7f4c325ee0fb23bc4a996477d92b8c39b" - integrity sha512-Is+l3mcHvs47sKy+afn2O1rV4ldZFU7W8101cNlOd+MRbjM4Onida8jSZnJdTe/0Pcf25g9BNIUsuugmE6puHA== - -"@types/range-parser@*": - version "1.2.3" - resolved "https://registry.yarnpkg.com/@types/range-parser/-/range-parser-1.2.3.tgz#7ee330ba7caafb98090bece86a5ee44115904c2c" - integrity sha512-ewFXqrQHlFsgc09MK5jP5iR7vumV/BYayNC6PgJO2LPe8vrnNFyjQjSppfEngITi0qvfKtzFvgKymGheFM9UOA== - -"@types/request@^2.48.2": - version "2.48.3" - resolved "https://registry.yarnpkg.com/@types/request/-/request-2.48.3.tgz#970b8ed2317568c390361d29c555a95e74bd6135" - integrity sha512-3Wo2jNYwqgXcIz/rrq18AdOZUQB8cQ34CXZo+LUwPJNpvRAL86+Kc2wwI8mqpz9Cr1V+enIox5v+WZhy/p3h8w== - dependencies: - "@types/caseless" "*" - "@types/node" "*" - "@types/tough-cookie" "*" - form-data "^2.5.0" - -"@types/serve-static@*": - version "1.13.3" - resolved "https://registry.yarnpkg.com/@types/serve-static/-/serve-static-1.13.3.tgz#eb7e1c41c4468272557e897e9171ded5e2ded9d1" - integrity sha512-oprSwp094zOglVrXdlo/4bAHtKTAxX6VT8FOZlBKrmyLbNvE1zxZyJ6yikMVtHIvwP45+ZQGJn+FdXGKTozq0g== - dependencies: - "@types/express-serve-static-core" "*" - "@types/mime" "*" - -"@types/tough-cookie@*": - version "2.3.6" - resolved "https://registry.yarnpkg.com/@types/tough-cookie/-/tough-cookie-2.3.6.tgz#c880579e087d7a0db13777ff8af689f4ffc7b0d5" - integrity sha512-wHNBMnkoEBiRAd3s8KTKwIuO9biFtTf0LehITzBhSco+HQI0xkXZbLOD55SW3Aqw3oUkHstkm5SPv58yaAdFPQ== - -"@types/ws@^6.0.4": - version "6.0.4" - resolved "https://registry.yarnpkg.com/@types/ws/-/ws-6.0.4.tgz#7797707c8acce8f76d8c34b370d4645b70421ff1" - integrity sha512-PpPrX7SZW9re6+Ha8ojZG4Se8AZXgf0GK6zmfqEuCsY49LFDNXO3SByp44X3dFEqtB73lkCDAdUazhAjVPiNwg== - dependencies: - "@types/node" "*" - -accepts@~1.3.5, accepts@~1.3.7: - version "1.3.7" - resolved "https://registry.yarnpkg.com/accepts/-/accepts-1.3.7.tgz#531bc726517a3b2b41f850021c6cc15eaab507cd" - integrity sha512-Il80Qs2WjYlJIBNzNkK6KYqlVMTbZLXgHx2oT0pU/fjRHyEp+PEfEPY0R3WCwAGVOtauxh1hOxNgIf5bv7dQpA== - dependencies: - mime-types "~2.1.24" - negotiator "0.6.2" - -ajv@^6.5.5: - version "6.10.2" - resolved "https://registry.yarnpkg.com/ajv/-/ajv-6.10.2.tgz#d3cea04d6b017b2894ad69040fec8b623eb4bd52" - integrity sha512-TXtUUEYHuaTEbLZWIKUr5pmBuhDLy+8KYtPYdcV8qC+pOZL+NKqYwvWSRrVXHn+ZmRRAu8vJTAznH7Oag6RVRw== - dependencies: - fast-deep-equal "^2.0.1" - fast-json-stable-stringify "^2.0.0" - json-schema-traverse "^0.4.1" - uri-js "^4.2.2" - -ansi-styles@^3.2.1: - version "3.2.1" - resolved "https://registry.yarnpkg.com/ansi-styles/-/ansi-styles-3.2.1.tgz#41fbb20243e50b12be0f04b8dedbf07520ce841d" - integrity sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA== - dependencies: - color-convert "^1.9.0" - -argparse@^1.0.7: - version "1.0.10" - resolved "https://registry.yarnpkg.com/argparse/-/argparse-1.0.10.tgz#bcd6791ea5ae09725e17e5ad988134cd40b3d911" - integrity sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg== - dependencies: - sprintf-js "~1.0.2" - -array-flatten@1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/array-flatten/-/array-flatten-1.1.1.tgz#9a5f699051b1e7073328f2a008968b64ea2955d2" - integrity sha1-ml9pkFGx5wczKPKgCJaLZOopVdI= - -asn1@~0.2.3: - version "0.2.4" - resolved "https://registry.yarnpkg.com/asn1/-/asn1-0.2.4.tgz#8d2475dfab553bb33e77b54e59e880bb8ce23136" - integrity sha512-jxwzQpLQjSmWXgwaCZE9Nz+glAG01yF1QnWgbhGwHI5A6FRIEY6IVqtHhIepHqI7/kyEyQEagBC5mBEFlIYvdg== - dependencies: - safer-buffer "~2.1.0" - -assert-plus@1.0.0, assert-plus@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/assert-plus/-/assert-plus-1.0.0.tgz#f12e0f3c5d77b0b1cdd9146942e4e96c1e4dd525" - integrity sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU= - -asynckit@^0.4.0: - version "0.4.0" - resolved "https://registry.yarnpkg.com/asynckit/-/asynckit-0.4.0.tgz#c79ed97f7f34cb8f2ba1bc9790bcc366474b4b79" - integrity sha1-x57Zf380y48robyXkLzDZkdLS3k= - -aws-sign2@~0.7.0: - version "0.7.0" - resolved "https://registry.yarnpkg.com/aws-sign2/-/aws-sign2-0.7.0.tgz#b46e890934a9591f2d2f6f86d7e6a9f1b3fe76a8" - integrity sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg= - -aws4@^1.8.0: - version "1.9.0" - resolved "https://registry.yarnpkg.com/aws4/-/aws4-1.9.0.tgz#24390e6ad61386b0a747265754d2a17219de862c" - integrity sha512-Uvq6hVe90D0B2WEnUqtdgY1bATGz3mw33nH9Y+dmA+w5DHvUmBgkr5rM/KCHpCsiFNRUfokW/szpPPgMK2hm4A== - -balanced-match@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.0.tgz#89b4d199ab2bee49de164ea02b89ce462d71b767" - integrity sha1-ibTRmasr7kneFk6gK4nORi1xt2c= - -bcrypt-pbkdf@^1.0.0: - version "1.0.2" - resolved "https://registry.yarnpkg.com/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz#a4301d389b6a43f9b67ff3ca11a3f6637e360e9e" - integrity sha1-pDAdOJtqQ/m2f/PKEaP2Y342Dp4= - dependencies: - tweetnacl "^0.14.3" - -body-parser@1.19.0: - version "1.19.0" - resolved "https://registry.yarnpkg.com/body-parser/-/body-parser-1.19.0.tgz#96b2709e57c9c4e09a6fd66a8fd979844f69f08a" - integrity sha512-dhEPs72UPbDnAQJ9ZKMNTP6ptJaionhP5cBb541nXPlW60Jepo9RV/a4fX4XWW9CuFNK22krhrj1+rgzifNCsw== - dependencies: - bytes "3.1.0" - content-type "~1.0.4" - debug "2.6.9" - depd "~1.1.2" - http-errors "1.7.2" - iconv-lite "0.4.24" - on-finished "~2.3.0" - qs "6.7.0" - raw-body "2.4.0" - type-is "~1.6.17" - -brace-expansion@^1.1.7: - version "1.1.11" - resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-1.1.11.tgz#3c7fcbf529d87226f3d2f52b966ff5271eb441dd" - integrity sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA== - dependencies: - balanced-match "^1.0.0" - concat-map "0.0.1" - -builtin-modules@^1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/builtin-modules/-/builtin-modules-1.1.1.tgz#270f076c5a72c02f5b65a47df94c5fe3a278892f" - integrity sha1-Jw8HbFpywC9bZaR9+Uxf46J4iS8= - -bytes@3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.0.0.tgz#d32815404d689699f85a4ea4fa8755dd13a96048" - integrity sha1-0ygVQE1olpn4Wk6k+odV3ROpYEg= - -bytes@3.1.0: - version "3.1.0" - resolved "https://registry.yarnpkg.com/bytes/-/bytes-3.1.0.tgz#f6cf7933a360e0588fa9fde85651cdc7f805d1f6" - integrity sha512-zauLjrfCG+xvoyaqLoV8bLVXXNGC4JqlxFCutSDWA6fJrTo2ZuvLYTqZ7aHBLZSMOopbzwv8f+wZcVzfVTI2Dg== - -caseless@~0.12.0: - version "0.12.0" - resolved "https://registry.yarnpkg.com/caseless/-/caseless-0.12.0.tgz#1b681c21ff84033c826543090689420d187151dc" - integrity sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw= - -chalk@^2.0.0, chalk@^2.3.0: - version "2.4.2" - resolved "https://registry.yarnpkg.com/chalk/-/chalk-2.4.2.tgz#cd42541677a54333cf541a49108c1432b44c9424" - integrity sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ== - dependencies: - ansi-styles "^3.2.1" - escape-string-regexp "^1.0.5" - supports-color "^5.3.0" - -color-convert@^1.9.0: - version "1.9.3" - resolved "https://registry.yarnpkg.com/color-convert/-/color-convert-1.9.3.tgz#bb71850690e1f136567de629d2d5471deda4c1e8" - integrity sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg== - dependencies: - color-name "1.1.3" - -color-name@1.1.3: - version "1.1.3" - resolved "https://registry.yarnpkg.com/color-name/-/color-name-1.1.3.tgz#a7d0558bd89c42f795dd42328f740831ca53bc25" - integrity sha1-p9BVi9icQveV3UIyj3QIMcpTvCU= - -combined-stream@^1.0.6, combined-stream@~1.0.6: - version "1.0.8" - resolved "https://registry.yarnpkg.com/combined-stream/-/combined-stream-1.0.8.tgz#c3d45a8b34fd730631a110a8a2520682b31d5a7f" - integrity sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg== - dependencies: - delayed-stream "~1.0.0" - -commander@^2.12.1: - version "2.20.3" - resolved "https://registry.yarnpkg.com/commander/-/commander-2.20.3.tgz#fd485e84c03eb4881c20722ba48035e8531aeb33" - integrity sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ== - -compressible@~2.0.16: - version "2.0.17" - resolved "https://registry.yarnpkg.com/compressible/-/compressible-2.0.17.tgz#6e8c108a16ad58384a977f3a482ca20bff2f38c1" - integrity sha512-BGHeLCK1GV7j1bSmQQAi26X+GgWcTjLr/0tzSvMCl3LH1w1IJ4PFSPoV5316b30cneTziC+B1a+3OjoSUcQYmw== - dependencies: - mime-db ">= 1.40.0 < 2" - -compression@^1.7.4: - version "1.7.4" - resolved "https://registry.yarnpkg.com/compression/-/compression-1.7.4.tgz#95523eff170ca57c29a0ca41e6fe131f41e5bb8f" - integrity sha512-jaSIDzP9pZVS4ZfQ+TzvtiWhdpFhE2RDHz8QJkpX9SIpLq88VueF5jJw6t+6CUQcAoA6t+x89MLrWAqpfDE8iQ== - dependencies: - accepts "~1.3.5" - bytes "3.0.0" - compressible "~2.0.16" - debug "2.6.9" - on-headers "~1.0.2" - safe-buffer "5.1.2" - vary "~1.1.2" - -concat-map@0.0.1: - version "0.0.1" - resolved "https://registry.yarnpkg.com/concat-map/-/concat-map-0.0.1.tgz#d8a96bd77fd68df7793a73036a3ba0d5405d477b" - integrity sha1-2Klr13/Wjfd5OnMDajug1UBdR3s= - -content-disposition@0.5.3: - version "0.5.3" - resolved "https://registry.yarnpkg.com/content-disposition/-/content-disposition-0.5.3.tgz#e130caf7e7279087c5616c2007d0485698984fbd" - integrity sha512-ExO0774ikEObIAEV9kDo50o+79VCUdEB6n6lzKgGwupcVeRlhrj3qGAfwq8G6uBJjkqLrhT0qEYFcWng8z1z0g== - dependencies: - safe-buffer "5.1.2" - -content-type@~1.0.4: - version "1.0.4" - resolved "https://registry.yarnpkg.com/content-type/-/content-type-1.0.4.tgz#e138cc75e040c727b1966fe5e5f8c9aee256fe3b" - integrity sha512-hIP3EEPs8tB9AT1L+NUqtwOAps4mk2Zob89MWXMHjHWg9milF/j4osnnQLXBCBFBk/tvIG/tUc9mOUJiPBhPXA== - -cookie-signature@1.0.6: - version "1.0.6" - resolved "https://registry.yarnpkg.com/cookie-signature/-/cookie-signature-1.0.6.tgz#e303a882b342cc3ee8ca513a79999734dab3ae2c" - integrity sha1-4wOogrNCzD7oylE6eZmXNNqzriw= - -cookie@0.4.0: - version "0.4.0" - resolved "https://registry.yarnpkg.com/cookie/-/cookie-0.4.0.tgz#beb437e7022b3b6d49019d088665303ebe9c14ba" - integrity sha512-+Hp8fLp57wnUSt0tY0tHEXh4voZRDnoIrZPqlo3DPiI4y9lwg/jqx+1Om94/W6ZaPDOUbnjOt/99w66zk+l1Xg== - -core-util-is@1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/core-util-is/-/core-util-is-1.0.2.tgz#b5fd54220aa2bc5ab57aab7140c940754503c1a7" - integrity sha1-tf1UIgqivFq1eqtxQMlAdUUDwac= - -dashdash@^1.12.0: - version "1.14.1" - resolved "https://registry.yarnpkg.com/dashdash/-/dashdash-1.14.1.tgz#853cfa0f7cbe2fed5de20326b8dd581035f6e2f0" - integrity sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA= - dependencies: - assert-plus "^1.0.0" - -debug@2.6.9: - version "2.6.9" - resolved "https://registry.yarnpkg.com/debug/-/debug-2.6.9.tgz#5d128515df134ff327e90a4c93f4e077a536341f" - integrity sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA== - dependencies: - ms "2.0.0" - -delayed-stream@~1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/delayed-stream/-/delayed-stream-1.0.0.tgz#df3ae199acadfb7d440aaae0b29e2272b24ec619" - integrity sha1-3zrhmayt+31ECqrgsp4icrJOxhk= - -denque@^1.4.1: - version "1.4.1" - resolved "https://registry.yarnpkg.com/denque/-/denque-1.4.1.tgz#6744ff7641c148c3f8a69c307e51235c1f4a37cf" - integrity sha512-OfzPuSZKGcgr96rf1oODnfjqBFmr1DVoc/TrItj3Ohe0Ah1C5WX5Baquw/9U9KovnQ88EqmJbD66rKYUQYN1tQ== - -depd@~1.1.2: - version "1.1.2" - resolved "https://registry.yarnpkg.com/depd/-/depd-1.1.2.tgz#9bcd52e14c097763e749b274c4346ed2e560b5a9" - integrity sha1-m81S4UwJd2PnSbJ0xDRu0uVgtak= - -destroy@~1.0.4: - version "1.0.4" - resolved "https://registry.yarnpkg.com/destroy/-/destroy-1.0.4.tgz#978857442c44749e4206613e37946205826abd80" - integrity sha1-l4hXRCxEdJ5CBmE+N5RiBYJqvYA= - -diff@^4.0.1: - version "4.0.1" - resolved "https://registry.yarnpkg.com/diff/-/diff-4.0.1.tgz#0c667cb467ebbb5cea7f14f135cc2dba7780a8ff" - integrity sha512-s2+XdvhPCOF01LRQBC8hf4vhbVmI2CGS5aZnxLJlT5FtdhPCDFq80q++zK2KlrVorVDdL5BOGZ/VfLrVtYNF+Q== - -ecc-jsbn@~0.1.1: - version "0.1.2" - resolved "https://registry.yarnpkg.com/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz#3a83a904e54353287874c564b7549386849a98c9" - integrity sha1-OoOpBOVDUyh4dMVkt1SThoSamMk= - dependencies: - jsbn "~0.1.0" - safer-buffer "^2.1.0" - -ee-first@1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/ee-first/-/ee-first-1.1.1.tgz#590c61156b0ae2f4f0255732a158b266bc56b21d" - integrity sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0= - -encodeurl@~1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/encodeurl/-/encodeurl-1.0.2.tgz#ad3ff4c86ec2d029322f5a02c3a9a606c95b3f59" - integrity sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k= - -escape-html@~1.0.3: - version "1.0.3" - resolved "https://registry.yarnpkg.com/escape-html/-/escape-html-1.0.3.tgz#0258eae4d3d0c0974de1c169188ef0051d1d1988" - integrity sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg= - -escape-string-regexp@^1.0.5: - version "1.0.5" - resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz#1b61c0562190a8dff6ae3bb2cf0200ca130b86d4" - integrity sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ= - -esprima@^4.0.0: - version "4.0.1" - resolved "https://registry.yarnpkg.com/esprima/-/esprima-4.0.1.tgz#13b04cdb3e6c5d19df91ab6987a8695619b0aa71" - integrity sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A== - -esutils@^2.0.2: - version "2.0.3" - resolved "https://registry.yarnpkg.com/esutils/-/esutils-2.0.3.tgz#74d2eb4de0b8da1293711910d50775b9b710ef64" - integrity sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g== - -etag@~1.8.1: - version "1.8.1" - resolved "https://registry.yarnpkg.com/etag/-/etag-1.8.1.tgz#41ae2eeb65efa62268aebfea83ac7d79299b0887" - integrity sha1-Qa4u62XvpiJorr/qg6x9eSmbCIc= - -express@^4.17.1: - version "4.17.1" - resolved "https://registry.yarnpkg.com/express/-/express-4.17.1.tgz#4491fc38605cf51f8629d39c2b5d026f98a4c134" - integrity sha512-mHJ9O79RqluphRrcw2X/GTh3k9tVv8YcoyY4Kkh4WDMUYKRZUq0h1o0w2rrrxBqM7VoeUVqgb27xlEMXTnYt4g== - dependencies: - accepts "~1.3.7" - array-flatten "1.1.1" - body-parser "1.19.0" - content-disposition "0.5.3" - content-type "~1.0.4" - cookie "0.4.0" - cookie-signature "1.0.6" - debug "2.6.9" - depd "~1.1.2" - encodeurl "~1.0.2" - escape-html "~1.0.3" - etag "~1.8.1" - finalhandler "~1.1.2" - fresh "0.5.2" - merge-descriptors "1.0.1" - methods "~1.1.2" - on-finished "~2.3.0" - parseurl "~1.3.3" - path-to-regexp "0.1.7" - proxy-addr "~2.0.5" - qs "6.7.0" - range-parser "~1.2.1" - safe-buffer "5.1.2" - send "0.17.1" - serve-static "1.14.1" - setprototypeof "1.1.1" - statuses "~1.5.0" - type-is "~1.6.18" - utils-merge "1.0.1" - vary "~1.1.2" - -extend@~3.0.2: - version "3.0.2" - resolved "https://registry.yarnpkg.com/extend/-/extend-3.0.2.tgz#f8b1136b4071fbd8eb140aff858b1019ec2915fa" - integrity sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g== - -extsprintf@1.3.0: - version "1.3.0" - resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.3.0.tgz#96918440e3041a7a414f8c52e3c574eb3c3e1e05" - integrity sha1-lpGEQOMEGnpBT4xS48V06zw+HgU= - -extsprintf@^1.2.0: - version "1.4.0" - resolved "https://registry.yarnpkg.com/extsprintf/-/extsprintf-1.4.0.tgz#e2689f8f356fad62cca65a3a91c5df5f9551692f" - integrity sha1-4mifjzVvrWLMplo6kcXfX5VRaS8= - -fast-deep-equal@^2.0.1: - version "2.0.1" - resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-2.0.1.tgz#7b05218ddf9667bf7f370bf7fdb2cb15fdd0aa49" - integrity sha1-ewUhjd+WZ79/Nwv3/bLLFf3Qqkk= - -fast-json-stable-stringify@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz#d5142c0caee6b1189f87d3a76111064f86c8bbf2" - integrity sha1-1RQsDK7msRifh9OnYREGT4bIu/I= - -finalhandler@~1.1.2: - version "1.1.2" - resolved "https://registry.yarnpkg.com/finalhandler/-/finalhandler-1.1.2.tgz#b7e7d000ffd11938d0fdb053506f6ebabe9f587d" - integrity sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA== - dependencies: - debug "2.6.9" - encodeurl "~1.0.2" - escape-html "~1.0.3" - on-finished "~2.3.0" - parseurl "~1.3.3" - statuses "~1.5.0" - unpipe "~1.0.0" - -forever-agent@~0.6.1: - version "0.6.1" - resolved "https://registry.yarnpkg.com/forever-agent/-/forever-agent-0.6.1.tgz#fbc71f0c41adeb37f96c577ad1ed42d8fdacca91" - integrity sha1-+8cfDEGt6zf5bFd60e1C2P2sypE= - -form-data@^2.5.0: - version "2.5.1" - resolved "https://registry.yarnpkg.com/form-data/-/form-data-2.5.1.tgz#f2cbec57b5e59e23716e128fe44d4e5dd23895f4" - integrity sha512-m21N3WOmEEURgk6B9GLOE4RuWOFf28Lhh9qGYeNlGq4VDXUlJy2th2slBNU8Gp8EzloYZOibZJ7t5ecIrFSjVA== - dependencies: - asynckit "^0.4.0" - combined-stream "^1.0.6" - mime-types "^2.1.12" - -form-data@~2.3.2: - version "2.3.3" - resolved "https://registry.yarnpkg.com/form-data/-/form-data-2.3.3.tgz#dcce52c05f644f298c6a7ab936bd724ceffbf3a6" - integrity sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ== - dependencies: - asynckit "^0.4.0" - combined-stream "^1.0.6" - mime-types "^2.1.12" - -forwarded@~0.1.2: - version "0.1.2" - resolved "https://registry.yarnpkg.com/forwarded/-/forwarded-0.1.2.tgz#98c23dab1175657b8c0573e8ceccd91b0ff18c84" - integrity sha1-mMI9qxF1ZXuMBXPozszZGw/xjIQ= - -fresh@0.5.2: - version "0.5.2" - resolved "https://registry.yarnpkg.com/fresh/-/fresh-0.5.2.tgz#3d8cadd90d976569fa835ab1f8e4b23a105605a7" - integrity sha1-PYyt2Q2XZWn6g1qx+OSyOhBWBac= - -fs.realpath@^1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/fs.realpath/-/fs.realpath-1.0.0.tgz#1504ad2523158caa40db4a2787cb01411994ea4f" - integrity sha1-FQStJSMVjKpA20onh8sBQRmU6k8= - -generate-function@^2.3.1: - version "2.3.1" - resolved "https://registry.yarnpkg.com/generate-function/-/generate-function-2.3.1.tgz#f069617690c10c868e73b8465746764f97c3479f" - integrity sha512-eeB5GfMNeevm/GRYq20ShmsaGcmI81kIX2K9XQx5miC8KdHaC6Jm0qQ8ZNeGOi7wYB8OsdxKs+Y2oVuTFuVwKQ== - dependencies: - is-property "^1.0.2" - -getpass@^0.1.1: - version "0.1.7" - resolved "https://registry.yarnpkg.com/getpass/-/getpass-0.1.7.tgz#5eff8e3e684d569ae4cb2b1282604e8ba62149fa" - integrity sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo= - dependencies: - assert-plus "^1.0.0" - -glob@^7.1.1: - version "7.1.6" - resolved "https://registry.yarnpkg.com/glob/-/glob-7.1.6.tgz#141f33b81a7c2492e125594307480c46679278a6" - integrity sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA== - dependencies: - fs.realpath "^1.0.0" - inflight "^1.0.4" - inherits "2" - minimatch "^3.0.4" - once "^1.3.0" - path-is-absolute "^1.0.0" - -har-schema@^2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/har-schema/-/har-schema-2.0.0.tgz#a94c2224ebcac04782a0d9035521f24735b7ec92" - integrity sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI= - -har-validator@~5.1.3: - version "5.1.3" - resolved "https://registry.yarnpkg.com/har-validator/-/har-validator-5.1.3.tgz#1ef89ebd3e4996557675eed9893110dc350fa080" - integrity sha512-sNvOCzEQNr/qrvJgc3UG/kD4QtlHycrzwS+6mfTrrSq97BvaYcPZZI1ZSqGSPR73Cxn4LKTD4PttRwfU7jWq5g== - dependencies: - ajv "^6.5.5" - har-schema "^2.0.0" - -has-flag@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/has-flag/-/has-flag-3.0.0.tgz#b5d454dc2199ae225699f3467e5a07f3b955bafd" - integrity sha1-tdRU3CGZriJWmfNGfloH87lVuv0= - -http-errors@1.7.2: - version "1.7.2" - resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-1.7.2.tgz#4f5029cf13239f31036e5b2e55292bcfbcc85c8f" - integrity sha512-uUQBt3H/cSIVfch6i1EuPNy/YsRSOUBXTVfZ+yR7Zjez3qjBz6i9+i4zjNaoqcoFVI4lQJ5plg63TvGfRSDCRg== - dependencies: - depd "~1.1.2" - inherits "2.0.3" - setprototypeof "1.1.1" - statuses ">= 1.5.0 < 2" - toidentifier "1.0.0" - -http-errors@~1.7.2: - version "1.7.3" - resolved "https://registry.yarnpkg.com/http-errors/-/http-errors-1.7.3.tgz#6c619e4f9c60308c38519498c14fbb10aacebb06" - integrity sha512-ZTTX0MWrsQ2ZAhA1cejAwDLycFsd7I7nVtnkT3Ol0aqodaKW+0CTZDQ1uBv5whptCnc8e8HeRRJxRs0kmm/Qfw== - dependencies: - depd "~1.1.2" - inherits "2.0.4" - setprototypeof "1.1.1" - statuses ">= 1.5.0 < 2" - toidentifier "1.0.0" - -http-signature@~1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/http-signature/-/http-signature-1.2.0.tgz#9aecd925114772f3d95b65a60abb8f7c18fbace1" - integrity sha1-muzZJRFHcvPZW2WmCruPfBj7rOE= - dependencies: - assert-plus "^1.0.0" - jsprim "^1.2.2" - sshpk "^1.7.0" - -iconv-lite@0.4.24: - version "0.4.24" - resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.4.24.tgz#2022b4b25fbddc21d2f524974a474aafe733908b" - integrity sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA== - dependencies: - safer-buffer ">= 2.1.2 < 3" - -iconv-lite@^0.5.0: - version "0.5.1" - resolved "https://registry.yarnpkg.com/iconv-lite/-/iconv-lite-0.5.1.tgz#b2425d3c7b18f7219f2ca663d103bddb91718d64" - integrity sha512-ONHr16SQvKZNSqjQT9gy5z24Jw+uqfO02/ngBSBoqChZ+W8qXX7GPRa1RoUnzGADw8K63R1BXUMzarCVQBpY8Q== - dependencies: - safer-buffer ">= 2.1.2 < 3" - -inflight@^1.0.4: - version "1.0.6" - resolved "https://registry.yarnpkg.com/inflight/-/inflight-1.0.6.tgz#49bd6331d7d02d0c09bc910a1075ba8165b56df9" - integrity sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk= - dependencies: - once "^1.3.0" - wrappy "1" - -inherits@2, inherits@2.0.4: - version "2.0.4" - resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.4.tgz#0fa2c64f932917c3433a0ded55363aae37416b7c" - integrity sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ== - -inherits@2.0.3: - version "2.0.3" - resolved "https://registry.yarnpkg.com/inherits/-/inherits-2.0.3.tgz#633c2c83e3da42a502f52466022480f4208261de" - integrity sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4= - -ipaddr.js@1.9.0: - version "1.9.0" - resolved "https://registry.yarnpkg.com/ipaddr.js/-/ipaddr.js-1.9.0.tgz#37df74e430a0e47550fe54a2defe30d8acd95f65" - integrity sha512-M4Sjn6N/+O6/IXSJseKqHoFc+5FdGJ22sXqnjTpdZweHK64MzEPAyQZyEU3R/KRv2GLoa7nNtg/C2Ev6m7z+eA== - -is-property@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/is-property/-/is-property-1.0.2.tgz#57fe1c4e48474edd65b09911f26b1cd4095dda84" - integrity sha1-V/4cTkhHTt1lsJkR8msc1Ald2oQ= - -is-typedarray@~1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/is-typedarray/-/is-typedarray-1.0.0.tgz#e479c80858df0c1b11ddda6940f96011fcda4a9a" - integrity sha1-5HnICFjfDBsR3dppQPlgEfzaSpo= - -isstream@~0.1.2: - version "0.1.2" - resolved "https://registry.yarnpkg.com/isstream/-/isstream-0.1.2.tgz#47e63f7af55afa6f92e1500e690eb8b8529c099a" - integrity sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo= - -js-tokens@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/js-tokens/-/js-tokens-4.0.0.tgz#19203fb59991df98e3a287050d4647cdeaf32499" - integrity sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ== - -js-yaml@^3.13.1: - version "3.13.1" - resolved "https://registry.yarnpkg.com/js-yaml/-/js-yaml-3.13.1.tgz#aff151b30bfdfa8e49e05da22e7415e9dfa37847" - integrity sha512-YfbcO7jXDdyj0DGxYVSlSeQNHbD7XPWvrVWeVUujrQEoZzWJIRrCPoyk6kL6IAjAG2IolMK4T0hNUe0HOUs5Jw== - dependencies: - argparse "^1.0.7" - esprima "^4.0.0" - -jsbn@~0.1.0: - version "0.1.1" - resolved "https://registry.yarnpkg.com/jsbn/-/jsbn-0.1.1.tgz#a5e654c2e5a2deb5f201d96cefbca80c0ef2f513" - integrity sha1-peZUwuWi3rXyAdls77yoDA7y9RM= - -json-schema-traverse@^0.4.1: - version "0.4.1" - resolved "https://registry.yarnpkg.com/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz#69f6a87d9513ab8bb8fe63bdb0979c448e684660" - integrity sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg== - -json-schema@0.2.3: - version "0.2.3" - resolved "https://registry.yarnpkg.com/json-schema/-/json-schema-0.2.3.tgz#b480c892e59a2f05954ce727bd3f2a4e882f9e13" - integrity sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM= - -json-stringify-safe@~5.0.1: - version "5.0.1" - resolved "https://registry.yarnpkg.com/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz#1296a2d58fd45f19a0f6ce01d65701e2c735b6eb" - integrity sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus= - -jsprim@^1.2.2: - version "1.4.1" - resolved "https://registry.yarnpkg.com/jsprim/-/jsprim-1.4.1.tgz#313e66bc1e5cc06e438bc1b7499c2e5c56acb6a2" - integrity sha1-MT5mvB5cwG5Di8G3SZwuXFastqI= - dependencies: - assert-plus "1.0.0" - extsprintf "1.3.0" - json-schema "0.2.3" - verror "1.10.0" - -long@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/long/-/long-4.0.0.tgz#9a7b71cfb7d361a194ea555241c92f7468d5bf28" - integrity sha512-XsP+KhQif4bjX1kbuSiySJFNAehNxgLb6hPRGJ9QsUr8ajHkuXGdrHmFUTUUXhDwVX2R5bY4JNZEwbUiMhV+MA== - -lru-cache@^4.1.3: - version "4.1.5" - resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-4.1.5.tgz#8bbe50ea85bed59bc9e33dcab8235ee9bcf443cd" - integrity sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g== - dependencies: - pseudomap "^1.0.2" - yallist "^2.1.2" - -lru-cache@^5.1.1: - version "5.1.1" - resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-5.1.1.tgz#1da27e6710271947695daf6848e847f01d84b920" - integrity sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w== - dependencies: - yallist "^3.0.2" - -media-typer@0.3.0: - version "0.3.0" - resolved "https://registry.yarnpkg.com/media-typer/-/media-typer-0.3.0.tgz#8710d7af0aa626f8fffa1ce00168545263255748" - integrity sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g= - -merge-descriptors@1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/merge-descriptors/-/merge-descriptors-1.0.1.tgz#b00aaa556dd8b44568150ec9d1b953f3f90cbb61" - integrity sha1-sAqqVW3YtEVoFQ7J0blT8/kMu2E= - -methods@~1.1.2: - version "1.1.2" - resolved "https://registry.yarnpkg.com/methods/-/methods-1.1.2.tgz#5529a4d67654134edcc5266656835b0f851afcee" - integrity sha1-VSmk1nZUE07cxSZmVoNbD4Ua/O4= - -mime-db@1.42.0, "mime-db@>= 1.40.0 < 2": - version "1.42.0" - resolved "https://registry.yarnpkg.com/mime-db/-/mime-db-1.42.0.tgz#3e252907b4c7adb906597b4b65636272cf9e7bac" - integrity sha512-UbfJCR4UAVRNgMpfImz05smAXK7+c+ZntjaA26ANtkXLlOe947Aag5zdIcKQULAiF9Cq4WxBi9jUs5zkA84bYQ== - -mime-types@^2.1.12, mime-types@~2.1.19, mime-types@~2.1.24: - version "2.1.25" - resolved "https://registry.yarnpkg.com/mime-types/-/mime-types-2.1.25.tgz#39772d46621f93e2a80a856c53b86a62156a6437" - integrity sha512-5KhStqB5xpTAeGqKBAMgwaYMnQik7teQN4IAzC7npDv6kzeU6prfkR67bc87J1kWMPGkoaZSq1npmexMgkmEVg== - dependencies: - mime-db "1.42.0" - -mime@1.6.0: - version "1.6.0" - resolved "https://registry.yarnpkg.com/mime/-/mime-1.6.0.tgz#32cd9e5c64553bd58d19a568af452acff04981b1" - integrity sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg== - -minimatch@^3.0.4: - version "3.0.4" - resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-3.0.4.tgz#5166e286457f03306064be5497e8dbb0c3d32083" - integrity sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA== - dependencies: - brace-expansion "^1.1.7" - -minimist@0.0.8: - version "0.0.8" - resolved "https://registry.yarnpkg.com/minimist/-/minimist-0.0.8.tgz#857fcabfc3397d2625b8228262e86aa7a011b05d" - integrity sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0= - -mkdirp@^0.5.1: - version "0.5.1" - resolved "https://registry.yarnpkg.com/mkdirp/-/mkdirp-0.5.1.tgz#30057438eac6cf7f8c4767f38648d6697d75c903" - integrity sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM= - dependencies: - minimist "0.0.8" - -ms@2.0.0: - version "2.0.0" - resolved "https://registry.yarnpkg.com/ms/-/ms-2.0.0.tgz#5608aeadfc00be6c2901df5f9861788de0d597c8" - integrity sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g= - -ms@2.1.1: - version "2.1.1" - resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.1.tgz#30a5864eb3ebb0a66f2ebe6d727af06a09d86e0a" - integrity sha512-tgp+dl5cGk28utYktBsrFqA7HKgrhgPsg6Z/EfhWI4gl1Hwq8B/GmY/0oXZ6nF8hDVesS/FpnYaD/kOWhYQvyg== - -mysql2@^1.6.1: - version "1.7.0" - resolved "https://registry.yarnpkg.com/mysql2/-/mysql2-1.7.0.tgz#2fbf314da016a61d038ffcd57a2a0aa3b7b8eacc" - integrity sha512-xTWWQPjP5rcrceZQ7CSTKR/4XIDeH/cRkNH/uzvVGQ7W5c7EJ0dXeJUusk7OKhIoHj7uFKUxDVSCfLIl+jluog== - dependencies: - denque "^1.4.1" - generate-function "^2.3.1" - iconv-lite "^0.5.0" - long "^4.0.0" - lru-cache "^5.1.1" - named-placeholders "^1.1.2" - seq-queue "^0.0.5" - sqlstring "^2.3.1" - -named-placeholders@^1.1.2: - version "1.1.2" - resolved "https://registry.yarnpkg.com/named-placeholders/-/named-placeholders-1.1.2.tgz#ceb1fbff50b6b33492b5cf214ccf5e39cef3d0e8" - integrity sha512-wiFWqxoLL3PGVReSZpjLVxyJ1bRqe+KKJVbr4hGs1KWfTZTQyezHFBbuKj9hsizHyGV2ne7EMjHdxEGAybD5SA== - dependencies: - lru-cache "^4.1.3" - -negotiator@0.6.2: - version "0.6.2" - resolved "https://registry.yarnpkg.com/negotiator/-/negotiator-0.6.2.tgz#feacf7ccf525a77ae9634436a64883ffeca346fb" - integrity sha512-hZXc7K2e+PgeI1eDBe/10Ard4ekbfrrqG8Ep+8Jmf4JID2bNg7NvCPOZN+kfF574pFQI7mum2AUqDidoKqcTOw== - -oauth-sign@~0.9.0: - version "0.9.0" - resolved "https://registry.yarnpkg.com/oauth-sign/-/oauth-sign-0.9.0.tgz#47a7b016baa68b5fa0ecf3dee08a85c679ac6455" - integrity sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ== - -on-finished@~2.3.0: - version "2.3.0" - resolved "https://registry.yarnpkg.com/on-finished/-/on-finished-2.3.0.tgz#20f1336481b083cd75337992a16971aa2d906947" - integrity sha1-IPEzZIGwg811M3mSoWlxqi2QaUc= - dependencies: - ee-first "1.1.1" - -on-headers@~1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/on-headers/-/on-headers-1.0.2.tgz#772b0ae6aaa525c399e489adfad90c403eb3c28f" - integrity sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA== - -once@^1.3.0: - version "1.4.0" - resolved "https://registry.yarnpkg.com/once/-/once-1.4.0.tgz#583b1aa775961d4b113ac17d9c50baef9dd76bd1" - integrity sha1-WDsap3WWHUsROsF9nFC6753Xa9E= - dependencies: - wrappy "1" - -parseurl@~1.3.3: - version "1.3.3" - resolved "https://registry.yarnpkg.com/parseurl/-/parseurl-1.3.3.tgz#9da19e7bee8d12dff0513ed5b76957793bc2e8d4" - integrity sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ== - -path-is-absolute@^1.0.0: - version "1.0.1" - resolved "https://registry.yarnpkg.com/path-is-absolute/-/path-is-absolute-1.0.1.tgz#174b9268735534ffbc7ace6bf53a5a9e1b5c5f5f" - integrity sha1-F0uSaHNVNP+8es5r9TpanhtcX18= - -path-parse@^1.0.6: - version "1.0.6" - resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.6.tgz#d62dbb5679405d72c4737ec58600e9ddcf06d24c" - integrity sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw== - -path-to-regexp@0.1.7: - version "0.1.7" - resolved "https://registry.yarnpkg.com/path-to-regexp/-/path-to-regexp-0.1.7.tgz#df604178005f522f15eb4490e7247a1bfaa67f8c" - integrity sha1-32BBeABfUi8V60SQ5yR6G/qmf4w= - -performance-now@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/performance-now/-/performance-now-2.1.0.tgz#6309f4e0e5fa913ec1c69307ae364b4b377c9e7b" - integrity sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns= - -proxy-addr@~2.0.5: - version "2.0.5" - resolved "https://registry.yarnpkg.com/proxy-addr/-/proxy-addr-2.0.5.tgz#34cbd64a2d81f4b1fd21e76f9f06c8a45299ee34" - integrity sha512-t/7RxHXPH6cJtP0pRG6smSr9QJidhB+3kXu0KgXnbGYMgzEnUxRQ4/LDdfOwZEMyIh3/xHb8PX3t+lfL9z+YVQ== - dependencies: - forwarded "~0.1.2" - ipaddr.js "1.9.0" - -pseudomap@^1.0.2: - version "1.0.2" - resolved "https://registry.yarnpkg.com/pseudomap/-/pseudomap-1.0.2.tgz#f052a28da70e618917ef0a8ac34c1ae5a68286b3" - integrity sha1-8FKijacOYYkX7wqKw0wa5aaChrM= - -psl@^1.1.28: - version "1.8.0" - resolved "https://registry.yarnpkg.com/psl/-/psl-1.8.0.tgz#9326f8bcfb013adcc005fdff056acce020e51c24" - integrity sha512-RIdOzyoavK+hA18OGGWDqUTsCLhtA7IcZ/6NCs4fFJaHBDab+pDDmDIByWFRQJq2Cd7r1OoQxBGKOaztq+hjIQ== - -punycode@^2.1.0, punycode@^2.1.1: - version "2.1.1" - resolved "https://registry.yarnpkg.com/punycode/-/punycode-2.1.1.tgz#b58b010ac40c22c5657616c8d2c2c02c7bf479ec" - integrity sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A== - -qs@6.7.0: - version "6.7.0" - resolved "https://registry.yarnpkg.com/qs/-/qs-6.7.0.tgz#41dc1a015e3d581f1621776be31afb2876a9b1bc" - integrity sha512-VCdBRNFTX1fyE7Nb6FYoURo/SPe62QCaAyzJvUjwRaIsc+NePBEniHlvxFmmX56+HZphIGtV0XeCirBtpDrTyQ== - -qs@~6.5.2: - version "6.5.2" - resolved "https://registry.yarnpkg.com/qs/-/qs-6.5.2.tgz#cb3ae806e8740444584ef154ce8ee98d403f3e36" - integrity sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA== - -range-parser@~1.2.1: - version "1.2.1" - resolved "https://registry.yarnpkg.com/range-parser/-/range-parser-1.2.1.tgz#3cf37023d199e1c24d1a55b84800c2f3e6468031" - integrity sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg== - -raw-body@2.4.0: - version "2.4.0" - resolved "https://registry.yarnpkg.com/raw-body/-/raw-body-2.4.0.tgz#a1ce6fb9c9bc356ca52e89256ab59059e13d0332" - integrity sha512-4Oz8DUIwdvoa5qMJelxipzi/iJIi40O5cGV1wNYp5hvZP8ZN0T+jiNkL0QepXs+EsQ9XJ8ipEDoiH70ySUJP3Q== - dependencies: - bytes "3.1.0" - http-errors "1.7.2" - iconv-lite "0.4.24" - unpipe "1.0.0" - -request@^2.88.2: - version "2.88.2" - resolved "https://registry.yarnpkg.com/request/-/request-2.88.2.tgz#d73c918731cb5a87da047e207234146f664d12b3" - integrity sha512-MsvtOrfG9ZcrOwAW+Qi+F6HbD0CWXEh9ou77uOb7FM2WPhwT7smM833PzanhJLsgXjN89Ir6V2PczXNnMpwKhw== - dependencies: - aws-sign2 "~0.7.0" - aws4 "^1.8.0" - caseless "~0.12.0" - combined-stream "~1.0.6" - extend "~3.0.2" - forever-agent "~0.6.1" - form-data "~2.3.2" - har-validator "~5.1.3" - http-signature "~1.2.0" - is-typedarray "~1.0.0" - isstream "~0.1.2" - json-stringify-safe "~5.0.1" - mime-types "~2.1.19" - oauth-sign "~0.9.0" - performance-now "^2.1.0" - qs "~6.5.2" - safe-buffer "^5.1.2" - tough-cookie "~2.5.0" - tunnel-agent "^0.6.0" - uuid "^3.3.2" - -resolve@^1.3.2: - version "1.13.1" - resolved "https://registry.yarnpkg.com/resolve/-/resolve-1.13.1.tgz#be0aa4c06acd53083505abb35f4d66932ab35d16" - integrity sha512-CxqObCX8K8YtAhOBRg+lrcdn+LK+WYOS8tSjqSFbjtrI5PnS63QPhZl4+yKfrU9tdsbMu9Anr/amegT87M9Z6w== - dependencies: - path-parse "^1.0.6" - -safe-buffer@5.1.2: - version "5.1.2" - resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.1.2.tgz#991ec69d296e0313747d59bdfd2b745c35f8828d" - integrity sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g== - -safe-buffer@^5.0.1, safe-buffer@^5.1.2: - version "5.2.0" - resolved "https://registry.yarnpkg.com/safe-buffer/-/safe-buffer-5.2.0.tgz#b74daec49b1148f88c64b68d49b1e815c1f2f519" - integrity sha512-fZEwUGbVl7kouZs1jCdMLdt95hdIv0ZeHg6L7qPeciMZhZ+/gdesW4wgTARkrFWEpspjEATAzUGPG8N2jJiwbg== - -"safer-buffer@>= 2.1.2 < 3", safer-buffer@^2.0.2, safer-buffer@^2.1.0, safer-buffer@~2.1.0: - version "2.1.2" - resolved "https://registry.yarnpkg.com/safer-buffer/-/safer-buffer-2.1.2.tgz#44fa161b0187b9549dd84bb91802f9bd8385cd6a" - integrity sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg== - -semver@^5.3.0: - version "5.7.1" - resolved "https://registry.yarnpkg.com/semver/-/semver-5.7.1.tgz#a954f931aeba508d307bbf069eff0c01c96116f7" - integrity sha512-sauaDf/PZdVgrLTNYHRtpXa1iRiKcaebiKQ1BJdpQlWH2lCvexQdX55snPFyK7QzpudqbCI0qXFfOasHdyNDGQ== - -send@0.17.1: - version "0.17.1" - resolved "https://registry.yarnpkg.com/send/-/send-0.17.1.tgz#c1d8b059f7900f7466dd4938bdc44e11ddb376c8" - integrity sha512-BsVKsiGcQMFwT8UxypobUKyv7irCNRHk1T0G680vk88yf6LBByGcZJOTJCrTP2xVN6yI+XjPJcNuE3V4fT9sAg== - dependencies: - debug "2.6.9" - depd "~1.1.2" - destroy "~1.0.4" - encodeurl "~1.0.2" - escape-html "~1.0.3" - etag "~1.8.1" - fresh "0.5.2" - http-errors "~1.7.2" - mime "1.6.0" - ms "2.1.1" - on-finished "~2.3.0" - range-parser "~1.2.1" - statuses "~1.5.0" - -seq-queue@^0.0.5: - version "0.0.5" - resolved "https://registry.yarnpkg.com/seq-queue/-/seq-queue-0.0.5.tgz#d56812e1c017a6e4e7c3e3a37a1da6d78dd3c93e" - integrity sha1-1WgS4cAXpuTnw+Ojeh2m143TyT4= - -serve-static@1.14.1: - version "1.14.1" - resolved "https://registry.yarnpkg.com/serve-static/-/serve-static-1.14.1.tgz#666e636dc4f010f7ef29970a88a674320898b2f9" - integrity sha512-JMrvUwE54emCYWlTI+hGrGv5I8dEwmco/00EvkzIIsR7MqrHonbD9pO2MOfFnpFntl7ecpZs+3mW+XbQZu9QCg== - dependencies: - encodeurl "~1.0.2" - escape-html "~1.0.3" - parseurl "~1.3.3" - send "0.17.1" - -setprototypeof@1.1.1: - version "1.1.1" - resolved "https://registry.yarnpkg.com/setprototypeof/-/setprototypeof-1.1.1.tgz#7e95acb24aa92f5885e0abef5ba131330d4ae683" - integrity sha512-JvdAWfbXeIGaZ9cILp38HntZSFSo3mWg6xGcJJsd+d4aRMOqauag1C63dJfDw7OaMYwEbHMOxEZ1lqVRYP2OAw== - -sprintf-js@~1.0.2: - version "1.0.3" - resolved "https://registry.yarnpkg.com/sprintf-js/-/sprintf-js-1.0.3.tgz#04e6926f662895354f3dd015203633b857297e2c" - integrity sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw= - -sqlstring@^2.3.1: - version "2.3.1" - resolved "https://registry.yarnpkg.com/sqlstring/-/sqlstring-2.3.1.tgz#475393ff9e91479aea62dcaf0ca3d14983a7fb40" - integrity sha1-R1OT/56RR5rqYtyvDKPRSYOn+0A= - -sshpk@^1.7.0: - version "1.16.1" - resolved "https://registry.yarnpkg.com/sshpk/-/sshpk-1.16.1.tgz#fb661c0bef29b39db40769ee39fa70093d6f6877" - integrity sha512-HXXqVUq7+pcKeLqqZj6mHFUMvXtOJt1uoUx09pFW6011inTMxqI8BA8PM95myrIyyKwdnzjdFjLiE6KBPVtJIg== - dependencies: - asn1 "~0.2.3" - assert-plus "^1.0.0" - bcrypt-pbkdf "^1.0.0" - dashdash "^1.12.0" - ecc-jsbn "~0.1.1" - getpass "^0.1.1" - jsbn "~0.1.0" - safer-buffer "^2.0.2" - tweetnacl "~0.14.0" - -"statuses@>= 1.5.0 < 2", statuses@~1.5.0: - version "1.5.0" - resolved "https://registry.yarnpkg.com/statuses/-/statuses-1.5.0.tgz#161c7dac177659fd9811f43771fa99381478628c" - integrity sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow= - -supports-color@^5.3.0: - version "5.5.0" - resolved "https://registry.yarnpkg.com/supports-color/-/supports-color-5.5.0.tgz#e2e69a44ac8772f78a1ec0b35b689df6530efc8f" - integrity sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow== - dependencies: - has-flag "^3.0.0" - -toidentifier@1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/toidentifier/-/toidentifier-1.0.0.tgz#7e1be3470f1e77948bc43d94a3c8f4d7752ba553" - integrity sha512-yaOH/Pk/VEhBWWTlhI+qXxDFXlejDGcQipMlyxda9nthulaxLZUNcUqFxokp0vcYnvteJln5FNQDRrxj3YcbVw== - -tough-cookie@~2.5.0: - version "2.5.0" - resolved "https://registry.yarnpkg.com/tough-cookie/-/tough-cookie-2.5.0.tgz#cd9fb2a0aa1d5a12b473bd9fb96fa3dcff65ade2" - integrity sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g== - dependencies: - psl "^1.1.28" - punycode "^2.1.1" - -tslib@^1.8.0, tslib@^1.8.1: - version "1.10.0" - resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.10.0.tgz#c3c19f95973fb0a62973fb09d90d961ee43e5c8a" - integrity sha512-qOebF53frne81cf0S9B41ByenJ3/IuH8yJKngAX35CmiZySA0khhkovshKK+jGCaMnVomla7gVlIcc3EvKPbTQ== - -tslint@^5.11.0: - version "5.20.1" - resolved "https://registry.yarnpkg.com/tslint/-/tslint-5.20.1.tgz#e401e8aeda0152bc44dd07e614034f3f80c67b7d" - integrity sha512-EcMxhzCFt8k+/UP5r8waCf/lzmeSyVlqxqMEDQE7rWYiQky8KpIBz1JAoYXfROHrPZ1XXd43q8yQnULOLiBRQg== - dependencies: - "@babel/code-frame" "^7.0.0" - builtin-modules "^1.1.1" - chalk "^2.3.0" - commander "^2.12.1" - diff "^4.0.1" - glob "^7.1.1" - js-yaml "^3.13.1" - minimatch "^3.0.4" - mkdirp "^0.5.1" - resolve "^1.3.2" - semver "^5.3.0" - tslib "^1.8.0" - tsutils "^2.29.0" - -tsutils@^2.29.0: - version "2.29.0" - resolved "https://registry.yarnpkg.com/tsutils/-/tsutils-2.29.0.tgz#32b488501467acbedd4b85498673a0812aca0b99" - integrity sha512-g5JVHCIJwzfISaXpXE1qvNalca5Jwob6FjI4AoPlqMusJ6ftFE7IkkFoMhVLRgK+4Kx3gkzb8UZK5t5yTTvEmA== - dependencies: - tslib "^1.8.1" - -tunnel-agent@^0.6.0: - version "0.6.0" - resolved "https://registry.yarnpkg.com/tunnel-agent/-/tunnel-agent-0.6.0.tgz#27a5dea06b36b04a0a9966774b290868f0fc40fd" - integrity sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0= - dependencies: - safe-buffer "^5.0.1" - -tweetnacl@^0.14.3, tweetnacl@~0.14.0: - version "0.14.5" - resolved "https://registry.yarnpkg.com/tweetnacl/-/tweetnacl-0.14.5.tgz#5ae68177f192d4456269d108afa93ff8743f4f64" - integrity sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q= - -type-is@~1.6.17, type-is@~1.6.18: - version "1.6.18" - resolved "https://registry.yarnpkg.com/type-is/-/type-is-1.6.18.tgz#4e552cd05df09467dcbc4ef739de89f2cf37c131" - integrity sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g== - dependencies: - media-typer "0.3.0" - mime-types "~2.1.24" - -typescript@^3.6.4: - version "3.9.7" - resolved "https://registry.yarnpkg.com/typescript/-/typescript-3.9.7.tgz#98d600a5ebdc38f40cb277522f12dc800e9e25fa" - integrity sha512-BLbiRkiBzAwsjut4x/dsibSTB6yWpwT5qWmC2OfuCg3GgVQCSgMs4vEctYPhsaGtd0AeuuHMkjZ2h2WG8MSzRw== - -unpipe@1.0.0, unpipe@~1.0.0: - version "1.0.0" - resolved "https://registry.yarnpkg.com/unpipe/-/unpipe-1.0.0.tgz#b2bf4ee8514aae6165b4817829d21b2ef49904ec" - integrity sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw= - -uri-js@^4.2.2: - version "4.2.2" - resolved "https://registry.yarnpkg.com/uri-js/-/uri-js-4.2.2.tgz#94c540e1ff772956e2299507c010aea6c8838eb0" - integrity sha512-KY9Frmirql91X2Qgjry0Wd4Y+YTdrdZheS8TFwvkbLWf/G5KNJDCh6pKL5OZctEW4+0Baa5idK2ZQuELRwPznQ== - dependencies: - punycode "^2.1.0" - -utils-merge@1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/utils-merge/-/utils-merge-1.0.1.tgz#9f95710f50a267947b2ccc124741c1028427e713" - integrity sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM= - -uuid@^3.3.2: - version "3.3.3" - resolved "https://registry.yarnpkg.com/uuid/-/uuid-3.3.3.tgz#4568f0216e78760ee1dbf3a4d2cf53e224112866" - integrity sha512-pW0No1RGHgzlpHJO1nsVrHKpOEIxkGg1xB+v0ZmdNH5OAeAwzAVrCnI2/6Mtx+Uys6iaylxa+D3g4j63IKKjSQ== - -vary@~1.1.2: - version "1.1.2" - resolved "https://registry.yarnpkg.com/vary/-/vary-1.1.2.tgz#2299f02c6ded30d4a5961b0b9f74524a18f634fc" - integrity sha1-IpnwLG3tMNSllhsLn3RSShj2NPw= - -verror@1.10.0: - version "1.10.0" - resolved "https://registry.yarnpkg.com/verror/-/verror-1.10.0.tgz#3a105ca17053af55d6e270c1f8288682e18da400" - integrity sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA= - dependencies: - assert-plus "^1.0.0" - core-util-is "1.0.2" - extsprintf "^1.2.0" - -wrappy@1: - version "1.0.2" - resolved "https://registry.yarnpkg.com/wrappy/-/wrappy-1.0.2.tgz#b5243d8f3ec1aa35f1364605bc0d1036e30ab69f" - integrity sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8= - -ws@^7.3.1: - version "7.3.1" - resolved "https://registry.yarnpkg.com/ws/-/ws-7.3.1.tgz#d0547bf67f7ce4f12a72dfe31262c68d7dc551c8" - integrity sha512-D3RuNkynyHmEJIpD2qrgVkc9DQ23OrN/moAwZX4L8DfvszsJxpjQuUq3LMx6HoYji9fbIOBY18XWBsAux1ZZUA== - -yallist@^2.1.2: - version "2.1.2" - resolved "https://registry.yarnpkg.com/yallist/-/yallist-2.1.2.tgz#1c11f9218f076089a47dd512f93c6699a6a81d52" - integrity sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI= - -yallist@^3.0.2: - version "3.1.1" - resolved "https://registry.yarnpkg.com/yallist/-/yallist-3.1.1.tgz#dbb7daf9bfd8bac9ab45ebf602b8cbad0d5d08fd" - integrity sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g== diff --git a/contributors/0xBEEFCAF3.txt b/contributors/0xBEEFCAF3.txt new file mode 100644 index 0000000000..e00999be12 --- /dev/null +++ b/contributors/0xBEEFCAF3.txt @@ -0,0 +1,3 @@ +I hereby accept the terms of the Contributor License Agreement in the CONTRIBUTING.md file of the mempool/mempool git repository as of November 17, 2023. + +Signed: 0xBEEFCAF3 diff --git a/contributors/0xflicker.txt b/contributors/0xflicker.txt new file mode 100644 index 0000000000..fb3f198e2e --- /dev/null +++ b/contributors/0xflicker.txt @@ -0,0 +1,3 @@ +I hereby accept the terms of the Contributor License Agreement in the CONTRIBUTING.md file of the mempool/mempool git repository as of June 24, 2023. + +Signed: 0xflicker diff --git a/contributors/AlexLloyd0.txt b/contributors/AlexLloyd0.txt new file mode 100644 index 0000000000..065dbfe114 --- /dev/null +++ b/contributors/AlexLloyd0.txt @@ -0,0 +1,3 @@ +I hereby accept the terms of the Contributor License Agreement in the CONTRIBUTING.md file of the mempool/mempool git repository as of January 25, 2022. + +Signed: AlexLloyd0 diff --git a/contributors/Arooba-git.txt b/contributors/Arooba-git.txt new file mode 100644 index 0000000000..833d78ff4e --- /dev/null +++ b/contributors/Arooba-git.txt @@ -0,0 +1,3 @@ +I hereby accept the terms of the Contributor License Agreement in the CONTRIBUTING.md file of the mempool/mempool git repository as of January 25, 2022. + +Signed: Arooba-git \ No newline at end of file diff --git a/contributors/Czino.txt b/contributors/Czino.txt new file mode 100644 index 0000000000..08affb0955 --- /dev/null +++ b/contributors/Czino.txt @@ -0,0 +1,3 @@ +I hereby accept the terms of the Contributor License Agreement in the CONTRIBUTING.md file of the mempool/mempool git repository as of July 29, 2023. + +Signed: Czino diff --git a/contributors/TKone7.txt b/contributors/TKone7.txt new file mode 100644 index 0000000000..0112e34a3d --- /dev/null +++ b/contributors/TKone7.txt @@ -0,0 +1,3 @@ +I hereby accept the terms of the Contributor License Agreement in the CONTRIBUTING.md file of the mempool/mempool git repository as of October 23, 2023. + +Signed: TKone7 diff --git a/contributors/TechMiX.txt b/contributors/TechMiX.txt new file mode 100644 index 0000000000..e6a382eae8 --- /dev/null +++ b/contributors/TechMiX.txt @@ -0,0 +1,3 @@ +I hereby accept the terms of the Contributor License Agreement in the CONTRIBUTING.md file of the mempool/mempool git repository as of January 25, 2022. + +Signed: TechMiX diff --git a/contributors/TheBlueMatt.txt b/contributors/TheBlueMatt.txt new file mode 100644 index 0000000000..77b39e9829 --- /dev/null +++ b/contributors/TheBlueMatt.txt @@ -0,0 +1,3 @@ +I hereby accept the terms of the Contributor License Agreement in the CONTRIBUTING.md file with sha256 hash c80c5ee4c71c5a76a1f6cd35339bd0c45b25b491933ea7b02a66470e9f43a6fd. + +Signed: TheBlueMatt diff --git a/contributors/WesVleuten.txt b/contributors/WesVleuten.txt new file mode 100644 index 0000000000..a13bde1401 --- /dev/null +++ b/contributors/WesVleuten.txt @@ -0,0 +1,3 @@ +I hereby accept the terms of the Contributor License Agreement in the CONTRIBUTING.md file of the mempool/mempool git repository as of September 1, 2022. + +Signed: WesVleuten diff --git a/contributors/afahrer.txt b/contributors/afahrer.txt new file mode 100644 index 0000000000..1ce6dc8e57 --- /dev/null +++ b/contributors/afahrer.txt @@ -0,0 +1,3 @@ +I hereby accept the terms of the Contributor License Agreement in the CONTRIBUTING.md file of the mempool/mempool git repository as of January 23, 2024. + +Signed: afahrer \ No newline at end of file diff --git a/contributors/andrewtoth.txt b/contributors/andrewtoth.txt new file mode 100644 index 0000000000..bd2ed3d06e --- /dev/null +++ b/contributors/andrewtoth.txt @@ -0,0 +1,3 @@ +I hereby accept the terms of the Contributor License Agreement in the CONTRIBUTING.md file of the mempool/mempool git repository as of August 2, 2023. + +Signed: andrewtoth diff --git a/contributors/antonilol.txt b/contributors/antonilol.txt new file mode 100644 index 0000000000..94f5ba0c66 --- /dev/null +++ b/contributors/antonilol.txt @@ -0,0 +1,3 @@ +I hereby accept the terms of the Contributor License Agreement in the CONTRIBUTING.md file of the mempool/mempool git repository as of January 25, 2022. + +Signed: antonilol diff --git a/contributors/ayanamidev.txt b/contributors/ayanamidev.txt new file mode 100644 index 0000000000..c397f72865 --- /dev/null +++ b/contributors/ayanamidev.txt @@ -0,0 +1,3 @@ +I hereby accept the terms of the Contributor License Agreement in the CONTRIBUTING.md file of the mempool/mempool git repository as of May 15, 2022. + +Signed: ayanamidev diff --git a/contributors/bennyhodl.txt b/contributors/bennyhodl.txt new file mode 100644 index 0000000000..c5f779de6d --- /dev/null +++ b/contributors/bennyhodl.txt @@ -0,0 +1,3 @@ +I hereby accept the terms of the Contributor License Agreement in the CONTRIBUTING.md file of the mempool/mempool git repository as of June 28, 2023. + +Signed: bennyhodl diff --git a/contributors/bguillaumat.txt b/contributors/bguillaumat.txt new file mode 100644 index 0000000000..ac14a07c73 --- /dev/null +++ b/contributors/bguillaumat.txt @@ -0,0 +1,3 @@ +I hereby accept the terms of the Contributor License Agreement in the CONTRIBUTING.md file of the mempool/mempool git repository as of January 25, 2022. + +Signed: bguillaumat diff --git a/contributors/bitcoinmechanic.txt b/contributors/bitcoinmechanic.txt new file mode 100644 index 0000000000..b2574b2faf --- /dev/null +++ b/contributors/bitcoinmechanic.txt @@ -0,0 +1,3 @@ +I hereby accept the terms of the Contributor License Agreement in the CONTRIBUTING.md file of the mempool/mempool git repository as of January 25, 2022. + +Signed: bitcoinmechanic diff --git a/contributors/bosch-0.txt b/contributors/bosch-0.txt new file mode 100644 index 0000000000..366abbd7b8 --- /dev/null +++ b/contributors/bosch-0.txt @@ -0,0 +1,3 @@ +I hereby accept the terms of the Contributor License Agreement in the CONTRIBUTING.md file of the mempool/mempool git repository as of January 25, 2022. + +Signed: Bosch-0 diff --git a/contributors/daweilv.txt b/contributors/daweilv.txt new file mode 100644 index 0000000000..2abb9f73bf --- /dev/null +++ b/contributors/daweilv.txt @@ -0,0 +1,3 @@ +I hereby accept the terms of the Contributor License Agreement in the CONTRIBUTING.md file of the mempool/mempool git repository as of April 7, 2024. + +Signed: daweilv diff --git a/contributors/devinbileck.txt b/contributors/devinbileck.txt new file mode 100644 index 0000000000..bbabfad65c --- /dev/null +++ b/contributors/devinbileck.txt @@ -0,0 +1,3 @@ +I hereby accept the terms of the Contributor License Agreement in the CONTRIBUTING.md file of the mempool/mempool git repository as of July 21, 2023. + +Signed: devinbileck diff --git a/contributors/dsbaars.txt b/contributors/dsbaars.txt new file mode 100644 index 0000000000..8e4dcbb9a4 --- /dev/null +++ b/contributors/dsbaars.txt @@ -0,0 +1,3 @@ +I hereby accept the terms of the Contributor License Agreement in the CONTRIBUTING.md file of the mempool/mempool git repository as of January 25, 2022. + +Signed: dsbaars \ No newline at end of file diff --git a/contributors/emzy.txt b/contributors/emzy.txt new file mode 100644 index 0000000000..7d0a9409ed --- /dev/null +++ b/contributors/emzy.txt @@ -0,0 +1 @@ +Mempool Space K.K. has a signed CLA or other agreement on file with @emzy as of January 25, 2022 diff --git a/contributors/erikarvstedt.txt b/contributors/erikarvstedt.txt new file mode 100644 index 0000000000..0f84df7c24 --- /dev/null +++ b/contributors/erikarvstedt.txt @@ -0,0 +1,3 @@ +I hereby accept the terms of the Contributor License Agreement in the CONTRIBUTING.md file of the mempool/mempool git repository as of July 6, 2022. + +Signed: erikarvstedt diff --git a/contributors/fanquake.txt b/contributors/fanquake.txt new file mode 100644 index 0000000000..3212bdcbf7 --- /dev/null +++ b/contributors/fanquake.txt @@ -0,0 +1,3 @@ +I hereby accept the terms of the Contributor License Agreement in the CONTRIBUTING.md file of the mempool/mempool git repository as of October 23, 2023. + +Signed: fanquake diff --git a/contributors/fiatjaf.txt b/contributors/fiatjaf.txt new file mode 100644 index 0000000000..cdd716d3c3 --- /dev/null +++ b/contributors/fiatjaf.txt @@ -0,0 +1,5 @@ +I hereby accept the terms of the Contributor License Agreement in the CONTRIBUTING.md file of the mempool/mempool git repository as of January 25, 2022. +I also regret having ever contributed to this repository since they keep asking me to sign this legalese timewaste things. +And finally I don't care about licenses and won't sue anyone over intellectual property, which is a fake statist construct invented by evil lobby lawyers. + +Signed: fiatjaf diff --git a/contributors/fubz.txt b/contributors/fubz.txt new file mode 100644 index 0000000000..e799d641d0 --- /dev/null +++ b/contributors/fubz.txt @@ -0,0 +1,3 @@ +I hereby accept the terms of the Contributor License Agreement in the CONTRIBUTING.md file of the mempool/mempool git repository as of January 25, 2022. + +Signed: fubz diff --git a/contributors/hans-crypto.txt b/contributors/hans-crypto.txt new file mode 100644 index 0000000000..d43651294a --- /dev/null +++ b/contributors/hans-crypto.txt @@ -0,0 +1,3 @@ +I hereby accept the terms of the Contributor License Agreement in the CONTRIBUTING.md file of the mempool/mempool git repository as of May 21, 2024. + +Signed: hans-crypto diff --git a/contributors/henrialb.txt b/contributors/henrialb.txt new file mode 100644 index 0000000000..7902ebefb4 --- /dev/null +++ b/contributors/henrialb.txt @@ -0,0 +1,3 @@ +I hereby accept the terms of the Contributor License Agreement in the CONTRIBUTING.md file of the mempool/mempool git repository as of April 12, 2024. + +Signed: henrialb diff --git a/contributors/hunicus.txt b/contributors/hunicus.txt new file mode 100644 index 0000000000..bf8f3ed155 --- /dev/null +++ b/contributors/hunicus.txt @@ -0,0 +1 @@ +Mempool Space K.K. has a signed CLA or other agreement on file with @hunicus as of January 25, 2022 diff --git a/contributors/isghe.txt b/contributors/isghe.txt new file mode 100644 index 0000000000..5e556448a4 --- /dev/null +++ b/contributors/isghe.txt @@ -0,0 +1,3 @@ +I hereby accept the terms of the Contributor License Agreement in the CONTRIBUTING.md file of the mempool/mempool git repository as of January 18, 2024. + +Signed: isghe diff --git a/contributors/jamesblacklock.txt b/contributors/jamesblacklock.txt new file mode 100644 index 0000000000..11591f451b --- /dev/null +++ b/contributors/jamesblacklock.txt @@ -0,0 +1,3 @@ +I hereby accept the terms of the Contributor License Agreement in the CONTRIBUTING.md file of the mempool/mempool git repository as of December 20, 2023. + +Signed: jamesblacklock diff --git a/contributors/jlopp.txt b/contributors/jlopp.txt new file mode 100644 index 0000000000..aaebe73352 --- /dev/null +++ b/contributors/jlopp.txt @@ -0,0 +1,3 @@ +I hereby accept the terms of the Contributor License Agreement in the CONTRIBUTING.md file of the mempool/mempool git repository as of July 12, 2024. + +Signed: jlopp diff --git a/contributors/joostjager.txt b/contributors/joostjager.txt new file mode 100644 index 0000000000..2a31f307db --- /dev/null +++ b/contributors/joostjager.txt @@ -0,0 +1,3 @@ +I hereby accept the terms of the Contributor License Agreement in the CONTRIBUTING.md file of the mempool/mempool git repository as of January 25, 2022. + +Signed: joostjager diff --git a/contributors/junderw.txt b/contributors/junderw.txt new file mode 100644 index 0000000000..23f0e9a959 --- /dev/null +++ b/contributors/junderw.txt @@ -0,0 +1,3 @@ +I hereby accept the terms of the Contributor License Agreement in the CONTRIBUTING.md file of the mempool/mempool git repository as of August 19, 2022. + +Signed: junderw diff --git a/contributors/knorrium.txt b/contributors/knorrium.txt new file mode 100644 index 0000000000..144a966a43 --- /dev/null +++ b/contributors/knorrium.txt @@ -0,0 +1 @@ +Mempool Space K.K. has a signed CLA or other agreement on file with @knorrium as of January 25, 2022 diff --git a/contributors/learntheropes.txt b/contributors/learntheropes.txt new file mode 100644 index 0000000000..f8d79bf932 --- /dev/null +++ b/contributors/learntheropes.txt @@ -0,0 +1,3 @@ +I hereby accept the terms of the Contributor License Agreement in the CONTRIBUTING.md file of the mempool/mempool git repository as of April 7, 203. + +Signed: learntheropes diff --git a/contributors/mackalex.txt b/contributors/mackalex.txt new file mode 100644 index 0000000000..667e31a225 --- /dev/null +++ b/contributors/mackalex.txt @@ -0,0 +1,3 @@ +I hereby accept the terms of the Contributor License Agreement in the CONTRIBUTING.md file of the mempool/mempool git repository as of June 18th, 2024. + +Signed: mackalex diff --git a/contributors/miguelmedeiros.txt b/contributors/miguelmedeiros.txt new file mode 100644 index 0000000000..3a7a2baabf --- /dev/null +++ b/contributors/miguelmedeiros.txt @@ -0,0 +1 @@ +Mempool Space K.K. has a signed CLA or other agreement on file with @miguelmedeiros as of January 25, 2022 diff --git a/contributors/mononaut.txt b/contributors/mononaut.txt new file mode 100644 index 0000000000..fcd535c8e1 --- /dev/null +++ b/contributors/mononaut.txt @@ -0,0 +1,3 @@ +I hereby accept the terms of the Contributor License Agreement in the CONTRIBUTING.md file of the mempool/mempool git repository as of May 31, 2022. + +Signed: mononaut diff --git a/contributors/natsoni.txt b/contributors/natsoni.txt new file mode 100644 index 0000000000..ac1007ecf9 --- /dev/null +++ b/contributors/natsoni.txt @@ -0,0 +1,3 @@ +I hereby accept the terms of the Contributor License Agreement in the CONTRIBUTING.md file of the mempool/mempool git repository as of November 16, 2023. + +Signed: natsoni diff --git a/contributors/naveensrinivasan.txt b/contributors/naveensrinivasan.txt new file mode 100644 index 0000000000..84cdbdcdd1 --- /dev/null +++ b/contributors/naveensrinivasan.txt @@ -0,0 +1,3 @@ +I hereby accept the terms of the Contributor License Agreement in the CONTRIBUTING.md file of the mempool/mempool git repository as of March 11, 2022. + +Signed: naveensrinivasan diff --git a/contributors/nothing0012.txt b/contributors/nothing0012.txt new file mode 100644 index 0000000000..e26514d351 --- /dev/null +++ b/contributors/nothing0012.txt @@ -0,0 +1,3 @@ +I hereby accept the terms of the Contributor License Agreement in the CONTRIBUTING.md file of the mempool/mempool git repository as of April 8, 2023. + +Signed: nothing0012 diff --git a/contributors/nymkappa.txt b/contributors/nymkappa.txt new file mode 100644 index 0000000000..4e86a6f382 --- /dev/null +++ b/contributors/nymkappa.txt @@ -0,0 +1 @@ +Mempool Space K.K. has a signed CLA or other agreement on file with @nymkappa as of January 25, 2022 diff --git a/contributors/oleonardolima.txt b/contributors/oleonardolima.txt new file mode 100644 index 0000000000..79adbcb78b --- /dev/null +++ b/contributors/oleonardolima.txt @@ -0,0 +1,3 @@ +I hereby accept the terms of the Contributor License Agreement in the CONTRIBUTING.md file of the mempool/mempool git repository as of July 25, 2022. + +Signed: oleonardolima diff --git a/contributors/orangesurf.txt b/contributors/orangesurf.txt new file mode 100644 index 0000000000..c760a91256 --- /dev/null +++ b/contributors/orangesurf.txt @@ -0,0 +1,3 @@ +I hereby accept the terms of the Contributor License Agreement in the CONTRIBUTING.md file of the mempool/mempool git repository as of September 12, 2023. + +Signed: orange surf diff --git a/contributors/pedromvpg.txt b/contributors/pedromvpg.txt new file mode 100644 index 0000000000..ce98c41678 --- /dev/null +++ b/contributors/pedromvpg.txt @@ -0,0 +1,3 @@ +I hereby accept the terms of the Contributor License Agreement in the CONTRIBUTING.md file of the mempool/mempool git repository as of July 20, 2023. + +Signed: pedromvpg diff --git a/contributors/pfoytik.txt b/contributors/pfoytik.txt new file mode 100644 index 0000000000..f15f7cb332 --- /dev/null +++ b/contributors/pfoytik.txt @@ -0,0 +1,3 @@ +I hereby accept the terms of the Contributor License Agreement in the CONTRIBUTING.md file of the mempool/mempool git repository as of June 15, 2023. + +Signed pfoytik diff --git a/contributors/piterden.txt b/contributors/piterden.txt new file mode 100644 index 0000000000..86548831b1 --- /dev/null +++ b/contributors/piterden.txt @@ -0,0 +1,3 @@ +I hereby accept the terms of the Contributor License Agreement in the CONTRIBUTING.md file of the mempool/mempool git repository as of December 17, 2022. + +Signed: piterden diff --git a/contributors/rishkwal.txt b/contributors/rishkwal.txt new file mode 100644 index 0000000000..9a50bda6b8 --- /dev/null +++ b/contributors/rishkwal.txt @@ -0,0 +1,3 @@ +I hereby accept the terms of the Contributor License Agreement in the CONTRIBUTING.md file of the mempool/mempool git repository as of July 29, 2023. + +Signed: rishkwal diff --git a/contributors/russeree.txt b/contributors/russeree.txt new file mode 100644 index 0000000000..0aaef47e55 --- /dev/null +++ b/contributors/russeree.txt @@ -0,0 +1,3 @@ +I hereby accept the terms of the Contributor License Agreement in the CONTRIBUTING.md file of the mempool/mempool git repository as of March 8, 2024. + +Signed: PortlandHODL diff --git a/contributors/secondl1ght.txt b/contributors/secondl1ght.txt new file mode 100644 index 0000000000..a386a103a4 --- /dev/null +++ b/contributors/secondl1ght.txt @@ -0,0 +1,3 @@ +I hereby accept the terms of the Contributor License Agreement in the CONTRIBUTING.md file of the mempool/mempool git repository as of June 14, 2023. + +Signed: secondl1ght diff --git a/contributors/shubhamkmr04.txt b/contributors/shubhamkmr04.txt new file mode 100644 index 0000000000..ab7e49e0b6 --- /dev/null +++ b/contributors/shubhamkmr04.txt @@ -0,0 +1,3 @@ +I hereby accept the terms of the Contributor License Agreement in the CONTRIBUTING.md file of the mempool/mempool git repository as of November 15, 2023. + +Signed: shubhamkmr04 \ No newline at end of file diff --git a/contributors/softsimon.txt b/contributors/softsimon.txt new file mode 100644 index 0000000000..f33f99034a --- /dev/null +++ b/contributors/softsimon.txt @@ -0,0 +1,3 @@ +I hereby accept the terms of the Contributor License Agreement in the CONTRIBUTING.md file of the mempool/mempool git repository as of January 25, 2022. + +Signed: softsimon diff --git a/contributors/starius.txt b/contributors/starius.txt new file mode 100644 index 0000000000..df9fdbe8d6 --- /dev/null +++ b/contributors/starius.txt @@ -0,0 +1,3 @@ +I hereby accept the terms of the Contributor License Agreement in the CONTRIBUTING.md file of the mempool/mempool git repository as of Oct 13, 2023. + +Signed starius diff --git a/contributors/svrgnty.txt b/contributors/svrgnty.txt new file mode 100644 index 0000000000..e25fd5690b --- /dev/null +++ b/contributors/svrgnty.txt @@ -0,0 +1,3 @@ +I hereby accept the terms of the Contributor License Agreement in the CONTRIBUTING.md file of the mempool/mempool git repository as of July 9, 2024. + +Signed: svrgnty \ No newline at end of file diff --git a/contributors/takuabonn.txt b/contributors/takuabonn.txt new file mode 100644 index 0000000000..331019e910 --- /dev/null +++ b/contributors/takuabonn.txt @@ -0,0 +1,3 @@ +I hereby accept the terms of the Contributor License Agreement in the CONTRIBUTING.md file of the mempool/mempool git repository as of December 13, 2023. + +Signed: takuabonn \ No newline at end of file diff --git a/contributors/vostrnad.txt b/contributors/vostrnad.txt new file mode 100644 index 0000000000..6b295c715d --- /dev/null +++ b/contributors/vostrnad.txt @@ -0,0 +1,3 @@ +I hereby accept the terms of the Contributor License Agreement in the CONTRIBUTING.md file of the mempool/mempool git repository as of January 25, 2022. + +Signed: vostrnad diff --git a/contributors/wiz.txt b/contributors/wiz.txt new file mode 100644 index 0000000000..a006b4e040 --- /dev/null +++ b/contributors/wiz.txt @@ -0,0 +1,3 @@ +I hereby accept the terms of the Contributor License Agreement in the CONTRIBUTING.md file of the mempool/mempool git repository as of January 25, 2022. + +Signed: wiz diff --git a/docker/README.md b/docker/README.md new file mode 100644 index 0000000000..ce1548e910 --- /dev/null +++ b/docker/README.md @@ -0,0 +1,437 @@ +# Docker Installation + +This directory contains the Dockerfiles used to build and release the official images, as well as a `docker-compose.yml` to configure environment variables and other settings. + +If you are looking to use these Docker images to deploy your own instance of Mempool, note that they only containerize Mempool's frontend and backend. You will still need to deploy and configure Bitcoin Core and an Electrum Server separately, along with any other utilities specific to your use case (e.g., a reverse proxy, etc). Such configuration is mostly beyond the scope of the Mempool project, so please only proceed if you know what you're doing. + +See a video guide of this installation method by k3tan [on BitcoinTV.com](https://bitcointv.com/w/8fpAx6rf5CQ16mMhospwjg). + +Jump to a section in this doc: +- [Configure with Bitcoin Core Only](#configure-with-bitcoin-core-only) +- [Configure with Bitcoin Core + Electrum Server](#configure-with-bitcoin-core--electrum-server) +- [Further Configuration](#further-configuration) + +## Configure with Bitcoin Core Only + +_Note: address lookups require an Electrum Server and will not work with this configuration. [Add an Electrum Server](#configure-with-bitcoin-core--electrum-server) to your backend for full functionality._ + +The default Docker configuration assumes you have the following configuration in your `bitcoin.conf` file: + +```ini +txindex=1 +server=1 +rpcuser=mempool +rpcpassword=mempool +``` + +If you want to use different credentials, specify them in the `docker-compose.yml` file: + +```yaml + api: + environment: + MEMPOOL_BACKEND: "none" + CORE_RPC_HOST: "172.27.0.1" + CORE_RPC_PORT: "8332" + CORE_RPC_USERNAME: "customuser" + CORE_RPC_PASSWORD: "custompassword" + CORE_RPC_TIMEOUT: "60000" +``` + +The IP address in the example above refers to Docker's default gateway IP address so that the container can hit the `bitcoind` instance running on the host machine. If your setup is different, update it accordingly. + +Make sure `bitcoind` is running and synced. + +Now, run: + +```bash +docker-compose up +``` + +Your Mempool instance should be running at http://localhost. The graphs will be populated as new transactions are detected. + +## Configure with Bitcoin Core + Electrum Server + +First, configure `bitcoind` as specified above, and make sure your Electrum Server is running and synced. See [this FAQ](https://mempool.space/docs/faq#address-lookup-issues) if you need help picking an Electrum Server implementation. + +Then, set the following variables in `docker-compose.yml` so Mempool can connect to your Electrum Server: + +```yaml + api: + environment: + MEMPOOL_BACKEND: "electrum" + ELECTRUM_HOST: "172.27.0.1" + ELECTRUM_PORT: "50002" + ELECTRUM_TLS_ENABLED: "false" +``` + +Eligible values for `MEMPOOL_BACKEND`: + - "electrum" if you're using [romanz/electrs](https://github.com/romanz/electrs) or [cculianu/Fulcrum](https://github.com/cculianu/Fulcrum) + - "esplora" if you're using [Blockstream/electrs](https://github.com/Blockstream/electrs) + - "none" if you're not using any Electrum Server + +Of course, if your Docker host IP address is different, update accordingly. + +With `bitcoind` and Electrum Server set up, run Mempool with: + +```bash +docker-compose up +``` + +## Further Configuration + +Optionally, you can override any other backend settings from `mempool-config.json`. + +Below we list all settings from `mempool-config.json` and the corresponding overrides you can make in the `api` > `environment` section of `docker-compose.yml`. + +
+ +`mempool-config.json`: +```json + "MEMPOOL": { + "NETWORK": "mainnet", + "BACKEND": "electrum", + "ENABLED": true, + "HTTP_PORT": 8999, + "SPAWN_CLUSTER_PROCS": 0, + "API_URL_PREFIX": "/api/v1/", + "POLL_RATE_MS": 2000, + "CACHE_DIR": "./cache", + "CLEAR_PROTECTION_MINUTES": 20, + "RECOMMENDED_FEE_PERCENTILE": 50, + "BLOCK_WEIGHT_UNITS": 4000000, + "INITIAL_BLOCKS_AMOUNT": 8, + "MEMPOOL_BLOCKS_AMOUNT": 8, + "BLOCKS_SUMMARIES_INDEXING": false, + "USE_SECOND_NODE_FOR_MINFEE": false, + "EXTERNAL_ASSETS": [], + "STDOUT_LOG_MIN_PRIORITY": "info", + "INDEXING_BLOCKS_AMOUNT": false, + "AUTOMATIC_POOLS_UPDATE": false, + "POOLS_JSON_URL": "https://raw.githubusercontent.com/mempool/mining-pools/master/pools-v2.json", + "POOLS_JSON_TREE_URL": "https://api.github.com/repos/mempool/mining-pools/git/trees/master", + "CPFP_INDEXING": false, + "MAX_BLOCKS_BULK_QUERY": 0, + "DISK_CACHE_BLOCK_INTERVAL": 6, + "PRICE_UPDATES_PER_HOUR": 1 + }, +``` + +Corresponding `docker-compose.yml` overrides: +```yaml + api: + environment: + MEMPOOL_NETWORK: "" + MEMPOOL_BACKEND: "" + BACKEND_HTTP_PORT: "" + MEMPOOL_SPAWN_CLUSTER_PROCS: "" + MEMPOOL_API_URL_PREFIX: "" + MEMPOOL_POLL_RATE_MS: "" + MEMPOOL_CACHE_DIR: "" + MEMPOOL_CLEAR_PROTECTION_MINUTES: "" + MEMPOOL_RECOMMENDED_FEE_PERCENTILE: "" + MEMPOOL_BLOCK_WEIGHT_UNITS: "" + MEMPOOL_INITIAL_BLOCKS_AMOUNT: "" + MEMPOOL_MEMPOOL_BLOCKS_AMOUNT: "" + MEMPOOL_BLOCKS_SUMMARIES_INDEXING: "" + MEMPOOL_USE_SECOND_NODE_FOR_MINFEE: "" + MEMPOOL_EXTERNAL_ASSETS: "" + MEMPOOL_STDOUT_LOG_MIN_PRIORITY: "" + MEMPOOL_INDEXING_BLOCKS_AMOUNT: "" + MEMPOOL_AUTOMATIC_POOLS_UPDATE: "" + MEMPOOL_POOLS_JSON_URL: "" + MEMPOOL_POOLS_JSON_TREE_URL: "" + MEMPOOL_CPFP_INDEXING: "" + MEMPOOL_MAX_BLOCKS_BULK_QUERY: "" + MEMPOOL_DISK_CACHE_BLOCK_INTERVAL: "" + MEMPOOL_PRICE_UPDATES_PER_HOUR: "" + ... +``` + +`CPFP_INDEXING` enables indexing CPFP (Child Pays For Parent) information for the last `INDEXING_BLOCKS_AMOUNT` blocks. + +
+ +`mempool-config.json`: +```json + "CORE_RPC": { + "HOST": "127.0.0.1", + "PORT": 8332, + "USERNAME": "mempool", + "PASSWORD": "mempool", + "TIMEOUT": 60000, + "COOKIE": false, + "COOKIE_PATH": "" + }, +``` + +Corresponding `docker-compose.yml` overrides: +```yaml + api: + environment: + CORE_RPC_HOST: "" + CORE_RPC_PORT: "" + CORE_RPC_USERNAME: "" + CORE_RPC_PASSWORD: "" + CORE_RPC_TIMEOUT: 60000 + CORE_RPC_COOKIE: false + CORE_RPC_COOKIE_PATH: "" + ... +``` + +
+ +`mempool-config.json`: +```json + "ELECTRUM": { + "HOST": "127.0.0.1", + "PORT": 50002, + "TLS_ENABLED": true + }, +``` + +Corresponding `docker-compose.yml` overrides: +```yaml + api: + environment: + ELECTRUM_HOST: "" + ELECTRUM_PORT: "" + ELECTRUM_TLS_ENABLED: "" + ... +``` + +
+ +`mempool-config.json`: +```json + "ESPLORA": { + "REST_API_URL": "http://127.0.0.1:3000", + "UNIX_SOCKET_PATH": "/tmp/esplora-socket", + "RETRY_UNIX_SOCKET_AFTER": 30000 + }, +``` + +Corresponding `docker-compose.yml` overrides: +```yaml + api: + environment: + ESPLORA_REST_API_URL: "" + ESPLORA_UNIX_SOCKET_PATH: "" + ESPLORA_RETRY_UNIX_SOCKET_AFTER: "" + ... +``` + +
+ +`mempool-config.json`: +```json + "SECOND_CORE_RPC": { + "HOST": "127.0.0.1", + "PORT": 8332, + "USERNAME": "mempool", + "PASSWORD": "mempool", + "TIMEOUT": 60000, + "COOKIE": false, + "COOKIE_PATH": "" + }, +``` + +Corresponding `docker-compose.yml` overrides: +```yaml + api: + environment: + SECOND_CORE_RPC_HOST: "" + SECOND_CORE_RPC_PORT: "" + SECOND_CORE_RPC_USERNAME: "" + SECOND_CORE_RPC_PASSWORD: "" + SECOND_CORE_RPC_TIMEOUT: "" + SECOND_CORE_RPC_COOKIE: false + SECOND_CORE_RPC_COOKIE_PATH: "" + ... +``` + +
+ +`mempool-config.json`: +```json + "DATABASE": { + "ENABLED": true, + "HOST": "127.0.0.1", + "PORT": 3306, + "DATABASE": "mempool", + "USERNAME": "mempool", + "PASSWORD": "mempool" + }, +``` + +Corresponding `docker-compose.yml` overrides: +```yaml + api: + environment: + DATABASE_ENABLED: "" + DATABASE_HOST: "" + DATABASE_PORT: "" + DATABASE_DATABASE: "" + DATABASE_USERNAME: "" + DATABASE_PASSWORD: "" + DATABASE_TIMEOUT: "" + ... +``` + +
+ +`mempool-config.json`: +```json + "SYSLOG": { + "ENABLED": true, + "HOST": "127.0.0.1", + "PORT": 514, + "MIN_PRIORITY": "info", + "FACILITY": "local7" + }, +``` + +Corresponding `docker-compose.yml` overrides: +```yaml + api: + environment: + SYSLOG_ENABLED: "" + SYSLOG_HOST: "" + SYSLOG_PORT: "" + SYSLOG_MIN_PRIORITY: "" + SYSLOG_FACILITY: "" + ... +``` + +
+ +`mempool-config.json`: +```json + "STATISTICS": { + "ENABLED": true, + "TX_PER_SECOND_SAMPLE_PERIOD": 150 + }, +``` + +Corresponding `docker-compose.yml` overrides: +```yaml + api: + environment: + STATISTICS_ENABLED: "" + STATISTICS_TX_PER_SECOND_SAMPLE_PERIOD: "" + ... +``` + +
+ +`mempool-config.json`: +```json + "SOCKS5PROXY": { + "ENABLED": false, + "HOST": "127.0.0.1", + "PORT": "9050", + "USERNAME": "", + "PASSWORD": "" + } +``` + +Corresponding `docker-compose.yml` overrides: +```yaml + api: + environment: + SOCKS5PROXY_ENABLED: "" + SOCKS5PROXY_HOST: "" + SOCKS5PROXY_PORT: "" + SOCKS5PROXY_USERNAME: "" + SOCKS5PROXY_PASSWORD: "" + ... +``` + +
+ +`mempool-config.json`: +```json + "LIGHTNING": { + "ENABLED": false + "BACKEND": "lnd" + "TOPOLOGY_FOLDER": "" + "STATS_REFRESH_INTERVAL": 600 + "GRAPH_REFRESH_INTERVAL": 600 + "LOGGER_UPDATE_INTERVAL": 30 + } +``` + +Corresponding `docker-compose.yml` overrides: +```yaml + api: + environment: + LIGHTNING_ENABLED: false + LIGHTNING_BACKEND: "lnd" + LIGHTNING_TOPOLOGY_FOLDER: "" + LIGHTNING_STATS_REFRESH_INTERVAL: 600 + LIGHTNING_GRAPH_REFRESH_INTERVAL: 600 + LIGHTNING_LOGGER_UPDATE_INTERVAL: 30 + ... +``` + +
+ +`mempool-config.json`: +```json + "LND": { + "TLS_CERT_PATH": "" + "MACAROON_PATH": "" + "REST_API_URL": "https://localhost:8080" + "TIMEOUT": 10000 + } +``` + +Corresponding `docker-compose.yml` overrides: +```yaml + api: + environment: + LND_TLS_CERT_PATH: "" + LND_MACAROON_PATH: "" + LND_REST_API_URL: "https://localhost:8080" + LND_TIMEOUT: 10000 + ... +``` + +
+ +`mempool-config.json`: +```json + "CLIGHTNING": { + "SOCKET": "" + } +``` + +Corresponding `docker-compose.yml` overrides: +```yaml + api: + environment: + CLIGHTNING_SOCKET: "" + ... +``` + +
+ +`mempool-config.json`: +```json + "MAXMIND": { + "ENABLED": true, + "GEOLITE2_CITY": "/usr/local/share/GeoIP/GeoLite2-City.mmdb", + "GEOLITE2_ASN": "/usr/local/share/GeoIP/GeoLite2-ASN.mmdb", + "GEOIP2_ISP": "/usr/local/share/GeoIP/GeoIP2-ISP.mmdb" + } +``` + +Corresponding `docker-compose.yml` overrides: +```yaml + api: + environment: + MAXMIND_ENABLED: true, + MAXMIND_GEOLITE2_CITY: "/backend/GeoIP/GeoLite2-City.mmdb", + MAXMIND_GEOLITE2_ASN": "/backend/GeoIP/GeoLite2-ASN.mmdb", + MAXMIND_GEOIP2_ISP": "/backend/GeoIP/GeoIP2-ISP.mmdb" + ... +``` diff --git a/docker/backend/Dockerfile b/docker/backend/Dockerfile new file mode 100644 index 0000000000..60d663f206 --- /dev/null +++ b/docker/backend/Dockerfile @@ -0,0 +1,40 @@ +FROM node:20.15.0-buster-slim AS builder + +ARG commitHash +ENV MEMPOOL_COMMIT_HASH=${commitHash} + +WORKDIR /build +COPY . . + +RUN apt-get update +RUN apt-get install -y build-essential python3 pkg-config curl ca-certificates + +# Install Rust via rustup +RUN CPU_ARCH=$(uname -m); if [ "$CPU_ARCH" = "armv7l" ]; then c_rehash; fi +#RUN curl https://sh.rustup.rs -sSf | sh -s -- -y --default-toolchain stable +#Workaround to run on github actions from https://github.com/rust-lang/rustup/issues/2700#issuecomment-1367488985 +RUN curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sed 's#/proc/self/exe#\/bin\/sh#g' | sh -s -- -y --default-toolchain stable +ENV PATH="/root/.cargo/bin:$PATH" + +COPY --from=backend . . +COPY --from=rustgbt . ../rust/ +ENV FD=/build/rust-gbt +RUN npm install --omit=dev --omit=optional + +WORKDIR /build +RUN npm run package + +FROM node:20.15.0-buster-slim + +WORKDIR /backend + +RUN chown 1000:1000 ./ +COPY --from=builder --chown=1000:1000 /build/package ./package/ +COPY --from=builder --chown=1000:1000 /build/GeoIP ./GeoIP/ +COPY --from=builder --chown=1000:1000 /build/mempool-config.json /build/start.sh /build/wait-for-it.sh ./ + +USER 1000 + +EXPOSE 8999 + +CMD ["/backend/start.sh"] diff --git a/docker/backend/mempool-config.json b/docker/backend/mempool-config.json new file mode 100644 index 0000000000..79cd146448 --- /dev/null +++ b/docker/backend/mempool-config.json @@ -0,0 +1,159 @@ +{ + "MEMPOOL": { + "NETWORK": "__MEMPOOL_NETWORK__", + "BACKEND": "__MEMPOOL_BACKEND__", + "ENABLED": __MEMPOOL_ENABLED__, + "OFFICIAL": __MEMPOOL_OFFICIAL__, + "HTTP_PORT": __MEMPOOL_HTTP_PORT__, + "SPAWN_CLUSTER_PROCS": __MEMPOOL_SPAWN_CLUSTER_PROCS__, + "UNIX_SOCKET_PATH": "__MEMPOOL_UNIX_SOCKET_PATH__", + "API_URL_PREFIX": "__MEMPOOL_API_URL_PREFIX__", + "POLL_RATE_MS": __MEMPOOL_POLL_RATE_MS__, + "CACHE_DIR": "__MEMPOOL_CACHE_DIR__", + "CACHE_ENABLED": __MEMPOOL_CACHE_ENABLED__, + "CLEAR_PROTECTION_MINUTES": __MEMPOOL_CLEAR_PROTECTION_MINUTES__, + "RECOMMENDED_FEE_PERCENTILE": __MEMPOOL_RECOMMENDED_FEE_PERCENTILE__, + "BLOCK_WEIGHT_UNITS": __MEMPOOL_BLOCK_WEIGHT_UNITS__, + "INITIAL_BLOCKS_AMOUNT": __MEMPOOL_INITIAL_BLOCKS_AMOUNT__, + "MEMPOOL_BLOCKS_AMOUNT": __MEMPOOL_MEMPOOL_BLOCKS_AMOUNT__, + "USE_SECOND_NODE_FOR_MINFEE": __MEMPOOL_USE_SECOND_NODE_FOR_MINFEE__, + "EXTERNAL_ASSETS": __MEMPOOL_EXTERNAL_ASSETS__, + "EXTERNAL_MAX_RETRY": __MEMPOOL_EXTERNAL_MAX_RETRY__, + "EXTERNAL_RETRY_INTERVAL": __MEMPOOL_EXTERNAL_RETRY_INTERVAL__, + "USER_AGENT": "__MEMPOOL_USER_AGENT__", + "STDOUT_LOG_MIN_PRIORITY": "__MEMPOOL_STDOUT_LOG_MIN_PRIORITY__", + "INDEXING_BLOCKS_AMOUNT": __MEMPOOL_INDEXING_BLOCKS_AMOUNT__, + "BLOCKS_SUMMARIES_INDEXING": __MEMPOOL_BLOCKS_SUMMARIES_INDEXING__, + "GOGGLES_INDEXING": __MEMPOOL_GOGGLES_INDEXING__, + "AUTOMATIC_POOLS_UPDATE": __MEMPOOL_AUTOMATIC_POOLS_UPDATE__, + "AUDIT": __MEMPOOL_AUDIT__, + "RUST_GBT": __MEMPOOL_RUST_GBT__, + "LIMIT_GBT": __MEMPOOL_LIMIT_GBT__, + "CPFP_INDEXING": __MEMPOOL_CPFP_INDEXING__, + "MAX_BLOCKS_BULK_QUERY": __MEMPOOL_MAX_BLOCKS_BULK_QUERY__, + "DISK_CACHE_BLOCK_INTERVAL": __MEMPOOL_DISK_CACHE_BLOCK_INTERVAL__, + "MAX_PUSH_TX_SIZE_WEIGHT": __MEMPOOL_MAX_PUSH_TX_SIZE_WEIGHT__, + "ALLOW_UNREACHABLE": __MEMPOOL_ALLOW_UNREACHABLE__, + "POOLS_JSON_TREE_URL": "__MEMPOOL_POOLS_JSON_TREE_URL__", + "POOLS_JSON_URL": "__MEMPOOL_POOLS_JSON_URL__", + "PRICE_UPDATES_PER_HOUR": __MEMPOOL_PRICE_UPDATES_PER_HOUR__, + "MAX_TRACKED_ADDRESSES": __MEMPOOL_MAX_TRACKED_ADDRESSES__ + }, + "CORE_RPC": { + "HOST": "__CORE_RPC_HOST__", + "PORT": __CORE_RPC_PORT__, + "USERNAME": "__CORE_RPC_USERNAME__", + "PASSWORD": "__CORE_RPC_PASSWORD__", + "TIMEOUT": __CORE_RPC_TIMEOUT__, + "COOKIE": __CORE_RPC_COOKIE__, + "COOKIE_PATH": "__CORE_RPC_COOKIE_PATH__" + }, + "ELECTRUM": { + "HOST": "__ELECTRUM_HOST__", + "PORT": __ELECTRUM_PORT__, + "TLS_ENABLED": __ELECTRUM_TLS_ENABLED__ + }, + "ESPLORA": { + "REST_API_URL": "__ESPLORA_REST_API_URL__", + "UNIX_SOCKET_PATH": "__ESPLORA_UNIX_SOCKET_PATH__", + "BATCH_QUERY_BASE_SIZE": __ESPLORA_BATCH_QUERY_BASE_SIZE__, + "RETRY_UNIX_SOCKET_AFTER": __ESPLORA_RETRY_UNIX_SOCKET_AFTER__, + "REQUEST_TIMEOUT": __ESPLORA_REQUEST_TIMEOUT__, + "FALLBACK_TIMEOUT": __ESPLORA_FALLBACK_TIMEOUT__, + "FALLBACK": __ESPLORA_FALLBACK__, + "MAX_BEHIND_TIP": __ESPLORA_MAX_BEHIND_TIP__ + }, + "SECOND_CORE_RPC": { + "HOST": "__SECOND_CORE_RPC_HOST__", + "PORT": __SECOND_CORE_RPC_PORT__, + "USERNAME": "__SECOND_CORE_RPC_USERNAME__", + "PASSWORD": "__SECOND_CORE_RPC_PASSWORD__", + "TIMEOUT": __SECOND_CORE_RPC_TIMEOUT__, + "COOKIE": __SECOND_CORE_RPC_COOKIE__, + "COOKIE_PATH": "__SECOND_CORE_RPC_COOKIE_PATH__" + }, + "DATABASE": { + "ENABLED": __DATABASE_ENABLED__, + "HOST": "__DATABASE_HOST__", + "SOCKET": "__DATABASE_SOCKET__", + "PORT": __DATABASE_PORT__, + "DATABASE": "__DATABASE_DATABASE__", + "USERNAME": "__DATABASE_USERNAME__", + "PASSWORD": "__DATABASE_PASSWORD__", + "TIMEOUT": __DATABASE_TIMEOUT__, + "PID_DIR": "__DATABASE_PID_DIR__", + "POOL_SIZE": __DATABASE_POOL_SIZE__ + }, + "SYSLOG": { + "ENABLED": __SYSLOG_ENABLED__, + "HOST": "__SYSLOG_HOST__", + "PORT": __SYSLOG_PORT__, + "MIN_PRIORITY": "__SYSLOG_MIN_PRIORITY__", + "FACILITY": "__SYSLOG_FACILITY__" + }, + "STATISTICS": { + "ENABLED": __STATISTICS_ENABLED__, + "TX_PER_SECOND_SAMPLE_PERIOD": __STATISTICS_TX_PER_SECOND_SAMPLE_PERIOD__ + }, + "LIGHTNING": { + "ENABLED": __LIGHTNING_ENABLED__, + "BACKEND": "__LIGHTNING_BACKEND__", + "STATS_REFRESH_INTERVAL": __LIGHTNING_STATS_REFRESH_INTERVAL__, + "GRAPH_REFRESH_INTERVAL": __LIGHTNING_GRAPH_REFRESH_INTERVAL__, + "LOGGER_UPDATE_INTERVAL": __LIGHTNING_LOGGER_UPDATE_INTERVAL__, + "TOPOLOGY_FOLDER": "__LIGHTNING_TOPOLOGY_FOLDER__", + "FORENSICS_INTERVAL": __LIGHTNING_FORENSICS_INTERVAL__, + "FORENSICS_RATE_LIMIT": __LIGHTNING_FORENSICS_RATE_LIMIT__ + }, + "LND": { + "TLS_CERT_PATH": "__LND_TLS_CERT_PATH__", + "MACAROON_PATH": "__LND_MACAROON_PATH__", + "REST_API_URL": "__LND_REST_API_URL__", + "TIMEOUT": __LND_TIMEOUT__ + }, + "CLIGHTNING": { + "SOCKET": "__CLIGHTNING_SOCKET__" + }, + "SOCKS5PROXY": { + "ENABLED": __SOCKS5PROXY_ENABLED__, + "USE_ONION": __SOCKS5PROXY_USE_ONION__, + "HOST": "__SOCKS5PROXY_HOST__", + "PORT": "__SOCKS5PROXY_PORT__", + "USERNAME": "__SOCKS5PROXY_USERNAME__", + "PASSWORD": "__SOCKS5PROXY_PASSWORD__" + }, + "EXTERNAL_DATA_SERVER": { + "MEMPOOL_API": "__EXTERNAL_DATA_SERVER_MEMPOOL_API__", + "MEMPOOL_ONION": "__EXTERNAL_DATA_SERVER_MEMPOOL_ONION__", + "LIQUID_API": "__EXTERNAL_DATA_SERVER_LIQUID_API__", + "LIQUID_ONION": "__EXTERNAL_DATA_SERVER_LIQUID_ONION__" + }, + "MAXMIND": { + "ENABLED": __MAXMIND_ENABLED__, + "GEOLITE2_CITY": "__MAXMIND_GEOLITE2_CITY__", + "GEOLITE2_ASN": "__MAXMIND_GEOLITE2_ASN__", + "GEOIP2_ISP": "__MAXMIND_GEOIP2_ISP__" + }, + "REPLICATION": { + "ENABLED": __REPLICATION_ENABLED__, + "AUDIT": __REPLICATION_AUDIT__, + "AUDIT_START_HEIGHT": __REPLICATION_AUDIT_START_HEIGHT__, + "STATISTICS": __REPLICATION_STATISTICS__, + "STATISTICS_START_TIME": __REPLICATION_STATISTICS_START_TIME__, + "SERVERS": __REPLICATION_SERVERS__ + }, + "MEMPOOL_SERVICES": { + "API": "__MEMPOOL_SERVICES_API__", + "ACCELERATIONS": __MEMPOOL_SERVICES_ACCELERATIONS__ + }, + "REDIS": { + "ENABLED": __REDIS_ENABLED__, + "UNIX_SOCKET_PATH": "__REDIS_UNIX_SOCKET_PATH__", + "BATCH_QUERY_BASE_SIZE": __REDIS_BATCH_QUERY_BASE_SIZE__ + }, + "FIAT_PRICE": { + "ENABLED": __FIAT_PRICE_ENABLED__, + "PAID": __FIAT_PRICE_PAID__, + "API_KEY": "__FIAT_PRICE_API_KEY__" + } +} diff --git a/docker/backend/start.sh b/docker/backend/start.sh new file mode 100755 index 0000000000..daab09990e --- /dev/null +++ b/docker/backend/start.sh @@ -0,0 +1,309 @@ +#!/bin/sh + +# MEMPOOL +__MEMPOOL_NETWORK__=${MEMPOOL_NETWORK:=mainnet} +__MEMPOOL_BACKEND__=${MEMPOOL_BACKEND:=electrum} +__MEMPOOL_ENABLED__=${MEMPOOL_ENABLED:=true} +__MEMPOOL_OFFICIAL__=${MEMPOOL_OFFICIAL:=false} +__MEMPOOL_HTTP_PORT__=${BACKEND_HTTP_PORT:=8999} +__MEMPOOL_SPAWN_CLUSTER_PROCS__=${MEMPOOL_SPAWN_CLUSTER_PROCS:=0} +__MEMPOOL_UNIX_SOCKET_PATH__=${MEMPOOL_UNIX_SOCKET_PATH:=""} +__MEMPOOL_API_URL_PREFIX__=${MEMPOOL_API_URL_PREFIX:=/api/v1/} +__MEMPOOL_POLL_RATE_MS__=${MEMPOOL_POLL_RATE_MS:=2000} +__MEMPOOL_CACHE_DIR__=${MEMPOOL_CACHE_DIR:=./cache} +__MEMPOOL_CACHE_ENABLED__=${MEMPOOL_CACHE_ENABLED:=true} +__MEMPOOL_CLEAR_PROTECTION_MINUTES__=${MEMPOOL_CLEAR_PROTECTION_MINUTES:=20} +__MEMPOOL_RECOMMENDED_FEE_PERCENTILE__=${MEMPOOL_RECOMMENDED_FEE_PERCENTILE:=50} +__MEMPOOL_BLOCK_WEIGHT_UNITS__=${MEMPOOL_BLOCK_WEIGHT_UNITS:=4000000} +__MEMPOOL_INITIAL_BLOCKS_AMOUNT__=${MEMPOOL_INITIAL_BLOCKS_AMOUNT:=8} +__MEMPOOL_MEMPOOL_BLOCKS_AMOUNT__=${MEMPOOL_MEMPOOL_BLOCKS_AMOUNT:=8} +__MEMPOOL_INDEXING_BLOCKS_AMOUNT__=${MEMPOOL_INDEXING_BLOCKS_AMOUNT:=11000} +__MEMPOOL_BLOCKS_SUMMARIES_INDEXING__=${MEMPOOL_BLOCKS_SUMMARIES_INDEXING:=false} +__MEMPOOL_GOGGLES_INDEXING__=${MEMPOOL_GOGGLES_INDEXING:=false} +__MEMPOOL_USE_SECOND_NODE_FOR_MINFEE__=${MEMPOOL_USE_SECOND_NODE_FOR_MINFEE:=false} +__MEMPOOL_EXTERNAL_ASSETS__=${MEMPOOL_EXTERNAL_ASSETS:=[]} +__MEMPOOL_EXTERNAL_MAX_RETRY__=${MEMPOOL_EXTERNAL_MAX_RETRY:=1} +__MEMPOOL_EXTERNAL_RETRY_INTERVAL__=${MEMPOOL_EXTERNAL_RETRY_INTERVAL:=0} +__MEMPOOL_USER_AGENT__=${MEMPOOL_USER_AGENT:=mempool} +__MEMPOOL_STDOUT_LOG_MIN_PRIORITY__=${MEMPOOL_STDOUT_LOG_MIN_PRIORITY:=info} +__MEMPOOL_AUTOMATIC_POOLS_UPDATE__=${MEMPOOL_AUTOMATIC_POOLS_UPDATE:=false} +__MEMPOOL_POOLS_JSON_URL__=${MEMPOOL_POOLS_JSON_URL:=https://raw.githubusercontent.com/mempool/mining-pools/master/pools-v2.json} +__MEMPOOL_POOLS_JSON_TREE_URL__=${MEMPOOL_POOLS_JSON_TREE_URL:=https://api.github.com/repos/mempool/mining-pools/git/trees/master} +__MEMPOOL_AUDIT__=${MEMPOOL_AUDIT:=false} +__MEMPOOL_RUST_GBT__=${MEMPOOL_RUST_GBT:=false} +__MEMPOOL_LIMIT_GBT__=${MEMPOOL_LIMIT_GBT:=false} +__MEMPOOL_CPFP_INDEXING__=${MEMPOOL_CPFP_INDEXING:=false} +__MEMPOOL_MAX_BLOCKS_BULK_QUERY__=${MEMPOOL_MAX_BLOCKS_BULK_QUERY:=0} +__MEMPOOL_DISK_CACHE_BLOCK_INTERVAL__=${MEMPOOL_DISK_CACHE_BLOCK_INTERVAL:=6} +__MEMPOOL_MAX_PUSH_TX_SIZE_WEIGHT__=${MEMPOOL_MAX_PUSH_TX_SIZE_WEIGHT:=4000000} +__MEMPOOL_ALLOW_UNREACHABLE__=${MEMPOOL_ALLOW_UNREACHABLE:=true} +__MEMPOOL_PRICE_UPDATES_PER_HOUR__=${MEMPOOL_PRICE_UPDATES_PER_HOUR:=1} +__MEMPOOL_MAX_TRACKED_ADDRESSES__=${MEMPOOL_MAX_TRACKED_ADDRESSES:=1} + +# CORE_RPC +__CORE_RPC_HOST__=${CORE_RPC_HOST:=127.0.0.1} +__CORE_RPC_PORT__=${CORE_RPC_PORT:=8332} +__CORE_RPC_USERNAME__=${CORE_RPC_USERNAME:=mempool} +__CORE_RPC_PASSWORD__=${CORE_RPC_PASSWORD:=mempool} +__CORE_RPC_TIMEOUT__=${CORE_RPC_TIMEOUT:=60000} +__CORE_RPC_COOKIE__=${CORE_RPC_COOKIE:=false} +__CORE_RPC_COOKIE_PATH__=${CORE_RPC_COOKIE_PATH:=""} + +# ELECTRUM +__ELECTRUM_HOST__=${ELECTRUM_HOST:=127.0.0.1} +__ELECTRUM_PORT__=${ELECTRUM_PORT:=50002} +__ELECTRUM_TLS_ENABLED__=${ELECTRUM_TLS_ENABLED:=false} + +# ESPLORA +__ESPLORA_REST_API_URL__=${ESPLORA_REST_API_URL:=http://127.0.0.1:3000} +__ESPLORA_UNIX_SOCKET_PATH__=${ESPLORA_UNIX_SOCKET_PATH:=""} +__ESPLORA_BATCH_QUERY_BASE_SIZE__=${ESPLORA_BATCH_QUERY_BASE_SIZE:=1000} +__ESPLORA_RETRY_UNIX_SOCKET_AFTER__=${ESPLORA_RETRY_UNIX_SOCKET_AFTER:=30000} +__ESPLORA_REQUEST_TIMEOUT__=${ESPLORA_REQUEST_TIMEOUT:=5000} +__ESPLORA_FALLBACK_TIMEOUT__=${ESPLORA_FALLBACK_TIMEOUT:=5000} +__ESPLORA_FALLBACK__=${ESPLORA_FALLBACK:=[]} +__ESPLORA_MAX_BEHIND_TIP__=${ESPLORA_MAX_BEHIND_TIP:=2} + +# SECOND_CORE_RPC +__SECOND_CORE_RPC_HOST__=${SECOND_CORE_RPC_HOST:=127.0.0.1} +__SECOND_CORE_RPC_PORT__=${SECOND_CORE_RPC_PORT:=8332} +__SECOND_CORE_RPC_USERNAME__=${SECOND_CORE_RPC_USERNAME:=mempool} +__SECOND_CORE_RPC_PASSWORD__=${SECOND_CORE_RPC_PASSWORD:=mempool} +__SECOND_CORE_RPC_TIMEOUT__=${SECOND_CORE_RPC_TIMEOUT:=60000} +__SECOND_CORE_RPC_COOKIE__=${SECOND_CORE_RPC_COOKIE:=false} +__SECOND_CORE_RPC_COOKIE_PATH__=${SECOND_CORE_RPC_COOKIE_PATH:=""} + +# DATABASE +__DATABASE_ENABLED__=${DATABASE_ENABLED:=true} +__DATABASE_HOST__=${DATABASE_HOST:=127.0.0.1} +__DATABASE_SOCKET__=${DATABASE_SOCKET:=""} +__DATABASE_PORT__=${DATABASE_PORT:=3306} +__DATABASE_DATABASE__=${DATABASE_DATABASE:=mempool} +__DATABASE_USERNAME__=${DATABASE_USERNAME:=mempool} +__DATABASE_PASSWORD__=${DATABASE_PASSWORD:=mempool} +__DATABASE_TIMEOUT__=${DATABASE_TIMEOUT:=180000} +__DATABASE_PID_DIR__=${DATABASE_PID_DIR:=""} +__DATABASE_POOL_SIZE__=${DATABASE_POOL_SIZE:=100} + +# SYSLOG +__SYSLOG_ENABLED__=${SYSLOG_ENABLED:=false} +__SYSLOG_HOST__=${SYSLOG_HOST:=127.0.0.1} +__SYSLOG_PORT__=${SYSLOG_PORT:=514} +__SYSLOG_MIN_PRIORITY__=${SYSLOG_MIN_PRIORITY:=info} +__SYSLOG_FACILITY__=${SYSLOG_FACILITY:=local7} + +# STATISTICS +__STATISTICS_ENABLED__=${STATISTICS_ENABLED:=true} +__STATISTICS_TX_PER_SECOND_SAMPLE_PERIOD__=${STATISTICS_TX_PER_SECOND_SAMPLE_PERIOD:=150} + +# SOCKS5PROXY +__SOCKS5PROXY_ENABLED__=${SOCKS5PROXY_ENABLED:=false} +__SOCKS5PROXY_USE_ONION__=${SOCKS5PROXY_USE_ONION:=true} +__SOCKS5PROXY_HOST__=${SOCKS5PROXY_HOST:=localhost} +__SOCKS5PROXY_PORT__=${SOCKS5PROXY_PORT:=9050} +__SOCKS5PROXY_USERNAME__=${SOCKS5PROXY_USERNAME:=""} +__SOCKS5PROXY_PASSWORD__=${SOCKS5PROXY_PASSWORD:=""} + +# EXTERNAL_DATA_SERVER +__EXTERNAL_DATA_SERVER_MEMPOOL_API__=${EXTERNAL_DATA_SERVER_MEMPOOL_API:=https://mempool.space/api/v1} +__EXTERNAL_DATA_SERVER_MEMPOOL_ONION__=${EXTERNAL_DATA_SERVER_MEMPOOL_ONION:=http://mempoolhqx4isw62xs7abwphsq7ldayuidyx2v2oethdhhj6mlo2r6ad.onion/api/v1} +__EXTERNAL_DATA_SERVER_LIQUID_API__=${EXTERNAL_DATA_SERVER_LIQUID_API:=https://liquid.network/api/v1} +__EXTERNAL_DATA_SERVER_LIQUID_ONION__=${EXTERNAL_DATA_SERVER_LIQUID_ONION:=http://liquidmom47f6s3m53ebfxn47p76a6tlnxib3wp6deux7wuzotdr6cyd.onion/api/v1} + +# LIGHTNING +__LIGHTNING_ENABLED__=${LIGHTNING_ENABLED:=false} +__LIGHTNING_BACKEND__=${LIGHTNING_BACKEND:="lnd"} +__LIGHTNING_TOPOLOGY_FOLDER__=${LIGHTNING_TOPOLOGY_FOLDER:=""} +__LIGHTNING_STATS_REFRESH_INTERVAL__=${LIGHTNING_STATS_REFRESH_INTERVAL:=600} +__LIGHTNING_GRAPH_REFRESH_INTERVAL__=${LIGHTNING_GRAPH_REFRESH_INTERVAL:=600} +__LIGHTNING_LOGGER_UPDATE_INTERVAL__=${LIGHTNING_LOGGER_UPDATE_INTERVAL:=30} +__LIGHTNING_FORENSICS_INTERVAL__=${LIGHTNING_FORENSICS_INTERVAL:=43200} +__LIGHTNING_FORENSICS_RATE_LIMIT__=${LIGHTNING_FORENSICS_RATE_LIMIT:=20} + +# LND +__LND_TLS_CERT_PATH__=${LND_TLS_CERT_PATH:=""} +__LND_MACAROON_PATH__=${LND_MACAROON_PATH:=""} +__LND_REST_API_URL__=${LND_REST_API_URL:="https://localhost:8080"} +__LND_TIMEOUT__=${LND_TIMEOUT:=10000} + +# CLN +__CLIGHTNING_SOCKET__=${CLIGHTNING_SOCKET:=""} + +# MAXMIND +__MAXMIND_ENABLED__=${MAXMIND_ENABLED:=true} +__MAXMIND_GEOLITE2_CITY__=${MAXMIND_GEOLITE2_CITY:="/backend/GeoIP/GeoLite2-City.mmdb"} +__MAXMIND_GEOLITE2_ASN__=${MAXMIND_GEOLITE2_ASN:="/backend/GeoIP/GeoLite2-ASN.mmdb"} +__MAXMIND_GEOIP2_ISP__=${MAXMIND_GEOIP2_ISP:=""} + +# REPLICATION +__REPLICATION_ENABLED__=${REPLICATION_ENABLED:=false} +__REPLICATION_AUDIT__=${REPLICATION_AUDIT:=false} +__REPLICATION_AUDIT_START_HEIGHT__=${REPLICATION_AUDIT_START_HEIGHT:=774000} +__REPLICATION_STATISTICS__=${REPLICATION_STATISTICS:=false} +__REPLICATION_STATISTICS_START_TIME__=${REPLICATION_STATISTICS_START_TIME:=1481932800} +__REPLICATION_SERVERS__=${REPLICATION_SERVERS:=[]} + +# MEMPOOL_SERVICES +__MEMPOOL_SERVICES_API__=${MEMPOOL_SERVICES_API:=""} +__MEMPOOL_SERVICES_ACCELERATIONS__=${MEMPOOL_SERVICES_ACCELERATIONS:=false} + +# REDIS +__REDIS_ENABLED__=${REDIS_ENABLED:=false} +__REDIS_UNIX_SOCKET_PATH__=${REDIS_UNIX_SOCKET_PATH:=""} +__REDIS_BATCH_QUERY_BASE_SIZE__=${REDIS_BATCH_QUERY_BASE_SIZE:=5000} + +# FIAT_PRICE +__FIAT_PRICE_ENABLED__=${FIAT_PRICE_ENABLED:=true} +__FIAT_PRICE_PAID__=${FIAT_PRICE_PAID:=false} +__FIAT_PRICE_API_KEY__=${FIAT_PRICE_API_KEY:=""} + +mkdir -p "${__MEMPOOL_CACHE_DIR__}" + +sed -i "s!__MEMPOOL_NETWORK__!${__MEMPOOL_NETWORK__}!g" mempool-config.json +sed -i "s!__MEMPOOL_BACKEND__!${__MEMPOOL_BACKEND__}!g" mempool-config.json +sed -i "s!__MEMPOOL_ENABLED__!${__MEMPOOL_ENABLED__}!g" mempool-config.json +sed -i "s!__MEMPOOL_OFFICIAL__!${__MEMPOOL_OFFICIAL__}!g" mempool-config.json +sed -i "s!__MEMPOOL_HTTP_PORT__!${__MEMPOOL_HTTP_PORT__}!g" mempool-config.json +sed -i "s!__MEMPOOL_SPAWN_CLUSTER_PROCS__!${__MEMPOOL_SPAWN_CLUSTER_PROCS__}!g" mempool-config.json +sed -i "s!__MEMPOOL_UNIX_SOCKET_PATH__!${__MEMPOOL_UNIX_SOCKET_PATH__}!g" mempool-config.json +sed -i "s!__MEMPOOL_API_URL_PREFIX__!${__MEMPOOL_API_URL_PREFIX__}!g" mempool-config.json +sed -i "s!__MEMPOOL_POLL_RATE_MS__!${__MEMPOOL_POLL_RATE_MS__}!g" mempool-config.json +sed -i "s!__MEMPOOL_CACHE_DIR__!${__MEMPOOL_CACHE_DIR__}!g" mempool-config.json +sed -i "s!__MEMPOOL_CACHE_ENABLED__!${__MEMPOOL_CACHE_ENABLED__}!g" mempool-config.json +sed -i "s!__MEMPOOL_CLEAR_PROTECTION_MINUTES__!${__MEMPOOL_CLEAR_PROTECTION_MINUTES__}!g" mempool-config.json +sed -i "s!__MEMPOOL_RECOMMENDED_FEE_PERCENTILE__!${__MEMPOOL_RECOMMENDED_FEE_PERCENTILE__}!g" mempool-config.json +sed -i "s!__MEMPOOL_BLOCK_WEIGHT_UNITS__!${__MEMPOOL_BLOCK_WEIGHT_UNITS__}!g" mempool-config.json +sed -i "s!__MEMPOOL_INITIAL_BLOCKS_AMOUNT__!${__MEMPOOL_INITIAL_BLOCKS_AMOUNT__}!g" mempool-config.json +sed -i "s!__MEMPOOL_MEMPOOL_BLOCKS_AMOUNT__!${__MEMPOOL_MEMPOOL_BLOCKS_AMOUNT__}!g" mempool-config.json +sed -i "s!__MEMPOOL_INDEXING_BLOCKS_AMOUNT__!${__MEMPOOL_INDEXING_BLOCKS_AMOUNT__}!g" mempool-config.json +sed -i "s!__MEMPOOL_BLOCKS_SUMMARIES_INDEXING__!${__MEMPOOL_BLOCKS_SUMMARIES_INDEXING__}!g" mempool-config.json +sed -i "s!__MEMPOOL_GOGGLES_INDEXING__!${__MEMPOOL_GOGGLES_INDEXING__}!g" mempool-config.json +sed -i "s!__MEMPOOL_USE_SECOND_NODE_FOR_MINFEE__!${__MEMPOOL_USE_SECOND_NODE_FOR_MINFEE__}!g" mempool-config.json +sed -i "s!__MEMPOOL_EXTERNAL_ASSETS__!${__MEMPOOL_EXTERNAL_ASSETS__}!g" mempool-config.json +sed -i "s!__MEMPOOL_EXTERNAL_MAX_RETRY__!${__MEMPOOL_EXTERNAL_MAX_RETRY__}!g" mempool-config.json +sed -i "s!__MEMPOOL_EXTERNAL_RETRY_INTERVAL__!${__MEMPOOL_EXTERNAL_RETRY_INTERVAL__}!g" mempool-config.json +sed -i "s!__MEMPOOL_USER_AGENT__!${__MEMPOOL_USER_AGENT__}!g" mempool-config.json +sed -i "s!__MEMPOOL_STDOUT_LOG_MIN_PRIORITY__!${__MEMPOOL_STDOUT_LOG_MIN_PRIORITY__}!g" mempool-config.json +sed -i "s!__MEMPOOL_AUTOMATIC_POOLS_UPDATE__!${__MEMPOOL_AUTOMATIC_POOLS_UPDATE__}!g" mempool-config.json +sed -i "s!__MEMPOOL_POOLS_JSON_URL__!${__MEMPOOL_POOLS_JSON_URL__}!g" mempool-config.json +sed -i "s!__MEMPOOL_POOLS_JSON_TREE_URL__!${__MEMPOOL_POOLS_JSON_TREE_URL__}!g" mempool-config.json +sed -i "s!__MEMPOOL_AUDIT__!${__MEMPOOL_AUDIT__}!g" mempool-config.json +sed -i "s!__MEMPOOL_RUST_GBT__!${__MEMPOOL_RUST_GBT__}!g" mempool-config.json +sed -i "s!__MEMPOOL_LIMIT_GBT__!${__MEMPOOL_LIMIT_GBT__}!g" mempool-config.json +sed -i "s!__MEMPOOL_CPFP_INDEXING__!${__MEMPOOL_CPFP_INDEXING__}!g" mempool-config.json +sed -i "s!__MEMPOOL_MAX_BLOCKS_BULK_QUERY__!${__MEMPOOL_MAX_BLOCKS_BULK_QUERY__}!g" mempool-config.json +sed -i "s!__MEMPOOL_DISK_CACHE_BLOCK_INTERVAL__!${__MEMPOOL_DISK_CACHE_BLOCK_INTERVAL__}!g" mempool-config.json +sed -i "s!__MEMPOOL_MAX_PUSH_TX_SIZE_WEIGHT__!${__MEMPOOL_MAX_PUSH_TX_SIZE_WEIGHT__}!g" mempool-config.json +sed -i "s!__MEMPOOL_ALLOW_UNREACHABLE__!${__MEMPOOL_ALLOW_UNREACHABLE__}!g" mempool-config.json +sed -i "s!__MEMPOOL_PRICE_UPDATES_PER_HOUR__!${__MEMPOOL_PRICE_UPDATES_PER_HOUR__}!g" mempool-config.json +sed -i "s!__MEMPOOL_MAX_TRACKED_ADDRESSES__!${__MEMPOOL_MAX_TRACKED_ADDRESSES__}!g" mempool-config.json + +sed -i "s!__CORE_RPC_HOST__!${__CORE_RPC_HOST__}!g" mempool-config.json +sed -i "s!__CORE_RPC_PORT__!${__CORE_RPC_PORT__}!g" mempool-config.json +sed -i "s!__CORE_RPC_USERNAME__!${__CORE_RPC_USERNAME__}!g" mempool-config.json +sed -i "s!__CORE_RPC_PASSWORD__!${__CORE_RPC_PASSWORD__}!g" mempool-config.json +sed -i "s!__CORE_RPC_TIMEOUT__!${__CORE_RPC_TIMEOUT__}!g" mempool-config.json +sed -i "s!__CORE_RPC_COOKIE__!${__CORE_RPC_COOKIE__}!g" mempool-config.json +sed -i "s!__CORE_RPC_COOKIE_PATH__!${__CORE_RPC_COOKIE_PATH__}!g" mempool-config.json + +sed -i "s!__ELECTRUM_HOST__!${__ELECTRUM_HOST__}!g" mempool-config.json +sed -i "s!__ELECTRUM_PORT__!${__ELECTRUM_PORT__}!g" mempool-config.json +sed -i "s!__ELECTRUM_TLS_ENABLED__!${__ELECTRUM_TLS_ENABLED__}!g" mempool-config.json + +sed -i "s!__ESPLORA_REST_API_URL__!${__ESPLORA_REST_API_URL__}!g" mempool-config.json +sed -i "s!__ESPLORA_UNIX_SOCKET_PATH__!${__ESPLORA_UNIX_SOCKET_PATH__}!g" mempool-config.json +sed -i "s!__ESPLORA_BATCH_QUERY_BASE_SIZE__!${__ESPLORA_BATCH_QUERY_BASE_SIZE__}!g" mempool-config.json +sed -i "s!__ESPLORA_RETRY_UNIX_SOCKET_AFTER__!${__ESPLORA_RETRY_UNIX_SOCKET_AFTER__}!g" mempool-config.json +sed -i "s!__ESPLORA_REQUEST_TIMEOUT__!${__ESPLORA_REQUEST_TIMEOUT__}!g" mempool-config.json +sed -i "s!__ESPLORA_FALLBACK_TIMEOUT__!${__ESPLORA_FALLBACK_TIMEOUT__}!g" mempool-config.json +sed -i "s!__ESPLORA_FALLBACK__!${__ESPLORA_FALLBACK__}!g" mempool-config.json +sed -i "s!__ESPLORA_MAX_BEHIND_TIP__!${__ESPLORA_MAX_BEHIND_TIP__}!g" mempool-config.json + +sed -i "s!__SECOND_CORE_RPC_HOST__!${__SECOND_CORE_RPC_HOST__}!g" mempool-config.json +sed -i "s!__SECOND_CORE_RPC_PORT__!${__SECOND_CORE_RPC_PORT__}!g" mempool-config.json +sed -i "s!__SECOND_CORE_RPC_USERNAME__!${__SECOND_CORE_RPC_USERNAME__}!g" mempool-config.json +sed -i "s!__SECOND_CORE_RPC_PASSWORD__!${__SECOND_CORE_RPC_PASSWORD__}!g" mempool-config.json +sed -i "s!__SECOND_CORE_RPC_TIMEOUT__!${__SECOND_CORE_RPC_TIMEOUT__}!g" mempool-config.json +sed -i "s!__SECOND_CORE_RPC_COOKIE__!${__SECOND_CORE_RPC_COOKIE__}!g" mempool-config.json +sed -i "s!__SECOND_CORE_RPC_COOKIE_PATH__!${__SECOND_CORE_RPC_COOKIE_PATH__}!g" mempool-config.json + +sed -i "s!__DATABASE_ENABLED__!${__DATABASE_ENABLED__}!g" mempool-config.json +sed -i "s!__DATABASE_HOST__!${__DATABASE_HOST__}!g" mempool-config.json +sed -i "s!__DATABASE_SOCKET__!${__DATABASE_SOCKET__}!g" mempool-config.json +sed -i "s!__DATABASE_PORT__!${__DATABASE_PORT__}!g" mempool-config.json +sed -i "s!__DATABASE_DATABASE__!${__DATABASE_DATABASE__}!g" mempool-config.json +sed -i "s!__DATABASE_USERNAME__!${__DATABASE_USERNAME__}!g" mempool-config.json +sed -i "s!__DATABASE_PASSWORD__!${__DATABASE_PASSWORD__}!g" mempool-config.json +sed -i "s!__DATABASE_TIMEOUT__!${__DATABASE_TIMEOUT__}!g" mempool-config.json +sed -i "s!__DATABASE_PID_DIR__!${__DATABASE_PID_DIR__}!g" mempool-config.json +sed -i "s!__DATABASE_POOL_SIZE__!${__DATABASE_POOL_SIZE__}!g" mempool-config.json + +sed -i "s!__SYSLOG_ENABLED__!${__SYSLOG_ENABLED__}!g" mempool-config.json +sed -i "s!__SYSLOG_HOST__!${__SYSLOG_HOST__}!g" mempool-config.json +sed -i "s!__SYSLOG_PORT__!${__SYSLOG_PORT__}!g" mempool-config.json +sed -i "s!__SYSLOG_MIN_PRIORITY__!${__SYSLOG_MIN_PRIORITY__}!g" mempool-config.json +sed -i "s!__SYSLOG_FACILITY__!${__SYSLOG_FACILITY__}!g" mempool-config.json + +sed -i "s!__STATISTICS_ENABLED__!${__STATISTICS_ENABLED__}!g" mempool-config.json +sed -i "s!__STATISTICS_TX_PER_SECOND_SAMPLE_PERIOD__!${__STATISTICS_TX_PER_SECOND_SAMPLE_PERIOD__}!g" mempool-config.json + +sed -i "s!__SOCKS5PROXY_ENABLED__!${__SOCKS5PROXY_ENABLED__}!g" mempool-config.json +sed -i "s!__SOCKS5PROXY_USE_ONION__!${__SOCKS5PROXY_USE_ONION__}!g" mempool-config.json +sed -i "s!__SOCKS5PROXY_HOST__!${__SOCKS5PROXY_HOST__}!g" mempool-config.json +sed -i "s!__SOCKS5PROXY_PORT__!${__SOCKS5PROXY_PORT__}!g" mempool-config.json +sed -i "s!__SOCKS5PROXY_USERNAME__!${__SOCKS5PROXY_USERNAME__}!g" mempool-config.json +sed -i "s!__SOCKS5PROXY_PASSWORD__!${__SOCKS5PROXY_PASSWORD__}!g" mempool-config.json + +sed -i "s!__EXTERNAL_DATA_SERVER_MEMPOOL_API__!${__EXTERNAL_DATA_SERVER_MEMPOOL_API__}!g" mempool-config.json +sed -i "s!__EXTERNAL_DATA_SERVER_MEMPOOL_ONION__!${__EXTERNAL_DATA_SERVER_MEMPOOL_ONION__}!g" mempool-config.json +sed -i "s!__EXTERNAL_DATA_SERVER_LIQUID_API__!${__EXTERNAL_DATA_SERVER_LIQUID_API__}!g" mempool-config.json +sed -i "s!__EXTERNAL_DATA_SERVER_LIQUID_ONION__!${__EXTERNAL_DATA_SERVER_LIQUID_ONION__}!g" mempool-config.json + +# LIGHTNING +sed -i "s!__LIGHTNING_ENABLED__!${__LIGHTNING_ENABLED__}!g" mempool-config.json +sed -i "s!__LIGHTNING_BACKEND__!${__LIGHTNING_BACKEND__}!g" mempool-config.json +sed -i "s!__LIGHTNING_TOPOLOGY_FOLDER__!${__LIGHTNING_TOPOLOGY_FOLDER__}!g" mempool-config.json +sed -i "s!__LIGHTNING_STATS_REFRESH_INTERVAL__!${__LIGHTNING_STATS_REFRESH_INTERVAL__}!g" mempool-config.json +sed -i "s!__LIGHTNING_GRAPH_REFRESH_INTERVAL__!${__LIGHTNING_GRAPH_REFRESH_INTERVAL__}!g" mempool-config.json +sed -i "s!__LIGHTNING_LOGGER_UPDATE_INTERVAL__!${__LIGHTNING_LOGGER_UPDATE_INTERVAL__}!g" mempool-config.json +sed -i "s!__LIGHTNING_FORENSICS_INTERVAL__!${__LIGHTNING_FORENSICS_INTERVAL__}!g" mempool-config.json +sed -i "s!__LIGHTNING_FORENSICS_RATE_LIMIT__!${__LIGHTNING_FORENSICS_RATE_LIMIT__}!g" mempool-config.json + +# LND +sed -i "s!__LND_TLS_CERT_PATH__!${__LND_TLS_CERT_PATH__}!g" mempool-config.json +sed -i "s!__LND_MACAROON_PATH__!${__LND_MACAROON_PATH__}!g" mempool-config.json +sed -i "s!__LND_REST_API_URL__!${__LND_REST_API_URL__}!g" mempool-config.json +sed -i "s!__LND_TIMEOUT__!${__LND_TIMEOUT__}!g" mempool-config.json + +# CLN +sed -i "s!__CLIGHTNING_SOCKET__!${__CLIGHTNING_SOCKET__}!g" mempool-config.json + +# MAXMIND +sed -i "s!__MAXMIND_ENABLED__!${__MAXMIND_ENABLED__}!g" mempool-config.json +sed -i "s!__MAXMIND_GEOLITE2_CITY__!${__MAXMIND_GEOLITE2_CITY__}!g" mempool-config.json +sed -i "s!__MAXMIND_GEOLITE2_ASN__!${__MAXMIND_GEOLITE2_ASN__}!g" mempool-config.json +sed -i "s!__MAXMIND_GEOIP2_ISP__!${__MAXMIND_GEOIP2_ISP__}!g" mempool-config.json + +# REPLICATION +sed -i "s!__REPLICATION_ENABLED__!${__REPLICATION_ENABLED__}!g" mempool-config.json +sed -i "s!__REPLICATION_AUDIT__!${__REPLICATION_AUDIT__}!g" mempool-config.json +sed -i "s!__REPLICATION_AUDIT_START_HEIGHT__!${__REPLICATION_AUDIT_START_HEIGHT__}!g" mempool-config.json +sed -i "s!__REPLICATION_STATISTICS__!${__REPLICATION_STATISTICS__}!g" mempool-config.json +sed -i "s!__REPLICATION_STATISTICS_START_TIME__!${__REPLICATION_STATISTICS_START_TIME__}!g" mempool-config.json +sed -i "s!__REPLICATION_SERVERS__!${__REPLICATION_SERVERS__}!g" mempool-config.json + +# MEMPOOL_SERVICES +sed -i "s!__MEMPOOL_SERVICES_API__!${__MEMPOOL_SERVICES_API__}!g" mempool-config.json +sed -i "s!__MEMPOOL_SERVICES_ACCELERATIONS__!${__MEMPOOL_SERVICES_ACCELERATIONS__}!g" mempool-config.json + +# REDIS +sed -i "s!__REDIS_ENABLED__!${__REDIS_ENABLED__}!g" mempool-config.json +sed -i "s!__REDIS_UNIX_SOCKET_PATH__!${__REDIS_UNIX_SOCKET_PATH__}!g" mempool-config.json +sed -i "s!__REDIS_BATCH_QUERY_BASE_SIZE__!${__REDIS_BATCH_QUERY_BASE_SIZE__}!g" mempool-config.json + +# FIAT_PRICE +sed -i "s!__FIAT_PRICE_ENABLED__!${__FIAT_PRICE_ENABLED__}!g" mempool-config.json +sed -i "s!__FIAT_PRICE_PAID__!${__FIAT_PRICE_PAID__}!g" mempool-config.json +sed -i "s!__FIAT_PRICE_API_KEY__!${__FIAT_PRICE_API_KEY__}!g" mempool-config.json + +node /backend/package/index.js diff --git a/docker/backend/wait-for-it.sh b/docker/backend/wait-for-it.sh new file mode 100755 index 0000000000..d990e0d364 --- /dev/null +++ b/docker/backend/wait-for-it.sh @@ -0,0 +1,182 @@ +#!/usr/bin/env bash +# Use this script to test if a given TCP host/port are available + +WAITFORIT_cmdname=${0##*/} + +echoerr() { if [[ $WAITFORIT_QUIET -ne 1 ]]; then echo "$@" 1>&2; fi } + +usage() +{ + cat << USAGE >&2 +Usage: + $WAITFORIT_cmdname host:port [-s] [-t timeout] [-- command args] + -h HOST | --host=HOST Host or IP under test + -p PORT | --port=PORT TCP port under test + Alternatively, you specify the host and port as host:port + -s | --strict Only execute subcommand if the test succeeds + -q | --quiet Don't output any status messages + -t TIMEOUT | --timeout=TIMEOUT + Timeout in seconds, zero for no timeout + -- COMMAND ARGS Execute command with args after the test finishes +USAGE + exit 1 +} + +wait_for() +{ + if [[ $WAITFORIT_TIMEOUT -gt 0 ]]; then + echoerr "$WAITFORIT_cmdname: waiting $WAITFORIT_TIMEOUT seconds for $WAITFORIT_HOST:$WAITFORIT_PORT" + else + echoerr "$WAITFORIT_cmdname: waiting for $WAITFORIT_HOST:$WAITFORIT_PORT without a timeout" + fi + WAITFORIT_start_ts=$(date +%s) + while : + do + if [[ $WAITFORIT_ISBUSY -eq 1 ]]; then + nc -z $WAITFORIT_HOST $WAITFORIT_PORT + WAITFORIT_result=$? + else + (echo -n > /dev/tcp/$WAITFORIT_HOST/$WAITFORIT_PORT) >/dev/null 2>&1 + WAITFORIT_result=$? + fi + if [[ $WAITFORIT_result -eq 0 ]]; then + WAITFORIT_end_ts=$(date +%s) + echoerr "$WAITFORIT_cmdname: $WAITFORIT_HOST:$WAITFORIT_PORT is available after $((WAITFORIT_end_ts - WAITFORIT_start_ts)) seconds" + break + fi + sleep 1 + done + return $WAITFORIT_result +} + +wait_for_wrapper() +{ + # In order to support SIGINT during timeout: http://unix.stackexchange.com/a/57692 + if [[ $WAITFORIT_QUIET -eq 1 ]]; then + timeout $WAITFORIT_BUSYTIMEFLAG $WAITFORIT_TIMEOUT $0 --quiet --child --host=$WAITFORIT_HOST --port=$WAITFORIT_PORT --timeout=$WAITFORIT_TIMEOUT & + else + timeout $WAITFORIT_BUSYTIMEFLAG $WAITFORIT_TIMEOUT $0 --child --host=$WAITFORIT_HOST --port=$WAITFORIT_PORT --timeout=$WAITFORIT_TIMEOUT & + fi + WAITFORIT_PID=$! + trap "kill -INT -$WAITFORIT_PID" INT + wait $WAITFORIT_PID + WAITFORIT_RESULT=$? + if [[ $WAITFORIT_RESULT -ne 0 ]]; then + echoerr "$WAITFORIT_cmdname: timeout occurred after waiting $WAITFORIT_TIMEOUT seconds for $WAITFORIT_HOST:$WAITFORIT_PORT" + fi + return $WAITFORIT_RESULT +} + +# process arguments +while [[ $# -gt 0 ]] +do + case "$1" in + *:* ) + WAITFORIT_hostport=(${1//:/ }) + WAITFORIT_HOST=${WAITFORIT_hostport[0]} + WAITFORIT_PORT=${WAITFORIT_hostport[1]} + shift 1 + ;; + --child) + WAITFORIT_CHILD=1 + shift 1 + ;; + -q | --quiet) + WAITFORIT_QUIET=1 + shift 1 + ;; + -s | --strict) + WAITFORIT_STRICT=1 + shift 1 + ;; + -h) + WAITFORIT_HOST="$2" + if [[ $WAITFORIT_HOST == "" ]]; then break; fi + shift 2 + ;; + --host=*) + WAITFORIT_HOST="${1#*=}" + shift 1 + ;; + -p) + WAITFORIT_PORT="$2" + if [[ $WAITFORIT_PORT == "" ]]; then break; fi + shift 2 + ;; + --port=*) + WAITFORIT_PORT="${1#*=}" + shift 1 + ;; + -t) + WAITFORIT_TIMEOUT="$2" + if [[ $WAITFORIT_TIMEOUT == "" ]]; then break; fi + shift 2 + ;; + --timeout=*) + WAITFORIT_TIMEOUT="${1#*=}" + shift 1 + ;; + --) + shift + WAITFORIT_CLI=("$@") + break + ;; + --help) + usage + ;; + *) + echoerr "Unknown argument: $1" + usage + ;; + esac +done + +if [[ "$WAITFORIT_HOST" == "" || "$WAITFORIT_PORT" == "" ]]; then + echoerr "Error: you need to provide a host and port to test." + usage +fi + +WAITFORIT_TIMEOUT=${WAITFORIT_TIMEOUT:-15} +WAITFORIT_STRICT=${WAITFORIT_STRICT:-0} +WAITFORIT_CHILD=${WAITFORIT_CHILD:-0} +WAITFORIT_QUIET=${WAITFORIT_QUIET:-0} + +# Check to see if timeout is from busybox? +WAITFORIT_TIMEOUT_PATH=$(type -p timeout) +WAITFORIT_TIMEOUT_PATH=$(realpath $WAITFORIT_TIMEOUT_PATH 2>/dev/null || readlink -f $WAITFORIT_TIMEOUT_PATH) + +WAITFORIT_BUSYTIMEFLAG="" +if [[ $WAITFORIT_TIMEOUT_PATH =~ "busybox" ]]; then + WAITFORIT_ISBUSY=1 + # Check if busybox timeout uses -t flag + # (recent Alpine versions don't support -t anymore) + if timeout &>/dev/stdout | grep -q -e '-t '; then + WAITFORIT_BUSYTIMEFLAG="-t" + fi +else + WAITFORIT_ISBUSY=0 +fi + +if [[ $WAITFORIT_CHILD -gt 0 ]]; then + wait_for + WAITFORIT_RESULT=$? + exit $WAITFORIT_RESULT +else + if [[ $WAITFORIT_TIMEOUT -gt 0 ]]; then + wait_for_wrapper + WAITFORIT_RESULT=$? + else + wait_for + WAITFORIT_RESULT=$? + fi +fi + +if [[ $WAITFORIT_CLI != "" ]]; then + if [[ $WAITFORIT_RESULT -ne 0 && $WAITFORIT_STRICT -eq 1 ]]; then + echoerr "$WAITFORIT_cmdname: strict mode, refusing to execute subprocess" + exit $WAITFORIT_RESULT + fi + exec "${WAITFORIT_CLI[@]}" +else + exit $WAITFORIT_RESULT +fi diff --git a/frontend/src/app/bisq/bisq-blocks/bisq-blocks.component.scss b/docker/data/.gitkeep similarity index 100% rename from frontend/src/app/bisq/bisq-blocks/bisq-blocks.component.scss rename to docker/data/.gitkeep diff --git a/docker/docker-compose.yml b/docker/docker-compose.yml new file mode 100644 index 0000000000..4e1094306f --- /dev/null +++ b/docker/docker-compose.yml @@ -0,0 +1,46 @@ +version: "3.7" + +services: + web: + environment: + FRONTEND_HTTP_PORT: "8080" + BACKEND_MAINNET_HTTP_HOST: "api" + image: mempool/frontend:latest + user: "1000:1000" + restart: on-failure + stop_grace_period: 1m + command: "./wait-for db:3306 --timeout=720 -- nginx -g 'daemon off;'" + ports: + - 80:8080 + api: + environment: + MEMPOOL_BACKEND: "none" + CORE_RPC_HOST: "172.27.0.1" + CORE_RPC_PORT: "8332" + CORE_RPC_USERNAME: "mempool" + CORE_RPC_PASSWORD: "mempool" + DATABASE_ENABLED: "true" + DATABASE_HOST: "db" + DATABASE_DATABASE: "mempool" + DATABASE_USERNAME: "mempool" + DATABASE_PASSWORD: "mempool" + STATISTICS_ENABLED: "true" + image: mempool/backend:latest + user: "1000:1000" + restart: on-failure + stop_grace_period: 1m + command: "./wait-for-it.sh db:3306 --timeout=720 --strict -- ./start.sh" + volumes: + - ./data:/backend/cache + db: + environment: + MYSQL_DATABASE: "mempool" + MYSQL_USER: "mempool" + MYSQL_PASSWORD: "mempool" + MYSQL_ROOT_PASSWORD: "admin" + image: mariadb:10.5.21 + user: "1000:1000" + restart: on-failure + stop_grace_period: 1m + volumes: + - ./mysql/data:/var/lib/mysql diff --git a/docker/frontend/Dockerfile b/docker/frontend/Dockerfile new file mode 100644 index 0000000000..8374ebe49b --- /dev/null +++ b/docker/frontend/Dockerfile @@ -0,0 +1,42 @@ +FROM node:20.15.0-buster-slim AS builder + +ARG commitHash +ENV DOCKER_COMMIT_HASH=${commitHash} +ENV CYPRESS_INSTALL_BINARY=0 + +WORKDIR /build +COPY . . +RUN apt-get update +RUN apt-get install -y build-essential rsync +RUN cp mempool-frontend-config.sample.json mempool-frontend-config.json +RUN npm install --omit=dev --omit=optional + +RUN npm run build + +FROM nginx:1.27.0-alpine + +WORKDIR /patch + +COPY --from=builder /build/entrypoint.sh . +COPY --from=builder /build/wait-for . +COPY --from=builder /build/dist/mempool /var/www/mempool +COPY --from=builder /build/nginx.conf /etc/nginx/ +COPY --from=builder /build/nginx-mempool.conf /etc/nginx/conf.d/ + +RUN chmod +x /patch/entrypoint.sh +RUN chmod +x /patch/wait-for + +RUN chown -R 1000:1000 /patch && chmod -R 755 /patch && \ + chown -R 1000:1000 /var/cache/nginx && \ + chown -R 1000:1000 /var/log/nginx && \ + chown -R 1000:1000 /etc/nginx/nginx.conf && \ + chown -R 1000:1000 /etc/nginx/conf.d && \ + chown -R 1000:1000 /var/www/mempool + +RUN touch /var/run/nginx.pid && \ + chown -R 1000:1000 /var/run/nginx.pid + +USER 1000 + +ENTRYPOINT ["/patch/entrypoint.sh"] +CMD ["nginx", "-g", "daemon off;"] diff --git a/docker/frontend/entrypoint.sh b/docker/frontend/entrypoint.sh new file mode 100644 index 0000000000..dc0fa6f7a4 --- /dev/null +++ b/docker/frontend/entrypoint.sh @@ -0,0 +1,82 @@ +#!/bin/sh +__MEMPOOL_BACKEND_MAINNET_HTTP_HOST__=${BACKEND_MAINNET_HTTP_HOST:=127.0.0.1} +__MEMPOOL_BACKEND_MAINNET_HTTP_PORT__=${BACKEND_MAINNET_HTTP_PORT:=8999} +__MEMPOOL_FRONTEND_HTTP_PORT__=${FRONTEND_HTTP_PORT:=8080} + +sed -i "s/__MEMPOOL_BACKEND_MAINNET_HTTP_HOST__/${__MEMPOOL_BACKEND_MAINNET_HTTP_HOST__}/g" /etc/nginx/conf.d/nginx-mempool.conf +sed -i "s/__MEMPOOL_BACKEND_MAINNET_HTTP_PORT__/${__MEMPOOL_BACKEND_MAINNET_HTTP_PORT__}/g" /etc/nginx/conf.d/nginx-mempool.conf + +cp /etc/nginx/nginx.conf /patch/nginx.conf +sed -i "s/__MEMPOOL_FRONTEND_HTTP_PORT__/${__MEMPOOL_FRONTEND_HTTP_PORT__}/g" /patch/nginx.conf +cat /patch/nginx.conf > /etc/nginx/nginx.conf + +if [ "${LIGHTNING_DETECTED_PORT}" != "" ];then + export LIGHTNING=true +fi + +# Runtime overrides - read env vars defined in docker compose + +__MAINNET_ENABLED__=${MAINNET_ENABLED:=true} +__TESTNET_ENABLED__=${TESTNET_ENABLED:=false} +__TESTNET4_ENABLED__=${TESTNET_ENABLED:=false} +__SIGNET_ENABLED__=${SIGNET_ENABLED:=false} +__LIQUID_ENABLED__=${LIQUID_ENABLED:=false} +__LIQUID_TESTNET_ENABLED__=${LIQUID_TESTNET_ENABLED:=false} +__ITEMS_PER_PAGE__=${ITEMS_PER_PAGE:=10} +__KEEP_BLOCKS_AMOUNT__=${KEEP_BLOCKS_AMOUNT:=8} +__NGINX_PROTOCOL__=${NGINX_PROTOCOL:=http} +__NGINX_HOSTNAME__=${NGINX_HOSTNAME:=localhost} +__NGINX_PORT__=${NGINX_PORT:=8999} +__BLOCK_WEIGHT_UNITS__=${BLOCK_WEIGHT_UNITS:=4000000} +__MEMPOOL_BLOCKS_AMOUNT__=${MEMPOOL_BLOCKS_AMOUNT:=8} +__BASE_MODULE__=${BASE_MODULE:=mempool} +__ROOT_NETWORK__=${ROOT_NETWORK:=} +__MEMPOOL_WEBSITE_URL__=${MEMPOOL_WEBSITE_URL:=https://mempool.space} +__LIQUID_WEBSITE_URL__=${LIQUID_WEBSITE_URL:=https://liquid.network} +__MINING_DASHBOARD__=${MINING_DASHBOARD:=true} +__LIGHTNING__=${LIGHTNING:=false} +__AUDIT__=${AUDIT:=false} +__MAINNET_BLOCK_AUDIT_START_HEIGHT__=${MAINNET_BLOCK_AUDIT_START_HEIGHT:=0} +__TESTNET_BLOCK_AUDIT_START_HEIGHT__=${TESTNET_BLOCK_AUDIT_START_HEIGHT:=0} +__SIGNET_BLOCK_AUDIT_START_HEIGHT__=${SIGNET_BLOCK_AUDIT_START_HEIGHT:=0} +__ACCELERATOR__=${ACCELERATOR:=false} +__SERVICES_API__=${SERVICES_API:=false} +__PUBLIC_ACCELERATIONS__=${PUBLIC_ACCELERATIONS:=false} +__HISTORICAL_PRICE__=${HISTORICAL_PRICE:=true} +__ADDITIONAL_CURRENCIES__=${ADDITIONAL_CURRENCIES:=false} + +# Export as environment variables to be used by envsubst +export __MAINNET_ENABLED__ +export __TESTNET_ENABLED__ +export __TESTNET4_ENABLED__ +export __SIGNET_ENABLED__ +export __LIQUID_ENABLED__ +export __LIQUID_TESTNET_ENABLED__ +export __ITEMS_PER_PAGE__ +export __KEEP_BLOCKS_AMOUNT__ +export __NGINX_PROTOCOL__ +export __NGINX_HOSTNAME__ +export __NGINX_PORT__ +export __BLOCK_WEIGHT_UNITS__ +export __MEMPOOL_BLOCKS_AMOUNT__ +export __BASE_MODULE__ +export __ROOT_NETWORK__ +export __MEMPOOL_WEBSITE_URL__ +export __LIQUID_WEBSITE_URL__ +export __MINING_DASHBOARD__ +export __LIGHTNING__ +export __AUDIT__ +export __MAINNET_BLOCK_AUDIT_START_HEIGHT__ +export __TESTNET_BLOCK_AUDIT_START_HEIGHT__ +export __SIGNET_BLOCK_AUDIT_START_HEIGHT__ +export __ACCELERATOR__ +export __SERVICES_API__ +export __PUBLIC_ACCELERATIONS__ +export __HISTORICAL_PRICE__ +export __ADDITIONAL_CURRENCIES__ + +folder=$(find /var/www/mempool -name "config.js" | xargs dirname) +echo ${folder} +envsubst < ${folder}/config.template.js > ${folder}/config.js + +exec "$@" diff --git a/docker/frontend/wait-for b/docker/frontend/wait-for new file mode 100644 index 0000000000..e28e54cb0e --- /dev/null +++ b/docker/frontend/wait-for @@ -0,0 +1,84 @@ +#!/bin/sh + +TIMEOUT=15 +QUIET=0 + +echoerr() { + if [ "$QUIET" -ne 1 ]; then printf "%s\n" "$*" 1>&2; fi +} + +usage() { + exitcode="$1" + cat << USAGE >&2 +Usage: + $cmdname host:port [-t timeout] [-- command args] + -q | --quiet Do not output any status messages + -t TIMEOUT | --timeout=timeout Timeout in seconds, zero for no timeout + -- COMMAND ARGS Execute command with args after the test finishes +USAGE + exit "$exitcode" +} + +wait_for() { + if ! command -v nc >/dev/null; then + echoerr 'nc command is missing!' + exit 1 + fi + + for i in `seq $TIMEOUT` ; do + nc -z "$HOST" "$PORT" > /dev/null 2>&1 + + result=$? + if [ $result -eq 0 ] ; then + if [ $# -gt 0 ] ; then + exec "$@" + fi + exit 0 + fi + sleep 1 + done + echo "Operation timed out" >&2 + exit 1 +} + +while [ $# -gt 0 ] +do + case "$1" in + *:* ) + HOST=$(printf "%s\n" "$1"| cut -d : -f 1) + PORT=$(printf "%s\n" "$1"| cut -d : -f 2) + shift 1 + ;; + -q | --quiet) + QUIET=1 + shift 1 + ;; + -t) + TIMEOUT="$2" + if [ "$TIMEOUT" = "" ]; then break; fi + shift 2 + ;; + --timeout=*) + TIMEOUT="${1#*=}" + shift 1 + ;; + --) + shift + break + ;; + --help) + usage 0 + ;; + *) + echoerr "Unknown argument: $1" + usage 1 + ;; + esac +done + +if [ "$HOST" = "" -o "$PORT" = "" ]; then + echoerr "Error: you need to provide a host and port to test." + usage 2 +fi + +wait_for "$@" diff --git a/docker/init.sh b/docker/init.sh new file mode 100755 index 0000000000..3c5ec6aa31 --- /dev/null +++ b/docker/init.sh @@ -0,0 +1,20 @@ +#!/bin/sh + +#backend +cp -r ./docker/backend/* ./backend/ + +#geoip-data +mkdir -p ./backend/GeoIP/ +wget -O ./backend/GeoIP/GeoLite2-City.mmdb https://raw.githubusercontent.com/mempool/geoip-data/master/GeoLite2-City.mmdb +wget -O ./backend/GeoIP/GeoLite2-ASN.mmdb https://raw.githubusercontent.com/mempool/geoip-data/master/GeoLite2-ASN.mmdb + +#frontend +localhostIP="127.0.0.1" +cp ./docker/frontend/* ./frontend +cp ./nginx.conf ./frontend/ +cp ./nginx-mempool.conf ./frontend/ +sed -i"" -e "s/${localhostIP}:80/0.0.0.0:__MEMPOOL_FRONTEND_HTTP_PORT__/g" ./frontend/nginx.conf +sed -i"" -e "s/${localhostIP}/0.0.0.0/g" ./frontend/nginx.conf +sed -i"" -e "s/user nobody;//g" ./frontend/nginx.conf +sed -i"" -e "s!/etc/nginx/nginx-mempool.conf!/etc/nginx/conf.d/nginx-mempool.conf!g" ./frontend/nginx.conf +sed -i"" -e "s/${localhostIP}:8999/__MEMPOOL_BACKEND_MAINNET_HTTP_HOST__:__MEMPOOL_BACKEND_MAINNET_HTTP_PORT__/g" ./frontend/nginx-mempool.conf diff --git a/frontend/src/app/bisq/bisq-explorer/bisq-explorer.component.scss b/docker/mysql/data/.gitkeep similarity index 100% rename from frontend/src/app/bisq/bisq-explorer/bisq-explorer.component.scss rename to docker/mysql/data/.gitkeep diff --git a/docker/scripts/get_image_digest.sh b/docker/scripts/get_image_digest.sh new file mode 100755 index 0000000000..91f64e4dd1 --- /dev/null +++ b/docker/scripts/get_image_digest.sh @@ -0,0 +1,18 @@ +#!/bin/sh + +VERSION=$1 +IMAGE="" + +if [ -z "${VERSION}" ]; then + echo "no version provided (i.e, v2.2.0), using latest tag" + VERSION="latest" +fi + +for package in frontend backend; do + PACKAGE=mempool/"$package" + IMAGE="$PACKAGE":"$VERSION" + HASH=`docker pull $IMAGE > /dev/null && docker inspect $IMAGE | sed -n '/RepoDigests/{n;p;}' | grep -o '[0-9a-f]\{64\}'` + if [ -n "${HASH}" ]; then + echo "$IMAGE"@sha256:"$HASH" + fi +done diff --git a/entrypoint.sh b/entrypoint.sh deleted file mode 100644 index eab7121b75..0000000000 --- a/entrypoint.sh +++ /dev/null @@ -1,10 +0,0 @@ -#!/bin/sh -mysqld_safe& -sleep 5 -nginx -cd /mempool.space/backend -rm -f mempool-config.json -rm -f cache.json -touch cache.json -jq -n env > mempool-config.json -node dist/index.js diff --git a/frontend/.browserslistrc b/frontend/.browserslistrc index 80848532e4..e6f1183e77 100644 --- a/frontend/.browserslistrc +++ b/frontend/.browserslistrc @@ -2,11 +2,15 @@ # For additional information regarding the format and rule options, please see: # https://github.com/browserslist/browserslist#queries +# For the full list of supported browsers by the Angular framework, please see: +# https://angular.io/guide/browser-support + # You can see what browsers were selected by your queries by running: # npx browserslist -> 0.5% -last 2 versions +last 2 Chrome versions +last 1 Firefox version +last 2 Edge major versions +last 2 Safari major versions +last 2 iOS major versions Firefox ESR -not dead -not IE 9-11 # For IE 9-11 support, remove 'not'. \ No newline at end of file diff --git a/frontend/.editorconfig b/frontend/.editorconfig index e89330a618..9787413cd7 100644 --- a/frontend/.editorconfig +++ b/frontend/.editorconfig @@ -8,6 +8,10 @@ indent_size = 2 insert_final_newline = true trim_trailing_whitespace = true +[*.ts] +quote_type = single + [*.md] max_line_length = off trim_trailing_whitespace = false + diff --git a/frontend/.eslintignore b/frontend/.eslintignore new file mode 100644 index 0000000000..193c8a3180 --- /dev/null +++ b/frontend/.eslintignore @@ -0,0 +1,3 @@ +node_modules +dist +frontend diff --git a/frontend/.eslintrc b/frontend/.eslintrc new file mode 100644 index 0000000000..5162bf474c --- /dev/null +++ b/frontend/.eslintrc @@ -0,0 +1,41 @@ +{ + "root": true, + "parser": "@typescript-eslint/parser", + "plugins": [ + "@typescript-eslint" + ], + "extends": [ + "eslint:recommended", + "plugin:@typescript-eslint/eslint-recommended", + "plugin:@typescript-eslint/recommended" + ], + "rules": { + "@typescript-eslint/ban-ts-comment": 1, + "@typescript-eslint/ban-types": 1, + "@typescript-eslint/no-empty-function": 1, + "@typescript-eslint/no-explicit-any": 1, + "@typescript-eslint/no-inferrable-types": 0, + "@typescript-eslint/no-namespace": 1, + "@typescript-eslint/no-this-alias": 1, + "@typescript-eslint/no-var-requires": 1, + "@typescript-eslint/explicit-function-return-type": 1, + "@typescript-eslint/no-unused-vars": 1, + "no-case-declarations": 1, + "no-console": 1, + "no-constant-condition": 1, + "no-dupe-else-if": 1, + "no-empty": 1, + "no-extra-boolean-cast": 1, + "no-prototype-builtins": 1, + "no-self-assign": 1, + "no-useless-catch": 1, + "no-var": 1, + "prefer-const": 1, + "prefer-rest-params": 1, + "quotes": [1, "single", { "allowTemplateLiterals": true }], + "semi": 1, + "curly": [1, "all"], + "eqeqeq": 1, + "no-trailing-spaces": 1 + } +} diff --git a/frontend/.gitignore b/frontend/.gitignore index aa63d58c53..c10a009469 100644 --- a/frontend/.gitignore +++ b/frontend/.gitignore @@ -4,6 +4,15 @@ /dist /tmp /out-tsc +server.run.js + +# docker +Dockerfile +entrypoint.sh +nginx-mempool.conf +nginx.conf +wait-for + # Only exists if Bazel was run /bazel-out @@ -32,6 +41,7 @@ speed-measure-plugin.json .history/* # misc +/.angular/cache /.sass-cache /connect.lock /coverage @@ -47,8 +57,22 @@ Thumbs.db src/resources/assets.json src/resources/assets.minimal.json +src/resources/assets-testnet.json +src/resources/assets-testnet.minimal.json src/resources/pools.json +src/resources/mining-pools/* +src/resources/**/*.mp4 +src/resources/**/*.vtt +src/resources/customize.js # environment config mempool-frontend-config.json generated-config.js + +# e2e results +cypress/videos +cypress/screenshots + +# Base index +src/index.html + diff --git a/frontend/.prettierignore b/frontend/.prettierignore new file mode 100644 index 0000000000..d5f19d89b3 --- /dev/null +++ b/frontend/.prettierignore @@ -0,0 +1,2 @@ +node_modules +package-lock.json diff --git a/frontend/.prettierrc b/frontend/.prettierrc new file mode 100644 index 0000000000..b8039f8430 --- /dev/null +++ b/frontend/.prettierrc @@ -0,0 +1,6 @@ +{ + "endOfLine": "lf", + "printWidth": 80, + "tabWidth": 2, + "trailingComma": "es5" +} diff --git a/frontend/.tx/config b/frontend/.tx/config new file mode 100644 index 0000000000..825e77ddcb --- /dev/null +++ b/frontend/.tx/config @@ -0,0 +1,9 @@ +[main] +host = https://www.transifex.com + +[o:mempool:p:mempool:r:frontend-src-locale-messages-xlf--master] +file_filter = frontend/src/locale/messages..xlf +source_file = frontend/src/locale/messages.en-US.xlf +source_lang = en-US +type = XLIFF + diff --git a/frontend/README.md b/frontend/README.md index 1b91d4b98e..069f1d5f0a 100644 --- a/frontend/README.md +++ b/frontend/README.md @@ -1,27 +1,136 @@ -# Mempool Space +# Mempool Frontend -This project was generated with [Angular CLI](https://github.com/angular/angular-cli) version 8.1.2. +You can build and run the Mempool frontend and proxy to the production Mempool backend (for easier frontend development), or you can connect it to your own backend for a full Mempool development instance, custom deployment, etc. -## Development server +Jump to a section in this doc: +- [Quick Setup for Frontend Development](#quick-setup-for-frontend-development) +- [Manual Frontend Setup](#manual-setup) +- [Translations](#translations-transifex-project) -Run `ng serve` for a dev server. Navigate to `http://localhost:4200/`. The app will automatically reload if you change any of the source files. +## Quick Setup for Frontend Development -## Code scaffolding +If you want to quickly improve the UI, fix typos, or make other updates that don't require any backend changes, you don't need to set up an entire backend—you can simply run the Mempool frontend locally and proxy to the mempool.space backend. -Run `ng generate component component-name` to generate a new component. You can also use `ng generate directive|pipe|service|class|guard|interface|enum|module`. +### 1. Clone Mempool Repository -## Build +Get the latest Mempool code: -Run `ng build` to build the project. The build artifacts will be stored in the `dist/` directory. Use the `--prod` flag for a production build. +``` +git clone https://github.com/mempool/mempool +cd mempool/frontend +``` -## Running unit tests +### 2. Specify Website -Run `ng test` to execute the unit tests via [Karma](https://karma-runner.github.io). +The same frontend codebase is used for https://mempool.space and https://liquid.network. -## Running end-to-end tests +Configure the frontend for the site you want by running the corresponding command: -Run `ng e2e` to execute the end-to-end tests via [Protractor](http://www.protractortest.org/). +``` +$ npm run config:defaults:mempool +$ npm run config:defaults:liquid +``` -## Further help +### 3. Run the Frontend -To get more help on the Angular CLI use `ng help` or go check out the [Angular CLI README](https://github.com/angular/angular-cli/blob/master/README.md). +_Make sure to use Node.js 16.10 and npm 7._ + +Install project dependencies and run the frontend server: + +``` +$ npm install +$ npm run serve:local-prod +``` + +The frontend will be available at http://localhost:4200/ and all API requests will be proxied to the production server at https://mempool.space. + +### 4. Test + +After making your changes, you can run our end-to-end automation suite and check for possible regressions. + +Headless: + +``` +$ npm run config:defaults:mempool && npm run cypress:run +``` + +Interactive: + +``` +$ npm run config:defaults:mempool && npm run cypress:open +``` + +This will open the Cypress test runner, where you can select any of the test files to run. + +If all tests are green, submit your PR, and it will be reviewed by someone on the team as soon as possible. + +## Manual Setup + +Set up the [Mempool backend](../backend/) first, if you haven't already. + +### 1. Build the Frontend + +_Make sure to use Node.js 16.10 and npm 7._ + +Build the frontend: + +``` +cd frontend +npm install +npm run build +``` + +### 2. Run the Frontend + +#### Development + +To run your local Mempool frontend with your local Mempool backend: + +``` +npm run serve +``` + +#### Production + +The `npm run build` command from step 1 above should have generated a `dist` directory. Put the contents of `dist/` onto your web server. + +You will probably want to set up a reverse proxy, TLS, etc. There are sample nginx configuration files in the top level of the repository for reference, but note that support for such tasks is outside the scope of this project. + +## Translations: Transifex Project + +The Mempool frontend strings are localized into 20+ locales: +https://www.transifex.com/mempool/mempool/dashboard/ + +### Translators + +* Arabic @baro0k +* Czech @pixelmade2 +* Danish @pierrevendelboe +* German @Emzy +* English (default) +* Spanish @maxhodler @bisqes +* Persian @techmix +* French @Bayernatoor +* Korean @kcalvinalvinn @sogoagain +* Italian @HodlBits +* Lithuanian @eimze21 +* Hebrew @rapidlab309 +* Georgian @wyd_idk +* Hungarian @btcdragonlord +* Dutch @m__btc +* Japanese @wiz @japananon +* Norwegian @T82771355 +* Polish @maciejsoltysiak +* Portugese @jgcastro1985 +* Slovenian @thepkbadger +* Finnish @bio_bitcoin +* Swedish @softsimon_ +* Thai @Gusb3ll +* Turkish @stackmore +* Ukrainian @volbil +* Vietnamese @BitcoinvnNews +* Chinese @wdljt +* Russian @TonyCrusoe @Bitconan +* Romanian @mirceavesa +* Macedonian @SkechBoy +* Nepalese @kebinm diff --git a/frontend/angular.json b/frontend/angular.json index b6fce6d00d..1909822250 100644 --- a/frontend/angular.json +++ b/frontend/angular.json @@ -1,5 +1,8 @@ { "$schema": "./node_modules/@angular/cli/lib/config/schema.json", + "cli": { + "analytics": false + }, "version": 1, "newProjectRoot": "projects", "projects": { @@ -13,39 +16,207 @@ "root": "", "sourceRoot": "src", "prefix": "app", + "i18n": { + "sourceLocale": { + "code": "en-US", + "baseHref": "/" + }, + "locales": { + "ar": { + "translation": "src/locale/messages.ar.xlf", + "baseHref": "/ar/" + }, + "ca": { + "translation": "src/locale/messages.ca.xlf", + "baseHref": "/ca/" + }, + "cs": { + "translation": "src/locale/messages.cs.xlf", + "baseHref": "/cs/" + }, + "de": { + "translation": "src/locale/messages.de.xlf", + "baseHref": "/de/" + }, + "da": { + "translation": "src/locale/messages.da.xlf", + "baseHref": "/da/" + }, + "es": { + "translation": "src/locale/messages.es.xlf", + "baseHref": "/es/" + }, + "fa": { + "translation": "src/locale/messages.fa.xlf", + "baseHref": "/fa/" + }, + "fr": { + "translation": "src/locale/messages.fr.xlf", + "baseHref": "/fr/" + }, + "ja": { + "translation": "src/locale/messages.ja.xlf", + "baseHref": "/ja/" + }, + "ka": { + "translation": "src/locale/messages.ka.xlf", + "baseHref": "/ka/" + }, + "ko": { + "translation": "src/locale/messages.ko.xlf", + "baseHref": "/ko/" + }, + "it": { + "translation": "src/locale/messages.it.xlf", + "baseHref": "/it/" + }, + "he": { + "translation": "src/locale/messages.he.xlf", + "baseHref": "/he/" + }, + "nl": { + "translation": "src/locale/messages.nl.xlf", + "baseHref": "/nl/" + }, + "nb": { + "translation": "src/locale/messages.nb.xlf", + "baseHref": "/nb/" + }, + "pl": { + "translation": "src/locale/messages.pl.xlf", + "baseHref": "/pl/" + }, + "pt": { + "translation": "src/locale/messages.pt.xlf", + "baseHref": "/pt/" + }, + "sl": { + "translation": "src/locale/messages.sl.xlf", + "baseHref": "/sl/" + }, + "sv": { + "translation": "src/locale/messages.sv.xlf", + "baseHref": "/sv/" + }, + "th": { + "translation": "src/locale/messages.th.xlf", + "baseHref": "/th/" + }, + "tr": { + "translation": "src/locale/messages.tr.xlf", + "baseHref": "/tr/" + }, + "uk": { + "translation": "src/locale/messages.uk.xlf", + "baseHref": "/uk/" + }, + "fi": { + "translation": "src/locale/messages.fi.xlf", + "baseHref": "/fi/" + }, + "vi": { + "translation": "src/locale/messages.vi.xlf", + "baseHref": "/vi/" + }, + "hu": { + "translation": "src/locale/messages.hu.xlf", + "baseHref": "/hu/" + }, + "mk": { + "translation": "src/locale/messages.mk.xlf", + "baseHref": "/mk/" + }, + "zh": { + "translation": "src/locale/messages.zh.xlf", + "baseHref": "/zh/" + }, + "ro": { + "translation": "src/locale/messages.ro.xlf", + "baseHref": "/ro/" + }, + "ru": { + "translation": "src/locale/messages.ru.xlf", + "baseHref": "/ru/" + }, + "hi": { + "translation": "src/locale/messages.hi.xlf", + "baseHref": "/hi/" + }, + "ne": { + "translation": "src/locale/messages.ne.xlf", + "baseHref": "/ne/" + }, + "lt": { + "translation": "src/locale/messages.lt.xlf", + "baseHref": "/lt/" + } + } + }, "architect": { "build": { "builder": "@angular-devkit/build-angular:browser", "options": { - "outputPath": "dist/mempool", + "outputPath": "dist/mempool/browser", "index": "src/index.html", "main": "src/main.ts", "polyfills": "src/polyfills.ts", "tsConfig": "tsconfig.app.json", - "aot": true, "assets": [ "src/favicon.ico", - "src/resources" + "src/resources", + "src/robots.txt", + "src/config.js", + "src/customize.js", + "src/config.template.js" ], "styles": [ - "src/styles.scss" + "src/styles.scss", + { + "input": "src/theme-contrast.scss", + "bundleName": "contrast", + "inject": false + }, + { + "input": "src/theme-wiz.scss", + "bundleName": "wiz", + "inject": false + }, + { + "input": "src/theme-bukele.scss", + "bundleName": "bukele", + "inject": false + }, + "node_modules/@fortawesome/fontawesome-svg-core/styles.css" ], - "scripts": [ - "generated-config.js" - ] + "vendorChunk": true, + "extractLicenses": false, + "buildOptimizer": false, + "sourceMap": true, + "optimization": false, + "namedChunks": true }, "configurations": { "production": { + "assets": [ + "src/favicon.ico", + "src/robots.txt" + ], "fileReplacements": [ { "replace": "src/environments/environment.ts", "with": "src/environments/environment.prod.ts" } ], - "optimization": true, + "optimization": { + "scripts": true, + "styles": { + "minify": true, + "inlineCritical": false + }, + "fonts": true + }, "outputHashing": "all", "sourceMap": false, - "extractCss": true, "namedChunks": false, "extractLicenses": true, "vendorChunk": false, @@ -62,59 +233,122 @@ } ] } - } + }, + "defaultConfiguration": "" }, "serve": { "builder": "@angular-devkit/build-angular:dev-server", "options": { - "browserTarget": "mempool:build" + "buildTarget": "mempool:build" }, "configurations": { "production": { - "browserTarget": "mempool:build:production" + "buildTarget": "mempool:build:production" + }, + "local": { + "proxyConfig": "proxy.conf.local.js", + "verbose": true + }, + "local-esplora": { + "proxyConfig": "proxy.conf.local-esplora.js", + "verbose": true + }, + "mixed": { + "proxyConfig": "proxy.conf.mixed.js", + "verbose": true + }, + "staging": { + "proxyConfig": "proxy.conf.js", + "disableHostCheck": true, + "host": "0.0.0.0", + "verbose": true + }, + "local-prod": { + "proxyConfig": "proxy.conf.js", + "disableHostCheck": true, + "host": "0.0.0.0", + "verbose": false + }, + "local-staging": { + "proxyConfig": "proxy.conf.staging.js", + "disableHostCheck": true, + "host": "0.0.0.0", + "verbose": false } } }, "extract-i18n": { "builder": "@angular-devkit/build-angular:extract-i18n", "options": { - "browserTarget": "mempool:build" + "buildTarget": "mempool:build" } }, - "test": { - "builder": "@angular-devkit/build-angular:karma", + "e2e": { + "builder": "@cypress/schematic:cypress", "options": { - "main": "src/test.ts", - "polyfills": "src/polyfills.ts", - "tsConfig": "tsconfig.spec.json", - "karmaConfig": "karma.conf.js", - "assets": [ - "src/favicon.ico", - "src/resources" - ], - "styles": [ - "src/styles.scss" - ], - "scripts": [] + "devServerTarget": "mempool:serve:local-prod", + "watch": true, + "headless": false + }, + "configurations": { + "production": { + "devServerTarget": "mempool:serve:production" + } } }, - "lint": { - "builder": "@angular-devkit/build-angular:tslint", + "server": { + "builder": "@angular-devkit/build-angular:server", "options": { - "tsConfig": [ - "tsconfig.app.json", - "tsconfig.spec.json", - "e2e/tsconfig.json" - ], - "exclude": [ - "**/node_modules/**" + "outputPath": "dist/mempool/server", + "main": "server.ts", + "tsConfig": "tsconfig.server.json" + }, + "configurations": { + "production": { + "outputHashing": "media", + "fileReplacements": [ + { + "replace": "src/environments/environment.ts", + "with": "src/environments/environment.prod.ts" + } + ], + "sourceMap": false, + "localize": true, + "optimization": false + } + } + }, + "serve-ssr": { + "builder": "@angular-devkit/build-angular:ssr-dev-server", + "options": { + "browserTarget": "mempool:build", + "serverTarget": "mempool:server" + }, + "configurations": { + "production": { + "browserTarget": "mempool:build:production", + "serverTarget": "mempool:server:production", + "optimization": false, + "sourceMap": true + } + } + }, + "prerender": { + "builder": "@angular-devkit/build-angular:prerender", + "options": { + "browserTarget": "mempool:build:production", + "serverTarget": "mempool:server:production", + "routes": [ + "/" ] + }, + "configurations": { + "production": {} } }, - "e2e": { - "builder": "@angular-devkit/build-angular:protractor", + "cypress-run": { + "builder": "@cypress/schematic:cypress", "options": { - "protractorConfig": "e2e/protractor.conf.js", "devServerTarget": "mempool:serve" }, "configurations": { @@ -122,8 +356,15 @@ "devServerTarget": "mempool:serve:production" } } + }, + "cypress-open": { + "builder": "@cypress/schematic:cypress", + "options": { + "watch": true, + "headless": false + } } } - }}, - "defaultProject": "mempool" -} \ No newline at end of file + } + } +} diff --git a/frontend/custom-sv-config.json b/frontend/custom-sv-config.json new file mode 100644 index 0000000000..dee3dab18e --- /dev/null +++ b/frontend/custom-sv-config.json @@ -0,0 +1,52 @@ +{ + "theme": "bukele", + "enterprise": "onbtc", + "branding": { + "name": "onbtc", + "title": "Bitcoin Office", + "site_id": 19, + "header_img": "/resources/onbtclogo.svg", + "footer_img": "/resources/onbtclogo.svg", + "rounded_corner": true + }, + "dashboard": { + "widgets": [ + { + "component": "fees", + "mobileOrder": 4 + }, + { + "component": "balance", + "mobileOrder": 1, + "props": { + "address": "32ixEdVJWo3kmvJGMTZq5jAQVZZeuwnqzo" + } + }, + { + "component": "twitter", + "mobileOrder": 5, + "props": { + "handle": "nayibbukele" + } + }, + { + "component": "address", + "mobileOrder": 2, + "props": { + "address": "32ixEdVJWo3kmvJGMTZq5jAQVZZeuwnqzo", + "period": "1m" + } + }, + { + "component": "blocks" + }, + { + "component": "addressTransactions", + "mobileOrder": 3, + "props": { + "address": "32ixEdVJWo3kmvJGMTZq5jAQVZZeuwnqzo" + } + } + ] + } +} \ No newline at end of file diff --git a/frontend/cypress.config.ts b/frontend/cypress.config.ts new file mode 100644 index 0000000000..4bdbd257d0 --- /dev/null +++ b/frontend/cypress.config.ts @@ -0,0 +1,29 @@ +import { defineConfig } from 'cypress'; + +export default defineConfig({ + projectId: 'ry4br7', + videosFolder: 'cypress/videos', + screenshotsFolder: 'cypress/screenshots', + fixturesFolder: 'cypress/fixtures', + video: false, + retries: { + runMode: 3, + openMode: 0, + }, + chromeWebSecurity: false, + e2e: { + setupNodeEvents(on: any, config: any) { + const fs = require('fs'); + const CONFIG_FILE = 'mempool-frontend-config.json'; + if (fs.existsSync(CONFIG_FILE)) { + let contents = JSON.parse(fs.readFileSync(CONFIG_FILE, 'utf8')); + config.env.BASE_MODULE = contents.BASE_MODULE ? contents.BASE_MODULE : 'mempool'; + } else { + config.env.BASE_MODULE = 'mempool'; + } + return config; + }, + baseUrl: 'http://localhost:4200', + specPattern: 'cypress/e2e/**/*.{js,jsx,ts,tsx}', + }, +}); diff --git a/frontend/cypress/e2e/liquid/liquid.spec.ts b/frontend/cypress/e2e/liquid/liquid.spec.ts new file mode 100644 index 0000000000..c7d2a92eed --- /dev/null +++ b/frontend/cypress/e2e/liquid/liquid.spec.ts @@ -0,0 +1,208 @@ +describe('Liquid', () => { + const baseModule = Cypress.env('BASE_MODULE'); + const basePath = ''; + + beforeEach(() => { + cy.intercept('/liquid/api/block/**').as('block'); + cy.intercept('/liquid/api/blocks/').as('blocks'); + cy.intercept('/liquid/api/tx/**/outspends').as('outspends'); + cy.intercept('/liquid/api/block/**/txs/**').as('block-txs'); + + Cypress.Commands.add('waitForBlockData', () => { + cy.wait('@socket'); + cy.wait('@block'); + cy.wait('@outspends'); + }); + }); + + if (baseModule === 'liquid') { + + it('check first mempool block after skeleton loads', () => { + cy.visit(`${basePath}`); + cy.waitForSkeletonGone(); + cy.get('#mempool-block-0 > .blockLink').should('exist'); + }); + + it('load first mempool block after skeleton loads', () => { + cy.visit(`${basePath}`); + cy.waitForSkeletonGone(); + cy.get('#mempool-block-0 > .blockLink').click(); + cy.waitForSkeletonGone(); + }); + + it('loads the dashboard', () => { + cy.visit(`${basePath}`); + cy.waitForSkeletonGone(); + }); + + it('loads the blocks page', () => { + cy.visit(`${basePath}`); + cy.get('#btn-blocks').click().then(() => { + cy.wait(1000); + }); + cy.waitForSkeletonGone(); + }); + + it('loads a specific block page', () => { + cy.visit(`${basePath}/block/7e1369a23a5ab861e7bdede2aadcccae4ea873ffd9caf11c7c5541eb5bcdff54`); + cy.get('.pagination').scrollIntoView({ offset: { top: 200, left: 0 } }); + cy.waitForSkeletonGone(); + }); + + it('loads the graphs page', () => { + cy.visit(`${basePath}`); + cy.waitForSkeletonGone(); + cy.get('#btn-graphs').click().then(() => { + cy.wait(1000); + }); + }); + + it('loads the tv page - desktop', () => { + cy.visit(`${basePath}/tv`); + cy.waitForSkeletonGone(); + }); + + it('loads the graphs page - mobile', () => { + cy.visit(`${basePath}`) + cy.waitForSkeletonGone(); + cy.get('#btn-graphs').click().then(() => { + cy.viewport('iphone-6'); + cy.wait(1000); + cy.get('.tv-only').should('not.exist'); + }); + }); + + describe('peg in/peg out', () => { + it('loads peg in addresses', () => { + cy.visit(`${basePath}/tx/fe764f7bedfc2a37b29d9c8aef67d64a57d253a6b11c5a55555cfd5826483a58`); + cy.waitForSkeletonGone(); + //TODO: Change to an element id so we don't assert on a string + cy.get('.table-tx-vin').should('contain', 'Peg-in'); + //Remove the target=_blank attribute so the new url opens in the same tab + cy.get('.table-tx-vin a').invoke('removeAttr', 'target').click().then(() => { + cy.waitForSkeletonGone(); + if (baseModule === 'liquid') { + cy.url().should('eq', 'https://mempool.space/tx/f148c0d854db4174ea420655235f910543f0ec3680566dcfdf84fb0a1697b592#vout=0'); + } else { + //TODO: Use an environment variable to get the hostname + cy.url().should('eq', 'http://localhost:4200/tx/f148c0d854db4174ea420655235f910543f0ec3680566dcfdf84fb0a1697b592'); + } + }); + }); + + it('loads peg out addresses', () => { + cy.visit(`${basePath}/tx/ecf6eba04ffb3946faa172343c87162df76f1a57b07b0d6dc6ad956b13376dc8`); + cy.waitForSkeletonGone(); + //Remove the target=_blank attribute so the new url opens in the same tab + cy.get('.table-tx-vout a').first().invoke('removeAttr', 'target').click().then(() => { + cy.waitForSkeletonGone(); + if (baseModule === 'liquid') { + cy.url().should('eq', 'https://mempool.space/address/1BxoGcMg14oaH3CwHD2hF4gU9VcfgX5yoR'); + } else { + //TODO: Use an environment variable to get the hostname + cy.url().should('eq', 'http://localhost:4200/address/1BxoGcMg14oaH3CwHD2hF4gU9VcfgX5yoR'); + } + //TODO: Add a custom class so we don't assert on a string + cy.get('.badge').should('contain', 'Liquid Peg Out'); + }); + }); + }); + + describe('assets', () => { + it('shows the assets screen', () => { + cy.visit(`${basePath}/assets`); + cy.waitForSkeletonGone(); + cy.get('.featuredBox .card').should('have.length.at.least', 5); + }); + + it('allows searching assets', () => { + cy.visit(`${basePath}/assets`); + cy.waitForSkeletonGone(); + cy.get('.container-xl input').click().type('Liquid Bitcoin').then(() => { + cy.get('ngb-typeahead-window', { timeout: 30000 }).should('have.length', 1); + }); + }); + + it('shows a specific asset ID', () => { + cy.visit(`${basePath}/assets`); + cy.waitForSkeletonGone(); + cy.get('.container-xl input').click().type('Liquid AUD').then(() => { + cy.get('ngb-typeahead-window:nth-of-type(1) button', { timeout: 30000 }).click(); + }); + }); + }); + + + describe('unblinded TX', () => { + + it('should not show an unblinding error message for regular txs', () => { + cy.visit(`${basePath}/tx/82a479043ec3841e0d3f829afc8df4f0e2bbd675a13f013ea611b2fde0027d45`); + cy.waitForSkeletonGone(); + cy.get('.error-unblinded').should('not.exist'); + }); + + it('show unblinded TX', () => { + cy.visit(`${basePath}/tx/f2f41c0850e8e7e3f1af233161fd596662e67c11ef10ed15943884186fbb7f46#blinded=100000,6f0279e9ed041c3d710a9f57d0c02928416460c4b722ae3457a11eec381c526d,0ab9f70650f16b1db8dfada05237f7d0d65191c3a13183da8a2ddddfbde9a2ad,fd98b2edc5530d76acd553f206a431f4c1fab27e10e290ad719582af878e98fc,2364760,6f0279e9ed041c3d710a9f57d0c02928416460c4b722ae3457a11eec381c526d,90c7a43b15b905bca045ca42a01271cfe71d2efe3133f4197792c24505cb32ed,12eb5959d9293b8842e7dd8bc9aa9639fd3fd031c5de3ba911adeca94eb57a3a`); + cy.waitForSkeletonGone(); + cy.get('.table-tx-vin tr:nth-child(1) .amount').should('contain.text', '0.02465000 L-BTC'); + cy.get('.table-tx-vin tr').should('have.class', 'assetBox'); + cy.get('.table-tx-vout tr:nth-child(1) .amount').should('contain.text', '0.00100000 L-BTC'); + cy.get('.table-tx-vout tr:nth-child(2) .amount').should('contain.text', '0.02364760 L-BTC'); + cy.get('.table-tx-vout tr').should('have.class', 'assetBox'); + }); + + it('show empty unblinded TX', () => { + cy.visit(`${basePath}/tx/f2f41c0850e8e7e3f1af233161fd596662e67c11ef10ed15943884186fbb7f46#blinded=`); + cy.waitForSkeletonGone(); + cy.get('.table-tx-vin tr:nth-child(1)').should('have.class', 'ng-star-inserted'); + cy.get('.table-tx-vin tr:nth-child(1) .amount').should('contain.text', 'Confidential'); + cy.get('.table-tx-vout tr:nth-child(1)').should('have.class', 'ng-star-inserted'); + cy.get('.table-tx-vout tr:nth-child(2)').should('have.class', 'ng-star-inserted'); + cy.get('.table-tx-vout tr:nth-child(1) .amount').should('contain.text', 'Confidential'); + cy.get('.table-tx-vout tr:nth-child(2) .amount').should('contain.text', 'Confidential'); + }); + + it('show invalid unblinded TX hex', () => { + cy.visit(`${basePath}/tx/f2f41c0850e8e7e3f1af233161fd596662e67c11ef10ed15943884186fbb7f46#blinded=123`); + cy.waitForSkeletonGone(); + cy.get('.table-tx-vin tr').should('have.class', 'ng-star-inserted'); + cy.get('.table-tx-vout tr').should('have.class', 'ng-star-inserted'); + cy.get('.error-unblinded').contains('Error: Invalid blinding data (invalid hex)'); + }); + + it('show first unblinded vout', () => { + cy.visit(`${basePath}/tx/f2f41c0850e8e7e3f1af233161fd596662e67c11ef10ed15943884186fbb7f46#blinded=100000,6f0279e9ed041c3d710a9f57d0c02928416460c4b722ae3457a11eec381c526d,0ab9f70650f16b1db8dfada05237f7d0d65191c3a13183da8a2ddddfbde9a2ad,fd98b2edc5530d76acd553f206a431f4c1fab27e10e290ad719582af878e98fc`); + cy.waitForSkeletonGone(); + cy.get('.table-tx-vout tr:nth-child(1)').should('have.class', 'assetBox'); + cy.get('.table-tx-vout tr:nth-child(1) .amount').should('contain.text', '0.00100000 L-BTC'); + }); + + it('show second unblinded vout', () => { + cy.visit(`${basePath}/tx/f2f41c0850e8e7e3f1af233161fd596662e67c11ef10ed15943884186fbb7f46#blinded=2364760,6f0279e9ed041c3d710a9f57d0c02928416460c4b722ae3457a11eec381c526d,90c7a43b15b905bca045ca42a01271cfe71d2efe3133f4197792c24505cb32ed,12eb5959d9293b8842e7dd8bc9aa9639fd3fd031c5de3ba911adeca94eb57a3a`); + cy.get('.table-tx-vout tr:nth-child(2').should('have.class', 'assetBox'); + cy.get('.table-tx-vout tr:nth-child(2) .amount').should('contain.text', '0.02364760 L-BTC'); + }); + + it('show invalid error unblinded TX', () => { + cy.visit(`${basePath}/tx/f2f41c0850e8e7e3f1af233161fd596662e67c11ef10ed15943884186fbb7f46#blinded=100000,6f0279e9ed041c3d710a9f57d0c02928416460c4b722ae3457a11eec381c526d,0ab9f70650f16b1db8dfada05237f7d0d65191c3a13183da8a2ddddfbde9a2ad,fd98b2edc5530d76acd553f206a431f4c1fab27e10e290ad719582af878e98fc,2364760,6f0279e9ed041c3d710a9f57d0c02928416460c4b722ae3457a11eec381c526d,90c7a43b15b905bca045ca42a01271cfe71d2efe3133f4197792c24505cb32ed,12eb5959d9293b8842e7dd8bc9aa9639fd3fd031c5de3ba911adeca94eb57a3c`); + cy.waitForSkeletonGone(); + cy.get('.table-tx-vout tr').should('have.class', 'assetBox'); + cy.get('.error-unblinded').contains('Error: Invalid blinding data.'); + }); + + it('shows asset peg in/out and burn transactions', () => { + cy.visit(`${basePath}/assets/asset/6f0279e9ed041c3d710a9f57d0c02928416460c4b722ae3457a11eec381c526d`); + cy.waitForSkeletonGone(); + cy.get('.table-tx-vout tr').not('.assetBox'); + cy.get('.table-tx-vin tr').not('.assetBox'); + }); + + it('prevents regressing issue #644', () => { + cy.visit(`${basePath}/tx/393b890966f305e7c440fcfb12a13f51a7a9011cc59ff5f14f6f93214261bd82`); + cy.waitForSkeletonGone(); + }); + }); + } else { + it.skip(`Tests cannot be run on the selected BASE_MODULE ${baseModule}`); + } +}); diff --git a/frontend/cypress/e2e/liquidtestnet/liquidtestnet.spec.ts b/frontend/cypress/e2e/liquidtestnet/liquidtestnet.spec.ts new file mode 100644 index 0000000000..54e355ce80 --- /dev/null +++ b/frontend/cypress/e2e/liquidtestnet/liquidtestnet.spec.ts @@ -0,0 +1,177 @@ +describe('Liquid Testnet', () => { + const baseModule = Cypress.env('BASE_MODULE'); + const basePath = '/testnet'; + + beforeEach(() => { + cy.intercept('/liquidtestnet/api/block/**').as('block'); + cy.intercept('/liquidtestnet/api/blocks/').as('blocks'); + cy.intercept('/liquidtestnet/api/tx/**/outspends').as('outspends'); + cy.intercept('/liquidtestnet/api/block/**/txs/**').as('block-txs'); + + Cypress.Commands.add('waitForBlockData', () => { + cy.wait('@socket'); + cy.wait('@block'); + cy.wait('@outspends'); + }); + }); + + if (baseModule === 'liquid') { + + it('check first mempool block after skeleton loads', () => { + cy.visit(`${basePath}`); + cy.waitForSkeletonGone(); + cy.get('#mempool-block-0 > .blockLink').should('exist'); + }); + + it('loads the dashboard', () => { + cy.visit(`${basePath}`); + cy.waitForSkeletonGone(); + }); + + it.skip('loads the dashboard with no scrollbars on mobile', () => { + cy.viewport('iphone-xr'); + cy.visit(`${basePath}`); + cy.waitForSkeletonGone(); + cy.window().then(window => { + const htmlWidth = Cypress.$('html')[0].scrollWidth; + const scrollBarWidth = window.innerWidth - htmlWidth; + expect(scrollBarWidth).to.be.eq(0); //check for no horizontal scrollbar + }); + }); + + it('loads the blocks page', () => { + cy.visit(`${basePath}`) + cy.get('#btn-blocks'); + cy.waitForSkeletonGone(); + }); + + it('loads a specific block page', () => { + cy.visit(`${basePath}/block/fb4cbcbff3993ca4bf8caf657d55a23db5ed4ab1cfa33c489303c2e04e1c38e0`); + cy.get('.pagination').scrollIntoView({ offset: { top: 200, left: 0 } }); + cy.waitForSkeletonGone(); + }); + + it('loads the graphs page', () => { + cy.visit(`${basePath}`); + cy.get('#btn-graphs'); + cy.waitForSkeletonGone(); + }); + + it('loads the tv page - desktop', () => { + cy.visit(`${basePath}/tv`); + cy.waitForSkeletonGone(); + }); + + it('loads the graphs page - mobile', () => { + cy.visit(`${basePath}`) + cy.waitForSkeletonGone(); + cy.viewport('iphone-6'); + cy.get('.tv-only').should('not.exist'); + }); + + it.skip('renders unconfidential transactions correctly on mobile', () => { + cy.viewport('iphone-xr'); + cy.visit(`${basePath}/tx/b119f338878416781dc285b94c0de52826341dea43566e4de4740d3ebfd1f6dc#blinded=99707,144c654344aa716d6f3abcc1ca90e5641e4e2a7f633bc09fe3baf64585819a49,1377e4ec8eb0c89296e14ffca57e377f4b51ad8f1c881e43364434d8430dbfda,cdd6caae4c3452586cfcb107478dd2b7acaa5f82714a6a966578255e857eee60`); + cy.waitForSkeletonGone(); + cy.window().then(window => { + const htmlWidth = Cypress.$('html')[0].scrollWidth; + const scrollBarWidth = window.innerWidth - htmlWidth; + expect(scrollBarWidth).to.be.eq(0); //check for no horizontal scrollbar + }); + }); + + describe('assets', () => { + it('allows searching assets', () => { + cy.visit(`${basePath}/assets`); + cy.waitForSkeletonGone(); + cy.get('.container-xl input').click().type('Liquid Bitcoin').then(() => { + cy.get('ngb-typeahead-window').should('have.length', 1); + }); + }); + + it('shows a specific asset ID', () => { + cy.visit(`${basePath}/assets`); + cy.waitForSkeletonGone(); + cy.get('.container-xl input').click().type('Liquid CAD').then(() => { + cy.get('ngb-typeahead-window:nth-of-type(1) button').click(); + }); + }); + }); + + describe('unblinded TX', () => { + it('should not show an unblinding error message for regular txs', () => { + cy.visit(`${basePath}/tx/82a479043ec3841e0d3f829afc8df4f0e2bbd675a13f013ea611b2fde0027d45`); + cy.waitForSkeletonGone(); + cy.get('.error-unblinded').should('not.exist'); + }); + + it('show unblinded TX', () => { + cy.visit(`${basePath}/tx/c3d908ab77891e4c569b0df71aae90f4720b157019ebb20db176f4f9c4d626b8#blinded=100000,144c654344aa716d6f3abcc1ca90e5641e4e2a7f633bc09fe3baf64585819a49,df290ead654d7d110ebc5aaf0bcf11d5b5d360431a467f1cde0a856fde986893,33cb3a2fd2e76643843691cf44a78c5cd28ec652a414da752160ad63fbd37bc9,49741,144c654344aa716d6f3abcc1ca90e5641e4e2a7f633bc09fe3baf64585819a49,edb0713bcbfcb3daabf601cb50978439667d208e15fed8a5ebbfea5696cda1d5,4de70115501e8c7d6bd763e229bf42781edeacf6e75e1d7bdfa4c63104bc508a`); + cy.waitForSkeletonGone(); + cy.get('.table-tx-vin tr:nth-child(1) .amount').should('contain.text', '0.00100000 tL-BTC'); + cy.get('.table-tx-vin tr').should('have.class', 'assetBox'); + cy.get('.table-tx-vout tr:nth-child(1) .amount').should('contain.text', '0.00050000 tL-BTC'); + cy.get('.table-tx-vout tr:nth-child(2) .amount').should('contain.text', '0.00049741 tL-BTC'); + cy.get('.table-tx-vout tr').should('have.class', 'assetBox'); + }); + + it('show empty unblinded TX', () => { + cy.visit(`${basePath}/tx/c3d908ab77891e4c569b0df71aae90f4720b157019ebb20db176f4f9c4d626b8#blinded=`); + cy.waitForSkeletonGone(); + cy.get('.table-tx-vin tr:nth-child(1)').should('have.class', 'ng-star-inserted'); + cy.get('.table-tx-vin tr:nth-child(1) .amount').should('contain.text', 'Confidential'); + cy.get('.table-tx-vout tr:nth-child(1)').should('have.class', 'ng-star-inserted'); + cy.get('.table-tx-vout tr:nth-child(2)').should('have.class', 'ng-star-inserted'); + cy.get('.table-tx-vout tr:nth-child(1) .amount').should('contain.text', 'Confidential'); + cy.get('.table-tx-vout tr:nth-child(2) .amount').should('contain.text', 'Confidential'); + }); + + it('show invalid unblinded TX hex', () => { + cy.visit(`${basePath}/tx/2477f220eef1d03f8ffa4a2861c275d155c3562adf0d79523aeeb0c59ee611ba#blinded=5000`); + cy.waitForSkeletonGone(); + cy.get('.table-tx-vin tr').should('have.class', 'ng-star-inserted'); + cy.get('.table-tx-vout tr').should('have.class', 'ng-star-inserted'); + cy.get('.error-unblinded').contains('Error: Invalid blinding data (invalid hex)'); + }); + + it('show first unblinded vout', () => { + cy.visit(`${basePath}/tx/0877bc0c7aa5c2b8d0e4b15450425879b8783c40e341806037a605ef836fb886#blinded=5000,38fca2d939696061a8f76d4e6b5eecd54e3b4221c846f24a6b279e79952850a5,328de54e90e867a9154b4f1eb7fcab86267e880fa2ee9e53b41a91e61dab86e6,8885831e6b089eaf06889d53a24843f0da533d300a7b1527b136883a6819f3ae,5000,38fca2d939696061a8f76d4e6b5eecd54e3b4221c846f24a6b279e79952850a5,aca78b953615d69ae0ae68c4c5c3c0ee077c10bc20ad3f0c5960706004e6cb56,d2ec175afe5f761e2dbd443faf46abbb7091f341deb3387e5787d812bdb2df9f,100000,144c654344aa716d6f3abcc1ca90e5641e4e2a7f633bc09fe3baf64585819a49,4b54a4ca809b3844f34dd88b68617c4c866d92a02211f02ba355755bac20a1c6,eddd02e92b0cfbad8cab89828570a50f2c643bb2a54d886c86e25ce47e818685,99729,144c654344aa716d6f3abcc1ca90e5641e4e2a7f633bc09fe3baf64585819a49,8b86d565c9549eb0352bb81ee576d01d064435b64fddcc045decebeb1d9913ce,b082ce3448d40d47b5b39f15d72b285f4a1046b636b56c25f32f498ece29d062,10000,38fca2d939696061a8f76d4e6b5eecd54e3b4221c846f24a6b279e79952850a5,62b04ee86198d6b41681cdd0acb450ab366af727a010aaee8ba0b9e69ff43896,3f98429bca9b538dc943c22111f25d9c4448d45a63ff0f4e58b22fd434c0365e`); + cy.waitForSkeletonGone(); + cy.get('.table-tx-vout tr:nth-child(1)').should('have.class', 'assetBox'); + cy.get('.table-tx-vout tr:nth-child(1) .amount').should('contain.text', '0.00099729 tL-BTC'); + }); + + it('show second unblinded vout (asset)', () => { + cy.visit(`${basePath}/tx/0877bc0c7aa5c2b8d0e4b15450425879b8783c40e341806037a605ef836fb886#blinded=5000,38fca2d939696061a8f76d4e6b5eecd54e3b4221c846f24a6b279e79952850a5,328de54e90e867a9154b4f1eb7fcab86267e880fa2ee9e53b41a91e61dab86e6,8885831e6b089eaf06889d53a24843f0da533d300a7b1527b136883a6819f3ae,5000,38fca2d939696061a8f76d4e6b5eecd54e3b4221c846f24a6b279e79952850a5,aca78b953615d69ae0ae68c4c5c3c0ee077c10bc20ad3f0c5960706004e6cb56,d2ec175afe5f761e2dbd443faf46abbb7091f341deb3387e5787d812bdb2df9f,100000,144c654344aa716d6f3abcc1ca90e5641e4e2a7f633bc09fe3baf64585819a49,4b54a4ca809b3844f34dd88b68617c4c866d92a02211f02ba355755bac20a1c6,eddd02e92b0cfbad8cab89828570a50f2c643bb2a54d886c86e25ce47e818685,99729,144c654344aa716d6f3abcc1ca90e5641e4e2a7f633bc09fe3baf64585819a49,8b86d565c9549eb0352bb81ee576d01d064435b64fddcc045decebeb1d9913ce,b082ce3448d40d47b5b39f15d72b285f4a1046b636b56c25f32f498ece29d062,10000,38fca2d939696061a8f76d4e6b5eecd54e3b4221c846f24a6b279e79952850a5,62b04ee86198d6b41681cdd0acb450ab366af727a010aaee8ba0b9e69ff43896,3f98429bca9b538dc943c22111f25d9c4448d45a63ff0f4e58b22fd434c0365e`); + cy.get('.table-tx-vout tr:nth-child(2)').should('have.class', 'assetBox'); + //TODO Update after the precision bug fix is merged + cy.get('.table-tx-vout tr:nth-child(2) .amount').should('contain.text', '0 TEST'); + }); + + it('should link to the asset page from the unblinded tx', () => { + cy.visit(`${basePath}/tx/0877bc0c7aa5c2b8d0e4b15450425879b8783c40e341806037a605ef836fb886#blinded=5000,38fca2d939696061a8f76d4e6b5eecd54e3b4221c846f24a6b279e79952850a5,328de54e90e867a9154b4f1eb7fcab86267e880fa2ee9e53b41a91e61dab86e6,8885831e6b089eaf06889d53a24843f0da533d300a7b1527b136883a6819f3ae,5000,38fca2d939696061a8f76d4e6b5eecd54e3b4221c846f24a6b279e79952850a5,aca78b953615d69ae0ae68c4c5c3c0ee077c10bc20ad3f0c5960706004e6cb56,d2ec175afe5f761e2dbd443faf46abbb7091f341deb3387e5787d812bdb2df9f,100000,144c654344aa716d6f3abcc1ca90e5641e4e2a7f633bc09fe3baf64585819a49,4b54a4ca809b3844f34dd88b68617c4c866d92a02211f02ba355755bac20a1c6,eddd02e92b0cfbad8cab89828570a50f2c643bb2a54d886c86e25ce47e818685,99729,144c654344aa716d6f3abcc1ca90e5641e4e2a7f633bc09fe3baf64585819a49,8b86d565c9549eb0352bb81ee576d01d064435b64fddcc045decebeb1d9913ce,b082ce3448d40d47b5b39f15d72b285f4a1046b636b56c25f32f498ece29d062,10000,38fca2d939696061a8f76d4e6b5eecd54e3b4221c846f24a6b279e79952850a5,62b04ee86198d6b41681cdd0acb450ab366af727a010aaee8ba0b9e69ff43896,3f98429bca9b538dc943c22111f25d9c4448d45a63ff0f4e58b22fd434c0365e`); + cy.get('.table-tx-vout tr:nth-child(2) .amount a').click().then(() => { + cy.waitForSkeletonGone(); + cy.url().should('contain', '/assets/asset/38fca2d939696061a8f76d4e6b5eecd54e3b4221c846f24a6b279e79952850a5'); + }); + }); + + it('show invalid error unblinded TX', () => { + cy.visit(`${basePath}/tx/c3d908ab77891e4c569b0df71aae90f4720b157019ebb20db176f4f9c4d626b8#blinded=100000,144c654344aa716d6f3abcc1ca90e5641e4e2a7f633bc09fe3baf64585819a49,df290ead654d7d110ebc5aaf0bcf11d5b5d360431a467f1cde0a856fde986893,33cb3a2fd2e76643843691cf44a78c5cd28ec652a414da752160ad63fbd37bc9,49741,144c654344aa716d6f3abcc1ca90e5641e4e2a7f633bc09fe3baf64585819a49,edb0713bcbfcb3daabf601cb50978439667d208e15fed8a5ebbfea5696cda1d5,4de70115501e8c7d6bd763e229bf42781edeacf6e75e1d7bdfa4c63104bc508c`); + cy.waitForSkeletonGone(); + cy.get('.table-tx-vin tr').should('have.class', 'assetBox'); + cy.get('.error-unblinded').contains('Error: Invalid blinding data.'); + }); + + it('shows asset peg in/out and burn transactions', () => { + cy.visit(`${basePath}/assets/asset/ac3e0ff248c5051ffd61e00155b7122e5ebc04fd397a0ecbdd4f4e4a56232926`); + cy.waitForSkeletonGone(); + cy.get('.table-tx-vout tr').not('.assetBox'); + cy.get('.table-tx-vin tr').not('.assetBox'); + }); + + }); + } else { + it.skip(`Tests cannot be run on the selected BASE_MODULE ${baseModule}`); + } +}); diff --git a/frontend/cypress/e2e/mainnet/mainnet.spec.ts b/frontend/cypress/e2e/mainnet/mainnet.spec.ts new file mode 100644 index 0000000000..4403949b62 --- /dev/null +++ b/frontend/cypress/e2e/mainnet/mainnet.spec.ts @@ -0,0 +1,606 @@ +import { emitMempoolInfo, dropWebSocket } from '../../support/websocket'; + +const baseModule = Cypress.env('BASE_MODULE'); + + +//Credit: https://github.com/bahmutov/cypress-examples/blob/6cedb17f83a3bb03ded13cf1d6a3f0656ca2cdf5/docs/recipes/overlapping-elements.md + +/** + * Returns true if two DOM rectangles are overlapping + * @param {DOMRect} rect1 the bounding client rectangle of the first element + * @param {DOMRect} rect2 the bounding client rectangle of the second element + * @returns {boolean} +*/ +const areOverlapping = (rect1, rect2) => { + // if one rectangle is on the left side of the other + if (rect1.right < rect2.left || rect2.right < rect1.left) { + return false + } + + // if one rectangle is above the other + if (rect1.bottom < rect2.top || rect2.bottom < rect1.top) { + return false + } + + // the rectangles must overlap + return true +} + +/** + * Returns the bounding rectangle of the first DOM + * element in the given jQuery object. + */ +const getRectangle = ($el) => $el[0].getBoundingClientRect(); + +describe('Mainnet', () => { + beforeEach(() => { + //cy.intercept('/sockjs-node/info*').as('socket'); + // cy.intercept('/api/block-height/*').as('block-height'); + // cy.intercept('/api/v1/block/*').as('block'); + // cy.intercept('/api/block/*/txs/0').as('block-txs'); + // cy.intercept('/api/v1/block/*/summary').as('block-summary'); + // cy.intercept('/api/v1/outspends/*').as('outspends'); + // cy.intercept('/api/tx/*/outspends').as('tx-outspends'); + + // Search Auto Complete + cy.intercept('/api/address-prefix/1wiz').as('search-1wiz'); + cy.intercept('/api/address-prefix/1wizS').as('search-1wizS'); + cy.intercept('/api/address-prefix/1wizSA').as('search-1wizSA'); + + // Cypress.Commands.add('waitForBlockData', () => { + // cy.wait('@tx-outspends'); + // cy.wait('@pools'); + // }); + }); + + if (baseModule === 'mempool') { + + it('check first mempool block after skeleton loads', () => { + cy.visit('/'); + cy.waitForSkeletonGone(); + cy.get('#mempool-block-0 > .blockLink').should('exist'); + }); + + it('loads the status screen', () => { + cy.visit('/status'); + cy.get('#mempool-block-0').should('be.visible'); + cy.get('[id^="bitcoin-block-"]').should('have.length', 22); + cy.get('.footer').should('be.visible'); + cy.get('.row > :nth-child(1)').invoke('text').then((text) => { + expect(text).to.match(/Incoming Transactions.* vB\/s/); + }); + cy.get('.row > :nth-child(2)').invoke('text').then((text) => { + expect(text).to.match(/Unconfirmed:(.*)/); + }); + cy.get('.row > :nth-child(3)').invoke('text').then((text) => { + expect(text).to.match(/Mempool size:(.*) (kB|MB) \((\d+) (block|blocks)\)/); + }); + }); + + //TODO: This test is flaky, refactor later + it.skip('loads dashboard, drop websocket and reconnect', () => { + cy.viewport('macbook-16'); + cy.mockMempoolSocket(); + cy.visit('/'); + cy.get('.badge').should('not.exist'); + dropWebSocket(); + cy.get('.badge').should('be.visible'); + cy.get('.badge', { timeout: 25000 }).should('not.exist'); + emitMempoolInfo({ + 'params': { + command: 'init' + } + }); + cy.get(':nth-child(1) > #bitcoin-block-0').should('not.exist'); + cy.get(':nth-child(2) > #bitcoin-block-0').should('not.exist'); + cy.get(':nth-child(3) > #bitcoin-block-0').should('not.exist'); + }); + + it('loads the dashboard', () => { + cy.visit('/'); + cy.waitForSkeletonGone(); + }); + + it('check op_return tx tooltip', () => { + cy.visit('/block/00000000000000000003c5f542bed265319c6cf64238cf1f1bb9bca3ebf686d2'); + cy.get('.pagination').scrollIntoView({ offset: { top: 200, left: 0 } }); + cy.waitForSkeletonGone(); + cy.get('tbody > :nth-child(2) > :nth-child(1) > a').first().trigger('onmouseover'); + cy.get('tbody > :nth-child(2) > :nth-child(1) > a').first().trigger('mouseenter'); + cy.get('.tooltip-inner').should('be.visible'); + }); + + it('check op_return coinbase tooltip', () => { + cy.visit('/block/00000000000000000003c5f542bed265319c6cf64238cf1f1bb9bca3ebf686d2'); + cy.get('.pagination').scrollIntoView({ offset: { top: 200, left: 0 } }); + cy.waitForSkeletonGone(); + cy.get('tbody > :nth-child(2) > :nth-child(1) > a').first().trigger('onmouseover'); + cy.get('tbody > :nth-child(2) > :nth-child(1) > a').first().trigger('mouseenter'); + cy.get('.tooltip-inner').should('be.visible'); + }); + + describe('search', () => { + it('allows searching for partial Bitcoin addresses', () => { + cy.visit('/'); + cy.get('.search-box-container > .form-control').type('1wiz').then(() => { + cy.wait('@search-1wiz'); + cy.get('app-search-results button.dropdown-item').should('have.length', 10); + }); + + cy.get('.search-box-container > .form-control').type('S').then(() => { + cy.wait('@search-1wizS'); + cy.get('app-search-results button.dropdown-item').should('have.length', 6); + }); + + cy.get('.search-box-container > .form-control').type('A').then(() => { + cy.wait('@search-1wizSA'); + cy.get('app-search-results button.dropdown-item').should('have.length', 1) + }); + + cy.get('app-search-results button.dropdown-item.active').click().then(() => { + cy.url().should('include', '/address/1wizSAYSbuyXbt9d8JV8ytm5acqq2TorC'); + cy.waitForSkeletonGone(); + cy.get('.text-center').should('not.have.text', 'Invalid Bitcoin address'); + }); + }); + + ['BC1PQYQS', 'bc1PqYqS'].forEach((searchTerm) => { + it(`allows searching for partial case insensitive bech32m addresses: ${searchTerm}`, () => { + cy.visit('/'); + cy.get('.search-box-container > .form-control').type(searchTerm).then(() => { + cy.get('app-search-results button.dropdown-item').should('have.length', 10); + cy.get('app-search-results button.dropdown-item.active').click().then(() => { + cy.url().should('include', '/address/bc1pqyqs26fs4gnyw4aqttyjqa5ta7075zzfjftyz98qa8vdr49dh7fqm2zkv3'); + cy.waitForSkeletonGone(); + cy.get('.text-center').should('not.have.text', 'Invalid Bitcoin address'); + }); + }); + }); + }); + + ['BC1Q0003', 'bC1q0003'].forEach((searchTerm) => { + it(`allows searching for partial case insensitive bech32 addresses: ${searchTerm}`, () => { + cy.visit('/'); + cy.get('.search-box-container > .form-control').type(searchTerm).then(() => { + cy.get('app-search-results button.dropdown-item').should('have.length', 10); + cy.get('app-search-results button.dropdown-item.active').click().then(() => { + cy.url().should('include', '/address/bc1q000303cgr9zazthut63kdktwtatfe206um8nyh'); + cy.waitForSkeletonGone(); + cy.get('.text-center').should('not.have.text', 'Invalid Bitcoin address'); + }); + }); + }); + }); + + }); + + describe('address highlighting', () => { + it('highlights single input addresses', () => { + const address = '1wiz32gbHZwMzJCRHMGehJuBgsMTPdaCa'; + cy.visit(`/address/${address}`); + cy.waitForSkeletonGone(); + cy.get('[data-cy="tx-0"] .table-tx-vin .highlight').should('exist'); + cy.get('[data-cy="tx-0"] .table-tx-vin .highlight').invoke('text').should('contain', `${address}`); + }); + + it('highlights multiple input addresses', () => { + const address = '1wiz1rtKFBA58qjb582WF5KAFg9mWCuZV'; + cy.visit(`/address/${address}`); + cy.waitForSkeletonGone(); + cy.get('[data-cy="tx-2"] .table-tx-vin .highlight').should('exist'); + cy.get('[data-cy="tx-2"] .table-tx-vin .highlight').its('length').should('equal', 2); + cy.get('[data-cy="tx-2"] .table-tx-vin .highlight').invoke('text').should('contain', `${address}`); + }); + + it('highlights both input and output addresses in the same transaction', () => { + const address = 'bc1q03u63r6hm7a3v6em58zdqtp446w2pw30nm63mv'; + cy.visit(`/address/${address}`); + cy.waitForSkeletonGone(); + cy.get('[data-cy="tx-1"] .table-tx-vin .highlight').should('exist'); + cy.get('[data-cy="tx-1"] .table-tx-vout .highlight').should('exist'); + }); + + it('highlights single output addresses', () => { + const address = '1wiz32gbHZwMzJCRHMGehJuBgsMTPdaCa'; + cy.visit(`/address/${address}`); + cy.waitForSkeletonGone(); + cy.get('[data-cy="tx-1"] .table-tx-vout .highlight').should('exist'); + cy.get('[data-cy="tx-1"] .table-tx-vout .highlight').invoke('text').should('contain', `${address}`); + }); + + it('highlights multiple output addresses', () => { + const address = '1F3Q3sQmiGsWSqK5K6T9tYnX8yqzYRgQbe'; + cy.visit(`/address/${address}`); + cy.waitForSkeletonGone(); + cy.get('[data-cy="tx-1"] .table-tx-vout .highlight').should('exist'); + cy.get('[data-cy="tx-1"] .table-tx-vout .highlight').its('length').should('equal', 2); + cy.get('[data-cy="tx-1"] .table-tx-vout .highlight').invoke('text').should('contain', `${address}`); + }); + }); + + describe('blocks navigation', () => { + + describe('keyboard events', () => { + it('loads first blockchain block visible and keypress arrow right', () => { + cy.viewport('macbook-16'); + cy.visit('/'); + cy.waitForSkeletonGone(); + cy.get('[data-cy="bitcoin-block-offset-0-index-0"]').click().then(() => { + cy.get('[ngbtooltip="Next Block"] > .ng-fa-icon > .svg-inline--fa').should('not.exist'); + cy.get('[ngbtooltip="Previous Block"] > .ng-fa-icon > .svg-inline--fa').should('be.visible'); + cy.waitForPageIdle(); + cy.document().right(); + cy.get('[ngbtooltip="Next Block"] > .ng-fa-icon > .svg-inline--fa').should('be.visible'); + cy.get('[ngbtooltip="Previous Block"] > .ng-fa-icon > .svg-inline--fa').should('be.visible'); + }); + }); + + it('loads first blockchain block visible and keypress arrow left', () => { + cy.viewport('macbook-16'); + cy.visit('/'); + cy.waitForSkeletonGone(); + cy.get('[data-cy="bitcoin-block-offset-0-index-0"]').click().then(() => { + cy.waitForPageIdle(); + cy.get('[ngbtooltip="Next Block"] > .ng-fa-icon > .svg-inline--fa').should('not.exist'); + cy.get('[ngbtooltip="Previous Block"] > .ng-fa-icon > .svg-inline--fa').should('be.visible'); + cy.document().left(); + cy.get('.title-block h1').invoke('text').should('equal', 'Next Block'); + }); + }); + + it.skip('loads last blockchain block and keypress arrow right', () => { //Skip for now as "last" doesn't really work with infinite scrolling + cy.viewport('macbook-16'); + cy.visit('/'); + cy.waitForSkeletonGone(); + cy.get('bitcoin-block-offset-0-index-7').click().then(() => { + cy.waitForPageIdle(); + + // block 6 + cy.document().right(); + cy.wait(5000); + cy.get('[ngbtooltip="Next Block"] > .ng-fa-icon > .svg-inline--fa').should('be.visible'); + cy.get('[ngbtooltip="Previous Block"] > .ng-fa-icon > .svg-inline--fa').should('be.visible'); + + // block 7 + cy.document().right(); + cy.wait(5000); + cy.get('[ngbtooltip="Next Block"] > .ng-fa-icon > .svg-inline--fa').should('be.visible'); + cy.get('[ngbtooltip="Previous Block"] > .ng-fa-icon > .svg-inline--fa').should('be.visible'); + + // block 8 - last visible block + cy.document().right(); + cy.wait(5000); + cy.get('[ngbtooltip="Next Block"] > .ng-fa-icon > .svg-inline--fa').should('be.visible'); + cy.get('[ngbtooltip="Previous Block"] > .ng-fa-icon > .svg-inline--fa').should('be.visible'); + + // block 9 - not visible at the blochchain blocks visible block + cy.document().right(); + cy.wait(5000); + cy.get('[ngbtooltip="Next Block"] > .ng-fa-icon > .svg-inline--fa').should('be.visible'); + cy.get('[ngbtooltip="Previous Block"] > .ng-fa-icon > .svg-inline--fa').should('be.visible'); + + }); + }); + + it('loads genesis block and keypress arrow right', () => { + cy.viewport('macbook-16'); + cy.visit('/block/0'); + cy.get('.pagination').scrollIntoView({ offset: { top: 200, left: 0 } }); + cy.waitForSkeletonGone(); + cy.waitForPageIdle(); + + cy.document().right(); + cy.wait(5000); + cy.get('[ngbtooltip="Next Block"] > .ng-fa-icon > .svg-inline--fa').should('be.visible'); + cy.get('[ngbtooltip="Previous Block"] > .ng-fa-icon > .svg-inline--fa').should('not.exist'); + }); + + it('loads genesis block and keypress arrow left', () => { + cy.viewport('macbook-16'); + cy.visit('/block/0'); + cy.get('.pagination').scrollIntoView({ offset: { top: 200, left: 0 } }); + cy.waitForSkeletonGone(); + cy.waitForPageIdle(); + + cy.document().left(); + cy.wait(5000); + cy.get('[ngbtooltip="Next Block"] > .ng-fa-icon > .svg-inline--fa').should('be.visible'); + cy.get('[ngbtooltip="Previous Block"] > .ng-fa-icon > .svg-inline--fa').should('be.visible'); + }); + }); + describe('mouse events', () => { + it('loads first blockchain blocks visible and click on the arrow right', () => { + cy.viewport('macbook-16'); + cy.visit('/'); + cy.waitForSkeletonGone(); + cy.get('[data-cy="bitcoin-block-offset-0-index-0"]').click().then(() => { + cy.waitForPageIdle(); + cy.get('[ngbtooltip="Next Block"] > .ng-fa-icon > .svg-inline--fa').should('not.exist'); + cy.get('[ngbtooltip="Previous Block"] > .ng-fa-icon > .svg-inline--fa').should('be.visible'); + cy.get('[ngbtooltip="Previous Block"] > .ng-fa-icon > .svg-inline--fa').click().then(() => { + cy.get('[ngbtooltip="Next Block"] > .ng-fa-icon > .svg-inline--fa').should('be.visible'); + cy.get('[ngbtooltip="Previous Block"] > .ng-fa-icon > .svg-inline--fa').should('be.visible'); + }); + }); + }); + + it('loads genesis block and click on the arrow left', () => { + cy.viewport('macbook-16'); + cy.visit('/block/0'); + cy.get('.pagination').scrollIntoView({ offset: { top: 200, left: 0 } }); + cy.waitForSkeletonGone(); + cy.waitForPageIdle(); + cy.get('[ngbtooltip="Next Block"] > .ng-fa-icon > .svg-inline--fa').should('be.visible'); + cy.get('[ngbtooltip="Previous Block"] > .ng-fa-icon > .svg-inline--fa').should('not.exist'); + cy.get('[ngbtooltip="Next Block"] > .ng-fa-icon > .svg-inline--fa').click().then(() => { + cy.get('[ngbtooltip="Next Block"] > .ng-fa-icon > .svg-inline--fa').should('be.visible'); + cy.get('[ngbtooltip="Previous Block"] > .ng-fa-icon > .svg-inline--fa').should('be.visible'); + }); + }); + }); + }); + + it('loads skeleton when changes between networks', () => { + cy.visit('/'); + cy.waitForSkeletonGone(); + + cy.changeNetwork('testnet4'); + cy.changeNetwork('signet'); + cy.changeNetwork('mainnet'); + }); + + it.skip('loads the dashboard with the skeleton blocks', () => { + cy.mockMempoolSocket(); + cy.visit('/'); + cy.get(':nth-child(1) > #bitcoin-block-0').should('be.visible'); + cy.get(':nth-child(2) > #bitcoin-block-0').should('be.visible'); + cy.get(':nth-child(3) > #bitcoin-block-0').should('be.visible'); + cy.get('#mempool-block-0').should('be.visible'); + cy.get('#mempool-block-1').should('be.visible'); + cy.get('#mempool-block-2').should('be.visible'); + + emitMempoolInfo({ + 'params': { + command: 'init' + } + }); + + cy.get(':nth-child(1) > #bitcoin-block-0').should('not.exist'); + cy.get(':nth-child(2) > #bitcoin-block-0').should('not.exist'); + cy.get(':nth-child(3) > #bitcoin-block-0').should('not.exist'); + }); + + it('loads the pools screen', () => { + cy.visit('/'); + cy.waitForSkeletonGone(); + cy.get('#btn-pools').click().then(() => { + cy.wait(1000); + }); + }); + + it('loads the graphs screen', () => { + cy.visit('/'); + cy.waitForSkeletonGone(); + cy.get('#btn-graphs').click().then(() => { + cy.wait(1000); + }); + }); + + describe('graphs page', () => { + it('check buttons - mobile', () => { + cy.viewport('iphone-6'); + cy.visit('/graphs'); + cy.waitForSkeletonGone(); + cy.get('.small-buttons > :nth-child(2)').should('be.visible'); + cy.get('#dropdownFees').should('be.visible'); + cy.get('.btn-group').should('be.visible'); + }); + it('check buttons - tablet', () => { + cy.viewport('ipad-2'); + cy.visit('/graphs'); + cy.waitForSkeletonGone(); + cy.get('.small-buttons > :nth-child(2)').should('be.visible'); + cy.get('#dropdownFees').should('be.visible'); + cy.get('.btn-group').should('be.visible'); + }); + it('check buttons - desktop', () => { + cy.viewport('macbook-16'); + cy.visit('/graphs'); + cy.waitForSkeletonGone(); + cy.get('.small-buttons > :nth-child(2)').should('be.visible'); + cy.get('#dropdownFees').should('be.visible'); + cy.get('.btn-group').should('be.visible'); + }); + }); + + it('loads the tv screen - desktop', () => { + cy.viewport('macbook-16'); + cy.visit('/graphs/mempool'); + cy.waitForSkeletonGone(); + cy.get('#btn-tv').click().then(() => { + cy.viewport('macbook-16'); + cy.get('.chart-holder'); + cy.get('.blockchain-wrapper').should('be.visible'); + cy.get('#mempool-block-0').should('be.visible'); + }); + }); + + it('loads the tv screen - mobile', () => { + cy.viewport('iphone-6'); + cy.visit('/tv'); + cy.waitForSkeletonGone(); + cy.get('.chart-holder'); + cy.get('.blockchain-wrapper').should('not.visible'); + }); + + it('loads the api screen', () => { + cy.visit('/'); + cy.waitForSkeletonGone(); + cy.get('#btn-docs').click().then(() => { + cy.wait(1000); + }); + }); + + describe('blocks', () => { + it('shows empty blocks properly', () => { + cy.visit('/block/0000000000000000000bd14f744ef2e006e61c32214670de7eb891a5732ee775'); + cy.get('.pagination').scrollIntoView({ offset: { top: 200, left: 0 } }); + cy.waitForSkeletonGone(); + cy.waitForPageIdle(); + cy.get('h2').invoke('text').should('equal', '1 transaction'); + }); + + it('expands and collapses the block details', () => { + cy.visit('/block/0'); + cy.get('.pagination').scrollIntoView({ offset: { top: 200, left: 0 } }); + cy.waitForSkeletonGone(); + cy.waitForPageIdle(); + cy.get('.btn.btn-outline-info').click().then(() => { + cy.get('#details').should('be.visible'); + }); + + cy.get('.btn.btn-outline-info').click().then(() => { + cy.get('#details').should('not.be.visible'); + }); + }); + it('shows blocks with no pagination', () => { + cy.visit('/block/00000000000000000001ba40caf1ad4cec0ceb77692662315c151953bfd7c4c4'); + cy.get('.pagination').scrollIntoView({ offset: { top: 200, left: 0 } }); + cy.waitForSkeletonGone(); + cy.waitForPageIdle(); + cy.get('.block-tx-title h2').invoke('text').should('equal', '19 transactions'); + cy.get('.pagination-container ul.pagination').first().children().should('have.length', 5); + }); + + it('supports pagination on the block screen', () => { + // 41 txs + cy.visit('/block/00000000000000000009f9b7b0f63ad50053ad12ec3b7f5ca951332f134f83d8'); + cy.get('.pagination').scrollIntoView({ offset: { top: 200, left: 0 } }); + cy.waitForSkeletonGone(); + cy.get('.pagination-container a').invoke('text').then((text1) => { + cy.get('.active + li').first().click().then(() => { + cy.waitForSkeletonGone(); + cy.waitForPageIdle(); + cy.get('.header-bg.box > a').invoke('text').then((text2) => { + expect(text1).not.to.eq(text2); + }); + }); + }); + }); + + it('shows blocks pagination with 5 pages (desktop)', () => { + cy.viewport(760, 800); + cy.visit('/block/000000000000000000049281946d26fcba7d99fdabc1feac524bc3a7003d69b3').then(() => { + cy.get('.pagination').scrollIntoView({ offset: { top: 200, left: 0 } }); + cy.waitForSkeletonGone(); + cy.waitForPageIdle(); + }); + + // 5 pages + 4 buttons = 9 buttons + cy.get('.pagination-container ul.pagination').first().children().should('have.length', 9); + }); + + it('shows blocks pagination with 3 pages (mobile)', () => { + cy.viewport(669, 800); + cy.visit('/block/000000000000000000049281946d26fcba7d99fdabc1feac524bc3a7003d69b3').then(() => { + cy.get('.pagination').scrollIntoView({ offset: { top: 200, left: 0 } }); + cy.waitForSkeletonGone(); + cy.waitForPageIdle(); + }); + + // 3 pages + 4 buttons = 7 buttons + cy.get('.pagination-container ul.pagination').first().children().should('have.length', 7); + }); + }); + + describe('RBF transactions', () => { + it('shows RBF transactions properly (mobile)', () => { + cy.intercept('/api/v1/tx/21518a98d1aa9df524865d2f88c578499f524eb1d0c4d3e70312ab863508692f/cached', { + fixture: 'mainnet_tx_cached.json' + }).as('cached_tx'); + + cy.intercept('/api/v1/tx/f81a08699b62b2070ad8fe0f2a076f8bea0386a2fdcd8124caee42cbc564a0d5/rbf', { + fixture: 'mainnet_rbf_new.json' + }).as('rbf'); + + cy.viewport('iphone-xr'); + cy.mockMempoolSocket(); + cy.visit('/tx/21518a98d1aa9df524865d2f88c578499f524eb1d0c4d3e70312ab863508692f'); + + cy.waitForSkeletonGone(); + + emitMempoolInfo({ + 'params': { + command: 'init' + } + }); + + cy.get('#mempool-block-0'); + + emitMempoolInfo({ + 'params': { + command: 'rbfTransaction' + } + }); + + cy.get('.alert').should('be.visible'); + cy.get('.alert').invoke('css', 'width').then((alertWidth) => { + cy.get('.container-xl > :nth-child(3)').invoke('css', 'width').should('equal', alertWidth); + }); + + cy.get('.btn-warning').then(getRectangle).then((rectA) => { + cy.get('.alert').then(getRectangle).then((rectB) => { + expect(areOverlapping(rectA, rectB), 'Confirmations box and RBF alert are overlapping').to.be.false; + }); + }); + }); + + it('shows RBF transactions properly (desktop)', () => { + cy.intercept('/api/v1/tx/21518a98d1aa9df524865d2f88c578499f524eb1d0c4d3e70312ab863508692f/cached', { + fixture: 'mainnet_tx_cached.json' + }).as('cached_tx'); + + cy.intercept('/api/v1/tx/f81a08699b62b2070ad8fe0f2a076f8bea0386a2fdcd8124caee42cbc564a0d5/rbf', { + fixture: 'mainnet_rbf_new.json' + }).as('rbf'); + + cy.viewport('macbook-16'); + cy.mockMempoolSocket(); + cy.visit('/tx/21518a98d1aa9df524865d2f88c578499f524eb1d0c4d3e70312ab863508692f'); + + cy.waitForSkeletonGone(); + + emitMempoolInfo({ + 'params': { + command: 'init' + } + }); + + cy.get('#mempool-block-0'); + + emitMempoolInfo({ + 'params': { + command: 'rbfTransaction' + } + }); + + cy.get('.alert').should('be.visible'); + + const alertLocator = '.alert'; + const tableLocator = '.container-xl > :nth-child(3)'; + + cy.get(tableLocator).invoke('css', 'width').then((firstWidth) => { + cy.get(alertLocator).invoke('css', 'width').should('equal', firstWidth); + }); + + cy.get('.btn-warning').then(getRectangle).then((rectA) => { + cy.get('.alert').then(getRectangle).then((rectB) => { + expect(areOverlapping(rectA, rectB), 'Confirmations box and RBF alert are overlapping').to.be.false; + }); + }); + }); + }); + } else { + it.skip(`Tests cannot be run on the selected BASE_MODULE ${baseModule}`); + } +}); diff --git a/frontend/cypress/e2e/mainnet/mining.spec.ts b/frontend/cypress/e2e/mainnet/mining.spec.ts new file mode 100644 index 0000000000..cfaa400155 --- /dev/null +++ b/frontend/cypress/e2e/mainnet/mining.spec.ts @@ -0,0 +1,171 @@ +const baseModule = Cypress.env('BASE_MODULE'); + +describe('Mainnet - Mining Features', () => { + beforeEach(() => { + //https://github.com/cypress-io/cypress/issues/14459 + if (Cypress.browser.family === 'chromium') { + Cypress.automation('remote:debugger:protocol', { + command: 'Network.enable', + params: {} + }); + Cypress.automation('remote:debugger:protocol', { + command: 'Network.setCacheDisabled', + params: { cacheDisabled: true } + }); + } + }); + + if (baseModule === 'mempool') { + + describe('Miner page', () => { + beforeEach(() => { + cy.intercept('/api/v1/mining/pool/**').as('pool'); + cy.intercept('/api/v1/mining/hashrate/pools/**').as('hashrate'); + cy.intercept('/api/tx/**').as('tx'); + cy.intercept('/api/v1/outpends/**').as('outspends'); + }); + it('loads the mining pool page from the dashboard', () => { + cy.visit('/mining'); + cy.waitForSkeletonGone(); + cy.get('[data-cy="bitcoin-block-0-pool"]').click().then(() => { + cy.waitForSkeletonGone(); + cy.wait('@pool'); + cy.url().should('match', /\/mining\/pool\/(\w+)/); + }); + }); + + it('loads the mining pool page from the blocks page', () => { + cy.visit('/mining'); + cy.waitForSkeletonGone(); + cy.get('[data-cy="bitcoin-block-0-height"]').click().then(() => { + cy.waitForSkeletonGone(); + cy.get('[data-cy="block-details-miner-badge"]').click().then(() => { + cy.waitForSkeletonGone(); + cy.wait('@pool'); + cy.url().should('match', /\/mining\/pool\/(\w+)/); + }); + }); + }); + }); + + describe('Mining Dashboard Landing page widgets', () => { + + beforeEach(() => { + cy.visit('/mining'); + cy.waitForSkeletonGone(); + }); + + it('shows the mempool blocks', () => { + cy.get('[data-cy="mempool-block-0-fees"]').invoke('text').should('match', /~(.*) sat\/vB/); + cy.get('[data-cy="mempool-block-0-fee-span"]').invoke('text').should('match', /(.*) - (.*) sat\/vB/); + cy.get('[data-cy="mempool-block-0-total-fees"]').invoke('text').should('match', /(.*) BTC/); + cy.get('[data-cy="mempool-block-0-transaction-count"]').invoke('text').should('match', /(.*) transactions/); + cy.get('[data-cy="mempool-block-0-time"]').invoke('text').should('match', /In ~(.*) minutes/); + }); + + it('shows the mined blocks', () => { + cy.get('[data-cy="bitcoin-block-0-height"]').invoke('text').should('match', /(\d)/); + cy.get('[data-cy="bitcoin-block-0-fees"]').invoke('text').should('match', /~(.*) sat\/vB/); + cy.get('[data-cy="bitcoin-block-0-fee-span"]').invoke('text').should('match', /(.*) - (.*) sat\/vB/); + cy.get('[data-cy="bitcoin-block-0-total-fees"]').invoke('text').should('match', /(.*) BTC/); + cy.get('[data-cy="bitcoin-block-0-transactions"]').invoke('text').should('match', /(.*) transactions/); + cy.get('[data-cy="bitcoin-block-0-time"]').invoke('text').should('match', /((.*) ago|Just now)/); + cy.get('[data-cy="bitcoin-block-0-pool"]').invoke('text').should('match', /(\w)/); + }); + + it('shows the reward stats for the last 144 blocks', () => { + cy.get('[data-cy="reward-stats"]'); + }); + + it('shows the difficulty adjustment stats', () => { + cy.get('[data-cy="difficulty-adjustment"]'); + }); + + it('shows the latest blocks', () => { + cy.get('[data-cy="latest-blocks"]'); + }); + + it('shows the pools pie chart', () => { + cy.get('[data-cy="pool-distribution"]'); + }); + + it('shows the hashrate graph', () => { + cy.get('[data-cy="hashrate-graph"]'); + }); + it('shows the latest blocks', () => { + cy.get('[data-cy="latest-blocks"]'); + }); + + it('shows the latest adjustments', () => { + cy.get('[data-cy="difficulty-adjustments-table"]'); + }); + }); + + describe.only('mining graphs', () => { + describe('pools ranking', () => { + it('loads the graph', () => { + cy.visit('/graphs/mining/pools'); + cy.waitForSkeletonGone(); + cy.waitForPageIdle(); + cy.get('.spinner-border').should('not.exist'); + }); + }); + + describe('pools dominance', () => { + it('loads the graph', () => { + cy.visit('/graphs/mining/pools-dominance'); + cy.waitForSkeletonGone(); + cy.waitForPageIdle(); + cy.get('.spinner-border').should('not.exist'); + }); + }); + + describe('hashrate & difficulty', () => { + it('loads the graph', () => { + cy.visit('/graphs/mining/hashrate-difficulty'); + cy.waitForSkeletonGone(); + cy.waitForPageIdle(); + cy.get('.spinner-border').should('not.exist'); + }); + }); + + describe('block fee rates', () => { + it('loads the graph', () => { + cy.visit('/graphs/mining/block-fee-rates'); + cy.waitForSkeletonGone(); + cy.waitForPageIdle(); + cy.get('.spinner-border').should('not.exist'); + }); + }); + + describe('block fees', () => { + it('loads the graph', () => { + cy.visit('/graphs/mining/block-fees'); + cy.waitForSkeletonGone(); + cy.waitForPageIdle(); + cy.get('.spinner-border').should('not.exist'); + }); + }); + + describe('block rewards', () => { + it('loads the graph', () => { + cy.visit('/graphs/mining/block-rewards'); + cy.waitForSkeletonGone(); + cy.waitForPageIdle(); + cy.get('.spinner-border').should('not.exist'); + }); + }); + + describe('block sizes and weights', () => { + it('loads the graph', () => { + cy.visit('/graphs/mining/block-sizes-weights'); + cy.waitForSkeletonGone(); + cy.waitForPageIdle(); + cy.get('.spinner-border').should('not.exist'); + }); + }); + }); + } else { + it.skip(`Tests cannot be run on the selected BASE_MODULE ${baseModule}`); + } +}); diff --git a/frontend/cypress/e2e/signet/signet.spec.ts b/frontend/cypress/e2e/signet/signet.spec.ts new file mode 100644 index 0000000000..11c47d14d6 --- /dev/null +++ b/frontend/cypress/e2e/signet/signet.spec.ts @@ -0,0 +1,141 @@ +import { emitMempoolInfo } from '../../support/websocket'; + +const baseModule = Cypress.env('BASE_MODULE'); + +describe('Signet', () => { + beforeEach(() => { + cy.intercept('/api/block-height/*').as('block-height'); + cy.intercept('/api/block/*').as('block'); + cy.intercept('/api/block/*/txs/0').as('block-txs'); + cy.intercept('/api/tx/*/outspends').as('tx-outspends'); + }); + + + if (baseModule === 'mempool') { + it('loads the dashboard', () => { + cy.visit('/signet'); + cy.waitForSkeletonGone(); + }); + + it('check first mempool block after skeleton loads', () => { + cy.visit('/'); + cy.waitForSkeletonGone(); + cy.get('#mempool-block-0 > .blockLink').should('exist'); + }); + + it.skip('loads the dashboard with the skeleton blocks', () => { + cy.mockMempoolSocket(); + cy.visit('/signet'); + cy.get(':nth-child(1) > #bitcoin-block-0').should('be.visible'); + cy.get(':nth-child(2) > #bitcoin-block-0').should('be.visible'); + cy.get(':nth-child(3) > #bitcoin-block-0').should('be.visible'); + cy.get('#mempool-block-0').should('be.visible'); + cy.get('#mempool-block-1').should('be.visible'); + cy.get('#mempool-block-2').should('be.visible'); + + emitMempoolInfo({ + 'params': { + 'network': 'signet' + } + }); + + cy.get(':nth-child(1) > #bitcoin-block-0').should('not.exist'); + cy.get(':nth-child(2) > #bitcoin-block-0').should('not.exist'); + cy.get(':nth-child(3) > #bitcoin-block-0').should('not.exist'); + }); + + it('loads the pools screen', () => { + cy.visit('/signet'); + cy.waitForSkeletonGone(); + cy.get('#btn-pools').click().then(() => { + cy.wait(1000); + }); + }); + + it('loads the graphs screen', () => { + cy.visit('/signet'); + cy.waitForSkeletonGone(); + cy.get('#btn-graphs').click().then(() => { + cy.wait(1000); + }); + }); + + describe.skip('tv mode', () => { + it('loads the tv screen - desktop', () => { + cy.viewport('macbook-16'); + cy.visit('/signet/graphs'); + cy.waitForSkeletonGone(); + cy.get('#btn-tv').click().then(() => { + cy.get('.chart-holder').should('be.visible'); + cy.get('#mempool-block-0').should('be.visible'); + cy.get('.tv-only').should('not.exist'); + }); + }); + + it('loads the tv screen - mobile', () => { + cy.visit('/signet/graphs'); + cy.waitForSkeletonGone(); + cy.get('#btn-tv').click().then(() => { + cy.viewport('iphone-8'); + cy.get('.chart-holder').should('be.visible'); + cy.get('.tv-only').should('not.exist'); + cy.get('#mempool-block-0').should('be.visible'); + }); + }); + }); + + it('loads the api screen', () => { + cy.visit('/signet'); + cy.waitForSkeletonGone(); + cy.get('#btn-docs').click().then(() => { + cy.wait(1000); + }); + }); + + describe('blocks', () => { + it('shows empty blocks properly', () => { + cy.visit('/signet/block/00000133d54e4589f6436703b067ec23209e0a21b8a9b12f57d0592fd85f7a42'); + cy.get('.pagination').scrollIntoView({ offset: { top: 200, left: 0 } }); + cy.waitForSkeletonGone(); + cy.get('h2').invoke('text').should('equal', '1 transaction'); + }); + + it('expands and collapses the block details', () => { + cy.visit('/signet/block/0'); + cy.get('.pagination').scrollIntoView({ offset: { top: 200, left: 0 } }); + cy.waitForSkeletonGone(); + cy.get('.btn.btn-outline-info').click().then(() => { + cy.get('#details').should('be.visible'); + }); + + cy.get('.btn.btn-outline-info').click().then(() => { + cy.get('#details').should('not.be.visible'); + }); + }); + + it('shows blocks with no pagination', () => { + cy.visit('/signet/block/00000078f920a96a69089877b934ce7fd009ab55e3170920a021262cb258e7cc'); + cy.get('.pagination').scrollIntoView({ offset: { top: 200, left: 0 } }); + cy.waitForSkeletonGone(); + cy.get('h2').invoke('text').should('equal', '13 transactions'); + cy.get('ul.pagination').first().children().should('have.length', 5); + }); + + it('supports pagination on the block screen', () => { + // 43 txs + cy.visit('/signet/block/00000094bd52f73bdbfc4bece3a94c21fec2dc968cd54210496e69e4059d66a6'); + cy.get('.pagination').scrollIntoView({ offset: { top: 200, left: 0 } }); + cy.waitForSkeletonGone(); + cy.get('.header-bg.box > a').invoke('text').then((text1) => { + cy.get('.active + li').first().click().then(() => { + cy.get('.header-bg.box > a').invoke('text').then((text2) => { + expect(text1).not.to.eq(text2); + }); + }); + }); + }); + }); + } else { + it.skip(`Tests cannot be run on the selected BASE_MODULE ${baseModule}`); + } +}); diff --git a/frontend/cypress/e2e/testnet4/testnet4.spec.ts b/frontend/cypress/e2e/testnet4/testnet4.spec.ts new file mode 100644 index 0000000000..c67d2414b3 --- /dev/null +++ b/frontend/cypress/e2e/testnet4/testnet4.spec.ts @@ -0,0 +1,141 @@ +import { emitMempoolInfo } from '../../support/websocket'; + +const baseModule = Cypress.env('BASE_MODULE'); + +describe('Testnet4', () => { + beforeEach(() => { + cy.intercept('/api/block-height/*').as('block-height'); + cy.intercept('/api/block/*').as('block'); + cy.intercept('/api/block/*/txs/0').as('block-txs'); + cy.intercept('/api/tx/*/outspends').as('tx-outspends'); + }); + + if (baseModule === 'mempool') { + + it('loads the dashboard', () => { + cy.visit('/testnet4'); + cy.waitForSkeletonGone(); + }); + + it('check first mempool block after skeleton loads', () => { + cy.visit('/'); + cy.waitForSkeletonGone(); + cy.get('#mempool-block-0 > .blockLink').should('exist'); + }); + + it.skip('loads the dashboard with the skeleton blocks', () => { + cy.mockMempoolSocket(); + cy.visit('/testnet4'); + cy.get(':nth-child(1) > #bitcoin-block-0').should('be.visible'); + cy.get(':nth-child(2) > #bitcoin-block-0').should('be.visible'); + cy.get(':nth-child(3) > #bitcoin-block-0').should('be.visible'); + cy.get('#mempool-block-0').should('be.visible'); + cy.get('#mempool-block-1').should('be.visible'); + cy.get('#mempool-block-2').should('be.visible'); + + emitMempoolInfo({ + 'params': { + loaded: true + } + }); + + cy.get(':nth-child(1) > #bitcoin-block-0').should('not.exist'); + cy.get(':nth-child(2) > #bitcoin-block-0').should('not.exist'); + cy.get(':nth-child(3) > #bitcoin-block-0').should('not.exist'); + }); + + it('loads the pools screen', () => { + cy.visit('/testnet4'); + cy.waitForSkeletonGone(); + cy.get('#btn-pools').click().then(() => { + cy.wait(1000); + }); + }); + + it('loads the graphs screen', () => { + cy.visit('/testnet4'); + cy.waitForSkeletonGone(); + cy.get('#btn-graphs').click().then(() => { + cy.wait(1000); + }); + }); + + describe('tv mode', () => { + it('loads the tv screen - desktop', () => { + cy.viewport('macbook-16'); + cy.visit('/testnet4/graphs'); + cy.waitForSkeletonGone(); + cy.get('#btn-tv').click().then(() => { + cy.wait(1000); + cy.get('.tv-only').should('not.exist'); + cy.get('#mempool-block-0').should('be.visible'); + }); + }); + + it('loads the tv screen - mobile', () => { + cy.visit('/testnet4/graphs'); + cy.waitForSkeletonGone(); + cy.get('#btn-tv').click().then(() => { + cy.viewport('iphone-6'); + cy.wait(1000); + cy.get('.tv-only').should('not.exist'); + }); + }); + }); + + + it('loads the api screen', () => { + cy.visit('/testnet4'); + cy.waitForSkeletonGone(); + cy.get('#btn-docs').click().then(() => { + cy.wait(1000); + }); + }); + + describe('blocks', () => { + it('shows empty blocks properly', () => { + cy.visit('/testnet4/block/0'); + cy.get('.pagination').scrollIntoView({ offset: { top: 200, left: 0 } }); + cy.waitForSkeletonGone(); + cy.get('h2').invoke('text').should('equal', '1 transaction'); + }); + + it('expands and collapses the block details', () => { + cy.visit('/testnet4/block/0'); + cy.get('.pagination').scrollIntoView({ offset: { top: 200, left: 0 } }); + cy.waitForSkeletonGone(); + cy.get('.btn.btn-outline-info').click().then(() => { + cy.get('#details').should('be.visible'); + }); + + cy.get('.btn.btn-outline-info').click().then(() => { + cy.get('#details').should('not.be.visible'); + }); + }); + + it('shows blocks with no pagination', () => { + cy.visit('/testnet4/block/000000000066e8b6cc78a93f8989587f5819624bae2eb1c05f535cadded19f99'); + cy.get('.pagination').scrollIntoView({ offset: { top: 200, left: 0 } }); + cy.waitForSkeletonGone(); + cy.get('h2').invoke('text').should('equal', '18 transactions'); + cy.get('ul.pagination').first().children().should('have.length', 5); + }); + + it('supports pagination on the block screen', () => { + // 48 txs + cy.visit('/testnet4/block/000000000000006982d53f8273bdff21dafc380c292eabc669b5ab6d732311c3'); + cy.get('.pagination').scrollIntoView({ offset: { top: 200, left: 0 } }); + cy.waitForSkeletonGone(); + cy.get('.header-bg.box > a').invoke('text').then((text1) => { + cy.get('.active + li').first().click().then(() => { + cy.get('.header-bg.box > a').invoke('text').then((text2) => { + expect(text1).not.to.eq(text2); + }); + }); + }); + }); + }); + } else { + it.skip(`Tests cannot be run on the selected BASE_MODULE ${baseModule}`); + } +}); diff --git a/frontend/cypress/fixtures/assets.json b/frontend/cypress/fixtures/assets.json new file mode 100644 index 0000000000..93e137d219 --- /dev/null +++ b/frontend/cypress/fixtures/assets.json @@ -0,0 +1,119 @@ +{ + "f59c5f3e8141f322276daa63ed5f307085808aea6d4ef9ba61e28154533fdec7": { + "asset_id": "f59c5f3e8141f322276daa63ed5f307085808aea6d4ef9ba61e28154533fdec7", + "contract": { + "entity": { + "domain": "listedreserve.com" + }, + "issuer_pubkey": "031cc579d142a03b33cdd745922112821c16e5e8b74e3bd57f16f7fda872b6f1d0", + "name": "Liquid AUD", + "precision": 2, + "ticker": "AUDL", + "version": 0 + }, + "issuance_txin": { + "txid": "e5c5144ba3dc48259ae29023fe9f7775dec1fc049f456dd3d1f7178e31901fb5", + "vin": 0 + }, + "issuance_prevout": { + "txid": "ed48be2e035ffa425d2c6faaa82b6a7b648aed1246b6ac76c72e0408db8cf057", + "vout": 1 + }, + "name": "Liquid AUD", + "ticker": "AUDL", + "precision": 2, + "entity": { + "domain": "listedreserve.com" + }, + "version": 0, + "issuer_pubkey": "031cc579d142a03b33cdd745922112821c16e5e8b74e3bd57f16f7fda872b6f1d0" + }, + "0e99c1a6da379d1f4151fb9df90449d40d0608f6cb33a5bcbfc8c265f42bab0a": { + "asset_id": "0e99c1a6da379d1f4151fb9df90449d40d0608f6cb33a5bcbfc8c265f42bab0a", + "contract": { + "entity": { + "domain": "lcad.bullbitcoin.com" + }, + "issuer_pubkey": "027fa34026195b05f3aa217335416811dca4f5b579d00271a1bb6304c0152458a8", + "name": "Liquid CAD", + "precision": 8, + "ticker": "LCAD", + "version": 0 + }, + "issuance_txin": { + "txid": "238badf029cadcf546d90ce23c7eafc2fa2082585c9bd62dc26f1aa11c7bd850", + "vin": 0 + }, + "issuance_prevout": { + "txid": "a87f13917c08c7ccd8eddb1830c5c9a2bcd59c7d167e9d528659ba40808a6b76", + "vout": 0 + }, + "name": "Liquid CAD", + "ticker": "LCAD", + "precision": 8, + "entity": { + "domain": "lcad.bullbitcoin.com" + }, + "version": 0, + "issuer_pubkey": "027fa34026195b05f3aa217335416811dca4f5b579d00271a1bb6304c0152458a8" + }, + "3438ecb49fc45c08e687de4749ed628c511e326460ea4336794e1cf02741329e": { + "asset_id": "3438ecb49fc45c08e687de4749ed628c511e326460ea4336794e1cf02741329e", + "contract": { + "entity": { + "domain": "settlenet.io" + }, + "issuer_pubkey": "037b09d542bf7cea6a19fa624b4441790c1a6e44823597bf190e981a846a196541", + "name": "SETTLENET JPY Stablecoin by Crypto Garage", + "precision": 0, + "ticker": "JPYS", + "version": 0 + }, + "issuance_txin": { + "txid": "e33ad5ce8879297d8bfa7daa193920b94abd3fb12f4e8dade9543dbb292387cb", + "vin": 0 + }, + "issuance_prevout": { + "txid": "328c4fadd817ea75e634e3648eb4be0bf7e669539b8da921c0f77af3bc148894", + "vout": 1 + }, + "name": "SETTLENET JPY Stablecoin by Crypto Garage", + "ticker": "JPYS", + "precision": 0, + "entity": { + "domain": "settlenet.io" + }, + "version": 0, + "issuer_pubkey": "037b09d542bf7cea6a19fa624b4441790c1a6e44823597bf190e981a846a196541" + }, + "ce091c998b83c78bb71a632313ba3760f1763d9cfcffae02258ffa9865a37bd2": { + "asset_id": "ce091c998b83c78bb71a632313ba3760f1763d9cfcffae02258ffa9865a37bd2", + "contract": { + "entity": { + "domain": "tether.to" + }, + "issuer_pubkey": "0337cceec0beea0232ebe14cba0197a9fbd45fcf2ec946749de920e71434c2b904", + "name": "Tether USD", + "precision": 8, + "ticker": "USDt", + "version": 0 + }, + "issuance_txin": { + "txid": "abb4080d91849e933ee2ed65da6b436f7c385cf363fb4aa08399f1e27c58ff3d", + "vin": 0 + }, + "issuance_prevout": { + "txid": "9596d259270ef5bac0020435e6d859aea633409483ba64e232b8ba04ce288668", + "vout": 0 + }, + "name": "Tether USD", + "ticker": "USDt", + "precision": 8, + "entity": { + "domain": "tether.to" + }, + "version": 0, + "issuer_pubkey": "0337cceec0beea0232ebe14cba0197a9fbd45fcf2ec946749de920e71434c2b904" + } + } + \ No newline at end of file diff --git a/frontend/cypress/fixtures/assets.minimal.json b/frontend/cypress/fixtures/assets.minimal.json new file mode 100644 index 0000000000..c80ae7f411 --- /dev/null +++ b/frontend/cypress/fixtures/assets.minimal.json @@ -0,0 +1,33 @@ +{ + "f59c5f3e8141f322276daa63ed5f307085808aea6d4ef9ba61e28154533fdec7": [ + "listedreserve.com", + "AUDL", + "Liquid AUD", + 2 + ], + "0e99c1a6da379d1f4151fb9df90449d40d0608f6cb33a5bcbfc8c265f42bab0a": [ + "lcad.bullbitcoin.com", + "LCAD", + "Liquid CAD", + 8 + ], + "6f0279e9ed041c3d710a9f57d0c02928416460c4b722ae3457a11eec381c526d": [ + null, + "L-BTC", + "Liquid Bitcoin", + 8 + ], + "ce091c998b83c78bb71a632313ba3760f1763d9cfcffae02258ffa9865a37bd2": [ + "tether.to", + "USDt", + "Tether USD", + 8 + ], + "3438ecb49fc45c08e687de4749ed628c511e326460ea4336794e1cf02741329e": [ + "settlenet.io", + "JPYS", + "SETTLENET JPY Stablecoin by Crypto Garage", + 0 + ] + } + \ No newline at end of file diff --git a/frontend/cypress/fixtures/mainnet_live2hchart.json b/frontend/cypress/fixtures/mainnet_live2hchart.json new file mode 100644 index 0000000000..6acfc6d663 --- /dev/null +++ b/frontend/cypress/fixtures/mainnet_live2hchart.json @@ -0,0 +1 @@ +{"live-2h-chart":{"id":1319298,"added":"2021-07-23T18:27:34.000Z","unconfirmed_transactions":546,"tx_per_second":3.93333,"vbytes_per_second":1926,"mempool_byte_weight":1106656,"total_fee":6198583,"vsizes":[255,18128,43701,58534,17144,5532,4483,1759,2394,1089,1683,7409,751,101010,1151,592,1497,703,1369,4747,800,1221,0,0,712,0,0,0,0,0,0,0,0,0,0,0,0,0]}} \ No newline at end of file diff --git a/frontend/cypress/fixtures/mainnet_mempoolInfo.json b/frontend/cypress/fixtures/mainnet_mempoolInfo.json new file mode 100644 index 0000000000..5c41bd4dd7 --- /dev/null +++ b/frontend/cypress/fixtures/mainnet_mempoolInfo.json @@ -0,0 +1,771 @@ +{ + "mempoolInfo": { + "loaded": true, + "size": 112686, + "bytes": 175691391, + "usage": 856780672, + "total_fee": 5.10536864, + "maxmempool": 300000000, + "mempoolminfee": 0.00001305, + "minrelaytxfee": 0.00001, + "incrementalrelayfee": 0.00001, + "unbroadcastcount": 0, + "fullrbf": true + }, + "vBytesPerSecond": 2364, + "mempool-blocks": [ + { + "blockSize": 2162709, + "blockVSize": 997944, + "nTx": 4888, + "totalFees": 9079705, + "medianFee": 7.036906854130053, + "feeRange": [ + 7, + 7, + 7.010590015128593, + 7.022801302931596, + 7.12430426716141, + 10.01669449081803, + 236.07305936073058 + ] + }, + { + "blockSize": 2066789, + "blockVSize": 997996.25, + "nTx": 892, + "totalFees": 6623230, + "medianFee": 6.716362627217997, + "feeRange": [ + 6.189555125725338, + 6.42654028436019, + 6.636953672027368, + 6.994764397905759, + 7.005110732538331, + 7.005110732538331, + 7.00556586270872 + ] + }, + { + "blockSize": 1844287, + "blockVSize": 997956.25, + "nTx": 27, + "totalFees": 6370984, + "medianFee": 6.400148152967939, + "feeRange": [ + 6.152492668621701, + 6.156213928434013, + 6.165703275529865, + 6.179153864334673, + 6.400128130693307, + 6.400160164168272, + 6.400176181026004 + ] + }, + { + "blockSize": 1818283, + "blockVSize": 997984.75, + "nTx": 56, + "totalFees": 6365410, + "medianFee": 6.4000840859779125, + "feeRange": [ + 6.125, + 6.125, + 6.1303214596003475, + 6.149318801089918, + 6.161055058005517, + 6.400068069430819, + 6.400116119312593 + ] + }, + { + "blockSize": 1891412, + "blockVSize": 997993.25, + "nTx": 127, + "totalFees": 6355046, + "medianFee": 6.400068069430819, + "feeRange": [ + 6.024096385542169, + 6.033333333333333, + 6.049822064056939, + 6.080719839259195, + 6.123809523809523, + 6.141470180305132, + 6.400080081082096 + ] + }, + { + "blockSize": 1939469, + "blockVSize": 997987.25, + "nTx": 56, + "totalFees": 6350364, + "medianFee": 6.400036036577125, + "feeRange": [ + 6.01063829787234, + 6.014018691588785, + 6.01996303142329, + 6.023980815347722, + 6.031815335063076, + 6.4000200202705235, + 6.400052052963891 + ] + }, + { + "blockSize": 1906245, + "blockVSize": 997956, + "nTx": 28, + "totalFees": 6348648, + "medianFee": 6.4000200202705235, + "feeRange": [ + 6, + 6.010496568429552, + 6.011583011583012, + 6.019933554817276, + 6.400004004044084, + 6.400036036577125, + 6.400052052963891 + ] + }, + { + "blockSize": 333333741, + "blockVSize": 168604440, + "nTx": 106612, + "totalFees": 463043477, + "medianFee": 1.5796055679151149, + "feeRange": [ + 1.0005271543495804, + 1.1548204755273255, + 1.3540307201497894, + 1.408026342363497, + 1.519000275099878, + 1.5796055679151149, + 3.0039108631786284, + 3.927655905571819, + 5.004098751020287, + 5.041807153997041, + 6.4000294177934 + ] + } + ], + "transactions": [ + { + "txid": "6942073671954381264699dffce75b99d8afd1a3ccc8b58ff0201dcfd890be39", + "fee": 1094, + "vsize": 154, + "value": 365466, + "rate": 7.103896103896104 + }, + { + "txid": "e88521600e3c8348d0534777ca6490091cb3cdd1fac8a2abe95123f7cef319e5", + "fee": 2568, + "vsize": 208.25, + "value": 29143035, + "rate": 12.331332533013205 + }, + { + "txid": "e4c25dfb025084d0bad34e2350d3a49eff7cff7ee8dddeb069c56fa1511f5ce8", + "fee": 4548, + "vsize": 535.5, + "value": 215164, + "rate": 8.492997198879552 + }, + { + "txid": "dde3a5ac76a1aa79639a1b2f7509ab5c71996de00140ada84218bce12f2516f5", + "fee": 2110, + "vsize": 211.5, + "value": 196181, + "rate": 9.976359338061465 + }, + { + "txid": "28319981d28aa77dd3c75ad31cadc78c20c292d4713ecec1d4f7f6c495f3843b", + "fee": 3000, + "vsize": 202, + "value": 546, + "rate": 14.851485148514852 + }, + { + "txid": "29a2292326cdf97bb1189ea67e1ae5094db4be15ea05ff3b0624e4ee61ec1441", + "fee": 1970, + "vsize": 197, + "value": 3875456, + "rate": 10 + } + ], + "loadingIndicators": {}, + "fees": { + "fastestFee": 8, + "halfHourFee": 8, + "hourFee": 8, + "economyFee": 4, + "minimumFee": 2 + }, + "rbfSummary": [ + { + "txid": "feae4fb145c57d48c32b11c7f9ca15f2be10f102894dceed1b67f796b520c740", + "mined": false, + "fullRbf": false, + "oldFee": 8400, + "oldVsize": 345, + "newFee": 13301, + "newVsize": 346 + }, + { + "txid": "02b30c113a096d73871ea2d7c34189aadd04a60c3477043f19e3c806f6d69960", + "mined": false, + "fullRbf": false, + "oldFee": 2450, + "oldVsize": 263.25, + "newFee": 3151, + "newVsize": 263.25 + }, + { + "txid": "1d10e449f9b38126a707b6b88089d28ef81114acd2d8f9b0bd3f3266a7496e1f", + "mined": false, + "fullRbf": false, + "oldFee": 1967, + "oldVsize": 109.5, + "newFee": 3933, + "newVsize": 109.5 + }, + { + "txid": "281b1567a1de2a5c9109470b0a523702e438e935a4aa387727506ee852486a77", + "mined": false, + "fullRbf": false, + "oldFee": 1286, + "oldVsize": 143.25, + "newFee": 1550, + "newVsize": 143.25 + }, + { + "txid": "68ce3641b7e85fe60315bc1126cb93e8c61bdc3720f5d84bb0c8254e6cd58f82", + "mined": true, + "fullRbf": false, + "oldFee": 7579, + "oldVsize": 109.25, + "newFee": 14583, + "newVsize": 109.25 + }, + { + "txid": "08cf843ac10a7243d249d13912e27e4b635464ef5819c92488f6205d50d7c874", + "mined": true, + "fullRbf": false, + "oldFee": 1136, + "oldVsize": 141.5, + "newFee": 2272, + "newVsize": 141.5 + } + ], + "blocks": [ + { + "id": "0000000000000000000200e0829f5dd72b02401660837bf67379f6a7adf4d8c9", + "height": 837043, + "version": 803872768, + "timestamp": 1711850338, + "bits": 386097875, + "nonce": 2002092656, + "difficulty": 83126997340024.61, + "merkle_root": "e328e882992bd2de39ffc0a3ac331c31e64d7f4eb33547bb8fcbc09c2a4bffa3", + "tx_count": 3191, + "size": 2117591, + "weight": 3992738, + "previousblockhash": "000000000000000000011cefb2db6b82b6ae69b4ec06eedc81fc85d16f97865d", + "mediantime": 1711847828, + "stale": false, + "extras": { + "reward": 635081690, + "coinbaseRaw": "03b3c50c0463c308662f466f756e6472792055534120506f6f6c202364726f70676f6c642f3ed1ff622486000000000000", + "orphans": [], + "medianFee": 8.020001813606207, + "feeRange": [ + 7, + 7.011686143572621, + 7.012612612612613, + 7.12430426716141, + 10.005032712632108, + 15.515151515151516, + 102.36199095022624 + ], + "totalFees": 10081690, + "avgFee": 3160, + "avgFeeRate": 10, + "utxoSetChange": 3295, + "avgTxSize": 663.52, + "totalInputs": 5670, + "totalOutputs": 8965, + "totalOutputAmt": 163033638953, + "segwitTotalTxs": 3117, + "segwitTotalSize": 2095166, + "segwitTotalWeight": 3903146, + "feePercentiles": null, + "virtualSize": 998184.5, + "coinbaseAddress": "bc1qxhmdufsvnuaaaer4ynz88fspdsxq2h9e9cetdj", + "coinbaseSignature": "OP_0 OP_PUSHBYTES_20 35f6de260c9f3bdee47524c473a6016c0c055cb9", + "coinbaseSignatureAscii": "\u0000\u0000\u0000\u0000\u0000\u0000", + "header": "0020ea2f5d86976fd185fc81dcee06ecb469aeb6826bdbb2ef1c01000000000000000000a3ff4b2a9cc0cb8fbb4735b34e7f4de6311c33aca3c0ff39ded22b9982e828e362c30866d362031770825577", + "utxoSetSize": null, + "totalInputAmt": null, + "pool": { + "id": 111, + "name": "Foundry USA", + "slug": "foundryusa" + }, + "matchRate": 100, + "expectedFees": 10293045, + "expectedWeight": 3991577, + "similarity": 0.9655852166344173 + } + }, + { + "id": "00000000000000000001911ff550eeb8493e589fdd6f1fc080f30969c26cf853", + "height": 837044, + "version": 1073676288, + "timestamp": 1711850704, + "bits": 386097875, + "nonce": 1562078084, + "difficulty": 83126997340024.61, + "merkle_root": "9756f896db91a4a7573cbd0e3baa4d8905c46a60ceed30cdcb440dc66d3fc102", + "tx_count": 3502, + "size": 1968923, + "weight": 3993734, + "previousblockhash": "0000000000000000000200e0829f5dd72b02401660837bf67379f6a7adf4d8c9", + "mediantime": 1711848750, + "stale": false, + "extras": { + "reward": 636442248, + "coinbaseRaw": "03b4c50c1b4d696e656420627920416e74506f6f6c38333035010001214a5697fabe6d6d89907adbb0addfe28be89c002fbe45908b9b32c68d1802b86ff36a5dfa22c6c810000000000000000000cbd2a647000000000000", + "orphans": [], + "medianFee": 9.015025041736227, + "feeRange": [ + 7, + 7.023255813953488, + 8.014973644733765, + 9.015025041736227, + 10.01669449081803, + 15.063829787234043, + 263.89487870619945 + ], + "totalFees": 11442248, + "avgFee": 3268, + "avgFeeRate": 11, + "utxoSetChange": 1740, + "avgTxSize": 562.09, + "totalInputs": 6657, + "totalOutputs": 8397, + "totalOutputAmt": 129424754973, + "segwitTotalTxs": 3428, + "segwitTotalSize": 1944942, + "segwitTotalWeight": 3897918, + "feePercentiles": null, + "virtualSize": 998433.5, + "coinbaseAddress": "37jKPSmbEGwgfacCr2nayn1wTaqMAbA94Z", + "coinbaseSignature": "OP_HASH160 OP_PUSHBYTES_20 42402a28dd61f2718a4b27ae72a4791d5bbdade7 OP_EQUAL", + "coinbaseSignatureAscii": "Mined by AntPool8305\u0001\u0000\u0001!J\u0010\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000\u0000", + "header": "0000ff3fc9d8f4ada7f67973f67b83601640022bd75d9f82e0000200000000000000000002c13f6dc60d44cbcd30edce606ac405894daa3b0ebd3c57a7a491db96f85697d0c40866d3620317846b1b5d", + "utxoSetSize": null, + "totalInputAmt": null, + "pool": { + "id": 44, + "name": "AntPool", + "slug": "antpool" + }, + "matchRate": 100, + "expectedFees": 11588891, + "expectedWeight": 3991949, + "similarity": 0.9797301408793522 + } + }, + { + "id": "00000000000000000001ee972656708fd787b570ec4b813ae8c5feee4f200c56", + "height": 837045, + "version": 637534208, + "timestamp": 1711853470, + "bits": 386097875, + "nonce": 235193117, + "difficulty": 83126997340024.61, + "merkle_root": "7e9ec459056b973b294dbe6dbcb821eb74b773c806e067db45ec36c781e4c18b", + "tx_count": 3135, + "size": 1521892, + "weight": 3997882, + "previousblockhash": "00000000000000000001911ff550eeb8493e589fdd6f1fc080f30969c26cf853", + "mediantime": 1711849305, + "stale": false, + "extras": { + "reward": 650142949, + "coinbaseRaw": "03b5c50c2cfabe6d6d96c7f8e8e15534e9902d846875d05bc0e5494b8519a860f51802daa2f48c215910000000f09f909f092f4632506f6f6c2f6700000000000000000000000000000000000000000000000000000000000000000000000500b4861602", + "orphans": [], + "medianFee": 19.30172311348782, + "feeRange": [ + 16, + 16.623739332816136, + 18, + 20.04728132387707, + 34.51977401129943, + 40.27210884353742, + 477.45358090185675 + ], + "totalFees": 25142949, + "avgFee": 8022, + "avgFeeRate": 25, + "utxoSetChange": 6554, + "avgTxSize": 485.28000000000003, + "totalInputs": 6655, + "totalOutputs": 13209, + "totalOutputAmt": 391783255749, + "segwitTotalTxs": 2914, + "segwitTotalSize": 1432235, + "segwitTotalWeight": 3639362, + "feePercentiles": null, + "virtualSize": 999470.5, + "coinbaseAddress": "1K6KoYC69NnafWJ7YgtrpwJxBLiijWqwa6", + "coinbaseSignature": "OP_DUP OP_HASH160 OP_PUSHBYTES_20 c6740a12d0a7d556f89782bf5faf0e12cf25a639 OP_EQUALVERIFY OP_CHECKSIG", + "coinbaseSignatureAscii": "\/F2Pool/", + "header": "0000002653f86cc26909f380c01f6fdd9f583e49b8ee50f51f91010000000000000000008bc1e481c736ec45db67e006c873b774eb21b8bc6dbe4d293b976b0559c49e7e9ecf0866d36203171dc3040e", + "utxoSetSize": null, + "totalInputAmt": null, + "pool": { + "id": 36, + "name": "F2Pool", + "slug": "f2pool" + }, + "matchRate": 99.9, + "expectedFees": 25286032, + "expectedWeight": 3991754, + "similarity": 0.9851630583666668 + } + }, + { + "id": "00000000000000000000ea58c5b60311988e9553e58ac5b4e7a2f1575d07a4f0", + "height": 837046, + "version": 732078080, + "timestamp": 1711853947, + "bits": 386097875, + "nonce": 2294678239, + "difficulty": 83126997340024.61, + "merkle_root": "0ea1bed22d6e98c256d92ee8c7e959949f88188872d290abaf89b3482ab5be55", + "tx_count": 3099, + "size": 1687564, + "weight": 3993067, + "previousblockhash": "00000000000000000001ee972656708fd787b570ec4b813ae8c5feee4f200c56", + "mediantime": 1711849492, + "stale": false, + "extras": { + "reward": 641586175, + "coinbaseRaw": "03b6c50c0484d108662f4d41524120506f6f6c202876303331393234292f38c0a19ff8fe2ab8e720838f0bd6411213114d8592000d010000ffffffff", + "orphans": [], + "medianFee": 15.003962563625333, + "feeRange": [ + 12, + 12.529550827423169, + 13.077227722772276, + 15.024711696869852, + 16.0427807486631, + 22.06646525679758, + 258.6666666666667 + ], + "totalFees": 16586175, + "avgFee": 5353, + "avgFeeRate": 16, + "utxoSetChange": 2417, + "avgTxSize": 544.45, + "totalInputs": 6941, + "totalOutputs": 9358, + "totalOutputAmt": 588984462870, + "segwitTotalTxs": 2969, + "segwitTotalSize": 1563622, + "segwitTotalWeight": 3497407, + "feePercentiles": null, + "virtualSize": 998266.75, + "coinbaseAddress": "15MdAHnkxt9TMC2Rj595hsg8Hnv693pPBB", + "coinbaseSignature": "OP_DUP OP_HASH160 OP_PUSHBYTES_20 2fc701e2049ee4957b07134b6c1d771dd5a96b21 OP_EQUALVERIFY OP_CHECKSIG", + "coinbaseSignatureAscii": "/MARA Pool (v031924)/", + "header": "00a0a22b560c204feefec5e83a814bec70b587d78f70562697ee0100000000000000000055beb52a48b389afab90d2728818889f9459e9c7e82ed956c2986e2dd2bea10e7bd10866d3620317df02c688", + "utxoSetSize": null, + "totalInputAmt": null, + "pool": { + "id": 115, + "name": "MARA Pool", + "slug": "marapool" + }, + "matchRate": 100, + "expectedFees": 16712235, + "expectedWeight": 3991968, + "similarity": 0.9876955157970453 + } + }, + { + "id": "000000000000000000021164d81f6059c18066bc0a93b928fdf455d2481c4708", + "height": 837047, + "version": 536936448, + "timestamp": 1711854238, + "bits": 386097875, + "nonce": 3048189996, + "difficulty": 83126997340024.61, + "merkle_root": "dbf52683cabe20a4bb4d2512cfed294a09e0825cac98bbe8fbafb3027ac9686a", + "tx_count": 2657, + "size": 1840568, + "weight": 3997883, + "previousblockhash": "00000000000000000000ea58c5b60311988e9553e58ac5b4e7a2f1575d07a4f0", + "mediantime": 1711849912, + "stale": false, + "extras": { + "reward": 637535865, + "coinbaseRaw": "03b7c50c2cfabe6d6d97e4a56bfc94081f5de141bab7dc7607f7511394a912e9f152f5e6d6e12f4d7210000000f09f909f092f4632506f6f6c2f7300000000000000000000000000000000000000000000000000000000000000000000000500b02a0c00", + "orphans": [], + "medianFee": 10.88611182786954, + "feeRange": [ + 9.610942249240122, + 10.003260515161395, + 10.42633371169126, + 11.058823529411764, + 12.969267139479905, + 18.044444444444444, + 422.5231646471846 + ], + "totalFees": 12535865, + "avgFee": 4719, + "avgFeeRate": 12, + "utxoSetChange": 3018, + "avgTxSize": 692.52, + "totalInputs": 6835, + "totalOutputs": 9853, + "totalOutputAmt": 272522814809, + "segwitTotalTxs": 2580, + "segwitTotalSize": 1813806, + "segwitTotalWeight": 3890943, + "feePercentiles": [ + 584, + 1492, + 1650, + 2002, + 3186, + 6487, + 942300 + ], + "medianFeeAmt": 2002, + "virtualSize": 999470.75, + "coinbaseAddress": "1K6KoYC69NnafWJ7YgtrpwJxBLiijWqwa6", + "coinbaseSignature": "OP_DUP OP_HASH160 OP_PUSHBYTES_20 c6740a12d0a7d556f89782bf5faf0e12cf25a639 OP_EQUALVERIFY OP_CHECKSIG", + "coinbaseSignatureAscii": "/F2Pool/", + "header": "00000120f0a4075d57f1a2e7b4c58ae553958e981103b6c558ea000000000000000000006a68c97a02b3affbe8bb98ac5c82e0094a29edcf12254dbba420beca8326f5db9ed20866d36203172cb0afb5", + "utxoSetSize": null, + "totalInputAmt": null, + "pool": { + "id": 36, + "name": "F2Pool", + "slug": "f2pool" + }, + "matchRate": 99.96, + "expectedFees": 12610218, + "expectedWeight": 3991619, + "similarity": 0.9361101713526737 + } + }, + { + "id": "00000000000000000001ab25f774a511e1cb09462dab28a36413f7495a65da2f", + "height": 837048, + "version": 536903680, + "timestamp": 1711854388, + "bits": 386097875, + "nonce": 665023114, + "difficulty": 83126997340024.61, + "merkle_root": "ffa1ea239fb6f9ed36f263d68c9739b691788f87f31ea826dbcf9eb64aaf66d7", + "tx_count": 2252, + "size": 1640520, + "weight": 3993366, + "previousblockhash": "000000000000000000021164d81f6059c18066bc0a93b928fdf455d2481c4708", + "mediantime": 1711850338, + "stale": false, + "extras": { + "reward": 636119622, + "coinbaseRaw": "03b8c50c172f5669614254432f4d696e65642062792032373931312f2cfabe6d6d8f86142521fd5c467f05b95e96adf049f4b3716c0cbf20aa9fa92a3a0cefe5761000000000000000108a5eab06f0c0bb91c6f4919eba6e030000000000", + "orphans": [], + "medianFee": 9.02733100888539, + "feeRange": [ + 9, + 9.015025041736227, + 9.015025041736227, + 9.015025041736227, + 11.499042512447339, + 15.024744308808973, + 146.4480408858603 + ], + "totalFees": 11119622, + "avgFee": 4939, + "avgFeeRate": 11, + "utxoSetChange": 908, + "avgTxSize": 728.3000000000001, + "totalInputs": 5995, + "totalOutputs": 6903, + "totalOutputAmt": 93595027274, + "segwitTotalTxs": 2194, + "segwitTotalSize": 1345859, + "segwitTotalWeight": 2814830, + "feePercentiles": null, + "virtualSize": 998341.5, + "coinbaseAddress": "18cBEMRxXHqzWWCxZNtU91F5sbUNKhL5PX", + "coinbaseSignature": "OP_DUP OP_HASH160 OP_PUSHBYTES_20 536ffa992491508dca0354e52f32a3a7a679a53a OP_EQUALVERIFY OP_CHECKSIG", + "coinbaseSignatureAscii": "/ViaBTC/Mined by 27911/", + "header": "0080002008471c48d255f4fd28b9930abc6680c159601fd8641102000000000000000000d766af4ab69ecfdb26a81ef3878f7891b639978cd663f236edf9b69f23eaa1ff34d30866d36203178a72a327", + "utxoSetSize": null, + "totalInputAmt": null, + "pool": { + "id": 73, + "name": "ViaBTC", + "slug": "viabtc" + }, + "matchRate": 100, + "expectedFees": 11558843, + "expectedWeight": 3991937, + "similarity": 0.9606822794906695 + } + }, + { + "id": "000000000000000000012a9794fcc2fd81bd0f54df00f7589ea96ff9f3f2ef49", + "height": 837049, + "version": 536944640, + "timestamp": 1711854621, + "bits": 386097875, + "nonce": 2568084255, + "difficulty": 83126997340024.61, + "merkle_root": "5d02722d5d17fa71ec0dd4a3ac72959b84c089e527d14f6f90a6651982b212e2", + "tx_count": 3260, + "size": 2027949, + "weight": 3992970, + "previousblockhash": "00000000000000000001ab25f774a511e1cb09462dab28a36413f7495a65da2f", + "mediantime": 1711850704, + "stale": false, + "extras": { + "reward": 635976151, + "coinbaseRaw": "03b9c50c041ed408662f466f756e6472792055534120506f6f6c202364726f70676f6c642f407c3137c5140b0000000000", + "orphans": [], + "medianFee": 8.965500401011468, + "feeRange": [ + 7.980922098569158, + 8.03076923076923, + 8.753180661577607, + 9.015025041736227, + 9.044925124792014, + 12.042105263157895, + 200.85543199315654 + ], + "totalFees": 10976151, + "avgFee": 3367, + "avgFeeRate": 10, + "utxoSetChange": -176, + "avgTxSize": 621.98, + "totalInputs": 7230, + "totalOutputs": 7054, + "totalOutputAmt": 99412242005, + "segwitTotalTxs": 3216, + "segwitTotalSize": 1992038, + "segwitTotalWeight": 3849434, + "feePercentiles": null, + "virtualSize": 998242.5, + "coinbaseAddress": "bc1qxhmdufsvnuaaaer4ynz88fspdsxq2h9e9cetdj", + "coinbaseSignature": "OP_0 OP_PUSHBYTES_20 35f6de260c9f3bdee47524c473a6016c0c055cb9", + "coinbaseSignatureAscii": "/Foundry USA Pool #dropgold/", + "header": "002001202fda655a49f71364a328ab2d4609cbe111a574f725ab01000000000000000000e212b2821965a6906f4fd127e589c0849b9572aca3d40dec71fa175d2d72025d1dd40866d36203171fdb1199", + "utxoSetSize": null, + "totalInputAmt": null, + "pool": { + "id": 111, + "name": "Foundry USA", + "slug": "foundryusa" + }, + "matchRate": 100, + "expectedFees": 11047051, + "expectedWeight": 3991840, + "similarity": 0.9522324867980367 + } + }, + { + "id": "00000000000000000000e7d533924ecd9e2096bdf261ae3daf3f04861150c5a8", + "height": 837050, + "version": 548552704, + "timestamp": 1711854927, + "bits": 386097875, + "nonce": 1647633217, + "difficulty": 83126997340024.61, + "merkle_root": "4b7d3685fcdefae2a34359f1b3a4181969f7d84061fca9e5b185a6a81c4cd0d1", + "tx_count": 2659, + "size": 2137871, + "weight": 3992678, + "previousblockhash": "000000000000000000012a9794fcc2fd81bd0f54df00f7589ea96ff9f3f2ef49", + "mediantime": 1711853470, + "stale": false, + "extras": { + "reward": 635929414, + "coinbaseRaw": "03bac50c044fd508662f466f756e6472792055534120506f6f6c202364726f70676f6c642f4344be31b3818e6d00000000", + "orphans": [], + "medianFee": 8.971294962196815, + "feeRange": [ + 7.12430426716141, + 7.9810874704491725, + 8.013355592654424, + 8.01920768307323, + 10.047908843713582, + 17.270506108202444, + 261.78010471204186 + ], + "totalFees": 10929414, + "avgFee": 4111, + "avgFeeRate": 10, + "utxoSetChange": 591, + "avgTxSize": 803.9, + "totalInputs": 6276, + "totalOutputs": 6867, + "totalOutputAmt": 89075789136, + "segwitTotalTxs": 2607, + "segwitTotalSize": 2082733, + "segwitTotalWeight": 3772234, + "feePercentiles": null, + "virtualSize": 998169.5, + "coinbaseAddress": "bc1qxhmdufsvnuaaaer4ynz88fspdsxq2h9e9cetdj", + "coinbaseSignature": "OP_0 OP_PUSHBYTES_20 35f6de260c9f3bdee47524c473a6016c0c055cb9", + "coinbaseSignatureAscii": "/Foundry USA Pool #dropgold/", + "header": "0040b22049eff2f3f96fa99e58f700df540fbd81fdc2fc94972a01000000000000000000d1d04c1ca8a685b1e5a9fc6140d8f7691918a4b3f15943a3e2fadefc85367d4b4fd50866d362031741e33462", + "utxoSetSize": null, + "totalInputAmt": null, + "pool": { + "id": 111, + "name": "Foundry USA", + "slug": "foundryusa" + }, + "matchRate": 100, + "expectedFees": 11074070, + "expectedWeight": 3991755, + "similarity": 0.9867917444269922 + } + } + ], + "conversions": { + "time": 1711854906, + "USD": 69880, + "EUR": 64823, + "GBP": 55198, + "CAD": 95154, + "CHF": 63041, + "AUD": 107374, + "JPY": 10601000 + }, + "backendInfo": { + "hostname": "node205.tk7.mempool.space", + "version": "3.0.0-dev", + "gitCommit": "abbc8a134", + "lightning": false + }, + "da": { + "progressPercent": 20.33730158730159, + "difficultyChange": 5.914788959658535, + "estimatedRetargetDate": 1712766704114, + "remainingBlocks": 1606, + "remainingTime": 911596114, + "previousRetarget": -0.9778871328980188, + "previousTime": 1711619463, + "nextRetargetHeight": 838656, + "timeAvg": 574743, + "adjustedTimeAvg": 567619, + "timeOffset": 0, + "expectedBlocks": 392.7416666666667 + } + } \ No newline at end of file diff --git a/frontend/cypress/fixtures/mainnet_rbf.json b/frontend/cypress/fixtures/mainnet_rbf.json new file mode 100644 index 0000000000..f4db772c2e --- /dev/null +++ b/frontend/cypress/fixtures/mainnet_rbf.json @@ -0,0 +1,4 @@ +{ +"txReplaced": { + "txid": "8913ec7ba0ede285dbd120e46f6d61a28f2903c10814a6f6c4f97d0edf3e1f46" +}} \ No newline at end of file diff --git a/frontend/cypress/fixtures/mainnet_rbf_new.json b/frontend/cypress/fixtures/mainnet_rbf_new.json new file mode 100644 index 0000000000..2b23db4db3 --- /dev/null +++ b/frontend/cypress/fixtures/mainnet_rbf_new.json @@ -0,0 +1,31 @@ +{ + "replacements": { + "tx": { + "txid": "f22735aaa8eb84bcae3e7705f78609c6f5f0cd7dfc34ae03094e61f2dab0cc64", + "fee": 13843, + "vsize": 109.25, + "value": 253003805, + "rate": 36.04666732302845, + "rbf": true + }, + "time": 1683865345, + "fullRbf": false, + "replaces": [ + { + "tx": { + "txid": "21518a98d1aa9df524865d2f88c578499f524eb1d0c4d3e70312ab863508692f", + "fee": 8794, + "vsize": 109.25, + "value": 253008854, + "rate": 35.05247612484001, + "rbf": true + }, + "time": 1683864993, + "interval": 352, + "fullRbf": false, + "replaces": [] + } + ] + }, + "replaces": null +} diff --git a/frontend/cypress/fixtures/mainnet_tx_cached.json b/frontend/cypress/fixtures/mainnet_tx_cached.json new file mode 100644 index 0000000000..f4e4338a4e --- /dev/null +++ b/frontend/cypress/fixtures/mainnet_tx_cached.json @@ -0,0 +1,60 @@ +{ + "vsize": 109, + "feePerVsize": 80.49427917620137, + "effectiveFeePerVsize": 35.05247612484001, + "txid": "21518a98d1aa9df524865d2f88c578499f524eb1d0c4d3e70312ab863508692f", + "version": 2, + "locktime": 0, + "vin": [ + { + "txid": "1e3bd5c634781a6ba8bb3d3385b14739bf38cad5332d5fbc5c0ab775e54b9aef", + "vout": 144, + "prevout": { + "scriptpubkey": "0014d98654186b90d95da7e31a30929f5b5b6a0af250", + "scriptpubkey_asm": "OP_0 OP_PUSHBYTES_20 d98654186b90d95da7e31a30929f5b5b6a0af250", + "scriptpubkey_type": "v0_p2wpkh", + "scriptpubkey_address": "bc1qmxr9gxrtjrv4mflrrgcf986mtd4q4ujss432tk", + "value": 253017648 + }, + "scriptsig": "", + "scriptsig_asm": "", + "witness": [ + "30440220448e8f58fcdea87c1969d58438b49da5b43712380bc4c68b02d22cf6b164907302207b2ed660f1a5b3b74f712961ffb3f3a7d1ac6e48b269ea6ff15df985042211f301", + "02e39a1f3583e382cec1a1fab6a3f5950b6403c953fada58d809127a497f502ebe" + ], + "is_coinbase": false, + "sequence": 4294967293 + } + ], + "vout": [ + { + "scriptpubkey": "0014edb5167da7e97c73d7931eb2130ac3e34e6845a9", + "scriptpubkey_asm": "OP_0 OP_PUSHBYTES_20 edb5167da7e97c73d7931eb2130ac3e34e6845a9", + "scriptpubkey_type": "v0_p2wpkh", + "scriptpubkey_address": "bc1qak63vld8a97884unr6epxzkrud8xs3dfdqswy2", + "value": 253008854 + } + ], + "size": 191, + "weight": 437, + "fee": 8794, + "status": { + "confirmed": false + }, + "firstSeen": 1683864993, + "uid": 298353, + "position": { + "block": 0, + "vsize": 886207.5 + }, + "cpfpChecked": true, + "ancestors": [ + { + "txid": "1e3bd5c634781a6ba8bb3d3385b14739bf38cad5332d5fbc5c0ab775e54b9aef", + "fee": 169220, + "weight": 19877 + } + ], + "descendants": [], + "bestDescendant": null +} diff --git a/frontend/cypress/fixtures/pools.json b/frontend/cypress/fixtures/pools.json new file mode 100644 index 0000000000..1a69517e86 --- /dev/null +++ b/frontend/cypress/fixtures/pools.json @@ -0,0 +1,1238 @@ +{ + "coinbase_tags" : { + "/LUXOR/": { + "name": "Luxor", + "link": "https://mining.luxor.tech" + }, + "/1THash&58COIN/": { + "name": "1THash", + "link": "https://www.1thash.top" + }, + "/1THash/": { + "name": "1THash", + "link": "https://www.1thash.top" + }, + "/BTC.COM/" : { + "name" : "BTC.com", + "link" : "https://pool.btc.com" + }, + "/BTC.com/" : { + "name" : "BTC.com", + "link" : "https://pool.btc.com" + }, + "BITFARMS": { + "name": "Bitfarms", + "link": "https://www.bitarms.io/" + }, + "/Huobi/": { + "name": "Huobi.pool", + "link": "https://www.hpt.com/" + }, + "/HuoBi/": { + "name": "Huobi.pool", + "link": "https://www.hpt.com/" + }, + "/E2M & BTC.TOP/": { + "name": "WAYI.CN", + "link": "http://www.easy2mine.com/" + }, + "/canoepool/": { + "name": "CanoePool", + "link": "https://www.canoepool.com/" + }, + "/BTC.TOP/": { + "name" : "BTC.TOP", + "link" : "http://www.btc.top/" + }, + "pool.bitcoin.com" : { + "name" : "Bitcoin.com", + "link" : "https://www.bitcoin.com/" + }, + "Mined By 175btc.com" : { + "name" : "175btc", + "link" : "http://www.175btc.com/" + }, + "/mined by gbminers/" : { + "name" : "GBMiners", + "link" : "http://gbminers.com/" + }, + "/A-XBT/" : { + "name" : "A-XBT", + "link" : "http://www.a-xbt.com" + }, + "ASICMiner" : { + "name" : "ASICMiner", + "link" : "http://www.asicminer.co" + }, + "BitMinter" : { + "name" : "BitMinter", + "link" : "https://bitminter.com/" + }, + "/Bitcoin-Russia.ru/" : { + "name" : "BitcoinRussia", + "link" : "https://bitcoin-russia.ru" + }, + "btcserv" : { + "name" : "BTCServ", + "link" : "http://btcserv.net/" + }, + "simplecoin" : { + "name" : "simplecoin.us", + "link" : "http://simplecoin.us/" + }, + "BTC Guild" : { + "name" : "BTC Guild", + "link" : "http://www.btcguild.com/" + }, + "Eligius" : { + "name" : "Eligius", + "link" : "http://eligius.st/" + }, + "ozco.in" : { + "name" : "OzCoin", + "link" : "http://ozcoin.net/" + }, + "ozcoin" : { + "name" : "OzCoin", + "link" : "http://ozcoin.net/" + }, + "EMC" : { + "name" : "EclipseMC", + "link" : "https://eclipsemc.com/" + }, + "MaxBTC" : { + "name" : "MaxBTC", + "link" : "http://maxbtc.com/" + }, + "triplemining" : { + "name" : "TripleMining", + "link" : "https://www.triplemining.com/" + }, + "Triplemining.com" : { + "name" : "TripleMining", + "link" : "https://www.triplemining.com/" + }, + "CoinLab" : { + "name" : "CoinLab", + "link" : "http://coinlab.com/" + }, + "50BTC" : { + "name" : "50BTC", + "link" : "https://www.50btc.com/" + }, + "ghash.io" : { + "name" : "GHash.IO", + "link" : "https://ghash.io/" + }, + "st mining corp" : { + "name" : "ST Mining Corp", + "link" : "https://bitcointalk.org/index.php?topic=77000.msg3207708#msg3207708" + }, + "bitparking" : { + "name" : "Bitparking", + "link" : "http://mmpool.bitparking.com/" + }, + "mmpool" : { + "name" : "mmpool", + "link" : "http://mmpool.org/pool" + }, + "by polmine.pl" : { + "name" : "Polmine", + "link" : "https://polmine.pl/" + }, + "bypmneU" : { + "name" : "Polmine", + "link" : "https://polmine.pl/" + }, + "KnCMiner" : { + "name" : "KnCMiner", + "link" : "https://portal.kncminer.com/pool" + }, + "Bitalo" : { + "name" : "Bitalo", + "link" : "https://bitalo.com/mining" + }, + "七彩神仙鱼" : { + "name" : "F2Pool", + "link" : "https://www.f2pool.com/" + }, + "🐟" : { + "name" : "F2Pool", + "link" : "https://www.f2pool.com/" + }, + "HHTT" : { + "name" : "HHTT", + "link" : "http://hhtt.1209k.com/" + }, + "megabigpower.com" : { + "name" : "MegaBigPower", + "link" : "http://megabigpower.com/" + }, + "/mtred/" : { + "name" : "Mt Red", + "link" : "https://mtred.com/" + }, + "nmcbit.com" : { + "name" : "NMCbit", + "link" : "http://nmcbit.com/" + }, + "yourbtc.net" : { + "name" : "Yourbtc.net", + "link" : "http://yourbtc.net/" + }, + "Give-Me-Coins" : { + "name" : "Give Me Coins", + "link" : "http://give-me-coins.com/" + }, + "/slush/" : { + "name" : "SlushPool", + "link" : "https://slushpool.com/" + }, + "Mined by AntPool" : { + "name" : "AntPool", + "link" : "https://www.antpool.com/" + }, + "Mined By AntPool" : { + "name" : "AntPool", + "link" : "https://www.antpool.com/" + }, + "/AntPool/" : { + "name" : "AntPool", + "link" : "https://www.antpool.com/" + }, + "Mined by MultiCoin.co" : { + "name" : "MultiCoin.co", + "link" : "http://multicoin.co" + }, + "bcpool.io" : { + "name" : "bcpool.io", + "link" : "https://bcpool.io/" + }, + "cointerra" : { + "name" : "Cointerra", + "link" : "http://cointerra.com/" + }, + "Kano" : { + "name" : "KanoPool", + "link" : "https://kano.is/" + }, + "/solo.ckpool.org/" : { + "name" : "Solo CK", + "link" : "http://solo.ckpool.org/" + }, + "/ckpool.org/" : { + "name" : "CKPool", + "link" : "http://ckpool.org" + }, + "/NiceHashSolo" : { + "name" : "NiceHash", + "link" : "https://solo.nicehash.com/" + }, + "/BitClub Network/" : { + "name" : "BitClub", + "link" : "https://bitclubpool.com/" + }, + "bitcoinaffiliatenetwork.com" : { + "name" : "Bitcoin Affiliate Network", + "link" : "https://mining.bitcoinaffiliatenetwork.com/" + }, + "BTCChina Pool" : { + "name" : "BTCC", + "link" : "https://pool.btcc.com/" + }, + "btcchina.com" : { + "name" : "BTCC", + "link" : "https://pool.btcc.com/" + }, + "BTCChina.com" : { + "name" : "BTCC", + "link" : "https://pool.btcc.com/" + }, + "/BTCC/" : { + "name" : "BTCC", + "link" : "https://pool.btcc.com/" + }, + "BW Pool" : { + "name" : "BWPool", + "link" : "https://bwpool.net/" + }, + "BWPool" : { + "name" : "BWPool", + "link" : "https://bwpool.net/" + }, + "xbtc.exx.com&bw.com" : { + "name" : "EXX&BW", + "link" : "https://xbtc.exx.com/" + }, + "Bitsolo Pool" : { + "name" : "Bitsolo", + "link" : "http://bitsolo.net/" + }, + "/BitFury/" : { + "name" : "BitFury", + "link" : "http://bitfury.com/" + }, + "/Bitfury/" : { + "name" : "BitFury", + "link" : "http://bitfury.com/" + }, + "/pool34/" : { + "name" : "21 Inc.", + "link" : "https://21.co/" + }, + "/agentD/" : { + "name" : "digitalBTC", + "link" : "http://digitalbtc.com/" + }, + "/八宝池 8baochi.com/" : { + "name" : "8baochi", + "link" : "http://8baochi.com/" + }, + "myBTCcoin Pool" : { + "name" : "myBTCcoin Pool", + "link" : "http://mybtccoin.com/" + }, + "TBDice" : { + "name" : "TBDice", + "link" : "http://tbdice.org/" + }, + "HASHPOOL" : { + "name" : "HASHPOOL", + "link" : "http://hashpool.com/" + }, + "/Nexious/" : { + "name" : "Nexious", + "link" : "https://nexious.com/" + }, + "/bravo-mining/" : { + "name" : "Bravo Mining", + "link" : "http://www.bravo-mining.com/" + }, + "/HotPool/" : { + "name": "HotPool", + "link": "https://hotpool.co/" + }, + "/www.okex.com/" : { + "name": "OKExPool", + "link": "https://www.okex.com/" + }, + "/BCMonster/" : { + "name": "BCMonster", + "link": "http://www.bcmonster.com/" + }, + "Mined by 1hash.com" : { + "name": "1Hash", + "link": "http://www.1hash.com/" + }, + "/HaoBTC/" : { + "name": "Bixin", + "link": "https://haopool.com/" + }, + "HAOBTC" : { + "name": "Bixin", + "link": "https://haopool.com/" + }, + "/Bixin/" : { + "name": "Bixin", + "link": "https://haopool.com/" + }, + "/ViaBTC/TATMAS Pool/" : { + "name" : "TATMAS Pool", + "link" : "https://tmsminer.com/" + }, + "viabtc.com deploy" : { + "name": "ViaBTC", + "link": "https://viabtc.com" + }, + "/ViaBTC/" : { + "name": "ViaBTC", + "link": "http://viabtc.com/" + }, + "/ConnectBTC - Home for Miners/" : { + "name" : "ConnectBTC", + "link" : "https://www.connectbtc.com/" + }, + "/BATPOOL/" : { + "name" : "BATPOOL", + "link" : "https://www.batpool.com/" + }, + "/CANOE/" : { + "name" : "CanoePool", + "link" : "https://btc.canoepool.com/" + }, + "/WATERHOLE.IO/" : { + "name" : "Waterhole", + "link" : "https://btc.waterhole.io/" + }, + "/DCExploration/" : { + "name" : "DCExploration", + "link" : "http://dcexploration.cn" + }, + "/DCEX/" : { + "name" : "DCEX", + "link" : "http://dcexploration.cn" + }, + "/BTPOOL/" : { + "name" : "BTPOOL", + "link" : "" + }, + "/58coin.com/" : { + "name" : "58COIN", + "link" : "https://www.58coin.com" + }, + "/Bitcoin-India/" : { + "name": "Bitcoin India", + "link": "https://bitcoin-india.org" + }, + "--Nug--" : { + "name": "shawnp0wers", + "link": "https://www.brainofshawn.com" + }, + "/phash.io/" : { + "name": "PHash.IO", + "link": "http://phash.io" + }, + "/phash.cn/" : { + "name": "PHash.IO", + "link": "http://phash.io" + }, + "/RigPool.com/" : { + "name": "RigPool", + "link": "https://www.rigpool.com" + }, + "/haozhuzhu/" : { + "name": "HAOZHUZHU", + "link": "http://haozhuzhu.com/" + }, + "/$Mined by 7pool.com/" : { + "name": "7pool", + "link": "https://7pool.com/" + }, + "/mined by poopbut/" : { + "name": "MiningKings", + "link": "https://miningkings.com/" + }, + "/Mined by HashBX.io/" : { + "name": "HashBX", + "link": "https://hashbx.io" + }, + "/DPOOL.TOP/": { + "name" : "DPOOL", + "link" : "http://www.dpool.top/" + }, + "/Rawpool.com/": { + "name" : "Rawpool", + "link" : "https://www.rawpool.com/" + }, + "/haominer/": { + "name" : "haominer", + "link" : "http://haominer.com/" + }, + "/Helix/": { + "name": "Helix", + "link": "" + }, + "/Bitcoin-Ukraine.com.ua/": { + "name": "Bitcoin-Ukraine", + "link": "https://bitcoin-ukraine.com.ua/" + }, + "/poolin.com": { + "name" : "Poolin", + "link" : "https://www.poolin.com/" + }, + "/SecretSuperstar/": { + "name" : "SecretSuperstar", + "link" : "" + }, + "/tigerpool.net": { + "name" : "tigerpool.net", + "link" : "" + }, + "/Sigmapool.com/": { + "name" : "Sigmapool.com", + "link" : "https://sigmapool.com" + }, + "/www.okpool.top/": { + "name" : "okpool.top", + "link" : "https://www.okpool.top" + }, + "HummerPool": { + "name" : "Hummerpool", + "link" : "https://www.hummerpool.com" + }, + "Hummerpool": { + "name" : "Hummerpool", + "link" : "https://www.hummerpool.com" + }, + "/Tangpool/": { + "name" : "Tangpool", + "link" : "http://www.tangpool.com/" + }, + "/bytepool.com/": { + "name" : "BytePool", + "link" : "https://www.bytepool.com/" + }, + "/SpiderPool/": { + "name" : "SpiderPool", + "link" : "https://www.spiderpool.com/" + }, + "/NovaBlock/": { + "name" : "NovaBlock", + "link" : "https://novablock.com" + }, + "MiningCity": { + "name" : "MiningCity", + "link" : "https://www.miningcity.com/" + }, + "/Binance/": { + "name" : "Binance Pool", + "link" : "https://pool.binance.com/" + }, + "/Mined in the USA by: /Minerium.com/" : { + "name" : "Minerium", + "link" : "https://www.minerium.com/" + }, + "/Minerium.com/" : { + "name" : "Minerium", + "link" : "https://www.minerium.com/" + }, + "/Buffett/": { + "name" : "Lubian.com", + "link" : "" + }, + "/lubian.com/" : { + "name" : "Lubian.com", + "link" : "http://www.lubian.com/" + }, + "/hash.okkong.com/" : { + "name" : "OKKONG", + "link" : "https://hash.okkong.com" + }, + "/AAOPOOL/" : { + "name" : "AAO Pool", + "link" : "https://btc.tmspool.top" + }, + "/one_more_mcd/" : { + "name" : "EMCDPool", + "link" : "https://pool.emcd.io" + }, + "Foundry USA Pool" : { + "name" : "Foundry USA", + "link" : "https://foundrydigital.com/" + }, + "/2cDw/" : { + "name" : "Foundry USA", + "link" : "https://foundrydigital.com/" + }, + "/SBICrypto.com Pool/" : { + "name" : "SBI Crypto", + "link" : "https://sbicrypto.com" + }, + "SBI Crypto": { + "name": "SBI Crypto", + "link": "https://www.sbicrypto.com" + }, + "SBICrypto": { + "name": "SBI Crypto", + "link": "https://www.sbicrypto.com" + }, + "/ArkPool/": { + "name": "ArkPool", + "link": "https://www.arkpool.com/" + }, + "/PureBTC.COM/": { + "name": "PureBTC.COM", + "link": "https://purebtc.com" + }, + "MARA Pool": { + "name": "MARA Pool", + "link": "https://marapool.com" + }, + "KuCoinPool": { + "name": "KuCoinPool", + "link": "https://www.kucoin.com/mining-pool/" + }, + "Entrustus" : { + "name": "Entrust Charity Pool", + "link": "pool.entustus.org" + } + }, + "payout_addresses" : { + "1MkCDCzHpBsYQivp8MxjY5AkTGG1f2baoe": { + "name": "Luxor", + "link": "https://mining.luxor.tech" + }, + "1ArTPjj6pV3aNRhLPjJVPYoxB98VLBzUmb": { + "name" : "KuCoinPool", + "link" : "https://www.kucoin.com/mining-pool/" + }, + "3Bmb9Jig8A5kHdDSxvDZ6eryj3AXd3swuJ": { + "name" : "NovaBlock", + "link" : "https://novablock.com" + }, + "3GvEGtnvgeBJ3p3EpdZhvUkxY4pDARkbjd" : { + "name" : "Bitfarms", + "link" : "https://www.bitfarms.io/" + }, + "1CjPR7Z5ZSyWk6WtXvSFgkptmpoi4UM9BC" : { + "name" : "GHash.IO", + "link" : "https://ghash.io/" + }, + "14R2r9FkyDmyxGB9xUVwVLdgsX9YfdVamk" : { + "name" : "BitcoinRussia", + "link" : "https://bitcoin-russia.ru/" + }, + "165GCEAx81wce33FWEnPCRhdjcXCrBJdKn" : { + "name" : "BitcoinRussia", + "link" : "https://bitcoin-russia.ru/" + }, + "17kkmDx8eSwj2JTTULb3HkJhCmexfysExz" : { + "name" : "Polmine", + "link" : "https://polmine.pl/" + }, + "1AajKXkaq2DsnDmP8ZPTrE5gH1HFo1x3AU" : { + "name" : "Polmine", + "link" : "https://polmine.pl/" + }, + "16cv7wyeG6RRqhvJpY21CnsjxuKj2gAoK2" : { + "name" : "Polmine", + "link" : "https://polmine.pl/" + }, + "13vWXwzNF5Ef9SUXNTdr7de7MqiV4G1gnL" : { + "name" : "Polmine", + "link" : "https://polmine.pl/" + }, + "1Nsvmnv8VcTMD643xMYAo35Aco3XA5YPpe" : { + "name" : "Polmine", + "link" : "https://polmine.pl/" + }, + "1JrYhdhP2jCY6JwuVzdk9jUwc4pctcSes7" : { + "name" : "Polmine", + "link" : "https://polmine.pl/" + }, + "1CK6KHY6MHgYvmRQ4PAafKYDrg1ejbH1cE" : { + "name" : "SlushPool", + "link" : "https://slushpool.com/" + }, + "1AqTMY7kmHZxBuLUR5wJjPFUvqGs23sesr" : { + "name" : "SlushPool", + "link" : "https://slushpool.com/" + }, + "1AcAj9p6zJn4xLXdvmdiuPCtY7YkBPTAJo" : { + "name" : "BitFury", + "link" : "http://bitfury.com/" + }, + "1BX5YoLwvqzvVwSrdD4dC32vbouHQn2tuF" : { + "name" : "Cointerra", + "link" : "http://cointerra.com/" + }, + "19PkHafEN18mquJ9ChwZt5YEFoCdPP5vYB" : { + "name" : "BitMinter", + "link" : "http://bitminter.com/" + }, + "15xiShqUqerfjFdyfgBH1K7Gwp6cbYmsTW" : { + "name" : "EclipseMC", + "link" : "https://eclipsemc.com/" + }, + "1BwZeHJo7b7M2op7VDfYnsmcpXsUYEcVHm" : { + "name" : "BTC Nuggets", + "link" : "http://104.197.8.250/" + }, + "1KFHE7w8BhaENAswwryaoccDb6qcT6DbYY" : { + "name" : "F2Pool", + "link" : "https://www.f2pool.com/" + }, + "3HuobiNg2wHjdPU2mQczL9on8WF7hZmaGd" : { + "name" : "Huobi.pool", + "link" : "https://www.hpt.com/" + }, + "18Zcyxqna6h7Z7bRjhKvGpr8HSfieQWXqj" : { + "name" : "Huobi.pool", + "link" : "https://www.hpt.com/" + }, + "1EepjXgvWUoRyNvuLSAxjiqZ1QqKGDANLW" : { + "name" : "Huobi.pool", + "link" : "https://www.hpt.com/" + }, + "1MvYASoHjqynMaMnP7SBmenyEWiLsTqoU6" : { + "name" : "Huobi.pool", + "link" : "https://www.hpt.com/" + }, + "1BDbsWi3Mrcjp1wdop3PWFNCNZtu4R7Hjy" : { + "name" : "EMCDPool", + "link" : "https://pool.emcd.io" + }, + "12QVFmJH2b4455YUHkMpEnWLeRY3eJ4Jb5" : { + "name" : "AAO Pool", + "link" : "https://btc.tmspool.top " + }, + "1ALA5v7h49QT7WYLcRsxcXqXUqEqaWmkvw" : { + "name" : "CloudHashing", + "link" : "https://cloudhashing.com/" + }, + "1K7znxRfkS8R1hcmyMvHDum1hAQreS4VQ4" : { + "name" : "MegaBigPower", + "link" : "https://megabigpower.com" + }, + "1HTejfsPZQGi3afCMEZTn2xdmoNzp13n3F" : { + "name" : "Bitalo", + "link" : "https://bitalo.com/mining" + }, + "1JLRXD8rjRgQtTS9MvfQALfHgGWau9L9ky" : { + "name" : "BWPool", + "link" : "https://bwpool.net/" + }, + "18zRehBcA2YkYvsC7dfQiFJNyjmWvXsvon" : { + "name" : "Bitsolo", + "link" : "http://bitsolo.net/" + }, + "155fzsEBHy9Ri2bMQ8uuuR3tv1YzcDywd4" : { + "name" : "BitClub", + "link" : "https://bitclubpool.com/" + }, + "14yfxkcpHnju97pecpM7fjuTkVdtbkcfE6" : { + "name" : "BitFury", + "link" : "http://bitfury.com/" + }, + "15rQXUSBQRubShPpiJfDLxmwS8ze2RUm4z" : { + "name" : "21 Inc.", + "link" : "https://21.co/" + }, + "1CdJi2xRTXJF6CEJqNHYyQDNEcM3X7fUhD" : { + "name" : "21 Inc.", + "link" : "https://21.co/" + }, + "1GC6HxDvnchDdb5cGkFXsJMZBFRsKAXfwi" : { + "name" : "21 Inc.", + "link" : "https://21.co/" + }, + "1MimPd6LrPKGftPRHWdfk8S3KYBfN4ELnD" : { + "name" : "digitalBTC", + "link" : "http://digitalbtc.com/" + }, + "1NY15MK947MLzmPUa2gL7UgyR8prLh2xfu" : { + "name" : "digitalX Mintsy", + "link" : "https://www.mintsy.co/" + }, + "1P4B6rx1js8TaEDXvZvtrkiEb9XrJgMQ19" : { + "name" : "Telco 214", + "link" : "http://www.telco214.com/" + }, + "1MoYfV4U61wqTPTHCyedzFmvf2o3uys2Ua" : { + "name" : "Telco 214", + "link" : "http://www.telco214.com/" + }, + "1GaKSh2t396nfSg5Ku2J3Yn1vfVsXrGuH5" : { + "name" : "Telco 214", + "link" : "http://www.telco214.com/" + }, + "1AsEJU4ht5wR7BzV6xsNQpwi5qRx4qH1ac" : { + "name" : "Telco 214", + "link" : "http://www.telco214.com/" + }, + "18ikmzPqk721ZNvWhDos1UL4H29w352Kj5" : { + "name" : "Telco 214", + "link" : "http://www.telco214.com/" + }, + "1DXRoTT67mCbhdHHL1it4J1xsSZHHnFxYR" : { + "name" : "Telco 214", + "link" : "http://www.telco214.com/" + }, + "152f1muMCNa7goXYhYAQC61hxEgGacmncB" : { + "name" : "BTCC", + "link" : "https://pool.btcc.com/" + }, + "1PmRrdp1YSkp1LxPyCfcmBHDEipG5X4eJB" : { + "name" : "BTC Pool Party", + "link" : "https://btcpoolparty.com/" + }, + "1Hk9gD8xMo2XBUhE73y5zXEM8xqgffTB5f" : { + "name" : "8baochi", + "link" : "http://8baochi.com/" + }, + "151T7r1MhizzJV6dskzzUkUdr7V8JxV2Dx" : { + "name" : "myBTCcoin Pool", + "link" : "http://www.mybtccoin.com/" + }, + "1MFsp2txCPwMMBJjNNeKaduGGs8Wi1Ce7X" : { + "name" : "A-XBT", + "link" : "http://www.a-xbt.com/" + }, + "1BUiW44WuJ2jiJgXiyxJVFMN8bc1GLdXRk" : { + "name" : "TBDice", + "link" : "http://tbdice.org/" + }, + "1MeffGLauEj2CZ18hRQqUauTXb9JAuLbGw" : { + "name" : "Multipool", + "link" : "https://www.multipool.us/" + }, + "1qtKetXKgqa7j1KrB19HbvfRiNUncmakk" : { + "name" : "transactioncoinmining", + "link" : "http://sha256.transactioncoinmining.com/" + }, + "15MxzsutVroEE9XiDckLxUHTCDAEZgPZJi" : { + "name" : "BTCDig", + "link" : "https://btcdig.com/" + }, + "1GBo1f2tzVx5jScV9kJXPUP9RjvYXuNzV7" : { + "name" : "Nexious", + "link" : "https://nexious.com/" + }, + "1AePMyovoijxvHuKhTqWvpaAkRCF4QswC6" : { + "name" : "Tricky's BTC Pool", + "link" : "http://pool.wemine.uk/" + }, + "17judvK4AC2M6KhaBbAEGw8CTKc9Pg8wup" : { + "name" : "HotPool", + "link" : "https://hotpool.co/" + }, + "1jKSjMLnDNup6NPgCjveeP9tUn4YpT94Y" : { + "name" : "BTCMP", + "link" : "https://www.btcmp.com/" + }, + "1MPxhNkSzeTNTHSZAibMaS8HS1esmUL1ne" : { + "name" : "Eobot", + "link" : "https://eobot.com/" + }, + "16GsNC3q6KgVXkUX7j7aPxSUdHrt1sN2yN" : { + "name" : "Eobot", + "link" : "https://eobot.com" + }, + "1F1xcRt8H8Wa623KqmkEontwAAVqDSAWCV" : { + "name" : "1Hash", + "link" : "http://www.1hash.com/" + }, + "1BRY8AD7vSNUEE75NjzfgiG18mWjGQSRuJ" : { + "name" : "UNOMP", + "link" : "http://199.115.116.7:8925/" + }, + "19RE4mz2UbDxDVougc6GGdoT4x5yXxwFq2" : { + "name" : "Patels", + "link" : "http://patelsminingpool.com/" + }, + "197miJmttpCt2ubVs6DDtGBYFDroxHmvVB" : { + "name" : "Patels", + "link" : "http://patelsminingpool.com/" + }, + "3NA8hsjfdgVkmmVS9moHmkZsVCoLxUkvvv" : { + "name" : "BTC.com", + "link" : "https://pool.btc.com" + }, + "34qkc2iac6RsyxZVfyE2S5U5WcRsbg2dpK" : { + "name" : "BTC.com", + "link" : "https://pool.btc.com" + }, + "3EhLZarJUNSfV6TWMZY1Nh5mi3FMsdHa5U" : { + "name" : "BTC.com", + "link" : "https://pool.btc.com" + }, + "bc1qjl8uwezzlech723lpnyuza0h2cdkvxvh54v3dn" : { + "name" : "BTC.com", + "link" : "https://pool.btc.com" + }, + "1Bf9sZvBHPFGVPX71WX2njhd1NXKv5y7v5" : { + "name" : "BTC.com", + "link" : "https://pool.btc.com" + }, + "18EPLvrs2UE11kWBB3ABS7Crwj5tTBYPoa" : { + "name" : "GoGreenLight", + "link" : "http://www.gogreenlight.se/" + }, + "1KPQkehgYAqwiC6UCcbojM3mbGjURrQJF2" : { + "name" : "ConnectBTC", + "link" : "https://www.connectbtc.com/" + }, + "167ApWWxUSFQmz2jdz9xop3oAKdLejvMML" : { + "name" : "BATPOOL", + "link" : "https://www.batpool.com/" + }, + "1KsFhYKLs8qb1GHqrPxHoywNQpet2CtP9t" : { + "name" : "Bixin", + "link" : "https://haopool.com/" + }, + "13hQVEstgo4iPQZv9C7VELnLWF7UWtF4Q3" : { + "name" : "Bixin", + "link" : "https://haopool.com/" + }, + "19qa95rTbDziNCS9EexUbh2hVY4viUU9tt" : { + "name" : "HAOZHUZHU", + "link" : "http://haozhuzhu.com" + }, + "1AZ6BkCo4zgTuuLpRStJH8iNsehXTMp456" : { + "name" : "BitcoinIndia", + "link" : "https://pool.bitcoin-india.org/" + }, + "1FLH1SoLv4U68yUERhDiWzrJn5TggMqkaZ" : { + "name" : "Waterhole", + "link" : "https://btc.waterhole.io/" + }, + "1GP8eWArgpwRum76saJS4cZKCHWJHs9PQo" : { + "name" : "CanoePool", + "link" : "https://btc.canoepool.com/" + }, + "199EDJoCpqV672qESEkfFgEqNT1iR2gj3t" : { + "name" : "58COIN", + "link" : "https://www.58coin.com/" + }, + "1Cs5RT9SRk1hxsdzivAfkjesNmVVJqfqkw" : { + "name" : "EkanemBTC", + "link" : "https://ekanembtc.com/" + }, + "13Sd8Y7nUao3z4bJFkZvCRXpFqHvLy49YY" : { + "name" : "Telco 214", + "link" : "http://www.telco214.com" + }, + "18hvMLisvfc58PvA5rHH7NsLN9CV5ddB2x" : { + "name" : "Telco 214", + "link" : "http://www.telco214.com" + }, + "1BUhwvF9oo3qkaSjjPpWrUzQxXNjkHdMZF" : { + "name" : "Telco 214", + "link" : "http://www.telco214.com" + }, + "1CNq2FAw6S5JfBiDkjkYJUVNQwjoeY4Zfi" : { + "name" : "Telco 214", + "link" : "http://www.telco214.com" + }, + "1LXWA3EEEwPixQcyFWXKX2hWHpkDoLknZW" : { + "name" : "Telco 214", + "link" : "http://www.telco214.com" + }, + "14M1pQ5KKeqmDrmqKyZEnaxAGJfBPrfWvQ" : { + "name" : "Telco 214", + "link" : "http://www.telco214.com" + }, + "12znnESiJ3bgCLftwwrg9wzQKN8fJtoBDa" : { + "name" : "shawnp0wers", + "link" : "https://www.brainofshawn.com" + }, + "18HEMWFXM9UGPVZHUMdBPD3CMFWYn2NPRX" : { + "name" : "shawnp0wers", + "link" : "https://www.brainofshawn.com" + }, + "1Hz96kJKF2HLPGY15JWLB5m9qGNxvt8tHJ" : { + "name" : "BTC.TOP", + "link" : "http://btc.top" + }, + "1Afcpc2FpPnREU6i52K3cicmHdvYRAH9Wo" : { + "name" : "CANOE", + "link" : "https://www.canoepool.com" + }, + "1JpKmtspBJQVXK67DJP64eBJcAPhDvJ9Er" : { + "name" : "RigPool", + "link" : "https://www.rigpool.com" + }, + "1E18BNyobcoiejcDYAz5SjbrzifNDEpM88" : { + "name" : "BCMonster", + "link" : "http://www.bcmonster.com" + }, + "1JLc3JxvpdL1g5zoX8sKLP4BkJQiwnJftU" : { + "name" : "7pool", + "link" : "https://7pool.com/" + }, + "1EowSPumj9D9AMTpE64Jr7vT3PJDNopVcz" : { + "name" : "MiningKings", + "link" : "https://miningkings.com/" + }, + "1ApE99VM5RJzMRRtwd2JMgmkGabtJqoMEz" : { + "name" : "MiningKings", + "link" : "https://miningkings.com/" + }, + "1KGbsDDAgJN2HDNBjmMHp9828qATo5B9c9" : { + "name" : "MiningKings", + "link" : "https://miningkings.com/" + }, + "1ACAgPuFFidYzPMXbiKptSrwT74Dg8hq2v" : { + "name" : "DPOOL", + "link" : "http://www.dpool.top/" + }, + "1FbBbv5oYqFKwiPm4CAqvAy8345n8AQ74b" : { + "name" : "Rawpool", + "link" : "https://www.rawpool.com/" + }, + "1LsFmhnne74EmU4q4aobfxfrWY4wfMVd8w" : { + "name" : "tiger", + "link" : "" + }, + "36n452uGq1x4mK7bfyZR8wgE47AnBb2pzi" : { + "name" : "Poolin", + "link" : "https://www.poolin.com/" + }, + "3KJrsjfg1dD6CrsTeHdHVH3KqMpvL2XWQn" : { + "name" : "Poolin", + "link" : "https://www.poolin.com/" + }, + "3JQSigWTCHyBLRD979JWgEtWP5YiiFwcQB" : { + "name" : "Poolin", + "link" : "https://www.poolin.com/" + }, + "1E8CZo2S3CqWg1VZSJNFCTbtT8hZPuQ2kB" : { + "name" : "Poolin", + "link" : "https://www.poolin.com/" + }, + "14sA8jqYQgMRQV9zUtGFvpeMEw7YDn77SK" : { + "name" : "Poolin", + "link" : "https://www.poolin.com/" + }, + "1GNgwA8JfG7Kc8akJ8opdNWJUihqUztfPe" : { + "name" : "Poolin", + "link" : "https://www.poolin.com/" + }, + "17tUZLvy3X2557JGhceXRiij2TNYuhRr4r" : { + "name" : "Poolin", + "link" : "https://www.poolin.com/" + }, + "12Taz8FFXQ3E2AGn3ZW1SZM5bLnYGX4xR6" : { + "name" : "Tangpool", + "link" : "http://www.tangpool.com/" + }, + "1M1Xw2rczxkF3p3wiNHaTmxvbpZZ7M6vaa" : { + "name": "1M1X", + "link": "" + }, + "39m5Wvn9ZqyhYmCYpsyHuGMt5YYw4Vmh1Z" : { + "name": "BytePool", + "link": "https://www.bytepool.com/" + }, + "38u1srayb1oybVB43UWKBJsrwJbdHGtPx2": { + "name" : "SpiderPool", + "link" : "https://www.spiderpool.com/" + }, + "125m2H43pwKpSZjLhMQHneuTwTJN5qRyYu": { + "name" : "SpiderPool", + "link" : "https://www.spiderpool.com/" + }, + "1Sjj2cPC3rTWcSTEYDeu2f3BavLosog4T": { + "name": "AntPool", + "link": "https://www.antpool.com/" + }, + "1jLVpwtNMfXWaHY4eiLDmGuBxokYLgv1X": { + "name": "AntPool", + "link": "https://www.antpool.com/" + }, + "15kiNKfDWsq7UsPg87UwxA8rVvWAjzRkYS": { + "name": "AntPool", + "link": "https://www.antpool.com/" + }, + "16MdTdqmXusauybtXTmFEW4GNFPPgGxQYE": { + "name": "AntPool", + "link": "https://www.antpool.com/" + }, + "16kUc5B48qnASbxeZTisCqTNx6G3DPXuKn": { + "name": "AntPool", + "link": "https://www.antpool.com/" + }, + "17gVZssumiJqYMCHozHKXGyaAvyu6NCX6V": { + "name": "AntPool", + "link": "https://www.antpool.com/" + }, + "1AJQ3jXhUF8WiisEcuVd8Xmfq4QJ7n1SdL": { + "name": "AntPool", + "link": "https://www.antpool.com/" + }, + "1BWW3pg5jb6rxebrNeo9TATarwJ1rthnoe": { + "name": "AntPool", + "link": "https://www.antpool.com/" + }, + "1CBqo1w3hmm9SCmbu2Yg6Ls4uLfkUqZJsx": { + "name": "AntPool", + "link": "https://www.antpool.com/" + }, + "1CyB8GJNEsNVXtPutB36nrDY3fMXBTzXSX": { + "name": "AntPool", + "link": "https://www.antpool.com/" + }, + "1D4UZG4qo8bF1MuZHSEyBHRZaxT8inatXS": { + "name": "AntPool", + "link": "https://www.antpool.com/" + }, + "1Dek9ArRHb9tyWb9gaaX8SWmkfi5V7U5Y6": { + "name": "AntPool", + "link": "https://www.antpool.com/" + }, + "1DDXyKUT6q3H9e5QXm2Gv6BNNWgztFG55g": { + "name": "AntPool", + "link": "https://www.antpool.com/" + }, + "1DyR7HPQWjM6Zrnk7SzHVY2GEpXRGNNH9o": { + "name": "AntPool", + "link": "https://www.antpool.com/" + }, + "1B7ZBX2C39b26M9chHLURGSFTJA6DDQkZv": { + "name": "AntPool", + "link": "https://www.antpool.com/" + }, + "1NS4gbx1G2D5rc9PnvVsPys12nKxGiQg72": { + "name": "AntPool", + "link": "https://www.antpool.com/" + }, + "1KmgBTL7cFmFFYTD7HcdkMcZXRcTkh2WwS": { + "name": "AntPool", + "link": "https://www.antpool.com/" + }, + "1Nh7uHdvY6fNwtQtM1G5EZAFPLC33B59rB": { + "name": "AntPool", + "link": "https://www.antpool.com/" + }, + "1LTGvTjDxiy5S9YcKEE9Lb7xSpZcPSqinw": { + "name": "AntPool", + "link": "https://www.antpool.com/" + }, + "1K8PNogxBZ6ts532DZnzxdbjgzJLjLdXqz": { + "name": "AntPool", + "link": "https://www.antpool.com/" + }, + "1JwUDWVSbAY5NeCBJhxQk1E8AfETfZuPj4": { + "name": "AntPool", + "link": "https://www.antpool.com/" + }, + "1JBVrhSSDrZrRmm4RnoWouqgGGqJMvWHi8": { + "name": "AntPool", + "link": "https://www.antpool.com/" + }, + "1H3u6R813MHGYhmGW6v86EYYriawRtACYD": { + "name": "AntPool", + "link": "https://www.antpool.com/" + }, + "1Gp7iCzDGMZiV55Kt8uKsux6VyoHe1aJaN": { + "name": "AntPool", + "link": "https://www.antpool.com/" + }, + "1GRcX882sdBYCAWyG99iF2oz7j3nYzXhLM": { + "name": "AntPool", + "link": "https://www.antpool.com/" + }, + "1FdJkPdpXtK3t5utZHJAop3saLZWfPfgak": { + "name": "AntPool", + "link": "https://www.antpool.com/" + }, + "12dRugNcdxK39288NjcDV4GX7rMsKCGn6B": { + "name": "AntPool", + "link": "https://www.antpool.com/" + }, + "1CZHhV67Qos4xXb8uYqvAGjK8Wq52woPi5": { + "name": "AntPool", + "link": "https://www.antpool.com/" + }, + "1Pzf7qT7bBGouvnjRvtRD8VhTyqjX1NrJT": { + "name": "AntPool", + "link": "https://www.antpool.com/" + }, + "3FaYVQF6wCMUB9NCeRe4tUp1zZx8qqM7H1": { + "name": "AntPool", + "link": "https://www.antpool.com/" + }, + "1MiQrT5sEKTUGNMbd9WS3yPPkSjWdpYA2r": { + "name": "AntPool", + "link": "https://www.antpool.com/" + }, + "1H6ckqNWikmVT3wpN3X1BQ6b156Xc9nT2L": { + "name": "AntPool", + "link": "https://www.antpool.com/" + }, + "1GT2N4dCufvbnTKMbS61QrQPN4SexCAFiH": { + "name": "AntPool", + "link": "https://www.antpool.com/" + }, + "1GEG1JR81jvUXs7TMAuo3SPBHZrpJijcjt": { + "name": "AntPool", + "link": "https://www.antpool.com/" + }, + "1FrHkVsW7csAYYaRbUUcrKSmv91hcQnsqQ": { + "name": "AntPool", + "link": "https://www.antpool.com/" + }, + "1DQaDTefKPjHz3beLuo8KHRZF9t2Sc6foP": { + "name": "AntPool", + "link": "https://www.antpool.com/" + }, + "1D9jw3QHNankXxtcGVihsDK7Z7THN6j7Pg": { + "name": "AntPool", + "link": "https://www.antpool.com/" + }, + "12cKiMNhCtBhZRUBCnYXo8A4WQzMUtYjmR": { + "name": "Sigmapool.com", + "link": "https://sigmapool.com/" + }, + "16JHXJ7M2MubWNX9grnqbjUqJ5PHwcCWw2": { + "name": "OKKONG", + "link": "https://hash.okkong.com/" + }, + "11wC5KcbgrWRBb43cwADdVrxgyF8mndVC": { + "name": "MiningCity", + "link": "https://www.miningcity.com/" + }, + "1DSh7vX6ed2cgTeKPwufV5i4hSi4pp373h": { + "name" : "Binance Pool", + "link" : "https://pool.binance.com/" + }, + "16moWjUJVRnDQKqhoCdcszfJg9wzBdoTHw": { + "name" : "Binance Pool", + "link" : "https://pool.binance.com/" + }, + "bc1qx9t2l3pyny2spqpqlye8svce70nppwtaxwdrp4": { + "name" : "Binance Pool", + "link" : "https://pool.binance.com/" + }, + "1JvXhnHCi6XqcanvrZJ5s2Qiv4tsmm2UMy": { + "name" : "Binance Pool", + "link" : "https://pool.binance.com/" + }, + "34Jpa4Eu3ApoPVUKNTN2WeuXVVq1jzxgPi": { + "name" : "Lubian.com", + "link" : "http://www.lubian.com/" + }, + "1FFxkVijzvUPUeHgkFjBk2Qw8j3wQY2cDw" : { + "name" : "Foundry USA", + "link" : "https://foundrydigital.com/" + }, + "1QEiAhdHdMhBgVbDM7zUXWGkNhgEEJ6uLd": { + "name": "ArkPool", + "link": "https://www.arkpool.com/" + }, + "147SwRQdpCfj5p8PnfsXV2SsVVpVcz3aPq": { + "name": "1THash", + "link": "https://www.1thash.top" + }, + "15vgygQ7ZsWdvZpctmTZK4673QBHsos6Sh": { + "name": "1THash", + "link": "https://www.1thash.top" + }, + "bc1qnnl503n04cqacpwvhr89qr70metxr79ht3n380": { + "name": "Rawpool", + "link": "https://www.rawpool.com" + }, + "bc1qwlrsvgtn99rqp3fgaxq6f6jkgms80rnej0a8tc": { + "name": "Rawpool", + "link": "https://www.rawpool.com" + }, + "bc1q8ej2g5uxdsg0jwl0mpl606qfjxgkyv3p29yf37": { + "name": "Rawpool", + "link": "https://www.rawpool.com" + }, + "bc1qru8mtv3e3u7ms6ecjmwgeakdakclemvhnw00q9": { + "name": "Rawpool", + "link": "https://www.rawpool.com" + }, + "3QYvfQoG9Gs9Vfvbpw6947muSqhoGagvF6": { + "name": "Rawpool", + "link": "https://www.rawpool.com" + }, + "35y82tEPDa2wm6tzkEacMG8GPPW7zbMj83": { + "name": "Rawpool", + "link": "https://www.rawpool.com" + }, + "3CLigLYNkrtoNgNcUwTaKoUSHCwr9W851W": { + "name": "Rawpool", + "link": "https://www.rawpool.com" + }, + "bc1qf274x7penhcd8hsv3jcmwa5xxzjl2a6pa9pxwm": { + "name" : "F2Pool", + "link" : "https://www.f2pool.com/" + }, + "1A32KFEX7JNPmU1PVjrtiXRrTQcesT3Nf1": { + "name": "MARA Pool", + "link": "https://marapool.com" + } + } +} \ No newline at end of file diff --git a/frontend/cypress/support/PageIdleDetector.ts b/frontend/cypress/support/PageIdleDetector.ts new file mode 100644 index 0000000000..3bfa2da3d6 --- /dev/null +++ b/frontend/cypress/support/PageIdleDetector.ts @@ -0,0 +1,63 @@ +// source: chrisp_68 @ https://stackoverflow.com/questions/50525143/how-do-you-reliably-wait-for-page-idle-in-cypress-io-test +export class PageIdleDetector +{ + defaultOptions: Object = { timeout: 60000 }; + + public WaitForPageToBeIdle(): void + { + this.WaitForPageToLoad(); + this.WaitForAngularRequestsToComplete(); + this.WaitForAngularDigestCycleToComplete(); + this.WaitForAnimationsToStop(); + } + + public WaitForPageToLoad(options: Object = this.defaultOptions): void + { + cy.document(options).should((myDocument: any) => + { + expect(myDocument.readyState, "WaitForPageToLoad").to.be.oneOf(["interactive", "complete"]); + }); + } + + public WaitForAngularRequestsToComplete(options: Object = this.defaultOptions): void + { + cy.window(options).should((myWindow: any) => + { + if (!!myWindow.angular) + { + expect(this.NumberOfPendingAngularRequests(myWindow), "WaitForAngularRequestsToComplete").to.have.length(0); + } + }); + } + + public WaitForAngularDigestCycleToComplete(options: Object = this.defaultOptions): void + { + cy.window(options).should((myWindow: any) => + { + if (!!myWindow.angular) + { + expect(this.AngularRootScopePhase(myWindow), "WaitForAngularDigestCycleToComplete").to.be.null; + } + }); + } + + public WaitForAnimationsToStop(options: Object = this.defaultOptions): void + { + cy.get(":animated", options).should("not.exist"); + } + + private getInjector(myWindow: any) + { + return myWindow.angular.element(myWindow.document.body).injector(); + } + + private NumberOfPendingAngularRequests(myWindow: any) + { + return this.getInjector(myWindow).get('$http').pendingRequests; + } + + private AngularRootScopePhase(myWindow: any) + { + return this.getInjector(myWindow).get("$rootScope").$$phase; + } +} diff --git a/frontend/cypress/support/commands.ts b/frontend/cypress/support/commands.ts new file mode 100644 index 0000000000..018f63569d --- /dev/null +++ b/frontend/cypress/support/commands.ts @@ -0,0 +1,142 @@ +// *********************************************** +// This example namespace declaration will help +// with Intellisense and code completion in your +// IDE or Text Editor. +// *********************************************** +// declare namespace Cypress { +// interface Chainable { +// customCommand(param: any): typeof customCommand; +// } +// } +// +// function customCommand(param: any): void { +// console.warn(param); +// } +// +// NOTE: You can use it like so: +// Cypress.Commands.add('customCommand', customCommand); +// +// *********************************************** +// This example commands.js shows you how to +// create various custom commands and overwrite +// existing commands. +// +// For more comprehensive examples of custom +// commands please read more here: +// https://on.cypress.io/custom-commands +// *********************************************** +// +// +// -- This is a parent command -- +// Cypress.Commands.add("login", (email, password) => { ... }) +// +// +// -- This is a child command -- +// Cypress.Commands.add("drag", { prevSubject: 'element'}, (subject, options) => { ... }) +// +// +// -- This is a dual command -- +// Cypress.Commands.add("dismiss", { prevSubject: 'optional'}, (subject, options) => { ... }) +// +// +// -- This will overwrite an existing command -- +// Cypress.Commands.overwrite("visit", (originalFn, url, options) => { ... }) + +import { PageIdleDetector } from './PageIdleDetector'; +import { mockWebSocket } from './websocket'; + +/* global Cypress */ +const codes = { + ArrowLeft: 37, + ArrowUp: 38, + ArrowRight: 39, + ArrowDown: 40 +} + +Cypress.Commands.add('waitForSkeletonGone', () => { + cy.waitUntil(() => { + return Cypress.$('.skeleton-loader').length === 0; + }, { verbose: true, description: "waitForSkeletonGone", errorMsg: "skeleton loaders never went away", timeout: 15000, interval: 50 }); +}); + +Cypress.Commands.add( + "waitForPageIdle", + () => { + console.warn("Waiting for page idle state"); + const pageIdleDetector = new PageIdleDetector(); + pageIdleDetector.WaitForPageToBeIdle(); + } +); + +Cypress.Commands.add('mockMempoolSocket', () => { + mockWebSocket(); +}); + +Cypress.Commands.add('changeNetwork', (network: "testnet" | "testnet4" | "signet" | "liquid" | "mainnet") => { + cy.get('.dropdown-toggle').click().then(() => { + cy.get(`a.${network}`).click().then(() => { + cy.waitForPageIdle(); + cy.waitForSkeletonGone(); + }); + }); +}); + +// https://github.com/bahmutov/cypress-arrows/blob/8f0303842a343550fbeaf01528d01d1ff213b70c/src/index.js +function keydownCommand($el, key) { + const message = `sending the "${key}" keydown event` + const log = Cypress.log({ + name: `keydown: ${key}`, + message: message, + consoleProps: function () { + return { + Subject: $el + } + } + }) + + const e = $el.createEvent('KeyboardEvent') + + Object.defineProperty(e, 'key', { + get: function () { + return key + } + }) + + Object.defineProperty(e, 'keyCode', { + get: function () { + return this.keyCodeVal + } + }) + Object.defineProperty(e, 'which', { + get: function () { + return this.keyCodeVal + } + }) + var metaKey = false + + Object.defineProperty(e, 'metaKey', { + get: function () { + return metaKey + } + }) + + Object.defineProperty(e, 'shiftKey', { + get: function () { + return false + } + }) + e.keyCodeVal = codes[key] + + e.initKeyboardEvent('keydown', true, true, + $el.defaultView, false, false, false, false, e.keyCodeVal, e.keyCodeVal) + + $el.dispatchEvent(e) + log.snapshot().end() + return $el +} + +Cypress.Commands.add('keydown', { prevSubject: "dom" }, keydownCommand) +Cypress.Commands.add('left', { prevSubject: "dom" }, $el => keydownCommand($el, 'ArrowLeft')) +Cypress.Commands.add('right', { prevSubject: "dom" }, $el => keydownCommand($el, 'ArrowRight')) +Cypress.Commands.add('up', { prevSubject: "dom" }, $el => keydownCommand($el, 'ArrowUp')) +Cypress.Commands.add('down', { prevSubject: "dom" }, $el => keydownCommand($el, 'ArrowDown')) diff --git a/frontend/cypress/support/e2e.ts b/frontend/cypress/support/e2e.ts new file mode 100644 index 0000000000..8b9e290271 --- /dev/null +++ b/frontend/cypress/support/e2e.ts @@ -0,0 +1,21 @@ +// *********************************************************** +// This example support/index.js is processed and +// loaded automatically before your test files. +// +// This is a great place to put global configuration and +// behavior that modifies Cypress. +// +// You can change the location of this file or turn off +// automatically serving support files with the +// 'supportFile' configuration option. +// +// You can read more here: +// https://on.cypress.io/configuration +// *********************************************************** + +// When a command from ./commands is ready to use, import with `import './commands'` syntax +import 'cypress-wait-until'; +import './commands'; +import failOnConsoleError from 'cypress-fail-on-console-error'; + +failOnConsoleError(); \ No newline at end of file diff --git a/frontend/cypress/support/index.d.ts b/frontend/cypress/support/index.d.ts new file mode 100644 index 0000000000..2c53283017 --- /dev/null +++ b/frontend/cypress/support/index.d.ts @@ -0,0 +1,10 @@ + +/// +declare namespace Cypress { + interface Chainable { + waitForSkeletonGone(): Chainable + waitForPageIdle(): Chainable + mockMempoolSocket(): Chainable + changeNetwork(network: "testnet"|"testnet4"|"signet"|"liquid"|"mainnet"): Chainable + } +} \ No newline at end of file diff --git a/frontend/cypress/support/websocket.ts b/frontend/cypress/support/websocket.ts new file mode 100644 index 0000000000..1356ccc769 --- /dev/null +++ b/frontend/cypress/support/websocket.ts @@ -0,0 +1,112 @@ +import { v4 as uuid } from 'uuid'; +import { WebSocket, Server } from 'mock-socket'; + +declare global { + interface Window { + mockServer: Server; + mockSocket: WebSocket; + } +} + +const mocks: { [key: string]: { server: Server; websocket: WebSocket } } = {}; + +const cleanupMock = (url: string) => { + if (mocks[url]) { + mocks[url].websocket.close(); + mocks[url].server.stop(); + delete mocks[url]; + } +}; + +const createMock = (url: string) => { + cleanupMock(url); + const server = new Server(url); + const websocket = new WebSocket(url); + mocks[url] = { server, websocket }; + + return mocks[url]; +}; + +export const mockWebSocket = () => { + cy.on('window:before:load', (win) => { + const winWebSocket = win.WebSocket; + cy.stub(win, 'WebSocket').callsFake((url) => { + console.log(url); + if ((new URL(url).pathname.indexOf('/sockjs-node/') !== 0)) { + const { server, websocket } = createMock(url); + + win.mockServer = server; + win.mockServer.on('connection', (socket) => { + win.mockSocket = socket; + win.mockSocket.send('{"conversions":{"USD":32365.338815782445}}'); + cy.readFile('cypress/fixtures/mainnet_live2hchart.json', 'ascii').then((fixture) => { + win.mockSocket.send(JSON.stringify(fixture)); + }); + cy.readFile('cypress/fixtures/mainnet_mempoolInfo.json', 'ascii').then((fixture) => { + win.mockSocket.send(JSON.stringify(fixture)); + }); + }); + + win.mockServer.on('message', (message) => { + console.log(message); + }); + + return websocket; + } else { + return new winWebSocket(url); + } + }); + }); + + cy.on('window:before:unload', () => { + for (const url in mocks) { + cleanupMock(url); + } + }); +}; + +export const emitMempoolInfo = ({ + params +}: { params?: any } = {}) => { + cy.window().then((win) => { + //TODO: Refactor to take into account different parameterized mocking scenarios + switch (params.network) { + //TODO: Use network specific mocks + case "signet": + case "testnet": + case "mainnet": + default: + break; + } + + switch (params.command) { + case "init": { + win.mockSocket.send('{"conversions":{"USD":32365.338815782445}}'); + cy.readFile('cypress/fixtures/mainnet_live2hchart.json', 'ascii').then((fixture) => { + win.mockSocket.send(JSON.stringify(fixture)); + }); + cy.readFile('cypress/fixtures/mainnet_mempoolInfo.json', 'ascii').then((fixture) => { + win.mockSocket.send(JSON.stringify(fixture)); + }); + break; + } + case "rbfTransaction": { + cy.readFile('cypress/fixtures/mainnet_rbf.json', 'ascii').then((fixture) => { + win.mockSocket.send(JSON.stringify(fixture)); + }); + break; + } + default: + break; + } + }); + cy.waitForSkeletonGone(); + return cy.get('#mempool-block-0'); +}; + +export const dropWebSocket = (() => { + cy.window().then((win) => { + win.mockServer.simulate("error"); + }); + return cy.wait(500); +}); diff --git a/frontend/cypress/tsconfig.json b/frontend/cypress/tsconfig.json new file mode 100644 index 0000000000..20e0cc8940 --- /dev/null +++ b/frontend/cypress/tsconfig.json @@ -0,0 +1,10 @@ +{ + "extends": "../tsconfig.json", + "include": ["**/*.ts"], + "compilerOptions": { + "types": ["cypress", "node", "cypress-wait-until"], + "lib": ["es2015", "dom"], + "allowJs": true, + "noEmit": true, + } +} diff --git a/frontend/e2e/protractor.conf.js b/frontend/e2e/protractor.conf.js deleted file mode 100644 index 73e4e6806c..0000000000 --- a/frontend/e2e/protractor.conf.js +++ /dev/null @@ -1,32 +0,0 @@ -// @ts-check -// Protractor configuration file, see link for more information -// https://github.com/angular/protractor/blob/master/lib/config.ts - -const { SpecReporter } = require('jasmine-spec-reporter'); - -/** - * @type { import("protractor").Config } - */ -exports.config = { - allScriptsTimeout: 11000, - specs: [ - './src/**/*.e2e-spec.ts' - ], - capabilities: { - 'browserName': 'chrome' - }, - directConnect: true, - baseUrl: 'http://localhost:4200/', - framework: 'jasmine', - jasmineNodeOpts: { - showColors: true, - defaultTimeoutInterval: 30000, - print: function() {} - }, - onPrepare() { - require('ts-node').register({ - project: require('path').join(__dirname, './tsconfig.json') - }); - jasmine.getEnv().addReporter(new SpecReporter({ spec: { displayStacktrace: true } })); - } -}; \ No newline at end of file diff --git a/frontend/e2e/src/app.e2e-spec.ts b/frontend/e2e/src/app.e2e-spec.ts deleted file mode 100644 index 51faedb71c..0000000000 --- a/frontend/e2e/src/app.e2e-spec.ts +++ /dev/null @@ -1,23 +0,0 @@ -import { AppPage } from './app.po'; -import { browser, logging } from 'protractor'; - -describe('workspace-project App', () => { - let page: AppPage; - - beforeEach(() => { - page = new AppPage(); - }); - - it('should display welcome message', () => { - page.navigateTo(); - expect(page.getTitleText()).toEqual('Welcome to mempool!'); - }); - - afterEach(async () => { - // Assert that there are no errors emitted from the browser - const logs = await browser.manage().logs().get(logging.Type.BROWSER); - expect(logs).not.toContain(jasmine.objectContaining({ - level: logging.Level.SEVERE, - } as logging.Entry)); - }); -}); diff --git a/frontend/e2e/src/app.po.ts b/frontend/e2e/src/app.po.ts deleted file mode 100644 index 5776aa9eb8..0000000000 --- a/frontend/e2e/src/app.po.ts +++ /dev/null @@ -1,11 +0,0 @@ -import { browser, by, element } from 'protractor'; - -export class AppPage { - navigateTo() { - return browser.get(browser.baseUrl) as Promise; - } - - getTitleText() { - return element(by.css('app-root h1')).getText() as Promise; - } -} diff --git a/frontend/e2e/tsconfig.json b/frontend/e2e/tsconfig.json deleted file mode 100644 index 6b87cc425b..0000000000 --- a/frontend/e2e/tsconfig.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "extends": "../tsconfig.base.json", - "compilerOptions": { - "outDir": "../out-tsc/e2e", - "module": "commonjs", - "target": "es2018", - "types": [ - "jasmine", - "jasminewd2", - "node" - ] - } -} diff --git a/frontend/frontend b/frontend/frontend new file mode 120000 index 0000000000..945c9b46d6 --- /dev/null +++ b/frontend/frontend @@ -0,0 +1 @@ +. \ No newline at end of file diff --git a/frontend/generate-config.js b/frontend/generate-config.js index 614e61e5f5..89d7143fd7 100644 --- a/frontend/generate-config.js +++ b/frontend/generate-config.js @@ -1,20 +1,59 @@ var fs = require('fs'); +const { spawnSync } = require('child_process'); const CONFIG_FILE_NAME = 'mempool-frontend-config.json'; -const GENERATED_CONFIG_FILE_NAME = 'generated-config.js'; +const GENERATED_CONFIG_FILE_NAME = 'src/resources/config.js'; +const GENERATED_TEMPLATE_CONFIG_FILE_NAME = 'src/resources/config.template.js'; +const GENERATED_CUSTOMIZATION_FILE_NAME = 'src/resources/customize.js'; let settings = []; let configContent = {}; +let gitCommitHash = ''; +let packetJsonVersion = ''; +let customConfig; +let customConfigContent; try { const rawConfig = fs.readFileSync(CONFIG_FILE_NAME); configContent = JSON.parse(rawConfig); + console.log(`${CONFIG_FILE_NAME} file found, using provided config`); } catch (e) { if (e.code !== 'ENOENT') { throw new Error(e); + } else { + console.log(`${CONFIG_FILE_NAME} file not found, using default config`); } } +if (configContent && configContent.CUSTOMIZATION) { + try { + customConfig = readConfig(configContent.CUSTOMIZATION); + customConfigContent = JSON.parse(customConfig); + } catch (e) { + console.log(`failed to load customization config from ${configContent.CUSTOMIZATION}`); + } +} + +const baseModuleName = configContent.BASE_MODULE || 'mempool'; +const customBuildName = (customConfigContent && customConfigContent.enterprise) ? ('.' + customConfigContent.enterprise) : ''; +const indexFilePath = 'src/index.' + baseModuleName + customBuildName + '.html'; + +try { + fs.copyFileSync(indexFilePath, 'src/index.html'); + console.log('Copied ' + indexFilePath + ' to src/index.html'); +} catch (e) { + console.log('Error copying the index file'); + throw new Error(e); +} + +try { + const packageJson = fs.readFileSync('package.json'); + packetJsonVersion = JSON.parse(packageJson).version; + console.log(`mempool version ${packetJsonVersion}`); +} catch (e) { + throw new Error(e); +} + for (setting in configContent) { settings.push({ key: setting, @@ -22,15 +61,92 @@ for (setting in configContent) { }); } -const code = `(function (window) { +if (process.env.DOCKER_COMMIT_HASH) { + gitCommitHash = process.env.DOCKER_COMMIT_HASH; +} else { + try { + const gitRevParse = spawnSync('git', ['rev-parse', '--short', 'HEAD']); + if (!gitRevParse.error) { + const output = gitRevParse.stdout.toString('utf-8').replace(/[\n\r\s]+$/, ''); + gitCommitHash = output ? output : '?'; + console.log(`mempool revision ${gitCommitHash}`); + } else if (gitRevParse.error.code === 'ENOENT') { + console.log('git not found, cannot parse git hash'); + gitCommitHash = '?'; + } + } catch (e) { + console.log('Could not load git commit info: ' + e.message); + gitCommitHash = '?'; + } +} + +const newConfig = `(function (window) { + window.__env = window.__env || {};${settings.reduce((str, obj) => `${str} + window.__env.${obj.key} = ${typeof obj.value === 'string' ? `'${obj.value}'` : obj.value};`, '')} + window.__env.GIT_COMMIT_HASH = '${gitCommitHash}'; + window.__env.PACKAGE_JSON_VERSION = '${packetJsonVersion}'; + }((typeof global !== 'undefined') ? global : this));`; + +const newConfigTemplate = `(function (window) { window.__env = window.__env || {};${settings.reduce((str, obj) => `${str} - window.__env.${obj.key} = ${ typeof obj.value === 'string' ? `'${obj.value}'` : obj.value };`, '')} + window.__env.${obj.key} = ${typeof obj.value === 'string' ? `'\${__${obj.key}__}'` : `\${__${obj.key}__}`};`, '')} + window.__env.GIT_COMMIT_HASH = '${gitCommitHash}'; + window.__env.PACKAGE_JSON_VERSION = '${packetJsonVersion}'; }(this));`; -try { - fs.writeFileSync(GENERATED_CONFIG_FILE_NAME, code, 'utf8'); -} catch (e) { - throw new Error(e); +function readConfig(path) { + try { + const currentConfig = fs.readFileSync(path).toString().trim(); + return currentConfig; + } catch (e) { + return false; + } +} + +function writeConfig(path, config) { + try { + fs.writeFileSync(path, config, 'utf8'); + } catch (e) { + throw new Error(e); + } } -console.log('Config file generated'); \ No newline at end of file +function writeConfigTemplate(path, config) { + try { + fs.writeFileSync(path, config, 'utf8'); + } catch (e) { + throw new Error(e); + } +} + +writeConfigTemplate(GENERATED_TEMPLATE_CONFIG_FILE_NAME, newConfigTemplate); + +const currentConfig = readConfig(GENERATED_CONFIG_FILE_NAME); + +let customConfigJs = ''; +if (customConfig) { + console.log(`Customizing frontend using ${configContent.CUSTOMIZATION}`); + customConfigJs = `(function (window) { + window.__env = window.__env || {}; + window.__env.customize = ${customConfig}; + }((typeof global !== 'undefined') ? global : this)); + `; +} +writeConfig(GENERATED_CUSTOMIZATION_FILE_NAME, customConfigJs); + +if (currentConfig && currentConfig === newConfig) { + console.log(`No configuration updates, skipping ${GENERATED_CONFIG_FILE_NAME} file update`); + return; +} else if (!currentConfig) { + console.log(`${GENERATED_CONFIG_FILE_NAME} file not found, creating new config file`); + console.log('CONFIG: ', newConfig); + writeConfig(GENERATED_CONFIG_FILE_NAME, newConfig); + console.log(`${GENERATED_CONFIG_FILE_NAME} file saved`); + return; +} else { + console.log(`Configuration changes detected, updating ${GENERATED_CONFIG_FILE_NAME} file`); + console.log('OLD CONFIG: ', currentConfig); + console.log('NEW CONFIG: ', newConfig); + writeConfig(GENERATED_CONFIG_FILE_NAME, newConfig); + console.log(`${GENERATED_CONFIG_FILE_NAME} file updated`); +} diff --git a/frontend/karma.conf.js b/frontend/karma.conf.js deleted file mode 100644 index 5aca0c320c..0000000000 --- a/frontend/karma.conf.js +++ /dev/null @@ -1,32 +0,0 @@ -// Karma configuration file, see link for more information -// https://karma-runner.github.io/1.0/config/configuration-file.html - -module.exports = function (config) { - config.set({ - basePath: '', - frameworks: ['jasmine', '@angular-devkit/build-angular'], - plugins: [ - require('karma-jasmine'), - require('karma-chrome-launcher'), - require('karma-jasmine-html-reporter'), - require('karma-coverage-istanbul-reporter'), - require('@angular-devkit/build-angular/plugins/karma') - ], - client: { - clearContext: false // leave Jasmine Spec Runner output visible in browser - }, - coverageIstanbulReporter: { - dir: require('path').join(__dirname, './coverage/mempool'), - reports: ['html', 'lcovonly', 'text-summary'], - fixWebpackSourcePaths: true - }, - reporters: ['progress', 'kjhtml'], - port: 9876, - colors: true, - logLevel: config.LOG_INFO, - autoWatch: true, - browsers: ['Chrome'], - singleRun: false, - restartOnFileChange: true - }); -}; diff --git a/frontend/mempool-frontend-config.sample.json b/frontend/mempool-frontend-config.sample.json index 579250e88d..38a671edf5 100644 --- a/frontend/mempool-frontend-config.sample.json +++ b/frontend/mempool-frontend-config.sample.json @@ -1,7 +1,30 @@ { "TESTNET_ENABLED": false, + "TESTNET4_ENABLED": false, + "SIGNET_ENABLED": false, "LIQUID_ENABLED": false, - "BISQ_ENABLED": false, - "ELCTRS_ITEMS_PER_PAGE": 25, - "KEEP_BLOCKS_AMOUNT": 8 -} \ No newline at end of file + "LIQUID_TESTNET_ENABLED": false, + "MAINNET_ENABLED": true, + "ITEMS_PER_PAGE": 10, + "KEEP_BLOCKS_AMOUNT": 8, + "NGINX_PROTOCOL": "http", + "NGINX_HOSTNAME": "127.0.0.1", + "NGINX_PORT": "80", + "BLOCK_WEIGHT_UNITS": 4000000, + "MEMPOOL_BLOCKS_AMOUNT": 8, + "BASE_MODULE": "mempool", + "ROOT_NETWORK": "", + "MEMPOOL_WEBSITE_URL": "https://mempool.space", + "LIQUID_WEBSITE_URL": "https://liquid.network", + "MINING_DASHBOARD": true, + "AUDIT": false, + "MAINNET_BLOCK_AUDIT_START_HEIGHT": 0, + "TESTNET_BLOCK_AUDIT_START_HEIGHT": 0, + "SIGNET_BLOCK_AUDIT_START_HEIGHT": 0, + "LIGHTNING": false, + "HISTORICAL_PRICE": true, + "ADDITIONAL_CURRENCIES": false, + "ACCELERATOR": false, + "PUBLIC_ACCELERATIONS": false, + "SERVICES_API": "https://mempool.space/api/v1/services" +} diff --git a/frontend/package-lock.json b/frontend/package-lock.json new file mode 100644 index 0000000000..d164bd8696 --- /dev/null +++ b/frontend/package-lock.json @@ -0,0 +1,31784 @@ +{ + "name": "mempool-frontend", + "version": "3.0.0-dev", + "lockfileVersion": 2, + "requires": true, + "packages": { + "": { + "name": "mempool-frontend", + "version": "3.0.0-dev", + "license": "GNU Affero General Public License v3.0", + "dependencies": { + "@angular-devkit/build-angular": "^17.3.1", + "@angular/animations": "^17.3.1", + "@angular/cli": "^17.3.1", + "@angular/common": "^17.3.1", + "@angular/compiler": "^17.3.1", + "@angular/core": "^17.3.1", + "@angular/forms": "^17.3.1", + "@angular/localize": "^17.3.1", + "@angular/platform-browser": "^17.3.1", + "@angular/platform-browser-dynamic": "^17.3.1", + "@angular/platform-server": "^17.3.1", + "@angular/router": "^17.3.1", + "@angular/ssr": "^17.3.1", + "@fortawesome/angular-fontawesome": "~0.14.1", + "@fortawesome/fontawesome-common-types": "~6.6.0", + "@fortawesome/fontawesome-svg-core": "~6.6.0", + "@fortawesome/free-solid-svg-icons": "~6.6.0", + "@mempool/mempool.js": "2.3.0", + "@ng-bootstrap/ng-bootstrap": "^16.0.0", + "@types/qrcode": "~1.5.0", + "bootstrap": "~4.6.2", + "browserify": "^17.0.0", + "clipboard": "^2.0.11", + "domino": "^2.1.6", + "echarts": "~5.5.0", + "esbuild": "^0.23.0", + "lightweight-charts": "~3.8.0", + "ngx-echarts": "~17.2.0", + "ngx-infinite-scroll": "^17.0.0", + "qrcode": "1.5.1", + "rxjs": "~7.8.1", + "tinyify": "^4.0.0", + "tlite": "^0.1.9", + "tslib": "~2.6.0", + "zone.js": "~0.14.4" + }, + "devDependencies": { + "@angular/compiler-cli": "^17.3.1", + "@angular/language-service": "^17.3.1", + "@types/node": "^18.11.9", + "@typescript-eslint/eslint-plugin": "^7.4.0", + "@typescript-eslint/parser": "^7.4.0", + "browser-sync": "^3.0.0", + "eslint": "^8.57.0", + "http-proxy-middleware": "~2.0.6", + "prettier": "^3.0.0", + "source-map-support": "^0.5.21", + "ts-node": "~10.9.1", + "typescript": "~5.4.3" + }, + "optionalDependencies": { + "@cypress/schematic": "^2.5.0", + "@types/cypress": "^1.1.3", + "cypress": "^13.13.0", + "cypress-fail-on-console-error": "~5.1.0", + "cypress-wait-until": "^2.0.1", + "mock-socket": "~9.3.1", + "start-server-and-test": "~2.0.0" + } + }, + "node_modules/@aashutoshrathi/word-wrap": { + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/@aashutoshrathi/word-wrap/-/word-wrap-1.2.6.tgz", + "integrity": "sha512-1Yjs2SvM8TflER/OD3cOjhWWOZb58A2t7wpE2S9XfBYTiIl+XFhQG2bjy4Pu1I+EAlCNUzRDYDdFwFYUKvXcIA==", + "dev": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/@ampproject/remapping": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.3.0.tgz", + "integrity": "sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==", + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.24" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@ampproject/remapping/node_modules/@jridgewell/trace-mapping": { + "version": "0.3.25", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz", + "integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==", + "dependencies": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, + "node_modules/@angular-devkit/architect": { + "version": "0.1703.1", + "resolved": "https://registry.npmjs.org/@angular-devkit/architect/-/architect-0.1703.1.tgz", + "integrity": "sha512-vkfvURv7O+3fHMTE9K+yUEiFS0v4JNYKsDP0LE1ChH5Ocy0bJXGcH2Cyz2W8qdJGDG/tKe41VzvOLpu88Xv3zQ==", + "dependencies": { + "@angular-devkit/core": "17.3.1", + "rxjs": "7.8.1" + }, + "engines": { + "node": "^18.13.0 || >=20.9.0", + "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", + "yarn": ">= 1.13.0" + } + }, + "node_modules/@angular-devkit/build-angular": { + "version": "17.3.1", + "resolved": "https://registry.npmjs.org/@angular-devkit/build-angular/-/build-angular-17.3.1.tgz", + "integrity": "sha512-e+hZvLVH5AvHCFbVtKRd5oJeFsEmjg7kK1V6hsVxH4YE2f2x399TSr+AGxwV+R3jnjZ67ujIeXXd0Uuf1RwcSg==", + "dependencies": { + "@ampproject/remapping": "2.3.0", + "@angular-devkit/architect": "0.1703.1", + "@angular-devkit/build-webpack": "0.1703.1", + "@angular-devkit/core": "17.3.1", + "@babel/core": "7.24.0", + "@babel/generator": "7.23.6", + "@babel/helper-annotate-as-pure": "7.22.5", + "@babel/helper-split-export-declaration": "7.22.6", + "@babel/plugin-transform-async-generator-functions": "7.23.9", + "@babel/plugin-transform-async-to-generator": "7.23.3", + "@babel/plugin-transform-runtime": "7.24.0", + "@babel/preset-env": "7.24.0", + "@babel/runtime": "7.24.0", + "@discoveryjs/json-ext": "0.5.7", + "@ngtools/webpack": "17.3.1", + "@vitejs/plugin-basic-ssl": "1.1.0", + "ansi-colors": "4.1.3", + "autoprefixer": "10.4.18", + "babel-loader": "9.1.3", + "babel-plugin-istanbul": "6.1.1", + "browserslist": "^4.21.5", + "copy-webpack-plugin": "11.0.0", + "critters": "0.0.22", + "css-loader": "6.10.0", + "esbuild-wasm": "0.20.1", + "fast-glob": "3.3.2", + "http-proxy-middleware": "2.0.6", + "https-proxy-agent": "7.0.4", + "inquirer": "9.2.15", + "jsonc-parser": "3.2.1", + "karma-source-map-support": "1.4.0", + "less": "4.2.0", + "less-loader": "11.1.0", + "license-webpack-plugin": "4.0.2", + "loader-utils": "3.2.1", + "magic-string": "0.30.8", + "mini-css-extract-plugin": "2.8.1", + "mrmime": "2.0.0", + "open": "8.4.2", + "ora": "5.4.1", + "parse5-html-rewriting-stream": "7.0.0", + "picomatch": "4.0.1", + "piscina": "4.4.0", + "postcss": "8.4.35", + "postcss-loader": "8.1.1", + "resolve-url-loader": "5.0.0", + "rxjs": "7.8.1", + "sass": "1.71.1", + "sass-loader": "14.1.1", + "semver": "7.6.0", + "source-map-loader": "5.0.0", + "source-map-support": "0.5.21", + "terser": "5.29.1", + "tree-kill": "1.2.2", + "tslib": "2.6.2", + "undici": "6.7.1", + "vite": "5.1.5", + "watchpack": "2.4.0", + "webpack": "5.90.3", + "webpack-dev-middleware": "6.1.1", + "webpack-dev-server": "4.15.1", + "webpack-merge": "5.10.0", + "webpack-subresource-integrity": "5.1.0" + }, + "engines": { + "node": "^18.13.0 || >=20.9.0", + "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", + "yarn": ">= 1.13.0" + }, + "optionalDependencies": { + "esbuild": "0.20.1" + }, + "peerDependencies": { + "@angular/compiler-cli": "^17.0.0", + "@angular/localize": "^17.0.0", + "@angular/platform-server": "^17.0.0", + "@angular/service-worker": "^17.0.0", + "@web/test-runner": "^0.18.0", + "browser-sync": "^3.0.2", + "jest": "^29.5.0", + "jest-environment-jsdom": "^29.5.0", + "karma": "^6.3.0", + "ng-packagr": "^17.0.0", + "protractor": "^7.0.0", + "tailwindcss": "^2.0.0 || ^3.0.0", + "typescript": ">=5.2 <5.5" + }, + "peerDependenciesMeta": { + "@angular/localize": { + "optional": true + }, + "@angular/platform-server": { + "optional": true + }, + "@angular/service-worker": { + "optional": true + }, + "@web/test-runner": { + "optional": true + }, + "browser-sync": { + "optional": true + }, + "jest": { + "optional": true + }, + "jest-environment-jsdom": { + "optional": true + }, + "karma": { + "optional": true + }, + "ng-packagr": { + "optional": true + }, + "protractor": { + "optional": true + }, + "tailwindcss": { + "optional": true + } + } + }, + "node_modules/@angular-devkit/build-angular/node_modules/@babel/core": { + "version": "7.24.0", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.24.0.tgz", + "integrity": "sha512-fQfkg0Gjkza3nf0c7/w6Xf34BW4YvzNfACRLmmb7XRLa6XHdR+K9AlJlxneFfWYf6uhOzuzZVTjF/8KfndZANw==", + "dependencies": { + "@ampproject/remapping": "^2.2.0", + "@babel/code-frame": "^7.23.5", + "@babel/generator": "^7.23.6", + "@babel/helper-compilation-targets": "^7.23.6", + "@babel/helper-module-transforms": "^7.23.3", + "@babel/helpers": "^7.24.0", + "@babel/parser": "^7.24.0", + "@babel/template": "^7.24.0", + "@babel/traverse": "^7.24.0", + "@babel/types": "^7.24.0", + "convert-source-map": "^2.0.0", + "debug": "^4.1.0", + "gensync": "^1.0.0-beta.2", + "json5": "^2.2.3", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/babel" + } + }, + "node_modules/@angular-devkit/build-angular/node_modules/@babel/core/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/@angular-devkit/build-angular/node_modules/@esbuild/aix-ppc64": { + "version": "0.20.1", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.20.1.tgz", + "integrity": "sha512-m55cpeupQ2DbuRGQMMZDzbv9J9PgVelPjlcmM5kxHnrBdBx6REaEd7LamYV7Dm8N7rCyR/XwU6rVP8ploKtIkA==", + "cpu": [ + "ppc64" + ], + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@angular-devkit/build-angular/node_modules/@esbuild/android-arm": { + "version": "0.20.1", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.20.1.tgz", + "integrity": "sha512-4j0+G27/2ZXGWR5okcJi7pQYhmkVgb4D7UKwxcqrjhvp5TKWx3cUjgB1CGj1mfdmJBQ9VnUGgUhign+FPF2Zgw==", + "cpu": [ + "arm" + ], + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@angular-devkit/build-angular/node_modules/@esbuild/android-arm64": { + "version": "0.20.1", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.20.1.tgz", + "integrity": "sha512-hCnXNF0HM6AjowP+Zou0ZJMWWa1VkD77BXe959zERgGJBBxB+sV+J9f/rcjeg2c5bsukD/n17RKWXGFCO5dD5A==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@angular-devkit/build-angular/node_modules/@esbuild/android-x64": { + "version": "0.20.1", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.20.1.tgz", + "integrity": "sha512-MSfZMBoAsnhpS+2yMFYIQUPs8Z19ajwfuaSZx+tSl09xrHZCjbeXXMsUF/0oq7ojxYEpsSo4c0SfjxOYXRbpaA==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@angular-devkit/build-angular/node_modules/@esbuild/darwin-arm64": { + "version": "0.20.1", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.20.1.tgz", + "integrity": "sha512-Ylk6rzgMD8klUklGPzS414UQLa5NPXZD5tf8JmQU8GQrj6BrFA/Ic9tb2zRe1kOZyCbGl+e8VMbDRazCEBqPvA==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@angular-devkit/build-angular/node_modules/@esbuild/darwin-x64": { + "version": "0.20.1", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.20.1.tgz", + "integrity": "sha512-pFIfj7U2w5sMp52wTY1XVOdoxw+GDwy9FsK3OFz4BpMAjvZVs0dT1VXs8aQm22nhwoIWUmIRaE+4xow8xfIDZA==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@angular-devkit/build-angular/node_modules/@esbuild/freebsd-arm64": { + "version": "0.20.1", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.20.1.tgz", + "integrity": "sha512-UyW1WZvHDuM4xDz0jWun4qtQFauNdXjXOtIy7SYdf7pbxSWWVlqhnR/T2TpX6LX5NI62spt0a3ldIIEkPM6RHw==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@angular-devkit/build-angular/node_modules/@esbuild/freebsd-x64": { + "version": "0.20.1", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.20.1.tgz", + "integrity": "sha512-itPwCw5C+Jh/c624vcDd9kRCCZVpzpQn8dtwoYIt2TJF3S9xJLiRohnnNrKwREvcZYx0n8sCSbvGH349XkcQeg==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@angular-devkit/build-angular/node_modules/@esbuild/linux-arm": { + "version": "0.20.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.20.1.tgz", + "integrity": "sha512-LojC28v3+IhIbfQ+Vu4Ut5n3wKcgTu6POKIHN9Wpt0HnfgUGlBuyDDQR4jWZUZFyYLiz4RBBBmfU6sNfn6RhLw==", + "cpu": [ + "arm" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@angular-devkit/build-angular/node_modules/@esbuild/linux-arm64": { + "version": "0.20.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.20.1.tgz", + "integrity": "sha512-cX8WdlF6Cnvw/DO9/X7XLH2J6CkBnz7Twjpk56cshk9sjYVcuh4sXQBy5bmTwzBjNVZze2yaV1vtcJS04LbN8w==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@angular-devkit/build-angular/node_modules/@esbuild/linux-ia32": { + "version": "0.20.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.20.1.tgz", + "integrity": "sha512-4H/sQCy1mnnGkUt/xszaLlYJVTz3W9ep52xEefGtd6yXDQbz/5fZE5dFLUgsPdbUOQANcVUa5iO6g3nyy5BJiw==", + "cpu": [ + "ia32" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@angular-devkit/build-angular/node_modules/@esbuild/linux-loong64": { + "version": "0.20.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.20.1.tgz", + "integrity": "sha512-c0jgtB+sRHCciVXlyjDcWb2FUuzlGVRwGXgI+3WqKOIuoo8AmZAddzeOHeYLtD+dmtHw3B4Xo9wAUdjlfW5yYA==", + "cpu": [ + "loong64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@angular-devkit/build-angular/node_modules/@esbuild/linux-mips64el": { + "version": "0.20.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.20.1.tgz", + "integrity": "sha512-TgFyCfIxSujyuqdZKDZ3yTwWiGv+KnlOeXXitCQ+trDODJ+ZtGOzLkSWngynP0HZnTsDyBbPy7GWVXWaEl6lhA==", + "cpu": [ + "mips64el" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@angular-devkit/build-angular/node_modules/@esbuild/linux-ppc64": { + "version": "0.20.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.20.1.tgz", + "integrity": "sha512-b+yuD1IUeL+Y93PmFZDZFIElwbmFfIKLKlYI8M6tRyzE6u7oEP7onGk0vZRh8wfVGC2dZoy0EqX1V8qok4qHaw==", + "cpu": [ + "ppc64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@angular-devkit/build-angular/node_modules/@esbuild/linux-riscv64": { + "version": "0.20.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.20.1.tgz", + "integrity": "sha512-wpDlpE0oRKZwX+GfomcALcouqjjV8MIX8DyTrxfyCfXxoKQSDm45CZr9fanJ4F6ckD4yDEPT98SrjvLwIqUCgg==", + "cpu": [ + "riscv64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@angular-devkit/build-angular/node_modules/@esbuild/linux-s390x": { + "version": "0.20.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.20.1.tgz", + "integrity": "sha512-5BepC2Au80EohQ2dBpyTquqGCES7++p7G+7lXe1bAIvMdXm4YYcEfZtQrP4gaoZ96Wv1Ute61CEHFU7h4FMueQ==", + "cpu": [ + "s390x" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@angular-devkit/build-angular/node_modules/@esbuild/linux-x64": { + "version": "0.20.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.20.1.tgz", + "integrity": "sha512-5gRPk7pKuaIB+tmH+yKd2aQTRpqlf1E4f/mC+tawIm/CGJemZcHZpp2ic8oD83nKgUPMEd0fNanrnFljiruuyA==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@angular-devkit/build-angular/node_modules/@esbuild/netbsd-x64": { + "version": "0.20.1", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.20.1.tgz", + "integrity": "sha512-4fL68JdrLV2nVW2AaWZBv3XEm3Ae3NZn/7qy2KGAt3dexAgSVT+Hc97JKSZnqezgMlv9x6KV0ZkZY7UO5cNLCg==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@angular-devkit/build-angular/node_modules/@esbuild/openbsd-x64": { + "version": "0.20.1", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.20.1.tgz", + "integrity": "sha512-GhRuXlvRE+twf2ES+8REbeCb/zeikNqwD3+6S5y5/x+DYbAQUNl0HNBs4RQJqrechS4v4MruEr8ZtAin/hK5iw==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@angular-devkit/build-angular/node_modules/@esbuild/sunos-x64": { + "version": "0.20.1", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.20.1.tgz", + "integrity": "sha512-ZnWEyCM0G1Ex6JtsygvC3KUUrlDXqOihw8RicRuQAzw+c4f1D66YlPNNV3rkjVW90zXVsHwZYWbJh3v+oQFM9Q==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@angular-devkit/build-angular/node_modules/@esbuild/win32-arm64": { + "version": "0.20.1", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.20.1.tgz", + "integrity": "sha512-QZ6gXue0vVQY2Oon9WyLFCdSuYbXSoxaZrPuJ4c20j6ICedfsDilNPYfHLlMH7vGfU5DQR0czHLmJvH4Nzis/A==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@angular-devkit/build-angular/node_modules/@esbuild/win32-ia32": { + "version": "0.20.1", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.20.1.tgz", + "integrity": "sha512-HzcJa1NcSWTAU0MJIxOho8JftNp9YALui3o+Ny7hCh0v5f90nprly1U3Sj1Ldj/CvKKdvvFsCRvDkpsEMp4DNw==", + "cpu": [ + "ia32" + ], + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@angular-devkit/build-angular/node_modules/@esbuild/win32-x64": { + "version": "0.20.1", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.20.1.tgz", + "integrity": "sha512-0MBh53o6XtI6ctDnRMeQ+xoCN8kD2qI1rY1KgF/xdWQwoFeKou7puvDfV8/Wv4Ctx2rRpET/gGdz3YlNtNACSA==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/@angular-devkit/build-angular/node_modules/convert-source-map": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", + "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==" + }, + "node_modules/@angular-devkit/build-angular/node_modules/esbuild": { + "version": "0.20.1", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.20.1.tgz", + "integrity": "sha512-OJwEgrpWm/PCMsLVWXKqvcjme3bHNpOgN7Tb6cQnR5n0TPbQx1/Xrn7rqM+wn17bYeT6MGB5sn1Bh5YiGi70nA==", + "hasInstallScript": true, + "optional": true, + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=12" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.20.1", + "@esbuild/android-arm": "0.20.1", + "@esbuild/android-arm64": "0.20.1", + "@esbuild/android-x64": "0.20.1", + "@esbuild/darwin-arm64": "0.20.1", + "@esbuild/darwin-x64": "0.20.1", + "@esbuild/freebsd-arm64": "0.20.1", + "@esbuild/freebsd-x64": "0.20.1", + "@esbuild/linux-arm": "0.20.1", + "@esbuild/linux-arm64": "0.20.1", + "@esbuild/linux-ia32": "0.20.1", + "@esbuild/linux-loong64": "0.20.1", + "@esbuild/linux-mips64el": "0.20.1", + "@esbuild/linux-ppc64": "0.20.1", + "@esbuild/linux-riscv64": "0.20.1", + "@esbuild/linux-s390x": "0.20.1", + "@esbuild/linux-x64": "0.20.1", + "@esbuild/netbsd-x64": "0.20.1", + "@esbuild/openbsd-x64": "0.20.1", + "@esbuild/sunos-x64": "0.20.1", + "@esbuild/win32-arm64": "0.20.1", + "@esbuild/win32-ia32": "0.20.1", + "@esbuild/win32-x64": "0.20.1" + } + }, + "node_modules/@angular-devkit/build-angular/node_modules/loader-utils": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-3.2.1.tgz", + "integrity": "sha512-ZvFw1KWS3GVyYBYb7qkmRM/WwL2TQQBxgCK62rlvm4WpVQ23Nb4tYjApUlfjrEGvOs7KHEsmyUn75OHZrJMWPw==", + "engines": { + "node": ">= 12.13.0" + } + }, + "node_modules/@angular-devkit/build-angular/node_modules/picomatch": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.1.tgz", + "integrity": "sha512-xUXwsxNjwTQ8K3GnT4pCJm+xq3RUPQbmkYJTP5aFIfNIvbcc/4MUxgBaaRSZJ6yGJZiGSyYlM6MzwTsRk8SYCg==", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/@angular-devkit/build-angular/node_modules/semver": { + "version": "7.6.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.0.tgz", + "integrity": "sha512-EnwXhrlwXMk9gKu5/flx5sv/an57AkRplG3hTK68W7FRDN+k+OWBj65M7719OkA82XLBxrcX0KSHj+X5COhOVg==", + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@angular-devkit/build-webpack": { + "version": "0.1703.1", + "resolved": "https://registry.npmjs.org/@angular-devkit/build-webpack/-/build-webpack-0.1703.1.tgz", + "integrity": "sha512-nVUzewX8RCzaEPQZ1JQpE42wpsYchKQwfXUSCkoUsuCMB2c6zuEz0Jt94nzJg3UjSEEV4ZqCH8v5MDOvB49Rlw==", + "dependencies": { + "@angular-devkit/architect": "0.1703.1", + "rxjs": "7.8.1" + }, + "engines": { + "node": "^18.13.0 || >=20.9.0", + "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", + "yarn": ">= 1.13.0" + }, + "peerDependencies": { + "webpack": "^5.30.0", + "webpack-dev-server": "^4.0.0" + } + }, + "node_modules/@angular-devkit/core": { + "version": "17.3.1", + "resolved": "https://registry.npmjs.org/@angular-devkit/core/-/core-17.3.1.tgz", + "integrity": "sha512-EP7zwqBEaOPuBJwzKmh2abfgNFITGX178BOyTG6zTymeMzEbrvy2OdeQXSslkJ/RGLCpx60GT+0CFW7wGlQR6Q==", + "dependencies": { + "ajv": "8.12.0", + "ajv-formats": "2.1.1", + "jsonc-parser": "3.2.1", + "picomatch": "4.0.1", + "rxjs": "7.8.1", + "source-map": "0.7.4" + }, + "engines": { + "node": "^18.13.0 || >=20.9.0", + "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", + "yarn": ">= 1.13.0" + }, + "peerDependencies": { + "chokidar": "^3.5.2" + }, + "peerDependenciesMeta": { + "chokidar": { + "optional": true + } + } + }, + "node_modules/@angular-devkit/core/node_modules/ajv": { + "version": "8.12.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.12.0.tgz", + "integrity": "sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==", + "dependencies": { + "fast-deep-equal": "^3.1.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/@angular-devkit/core/node_modules/json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==" + }, + "node_modules/@angular-devkit/core/node_modules/picomatch": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.1.tgz", + "integrity": "sha512-xUXwsxNjwTQ8K3GnT4pCJm+xq3RUPQbmkYJTP5aFIfNIvbcc/4MUxgBaaRSZJ6yGJZiGSyYlM6MzwTsRk8SYCg==", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/@angular-devkit/schematics": { + "version": "17.3.1", + "resolved": "https://registry.npmjs.org/@angular-devkit/schematics/-/schematics-17.3.1.tgz", + "integrity": "sha512-c3tp5zC5zp6XpK9w8wJf3d4Dyw9BNbmg/VEoXtePGivp4hzks6zuMAFknNRwdK7roOlH0HyM5No4WUZHBFpOmw==", + "dependencies": { + "@angular-devkit/core": "17.3.1", + "jsonc-parser": "3.2.1", + "magic-string": "0.30.8", + "ora": "5.4.1", + "rxjs": "7.8.1" + }, + "engines": { + "node": "^18.13.0 || >=20.9.0", + "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", + "yarn": ">= 1.13.0" + } + }, + "node_modules/@angular/animations": { + "version": "17.3.1", + "resolved": "https://registry.npmjs.org/@angular/animations/-/animations-17.3.1.tgz", + "integrity": "sha512-2TZ0M5J0IizhHpb404DeqArlv8Ki9BFz5ZUuET2uFROpKW8IMDCht8fSrn/DKHpjB9lvzPUhNFaRxNWEY6klnA==", + "dependencies": { + "tslib": "^2.3.0" + }, + "engines": { + "node": "^18.13.0 || >=20.9.0" + }, + "peerDependencies": { + "@angular/core": "17.3.1" + } + }, + "node_modules/@angular/cli": { + "version": "17.3.1", + "resolved": "https://registry.npmjs.org/@angular/cli/-/cli-17.3.1.tgz", + "integrity": "sha512-IVnnbRi53BZvZ3LE0PCfFefoB2uHlO1sHtilZf/xCpdV4E1Mkz0/hHln5CRHwAXErdSiY57VoMsF5tffxAfaBQ==", + "dependencies": { + "@angular-devkit/architect": "0.1703.1", + "@angular-devkit/core": "17.3.1", + "@angular-devkit/schematics": "17.3.1", + "@schematics/angular": "17.3.1", + "@yarnpkg/lockfile": "1.1.0", + "ansi-colors": "4.1.3", + "ini": "4.1.2", + "inquirer": "9.2.15", + "jsonc-parser": "3.2.1", + "npm-package-arg": "11.0.1", + "npm-pick-manifest": "9.0.0", + "open": "8.4.2", + "ora": "5.4.1", + "pacote": "17.0.6", + "resolve": "1.22.8", + "semver": "7.6.0", + "symbol-observable": "4.0.0", + "yargs": "17.7.2" + }, + "bin": { + "ng": "bin/ng.js" + }, + "engines": { + "node": "^18.13.0 || >=20.9.0", + "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", + "yarn": ">= 1.13.0" + } + }, + "node_modules/@angular/cli/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/@angular/cli/node_modules/cliui": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", + "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.1", + "wrap-ansi": "^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@angular/cli/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/@angular/cli/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + }, + "node_modules/@angular/cli/node_modules/semver": { + "version": "7.6.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.0.tgz", + "integrity": "sha512-EnwXhrlwXMk9gKu5/flx5sv/an57AkRplG3hTK68W7FRDN+k+OWBj65M7719OkA82XLBxrcX0KSHj+X5COhOVg==", + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/@angular/cli/node_modules/wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/@angular/cli/node_modules/y18n": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", + "engines": { + "node": ">=10" + } + }, + "node_modules/@angular/cli/node_modules/yargs": { + "version": "17.7.2", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", + "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==", + "dependencies": { + "cliui": "^8.0.1", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.3", + "y18n": "^5.0.5", + "yargs-parser": "^21.1.1" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@angular/cli/node_modules/yargs-parser": { + "version": "21.1.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", + "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", + "engines": { + "node": ">=12" + } + }, + "node_modules/@angular/common": { + "version": "17.3.1", + "resolved": "https://registry.npmjs.org/@angular/common/-/common-17.3.1.tgz", + "integrity": "sha512-HyUTJ4RxhE3bOmFRV6Fv2y01ixbrUb8Hd4MxPm8REbNMGKsWCfXhR3FfxFL18Sc03SAF+o0Md0wwekjFKTNKfQ==", + "dependencies": { + "tslib": "^2.3.0" + }, + "engines": { + "node": "^18.13.0 || >=20.9.0" + }, + "peerDependencies": { + "@angular/core": "17.3.1", + "rxjs": "^6.5.3 || ^7.4.0" + } + }, + "node_modules/@angular/compiler": { + "version": "17.3.1", + "resolved": "https://registry.npmjs.org/@angular/compiler/-/compiler-17.3.1.tgz", + "integrity": "sha512-8qqlWPGZEyD2FY5losOW3Aocro+lFysPDzsf0LHgQUM6Ub1b+pq4jUOjH6w0vzaxG3TfxkgzOQ9aNdWtSV67Rg==", + "dependencies": { + "tslib": "^2.3.0" + }, + "engines": { + "node": "^18.13.0 || >=20.9.0" + }, + "peerDependencies": { + "@angular/core": "17.3.1" + }, + "peerDependenciesMeta": { + "@angular/core": { + "optional": true + } + } + }, + "node_modules/@angular/compiler-cli": { + "version": "17.3.1", + "resolved": "https://registry.npmjs.org/@angular/compiler-cli/-/compiler-cli-17.3.1.tgz", + "integrity": "sha512-xLV9KU+zOpe57/2rQ59ku21EaStNpLSlR9+qkDYf8JR09fB+W9vY3UYbpi5RjHxAFIZBM5D9SFQjjll8rch26g==", + "dependencies": { + "@babel/core": "7.23.9", + "@jridgewell/sourcemap-codec": "^1.4.14", + "chokidar": "^3.0.0", + "convert-source-map": "^1.5.1", + "reflect-metadata": "^0.2.0", + "semver": "^7.0.0", + "tslib": "^2.3.0", + "yargs": "^17.2.1" + }, + "bin": { + "ng-xi18n": "bundles/src/bin/ng_xi18n.js", + "ngc": "bundles/src/bin/ngc.js", + "ngcc": "bundles/ngcc/index.js" + }, + "engines": { + "node": "^18.13.0 || >=20.9.0" + }, + "peerDependencies": { + "@angular/compiler": "17.3.1", + "typescript": ">=5.2 <5.5" + } + }, + "node_modules/@angular/compiler-cli/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/@angular/compiler-cli/node_modules/cliui": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", + "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^7.0.0" + } + }, + "node_modules/@angular/compiler-cli/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/@angular/compiler-cli/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + }, + "node_modules/@angular/compiler-cli/node_modules/wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/@angular/compiler-cli/node_modules/y18n": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", + "engines": { + "node": ">=10" + } + }, + "node_modules/@angular/compiler-cli/node_modules/yargs": { + "version": "17.3.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.3.0.tgz", + "integrity": "sha512-GQl1pWyDoGptFPJx9b9L6kmR33TGusZvXIZUT+BOz9f7X2L94oeAskFYLEg/FkhV06zZPBYLvLZRWeYId29lew==", + "dependencies": { + "cliui": "^7.0.2", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.3", + "y18n": "^5.0.5", + "yargs-parser": "^21.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@angular/compiler-cli/node_modules/yargs-parser": { + "version": "21.0.0", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.0.0.tgz", + "integrity": "sha512-z9kApYUOCwoeZ78rfRYYWdiU/iNL6mwwYlkkZfJoyMR1xps+NEBX5X7XmRpxkZHhXJ6+Ey00IwKxBBSW9FIjyA==", + "engines": { + "node": ">=12" + } + }, + "node_modules/@angular/core": { + "version": "17.3.1", + "resolved": "https://registry.npmjs.org/@angular/core/-/core-17.3.1.tgz", + "integrity": "sha512-Qf3/sgkXS1LHwOTtqAVYprySrn0YpPIZqerPc0tK+hyQfwAz5BQlpcBhbH8RWKlfCY8eO0cqo/j0+e8DQOgYfg==", + "dependencies": { + "tslib": "^2.3.0" + }, + "engines": { + "node": "^18.13.0 || >=20.9.0" + }, + "peerDependencies": { + "rxjs": "^6.5.3 || ^7.4.0", + "zone.js": "~0.14.0" + } + }, + "node_modules/@angular/forms": { + "version": "17.3.1", + "resolved": "https://registry.npmjs.org/@angular/forms/-/forms-17.3.1.tgz", + "integrity": "sha512-HndsO90k67sFHzd+sII+rhAUksffBvquFuAUCc6QR9WVjILxVg2fY7oBidgS1gKNqu0mptPG0GvuORnaW/0gSg==", + "dependencies": { + "tslib": "^2.3.0" + }, + "engines": { + "node": "^18.13.0 || >=20.9.0" + }, + "peerDependencies": { + "@angular/common": "17.3.1", + "@angular/core": "17.3.1", + "@angular/platform-browser": "17.3.1", + "rxjs": "^6.5.3 || ^7.4.0" + } + }, + "node_modules/@angular/language-service": { + "version": "17.3.1", + "resolved": "https://registry.npmjs.org/@angular/language-service/-/language-service-17.3.1.tgz", + "integrity": "sha512-awC+KHwIRXZ7biQz0Q7q+UZuuyeWHcxjxyQtvv0n1jwwyRpUo8WAXcduKRxl/wMOrxfZkB/tpGcd1/Eeql9CCw==", + "dev": true, + "engines": { + "node": "^18.13.0 || >=20.9.0" + } + }, + "node_modules/@angular/localize": { + "version": "17.3.1", + "resolved": "https://registry.npmjs.org/@angular/localize/-/localize-17.3.1.tgz", + "integrity": "sha512-ma8PD+DWv68OKgvbmxw7rVohT5HvIYgbmPnVg8lyEz/YkUa9lua0zzrgA+3HUComqv16oVrIaQr00oWxn/9lXQ==", + "dependencies": { + "@babel/core": "7.23.9", + "@types/babel__core": "7.20.5", + "fast-glob": "3.3.2", + "yargs": "^17.2.1" + }, + "bin": { + "localize-extract": "tools/bundles/src/extract/cli.js", + "localize-migrate": "tools/bundles/src/migrate/cli.js", + "localize-translate": "tools/bundles/src/translate/cli.js" + }, + "engines": { + "node": "^18.13.0 || >=20.9.0" + }, + "peerDependencies": { + "@angular/compiler": "17.3.1", + "@angular/compiler-cli": "17.3.1" + } + }, + "node_modules/@angular/localize/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/@angular/localize/node_modules/cliui": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", + "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^7.0.0" + } + }, + "node_modules/@angular/localize/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/@angular/localize/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + }, + "node_modules/@angular/localize/node_modules/wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/@angular/localize/node_modules/y18n": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", + "engines": { + "node": ">=10" + } + }, + "node_modules/@angular/localize/node_modules/yargs": { + "version": "17.3.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.3.0.tgz", + "integrity": "sha512-GQl1pWyDoGptFPJx9b9L6kmR33TGusZvXIZUT+BOz9f7X2L94oeAskFYLEg/FkhV06zZPBYLvLZRWeYId29lew==", + "dependencies": { + "cliui": "^7.0.2", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.3", + "y18n": "^5.0.5", + "yargs-parser": "^21.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@angular/localize/node_modules/yargs-parser": { + "version": "21.0.0", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.0.0.tgz", + "integrity": "sha512-z9kApYUOCwoeZ78rfRYYWdiU/iNL6mwwYlkkZfJoyMR1xps+NEBX5X7XmRpxkZHhXJ6+Ey00IwKxBBSW9FIjyA==", + "engines": { + "node": ">=12" + } + }, + "node_modules/@angular/platform-browser": { + "version": "17.3.1", + "resolved": "https://registry.npmjs.org/@angular/platform-browser/-/platform-browser-17.3.1.tgz", + "integrity": "sha512-8ABAL8PElSGzkIparVwifsU0NSu0DdqnWYw9YvLhhZQ6lOuWbG+dTUo/DXzmWhA6ezQWJGNakEZPJJytFIIy+A==", + "dependencies": { + "tslib": "^2.3.0" + }, + "engines": { + "node": "^18.13.0 || >=20.9.0" + }, + "peerDependencies": { + "@angular/animations": "17.3.1", + "@angular/common": "17.3.1", + "@angular/core": "17.3.1" + }, + "peerDependenciesMeta": { + "@angular/animations": { + "optional": true + } + } + }, + "node_modules/@angular/platform-browser-dynamic": { + "version": "17.3.1", + "resolved": "https://registry.npmjs.org/@angular/platform-browser-dynamic/-/platform-browser-dynamic-17.3.1.tgz", + "integrity": "sha512-ACW/npNaDxUNQtEomjjv/KIBY8jHEinePff5qosnAxLE0IpA4qE9eDp36zG35xoJqrPJPYjXbZCBRqqrzM7U7Q==", + "dependencies": { + "tslib": "^2.3.0" + }, + "engines": { + "node": "^18.13.0 || >=20.9.0" + }, + "peerDependencies": { + "@angular/common": "17.3.1", + "@angular/compiler": "17.3.1", + "@angular/core": "17.3.1", + "@angular/platform-browser": "17.3.1" + } + }, + "node_modules/@angular/platform-server": { + "version": "17.3.1", + "resolved": "https://registry.npmjs.org/@angular/platform-server/-/platform-server-17.3.1.tgz", + "integrity": "sha512-yC1WgUquIac8qFCPMLjRio2ViR3XHexlXKlZpFhqpWAFPsWSHjoCHTEW+KTUFZmOPhUEFR2W8fWOChur8mjthw==", + "dependencies": { + "tslib": "^2.3.0", + "xhr2": "^0.2.0" + }, + "engines": { + "node": "^18.13.0 || >=20.9.0" + }, + "peerDependencies": { + "@angular/animations": "17.3.1", + "@angular/common": "17.3.1", + "@angular/compiler": "17.3.1", + "@angular/core": "17.3.1", + "@angular/platform-browser": "17.3.1" + } + }, + "node_modules/@angular/router": { + "version": "17.3.1", + "resolved": "https://registry.npmjs.org/@angular/router/-/router-17.3.1.tgz", + "integrity": "sha512-H6H7lY9i5Ppu0SFwwpeWqJbCFw8cILOj8Rd1+AGoCN5m3ivPtjD2Ltz62PI2zZkqx+WhQdk19l61Wm3oRqg70A==", + "dependencies": { + "tslib": "^2.3.0" + }, + "engines": { + "node": "^18.13.0 || >=20.9.0" + }, + "peerDependencies": { + "@angular/common": "17.3.1", + "@angular/core": "17.3.1", + "@angular/platform-browser": "17.3.1", + "rxjs": "^6.5.3 || ^7.4.0" + } + }, + "node_modules/@angular/ssr": { + "version": "17.3.1", + "resolved": "https://registry.npmjs.org/@angular/ssr/-/ssr-17.3.1.tgz", + "integrity": "sha512-K/2FGTSC3xJOUJEvqRNVhhhoNGMDFMXUKJqnLXe6cNE8xNkOzO52tWTc0ZZr4ZYvFSwtVMuFY4E65HUxbhGTvA==", + "dependencies": { + "critters": "0.0.22", + "tslib": "^2.3.0" + }, + "peerDependencies": { + "@angular/common": "^17.0.0", + "@angular/core": "^17.0.0" + } + }, + "node_modules/@babel/code-frame": { + "version": "7.24.2", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.24.2.tgz", + "integrity": "sha512-y5+tLQyV8pg3fsiln67BVLD1P13Eg4lh5RW9mF0zUuvLrv9uIQ4MCL+CRT+FTsBlBjcIan6PGsLcBN0m3ClUyQ==", + "dependencies": { + "@babel/highlight": "^7.24.2", + "picocolors": "^1.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/compat-data": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.24.1.tgz", + "integrity": "sha512-Pc65opHDliVpRHuKfzI+gSA4zcgr65O4cl64fFJIWEEh8JoHIHh0Oez1Eo8Arz8zq/JhgKodQaxEwUPRtZylVA==", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/core": { + "version": "7.23.9", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.23.9.tgz", + "integrity": "sha512-5q0175NOjddqpvvzU+kDiSOAk4PfdO6FvwCWoQ6RO7rTzEe8vlo+4HVfcnAREhD4npMs0e9uZypjTwzZPCf/cw==", + "dependencies": { + "@ampproject/remapping": "^2.2.0", + "@babel/code-frame": "^7.23.5", + "@babel/generator": "^7.23.6", + "@babel/helper-compilation-targets": "^7.23.6", + "@babel/helper-module-transforms": "^7.23.3", + "@babel/helpers": "^7.23.9", + "@babel/parser": "^7.23.9", + "@babel/template": "^7.23.9", + "@babel/traverse": "^7.23.9", + "@babel/types": "^7.23.9", + "convert-source-map": "^2.0.0", + "debug": "^4.1.0", + "gensync": "^1.0.0-beta.2", + "json5": "^2.2.3", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/babel" + } + }, + "node_modules/@babel/core/node_modules/convert-source-map": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", + "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==" + }, + "node_modules/@babel/core/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/@babel/generator": { + "version": "7.23.6", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.23.6.tgz", + "integrity": "sha512-qrSfCYxYQB5owCmGLbl8XRpX1ytXlpueOb0N0UmQwA073KZxejgQTzAmJezxvpwQD9uGtK2shHdi55QT+MbjIw==", + "dependencies": { + "@babel/types": "^7.23.6", + "@jridgewell/gen-mapping": "^0.3.2", + "@jridgewell/trace-mapping": "^0.3.17", + "jsesc": "^2.5.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/generator/node_modules/@jridgewell/sourcemap-codec": { + "version": "1.4.14", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz", + "integrity": "sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==" + }, + "node_modules/@babel/generator/node_modules/@jridgewell/trace-mapping": { + "version": "0.3.18", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.18.tgz", + "integrity": "sha512-w+niJYzMHdd7USdiH2U6869nqhD2nbfZXND5Yp93qIbEmnDNk7PD48o+YchRVpzMU7M6jVCbenTR7PA1FLQ9pA==", + "dependencies": { + "@jridgewell/resolve-uri": "3.1.0", + "@jridgewell/sourcemap-codec": "1.4.14" + } + }, + "node_modules/@babel/helper-annotate-as-pure": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.22.5.tgz", + "integrity": "sha512-LvBTxu8bQSQkcyKOU+a1btnNFQ1dMAd0R6PyW3arXes06F6QLWLIrd681bxRPIXlrMGR3XYnW9JyML7dP3qgxg==", + "dependencies": { + "@babel/types": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-builder-binary-assignment-operator-visitor": { + "version": "7.22.15", + "resolved": "https://registry.npmjs.org/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.22.15.tgz", + "integrity": "sha512-QkBXwGgaoC2GtGZRoma6kv7Szfv06khvhFav67ZExau2RaXzy8MpHSMO2PNoP2XtmQphJQRHFfg77Bq731Yizw==", + "dependencies": { + "@babel/types": "^7.22.15" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-compilation-targets": { + "version": "7.23.6", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.23.6.tgz", + "integrity": "sha512-9JB548GZoQVmzrFgp8o7KxdgkTGm6xs9DW0o/Pim72UDjzr5ObUQ6ZzYPqA+g9OTS2bBQoctLJrky0RDCAWRgQ==", + "dependencies": { + "@babel/compat-data": "^7.23.5", + "@babel/helper-validator-option": "^7.23.5", + "browserslist": "^4.22.2", + "lru-cache": "^5.1.1", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-compilation-targets/node_modules/lru-cache": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", + "dependencies": { + "yallist": "^3.0.2" + } + }, + "node_modules/@babel/helper-compilation-targets/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/@babel/helper-compilation-targets/node_modules/yallist": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==" + }, + "node_modules/@babel/helper-create-class-features-plugin": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.24.1.tgz", + "integrity": "sha512-1yJa9dX9g//V6fDebXoEfEsxkZHk3Hcbm+zLhyu6qVgYFLvmTALTeV+jNU9e5RnYtioBrGEOdoI2joMSNQ/+aA==", + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.22.5", + "@babel/helper-environment-visitor": "^7.22.20", + "@babel/helper-function-name": "^7.23.0", + "@babel/helper-member-expression-to-functions": "^7.23.0", + "@babel/helper-optimise-call-expression": "^7.22.5", + "@babel/helper-replace-supers": "^7.24.1", + "@babel/helper-skip-transparent-expression-wrappers": "^7.22.5", + "@babel/helper-split-export-declaration": "^7.22.6", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-create-class-features-plugin/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/@babel/helper-create-regexp-features-plugin": { + "version": "7.22.15", + "resolved": "https://registry.npmjs.org/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.22.15.tgz", + "integrity": "sha512-29FkPLFjn4TPEa3RE7GpW+qbE8tlsu3jntNYNfcGsc49LphF1PQIiD+vMZ1z1xVOKt+93khA9tc2JBs3kBjA7w==", + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.22.5", + "regexpu-core": "^5.3.1", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-create-regexp-features-plugin/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/@babel/helper-define-polyfill-provider": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.6.1.tgz", + "integrity": "sha512-o7SDgTJuvx5vLKD6SFvkydkSMBvahDKGiNJzG22IZYXhiqoe9efY7zocICBgzHV4IRg5wdgl2nEL/tulKIEIbA==", + "dependencies": { + "@babel/helper-compilation-targets": "^7.22.6", + "@babel/helper-plugin-utils": "^7.22.5", + "debug": "^4.1.1", + "lodash.debounce": "^4.0.8", + "resolve": "^1.14.2" + }, + "peerDependencies": { + "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" + } + }, + "node_modules/@babel/helper-environment-visitor": { + "version": "7.22.20", + "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.22.20.tgz", + "integrity": "sha512-zfedSIzFhat/gFhWfHtgWvlec0nqB9YEIVrpuwjruLlXfUSnA8cJB0miHKwqDnQ7d32aKo2xt88/xZptwxbfhA==", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-function-name": { + "version": "7.23.0", + "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.23.0.tgz", + "integrity": "sha512-OErEqsrxjZTJciZ4Oo+eoZqeW9UIiOcuYKRJA4ZAgV9myA+pOXhhmpfNCKjEH/auVfEYVFJ6y1Tc4r0eIApqiw==", + "dependencies": { + "@babel/template": "^7.22.15", + "@babel/types": "^7.23.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-hoist-variables": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.22.5.tgz", + "integrity": "sha512-wGjk9QZVzvknA6yKIUURb8zY3grXCcOZt+/7Wcy8O2uctxhplmUPkOdlgoNhmdVee2c92JXbf1xpMtVNbfoxRw==", + "dependencies": { + "@babel/types": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-member-expression-to-functions": { + "version": "7.23.0", + "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.23.0.tgz", + "integrity": "sha512-6gfrPwh7OuT6gZyJZvd6WbTfrqAo7vm4xCzAXOusKqq/vWdKXphTpj5klHKNmRUU6/QRGlBsyU9mAIPaWHlqJA==", + "dependencies": { + "@babel/types": "^7.23.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-imports": { + "version": "7.24.3", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.24.3.tgz", + "integrity": "sha512-viKb0F9f2s0BCS22QSF308z/+1YWKV/76mwt61NBzS5izMzDPwdq1pTrzf+Li3npBWX9KdQbkeCt1jSAM7lZqg==", + "dependencies": { + "@babel/types": "^7.24.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-module-transforms": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.23.3.tgz", + "integrity": "sha512-7bBs4ED9OmswdfDzpz4MpWgSrV7FXlc3zIagvLFjS5H+Mk7Snr21vQ6QwrsoCGMfNC4e4LQPdoULEt4ykz0SRQ==", + "dependencies": { + "@babel/helper-environment-visitor": "^7.22.20", + "@babel/helper-module-imports": "^7.22.15", + "@babel/helper-simple-access": "^7.22.5", + "@babel/helper-split-export-declaration": "^7.22.6", + "@babel/helper-validator-identifier": "^7.22.20" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-optimise-call-expression": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.22.5.tgz", + "integrity": "sha512-HBwaojN0xFRx4yIvpwGqxiV2tUfl7401jlok564NgB9EHS1y6QT17FmKWm4ztqjeVdXLuC4fSvHc5ePpQjoTbw==", + "dependencies": { + "@babel/types": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-plugin-utils": { + "version": "7.24.0", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.24.0.tgz", + "integrity": "sha512-9cUznXMG0+FxRuJfvL82QlTqIzhVW9sL0KjMPHhAOOvpQGL8QtdxnBKILjBqxlHyliz0yCa1G903ZXI/FuHy2w==", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-remap-async-to-generator": { + "version": "7.22.20", + "resolved": "https://registry.npmjs.org/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.22.20.tgz", + "integrity": "sha512-pBGyV4uBqOns+0UvhsTO8qgl8hO89PmiDYv+/COyp1aeMcmfrfruz+/nCMFiYyFF/Knn0yfrC85ZzNFjembFTw==", + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.22.5", + "@babel/helper-environment-visitor": "^7.22.20", + "@babel/helper-wrap-function": "^7.22.20" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-replace-supers": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.24.1.tgz", + "integrity": "sha512-QCR1UqC9BzG5vZl8BMicmZ28RuUBnHhAMddD8yHFHDRH9lLTZ9uUPehX8ctVPT8l0TKblJidqcgUUKGVrePleQ==", + "dependencies": { + "@babel/helper-environment-visitor": "^7.22.20", + "@babel/helper-member-expression-to-functions": "^7.23.0", + "@babel/helper-optimise-call-expression": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/helper-simple-access": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.22.5.tgz", + "integrity": "sha512-n0H99E/K+Bika3++WNL17POvo4rKWZ7lZEp1Q+fStVbUi8nxPQEBOlTmCOxW/0JsS56SKKQ+ojAe2pHKJHN35w==", + "dependencies": { + "@babel/types": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-skip-transparent-expression-wrappers": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.22.5.tgz", + "integrity": "sha512-tK14r66JZKiC43p8Ki33yLBVJKlQDFoA8GYN67lWCDCqoL6EMMSuM9b+Iff2jHaM/RRFYl7K+iiru7hbRqNx8Q==", + "dependencies": { + "@babel/types": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-split-export-declaration": { + "version": "7.22.6", + "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.22.6.tgz", + "integrity": "sha512-AsUnxuLhRYsisFiaJwvp1QF+I3KjD5FOxut14q/GzovUe6orHLesW2C7d754kRm53h5gqrz6sFl6sxc4BVtE/g==", + "dependencies": { + "@babel/types": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-string-parser": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.24.1.tgz", + "integrity": "sha512-2ofRCjnnA9y+wk8b9IAREroeUP02KHp431N2mhKniy2yKIDKpbrHv9eXwm8cBeWQYcJmzv5qKCu65P47eCF7CQ==", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-identifier": { + "version": "7.22.20", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.20.tgz", + "integrity": "sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A==", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-validator-option": { + "version": "7.23.5", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.23.5.tgz", + "integrity": "sha512-85ttAOMLsr53VgXkTbkx8oA6YTfT4q7/HzXSLEYmjcSTJPMPQtvq1BD79Byep5xMUYbGRzEpDsjUf3dyp54IKw==", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helper-wrap-function": { + "version": "7.22.20", + "resolved": "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.22.20.tgz", + "integrity": "sha512-pms/UwkOpnQe/PDAEdV/d7dVCoBbB+R4FvYoHGZz+4VPcg7RtYy2KP7S2lbuWM6FCSgob5wshfGESbC/hzNXZw==", + "dependencies": { + "@babel/helper-function-name": "^7.22.5", + "@babel/template": "^7.22.15", + "@babel/types": "^7.22.19" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/helpers": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.24.1.tgz", + "integrity": "sha512-BpU09QqEe6ZCHuIHFphEFgvNSrubve1FtyMton26ekZ85gRGi6LrTF7zArARp2YvyFxloeiRmtSCq5sjh1WqIg==", + "dependencies": { + "@babel/template": "^7.24.0", + "@babel/traverse": "^7.24.1", + "@babel/types": "^7.24.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/highlight": { + "version": "7.24.2", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.24.2.tgz", + "integrity": "sha512-Yac1ao4flkTxTteCDZLEvdxg2fZfz1v8M4QpaGypq/WPDqg3ijHYbDfs+LG5hvzSoqaSZ9/Z9lKSP3CjZjv+pA==", + "dependencies": { + "@babel/helper-validator-identifier": "^7.22.20", + "chalk": "^2.4.2", + "js-tokens": "^4.0.0", + "picocolors": "^1.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/parser": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.24.1.tgz", + "integrity": "sha512-Zo9c7N3xdOIQrNip7Lc9wvRPzlRtovHVE4lkz8WEDr7uYh/GMQhSiIgFxGIArRHYdJE5kxtZjAf8rT0xhdLCzg==", + "bin": { + "parser": "bin/babel-parser.js" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression/-/plugin-bugfix-safari-id-destructuring-collision-in-function-expression-7.24.1.tgz", + "integrity": "sha512-y4HqEnkelJIOQGd+3g1bTeKsA5c6qM7eOn7VggGVbBc0y8MLSKHacwcIE2PplNlQSj0PqS9rrXL/nkPVK+kUNg==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining/-/plugin-bugfix-v8-spread-parameters-in-optional-chaining-7.24.1.tgz", + "integrity": "sha512-Hj791Ii4ci8HqnaKHAlLNs+zaLXb0EzSDhiAWp5VNlyvCNymYfacs64pxTxbH1znW/NcArSmwpmG9IKE/TUVVQ==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.0", + "@babel/helper-skip-transparent-expression-wrappers": "^7.22.5", + "@babel/plugin-transform-optional-chaining": "^7.24.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.13.0" + } + }, + "node_modules/@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly/-/plugin-bugfix-v8-static-class-fields-redefine-readonly-7.24.1.tgz", + "integrity": "sha512-m9m/fXsXLiHfwdgydIFnpk+7jlVbnvlK5B2EKiPdLUb6WX654ZaaEWJUjk8TftRbZpK0XibovlLWX4KIZhV6jw==", + "dependencies": { + "@babel/helper-environment-visitor": "^7.22.20", + "@babel/helper-plugin-utils": "^7.24.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-proposal-private-property-in-object": { + "version": "7.21.0-placeholder-for-preset-env.2", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-property-in-object/-/plugin-proposal-private-property-in-object-7.21.0-placeholder-for-preset-env.2.tgz", + "integrity": "sha512-SOSkfJDddaM7mak6cPEpswyTRnuRltl429hMraQEglW+OkovnCzsiszTmsrlY//qLFjCpQDFRvjdm2wA5pPm9w==", + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-async-generators": { + "version": "7.8.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz", + "integrity": "sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-class-properties": { + "version": "7.12.13", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.13.tgz", + "integrity": "sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.12.13" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-class-static-block": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-static-block/-/plugin-syntax-class-static-block-7.14.5.tgz", + "integrity": "sha512-b+YyPmr6ldyNnM6sqYeMWE+bgJcJpO6yS4QD7ymxgH34GBPNDM/THBh8iunyvKIZztiwLH4CJZ0RxTk9emgpjw==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.14.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-dynamic-import": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-dynamic-import/-/plugin-syntax-dynamic-import-7.8.3.tgz", + "integrity": "sha512-5gdGbFon+PszYzqs83S3E5mpi7/y/8M9eC90MRTZfduQOYW76ig6SOSPNe41IG5LoP3FGBn2N0RjVDSQiS94kQ==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-export-namespace-from": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-export-namespace-from/-/plugin-syntax-export-namespace-from-7.8.3.tgz", + "integrity": "sha512-MXf5laXo6c1IbEbegDmzGPwGNTsHZmEy6QGznu5Sh2UCWvueywb2ee+CCE4zQiZstxU9BMoQO9i6zUFSY0Kj0Q==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.3" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-import-assertions": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-assertions/-/plugin-syntax-import-assertions-7.24.1.tgz", + "integrity": "sha512-IuwnI5XnuF189t91XbxmXeCDz3qs6iDRO7GJ++wcfgeXNs/8FmIlKcpDSXNVyuLQxlwvskmI3Ct73wUODkJBlQ==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-import-attributes": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-attributes/-/plugin-syntax-import-attributes-7.24.1.tgz", + "integrity": "sha512-zhQTMH0X2nVLnb04tz+s7AMuasX8U0FnpE+nHTOhSOINjWMnopoZTxtIKsd45n4GQ/HIZLyfIpoul8e2m0DnRA==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-import-meta": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-meta/-/plugin-syntax-import-meta-7.10.4.tgz", + "integrity": "sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.10.4" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-json-strings": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz", + "integrity": "sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-logical-assignment-operators": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz", + "integrity": "sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.10.4" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-nullish-coalescing-operator": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz", + "integrity": "sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-numeric-separator": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.10.4.tgz", + "integrity": "sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.10.4" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-object-rest-spread": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz", + "integrity": "sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-optional-catch-binding": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz", + "integrity": "sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-optional-chaining": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz", + "integrity": "sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.8.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-private-property-in-object": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-private-property-in-object/-/plugin-syntax-private-property-in-object-7.14.5.tgz", + "integrity": "sha512-0wVnp9dxJ72ZUJDV27ZfbSj6iHLoytYZmh3rFcxNnvsJF3ktkzLDZPy/mA17HGsaQT3/DQsWYX1f1QGWkCoVUg==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.14.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-top-level-await": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.14.5.tgz", + "integrity": "sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.14.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-syntax-unicode-sets-regex": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-unicode-sets-regex/-/plugin-syntax-unicode-sets-regex-7.18.6.tgz", + "integrity": "sha512-727YkEAPwSIQTv5im8QHz3upqp92JTWhidIC81Tdx4VJYIte/VndKf1qKrfnnhPLiPghStWfvC/iFaMCQu7Nqg==", + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.6" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-transform-arrow-functions": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.24.1.tgz", + "integrity": "sha512-ngT/3NkRhsaep9ck9uj2Xhv9+xB1zShY3tM3g6om4xxCELwCDN4g4Aq5dRn48+0hasAql7s2hdBOysCfNpr4fw==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-async-generator-functions": { + "version": "7.23.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-generator-functions/-/plugin-transform-async-generator-functions-7.23.9.tgz", + "integrity": "sha512-8Q3veQEDGe14dTYuwagbRtwxQDnytyg1JFu4/HwEMETeofocrB0U0ejBJIXoeG/t2oXZ8kzCyI0ZZfbT80VFNQ==", + "dependencies": { + "@babel/helper-environment-visitor": "^7.22.20", + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/helper-remap-async-to-generator": "^7.22.20", + "@babel/plugin-syntax-async-generators": "^7.8.4" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-async-to-generator": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.23.3.tgz", + "integrity": "sha512-A7LFsKi4U4fomjqXJlZg/u0ft/n8/7n7lpffUP/ZULx/DtV9SGlNKZolHH6PE8Xl1ngCc0M11OaeZptXVkfKSw==", + "dependencies": { + "@babel/helper-module-imports": "^7.22.15", + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/helper-remap-async-to-generator": "^7.22.20" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-block-scoped-functions": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.24.1.tgz", + "integrity": "sha512-TWWC18OShZutrv9C6mye1xwtam+uNi2bnTOCBUd5sZxyHOiWbU6ztSROofIMrK84uweEZC219POICK/sTYwfgg==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-block-scoping": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.24.1.tgz", + "integrity": "sha512-h71T2QQvDgM2SmT29UYU6ozjMlAt7s7CSs5Hvy8f8cf/GM/Z4a2zMfN+fjVGaieeCrXR3EdQl6C4gQG+OgmbKw==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-class-properties": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-class-properties/-/plugin-transform-class-properties-7.24.1.tgz", + "integrity": "sha512-OMLCXi0NqvJfORTaPQBwqLXHhb93wkBKZ4aNwMl6WtehO7ar+cmp+89iPEQPqxAnxsOKTaMcs3POz3rKayJ72g==", + "dependencies": { + "@babel/helper-create-class-features-plugin": "^7.24.1", + "@babel/helper-plugin-utils": "^7.24.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-class-static-block": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-class-static-block/-/plugin-transform-class-static-block-7.24.1.tgz", + "integrity": "sha512-FUHlKCn6J3ERiu8Dv+4eoz7w8+kFLSyeVG4vDAikwADGjUCoHw/JHokyGtr8OR4UjpwPVivyF+h8Q5iv/JmrtA==", + "dependencies": { + "@babel/helper-create-class-features-plugin": "^7.24.1", + "@babel/helper-plugin-utils": "^7.24.0", + "@babel/plugin-syntax-class-static-block": "^7.14.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.12.0" + } + }, + "node_modules/@babel/plugin-transform-classes": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.24.1.tgz", + "integrity": "sha512-ZTIe3W7UejJd3/3R4p7ScyyOoafetUShSf4kCqV0O7F/RiHxVj/wRaRnQlrGwflvcehNA8M42HkAiEDYZu2F1Q==", + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.22.5", + "@babel/helper-compilation-targets": "^7.23.6", + "@babel/helper-environment-visitor": "^7.22.20", + "@babel/helper-function-name": "^7.23.0", + "@babel/helper-plugin-utils": "^7.24.0", + "@babel/helper-replace-supers": "^7.24.1", + "@babel/helper-split-export-declaration": "^7.22.6", + "globals": "^11.1.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-computed-properties": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.24.1.tgz", + "integrity": "sha512-5pJGVIUfJpOS+pAqBQd+QMaTD2vCL/HcePooON6pDpHgRp4gNRmzyHTPIkXntwKsq3ayUFVfJaIKPw2pOkOcTw==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.0", + "@babel/template": "^7.24.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-destructuring": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.24.1.tgz", + "integrity": "sha512-ow8jciWqNxR3RYbSNVuF4U2Jx130nwnBnhRw6N6h1bOejNkABmcI5X5oz29K4alWX7vf1C+o6gtKXikzRKkVdw==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-dotall-regex": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.24.1.tgz", + "integrity": "sha512-p7uUxgSoZwZ2lPNMzUkqCts3xlp8n+o05ikjy7gbtFJSt9gdU88jAmtfmOxHM14noQXBxfgzf2yRWECiNVhTCw==", + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.22.15", + "@babel/helper-plugin-utils": "^7.24.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-duplicate-keys": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.24.1.tgz", + "integrity": "sha512-msyzuUnvsjsaSaocV6L7ErfNsa5nDWL1XKNnDePLgmz+WdU4w/J8+AxBMrWfi9m4IxfL5sZQKUPQKDQeeAT6lA==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-dynamic-import": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dynamic-import/-/plugin-transform-dynamic-import-7.24.1.tgz", + "integrity": "sha512-av2gdSTyXcJVdI+8aFZsCAtR29xJt0S5tas+Ef8NvBNmD1a+N/3ecMLeMBgfcK+xzsjdLDT6oHt+DFPyeqUbDA==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.0", + "@babel/plugin-syntax-dynamic-import": "^7.8.3" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-exponentiation-operator": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.24.1.tgz", + "integrity": "sha512-U1yX13dVBSwS23DEAqU+Z/PkwE9/m7QQy8Y9/+Tdb8UWYaGNDYwTLi19wqIAiROr8sXVum9A/rtiH5H0boUcTw==", + "dependencies": { + "@babel/helper-builder-binary-assignment-operator-visitor": "^7.22.15", + "@babel/helper-plugin-utils": "^7.24.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-export-namespace-from": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-export-namespace-from/-/plugin-transform-export-namespace-from-7.24.1.tgz", + "integrity": "sha512-Ft38m/KFOyzKw2UaJFkWG9QnHPG/Q/2SkOrRk4pNBPg5IPZ+dOxcmkK5IyuBcxiNPyyYowPGUReyBvrvZs7IlQ==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.0", + "@babel/plugin-syntax-export-namespace-from": "^7.8.3" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-for-of": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.24.1.tgz", + "integrity": "sha512-OxBdcnF04bpdQdR3i4giHZNZQn7cm8RQKcSwA17wAAqEELo1ZOwp5FFgeptWUQXFyT9kwHo10aqqauYkRZPCAg==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.0", + "@babel/helper-skip-transparent-expression-wrappers": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-function-name": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.24.1.tgz", + "integrity": "sha512-BXmDZpPlh7jwicKArQASrj8n22/w6iymRnvHYYd2zO30DbE277JO20/7yXJT3QxDPtiQiOxQBbZH4TpivNXIxA==", + "dependencies": { + "@babel/helper-compilation-targets": "^7.23.6", + "@babel/helper-function-name": "^7.23.0", + "@babel/helper-plugin-utils": "^7.24.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-json-strings": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-json-strings/-/plugin-transform-json-strings-7.24.1.tgz", + "integrity": "sha512-U7RMFmRvoasscrIFy5xA4gIp8iWnWubnKkKuUGJjsuOH7GfbMkB+XZzeslx2kLdEGdOJDamEmCqOks6e8nv8DQ==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.0", + "@babel/plugin-syntax-json-strings": "^7.8.3" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-literals": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-literals/-/plugin-transform-literals-7.24.1.tgz", + "integrity": "sha512-zn9pwz8U7nCqOYIiBaOxoQOtYmMODXTJnkxG4AtX8fPmnCRYWBOHD0qcpwS9e2VDSp1zNJYpdnFMIKb8jmwu6g==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-logical-assignment-operators": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-logical-assignment-operators/-/plugin-transform-logical-assignment-operators-7.24.1.tgz", + "integrity": "sha512-OhN6J4Bpz+hIBqItTeWJujDOfNP+unqv/NJgyhlpSqgBTPm37KkMmZV6SYcOj+pnDbdcl1qRGV/ZiIjX9Iy34w==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.0", + "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-member-expression-literals": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.24.1.tgz", + "integrity": "sha512-4ojai0KysTWXzHseJKa1XPNXKRbuUrhkOPY4rEGeR+7ChlJVKxFa3H3Bz+7tWaGKgJAXUWKOGmltN+u9B3+CVg==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-modules-amd": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.24.1.tgz", + "integrity": "sha512-lAxNHi4HVtjnHd5Rxg3D5t99Xm6H7b04hUS7EHIXcUl2EV4yl1gWdqZrNzXnSrHveL9qMdbODlLF55mvgjAfaQ==", + "dependencies": { + "@babel/helper-module-transforms": "^7.23.3", + "@babel/helper-plugin-utils": "^7.24.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-modules-commonjs": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.24.1.tgz", + "integrity": "sha512-szog8fFTUxBfw0b98gEWPaEqF42ZUD/T3bkynW/wtgx2p/XCP55WEsb+VosKceRSd6njipdZvNogqdtI4Q0chw==", + "dependencies": { + "@babel/helper-module-transforms": "^7.23.3", + "@babel/helper-plugin-utils": "^7.24.0", + "@babel/helper-simple-access": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-modules-systemjs": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.24.1.tgz", + "integrity": "sha512-mqQ3Zh9vFO1Tpmlt8QPnbwGHzNz3lpNEMxQb1kAemn/erstyqw1r9KeOlOfo3y6xAnFEcOv2tSyrXfmMk+/YZA==", + "dependencies": { + "@babel/helper-hoist-variables": "^7.22.5", + "@babel/helper-module-transforms": "^7.23.3", + "@babel/helper-plugin-utils": "^7.24.0", + "@babel/helper-validator-identifier": "^7.22.20" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-modules-umd": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.24.1.tgz", + "integrity": "sha512-tuA3lpPj+5ITfcCluy6nWonSL7RvaG0AOTeAuvXqEKS34lnLzXpDb0dcP6K8jD0zWZFNDVly90AGFJPnm4fOYg==", + "dependencies": { + "@babel/helper-module-transforms": "^7.23.3", + "@babel/helper-plugin-utils": "^7.24.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-named-capturing-groups-regex": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.22.5.tgz", + "integrity": "sha512-YgLLKmS3aUBhHaxp5hi1WJTgOUb/NCuDHzGT9z9WTt3YG+CPRhJs6nprbStx6DnWM4dh6gt7SU3sZodbZ08adQ==", + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.22.5", + "@babel/helper-plugin-utils": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/plugin-transform-new-target": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.24.1.tgz", + "integrity": "sha512-/rurytBM34hYy0HKZQyA0nHbQgQNFm4Q/BOc9Hflxi2X3twRof7NaE5W46j4kQitm7SvACVRXsa6N/tSZxvPug==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-nullish-coalescing-operator": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-nullish-coalescing-operator/-/plugin-transform-nullish-coalescing-operator-7.24.1.tgz", + "integrity": "sha512-iQ+caew8wRrhCikO5DrUYx0mrmdhkaELgFa+7baMcVuhxIkN7oxt06CZ51D65ugIb1UWRQ8oQe+HXAVM6qHFjw==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.0", + "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-numeric-separator": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-numeric-separator/-/plugin-transform-numeric-separator-7.24.1.tgz", + "integrity": "sha512-7GAsGlK4cNL2OExJH1DzmDeKnRv/LXq0eLUSvudrehVA5Rgg4bIrqEUW29FbKMBRT0ztSqisv7kjP+XIC4ZMNw==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.0", + "@babel/plugin-syntax-numeric-separator": "^7.10.4" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-object-rest-spread": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-rest-spread/-/plugin-transform-object-rest-spread-7.24.1.tgz", + "integrity": "sha512-XjD5f0YqOtebto4HGISLNfiNMTTs6tbkFf2TOqJlYKYmbo+mN9Dnpl4SRoofiziuOWMIyq3sZEUqLo3hLITFEA==", + "dependencies": { + "@babel/helper-compilation-targets": "^7.23.6", + "@babel/helper-plugin-utils": "^7.24.0", + "@babel/plugin-syntax-object-rest-spread": "^7.8.3", + "@babel/plugin-transform-parameters": "^7.24.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-object-super": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.24.1.tgz", + "integrity": "sha512-oKJqR3TeI5hSLRxudMjFQ9re9fBVUU0GICqM3J1mi8MqlhVr6hC/ZN4ttAyMuQR6EZZIY6h/exe5swqGNNIkWQ==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.0", + "@babel/helper-replace-supers": "^7.24.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-optional-catch-binding": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-catch-binding/-/plugin-transform-optional-catch-binding-7.24.1.tgz", + "integrity": "sha512-oBTH7oURV4Y+3EUrf6cWn1OHio3qG/PVwO5J03iSJmBg6m2EhKjkAu/xuaXaYwWW9miYtvbWv4LNf0AmR43LUA==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.0", + "@babel/plugin-syntax-optional-catch-binding": "^7.8.3" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-optional-chaining": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-chaining/-/plugin-transform-optional-chaining-7.24.1.tgz", + "integrity": "sha512-n03wmDt+987qXwAgcBlnUUivrZBPZ8z1plL0YvgQalLm+ZE5BMhGm94jhxXtA1wzv1Cu2aaOv1BM9vbVttrzSg==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.0", + "@babel/helper-skip-transparent-expression-wrappers": "^7.22.5", + "@babel/plugin-syntax-optional-chaining": "^7.8.3" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-parameters": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.24.1.tgz", + "integrity": "sha512-8Jl6V24g+Uw5OGPeWNKrKqXPDw2YDjLc53ojwfMcKwlEoETKU9rU0mHUtcg9JntWI/QYzGAXNWEcVHZ+fR+XXg==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-private-methods": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-private-methods/-/plugin-transform-private-methods-7.24.1.tgz", + "integrity": "sha512-tGvisebwBO5em4PaYNqt4fkw56K2VALsAbAakY0FjTYqJp7gfdrgr7YX76Or8/cpik0W6+tj3rZ0uHU9Oil4tw==", + "dependencies": { + "@babel/helper-create-class-features-plugin": "^7.24.1", + "@babel/helper-plugin-utils": "^7.24.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-private-property-in-object": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-private-property-in-object/-/plugin-transform-private-property-in-object-7.24.1.tgz", + "integrity": "sha512-pTHxDVa0BpUbvAgX3Gat+7cSciXqUcY9j2VZKTbSB6+VQGpNgNO9ailxTGHSXlqOnX1Hcx1Enme2+yv7VqP9bg==", + "dependencies": { + "@babel/helper-annotate-as-pure": "^7.22.5", + "@babel/helper-create-class-features-plugin": "^7.24.1", + "@babel/helper-plugin-utils": "^7.24.0", + "@babel/plugin-syntax-private-property-in-object": "^7.14.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-property-literals": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.24.1.tgz", + "integrity": "sha512-LetvD7CrHmEx0G442gOomRr66d7q8HzzGGr4PMHGr+5YIm6++Yke+jxj246rpvsbyhJwCLxcTn6zW1P1BSenqA==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-regenerator": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.24.1.tgz", + "integrity": "sha512-sJwZBCzIBE4t+5Q4IGLaaun5ExVMRY0lYwos/jNecjMrVCygCdph3IKv0tkP5Fc87e/1+bebAmEAGBfnRD+cnw==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.0", + "regenerator-transform": "^0.15.2" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-reserved-words": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.24.1.tgz", + "integrity": "sha512-JAclqStUfIwKN15HrsQADFgeZt+wexNQ0uLhuqvqAUFoqPMjEcFCYZBhq0LUdz6dZK/mD+rErhW71fbx8RYElg==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-runtime": { + "version": "7.24.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-runtime/-/plugin-transform-runtime-7.24.0.tgz", + "integrity": "sha512-zc0GA5IitLKJrSfXlXmp8KDqLrnGECK7YRfQBmEKg1NmBOQ7e+KuclBEKJgzifQeUYLdNiAw4B4bjyvzWVLiSA==", + "dependencies": { + "@babel/helper-module-imports": "^7.22.15", + "@babel/helper-plugin-utils": "^7.24.0", + "babel-plugin-polyfill-corejs2": "^0.4.8", + "babel-plugin-polyfill-corejs3": "^0.9.0", + "babel-plugin-polyfill-regenerator": "^0.5.5", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-runtime/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/@babel/plugin-transform-shorthand-properties": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.24.1.tgz", + "integrity": "sha512-LyjVB1nsJ6gTTUKRjRWx9C1s9hE7dLfP/knKdrfeH9UPtAGjYGgxIbFfx7xyLIEWs7Xe1Gnf8EWiUqfjLhInZA==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-spread": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.24.1.tgz", + "integrity": "sha512-KjmcIM+fxgY+KxPVbjelJC6hrH1CgtPmTvdXAfn3/a9CnWGSTY7nH4zm5+cjmWJybdcPSsD0++QssDsjcpe47g==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.0", + "@babel/helper-skip-transparent-expression-wrappers": "^7.22.5" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-sticky-regex": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.24.1.tgz", + "integrity": "sha512-9v0f1bRXgPVcPrngOQvLXeGNNVLc8UjMVfebo9ka0WF3/7+aVUHmaJVT3sa0XCzEFioPfPHZiOcYG9qOsH63cw==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-template-literals": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.24.1.tgz", + "integrity": "sha512-WRkhROsNzriarqECASCNu/nojeXCDTE/F2HmRgOzi7NGvyfYGq1NEjKBK3ckLfRgGc6/lPAqP0vDOSw3YtG34g==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-typeof-symbol": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.24.1.tgz", + "integrity": "sha512-CBfU4l/A+KruSUoW+vTQthwcAdwuqbpRNB8HQKlZABwHRhsdHZ9fezp4Sn18PeAlYxTNiLMlx4xUBV3AWfg1BA==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-unicode-escapes": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.24.1.tgz", + "integrity": "sha512-RlkVIcWT4TLI96zM660S877E7beKlQw7Ig+wqkKBiWfj0zH5Q4h50q6er4wzZKRNSYpfo6ILJ+hrJAGSX2qcNw==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.24.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-unicode-property-regex": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-property-regex/-/plugin-transform-unicode-property-regex-7.24.1.tgz", + "integrity": "sha512-Ss4VvlfYV5huWApFsF8/Sq0oXnGO+jB+rijFEFugTd3cwSObUSnUi88djgR5528Csl0uKlrI331kRqe56Ov2Ng==", + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.22.15", + "@babel/helper-plugin-utils": "^7.24.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-unicode-regex": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.24.1.tgz", + "integrity": "sha512-2A/94wgZgxfTsiLaQ2E36XAOdcZmGAaEEgVmxQWwZXWkGhvoHbaqXcKnU8zny4ycpu3vNqg0L/PcCiYtHtA13g==", + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.22.15", + "@babel/helper-plugin-utils": "^7.24.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/plugin-transform-unicode-sets-regex": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-sets-regex/-/plugin-transform-unicode-sets-regex-7.24.1.tgz", + "integrity": "sha512-fqj4WuzzS+ukpgerpAoOnMfQXwUHFxXUZUE84oL2Kao2N8uSlvcpnAidKASgsNgzZHBsHWvcm8s9FPWUhAb8fA==", + "dependencies": { + "@babel/helper-create-regexp-features-plugin": "^7.22.15", + "@babel/helper-plugin-utils": "^7.24.0" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0" + } + }, + "node_modules/@babel/preset-env": { + "version": "7.24.0", + "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.24.0.tgz", + "integrity": "sha512-ZxPEzV9IgvGn73iK0E6VB9/95Nd7aMFpbE0l8KQFDG70cOV9IxRP7Y2FUPmlK0v6ImlLqYX50iuZ3ZTVhOF2lA==", + "dependencies": { + "@babel/compat-data": "^7.23.5", + "@babel/helper-compilation-targets": "^7.23.6", + "@babel/helper-plugin-utils": "^7.24.0", + "@babel/helper-validator-option": "^7.23.5", + "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": "^7.23.3", + "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": "^7.23.3", + "@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly": "^7.23.7", + "@babel/plugin-proposal-private-property-in-object": "7.21.0-placeholder-for-preset-env.2", + "@babel/plugin-syntax-async-generators": "^7.8.4", + "@babel/plugin-syntax-class-properties": "^7.12.13", + "@babel/plugin-syntax-class-static-block": "^7.14.5", + "@babel/plugin-syntax-dynamic-import": "^7.8.3", + "@babel/plugin-syntax-export-namespace-from": "^7.8.3", + "@babel/plugin-syntax-import-assertions": "^7.23.3", + "@babel/plugin-syntax-import-attributes": "^7.23.3", + "@babel/plugin-syntax-import-meta": "^7.10.4", + "@babel/plugin-syntax-json-strings": "^7.8.3", + "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4", + "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3", + "@babel/plugin-syntax-numeric-separator": "^7.10.4", + "@babel/plugin-syntax-object-rest-spread": "^7.8.3", + "@babel/plugin-syntax-optional-catch-binding": "^7.8.3", + "@babel/plugin-syntax-optional-chaining": "^7.8.3", + "@babel/plugin-syntax-private-property-in-object": "^7.14.5", + "@babel/plugin-syntax-top-level-await": "^7.14.5", + "@babel/plugin-syntax-unicode-sets-regex": "^7.18.6", + "@babel/plugin-transform-arrow-functions": "^7.23.3", + "@babel/plugin-transform-async-generator-functions": "^7.23.9", + "@babel/plugin-transform-async-to-generator": "^7.23.3", + "@babel/plugin-transform-block-scoped-functions": "^7.23.3", + "@babel/plugin-transform-block-scoping": "^7.23.4", + "@babel/plugin-transform-class-properties": "^7.23.3", + "@babel/plugin-transform-class-static-block": "^7.23.4", + "@babel/plugin-transform-classes": "^7.23.8", + "@babel/plugin-transform-computed-properties": "^7.23.3", + "@babel/plugin-transform-destructuring": "^7.23.3", + "@babel/plugin-transform-dotall-regex": "^7.23.3", + "@babel/plugin-transform-duplicate-keys": "^7.23.3", + "@babel/plugin-transform-dynamic-import": "^7.23.4", + "@babel/plugin-transform-exponentiation-operator": "^7.23.3", + "@babel/plugin-transform-export-namespace-from": "^7.23.4", + "@babel/plugin-transform-for-of": "^7.23.6", + "@babel/plugin-transform-function-name": "^7.23.3", + "@babel/plugin-transform-json-strings": "^7.23.4", + "@babel/plugin-transform-literals": "^7.23.3", + "@babel/plugin-transform-logical-assignment-operators": "^7.23.4", + "@babel/plugin-transform-member-expression-literals": "^7.23.3", + "@babel/plugin-transform-modules-amd": "^7.23.3", + "@babel/plugin-transform-modules-commonjs": "^7.23.3", + "@babel/plugin-transform-modules-systemjs": "^7.23.9", + "@babel/plugin-transform-modules-umd": "^7.23.3", + "@babel/plugin-transform-named-capturing-groups-regex": "^7.22.5", + "@babel/plugin-transform-new-target": "^7.23.3", + "@babel/plugin-transform-nullish-coalescing-operator": "^7.23.4", + "@babel/plugin-transform-numeric-separator": "^7.23.4", + "@babel/plugin-transform-object-rest-spread": "^7.24.0", + "@babel/plugin-transform-object-super": "^7.23.3", + "@babel/plugin-transform-optional-catch-binding": "^7.23.4", + "@babel/plugin-transform-optional-chaining": "^7.23.4", + "@babel/plugin-transform-parameters": "^7.23.3", + "@babel/plugin-transform-private-methods": "^7.23.3", + "@babel/plugin-transform-private-property-in-object": "^7.23.4", + "@babel/plugin-transform-property-literals": "^7.23.3", + "@babel/plugin-transform-regenerator": "^7.23.3", + "@babel/plugin-transform-reserved-words": "^7.23.3", + "@babel/plugin-transform-shorthand-properties": "^7.23.3", + "@babel/plugin-transform-spread": "^7.23.3", + "@babel/plugin-transform-sticky-regex": "^7.23.3", + "@babel/plugin-transform-template-literals": "^7.23.3", + "@babel/plugin-transform-typeof-symbol": "^7.23.3", + "@babel/plugin-transform-unicode-escapes": "^7.23.3", + "@babel/plugin-transform-unicode-property-regex": "^7.23.3", + "@babel/plugin-transform-unicode-regex": "^7.23.3", + "@babel/plugin-transform-unicode-sets-regex": "^7.23.3", + "@babel/preset-modules": "0.1.6-no-external-plugins", + "babel-plugin-polyfill-corejs2": "^0.4.8", + "babel-plugin-polyfill-corejs3": "^0.9.0", + "babel-plugin-polyfill-regenerator": "^0.5.5", + "core-js-compat": "^3.31.0", + "semver": "^6.3.1" + }, + "engines": { + "node": ">=6.9.0" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0" + } + }, + "node_modules/@babel/preset-env/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/@babel/preset-modules": { + "version": "0.1.6-no-external-plugins", + "resolved": "https://registry.npmjs.org/@babel/preset-modules/-/preset-modules-0.1.6-no-external-plugins.tgz", + "integrity": "sha512-HrcgcIESLm9aIR842yhJ5RWan/gebQUJ6E/E5+rf0y9o6oj7w0Br+sWuL6kEQ/o/AdfvR1Je9jG18/gnpwjEyA==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.0.0", + "@babel/types": "^7.4.4", + "esutils": "^2.0.2" + }, + "peerDependencies": { + "@babel/core": "^7.0.0-0 || ^8.0.0-0 <8.0.0" + } + }, + "node_modules/@babel/regjsgen": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/@babel/regjsgen/-/regjsgen-0.8.0.tgz", + "integrity": "sha512-x/rqGMdzj+fWZvCOYForTghzbtqPDZ5gPwaoNGHdgDfF2QA/XZbCBp4Moo5scrkAMPhB7z26XM/AaHuIJdgauA==" + }, + "node_modules/@babel/runtime": { + "version": "7.24.0", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.24.0.tgz", + "integrity": "sha512-Chk32uHMg6TnQdvw2e9IlqPpFX/6NLuK0Ys2PqLb7/gL5uFn9mXvK715FGLlOLQrcO4qIkNHkvPGktzzXexsFw==", + "dependencies": { + "regenerator-runtime": "^0.14.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/template": { + "version": "7.24.0", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.24.0.tgz", + "integrity": "sha512-Bkf2q8lMB0AFpX0NFEqSbx1OkTHf0f+0j82mkw+ZpzBnkk7e9Ql0891vlfgi+kHwOk8tQjiQHpqh4LaSa0fKEA==", + "dependencies": { + "@babel/code-frame": "^7.23.5", + "@babel/parser": "^7.24.0", + "@babel/types": "^7.24.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/traverse": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.24.1.tgz", + "integrity": "sha512-xuU6o9m68KeqZbQuDt2TcKSxUw/mrsvavlEqQ1leZ/B+C9tk6E4sRWy97WaXgvq5E+nU3cXMxv3WKOCanVMCmQ==", + "dependencies": { + "@babel/code-frame": "^7.24.1", + "@babel/generator": "^7.24.1", + "@babel/helper-environment-visitor": "^7.22.20", + "@babel/helper-function-name": "^7.23.0", + "@babel/helper-hoist-variables": "^7.22.5", + "@babel/helper-split-export-declaration": "^7.22.6", + "@babel/parser": "^7.24.1", + "@babel/types": "^7.24.0", + "debug": "^4.3.1", + "globals": "^11.1.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/traverse/node_modules/@babel/generator": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.24.1.tgz", + "integrity": "sha512-DfCRfZsBcrPEHUfuBMgbJ1Ut01Y/itOs+hY2nFLgqsqXd52/iSiVq5TITtUasIUgm+IIKdY2/1I7auiQOEeC9A==", + "dependencies": { + "@babel/types": "^7.24.0", + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.25", + "jsesc": "^2.5.1" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@babel/traverse/node_modules/@jridgewell/trace-mapping": { + "version": "0.3.25", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz", + "integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==", + "dependencies": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, + "node_modules/@babel/types": { + "version": "7.24.0", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.24.0.tgz", + "integrity": "sha512-+j7a5c253RfKh8iABBhywc8NSfP5LURe7Uh4qpsh6jc+aLJguvmIUBdjSdEMQv2bENrCR5MfRdjGo7vzS/ob7w==", + "dependencies": { + "@babel/helper-string-parser": "^7.23.4", + "@babel/helper-validator-identifier": "^7.22.20", + "to-fast-properties": "^2.0.0" + }, + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/@browserify/envify": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/@browserify/envify/-/envify-6.0.0.tgz", + "integrity": "sha512-ovxHR0KTsRCyMNwD7MGV0+VCU1sT6Ds+itC4DaQHM41eUId+w5Jd0qlhLVoDkkIVBnkY3BAAM8yb2QfpBlHkPw==", + "dependencies": { + "acorn-node": "^2.0.1", + "dash-ast": "^2.0.1", + "multisplice": "^1.0.0", + "through2": "^4.0.2" + }, + "bin": { + "envify": "bin/envify" + } + }, + "node_modules/@browserify/envify/node_modules/acorn-node": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/acorn-node/-/acorn-node-2.0.1.tgz", + "integrity": "sha512-VLR5sHqjk+8c5hrKeP2fWaIHb8eewsoxnZ8r2qpwRHXMHuC7KyOPflnOx9dLssVQUurzJ7rO0OzIFjHcndafWw==", + "dependencies": { + "acorn": "^7.0.0", + "acorn-walk": "^7.0.0", + "xtend": "^4.0.2" + } + }, + "node_modules/@browserify/envify/node_modules/dash-ast": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/dash-ast/-/dash-ast-2.0.1.tgz", + "integrity": "sha512-5TXltWJGc+RdnabUGzhRae1TRq6m4gr+3K2wQX0is5/F2yS6MJXJvLyI3ErAnsAXuJoGqvfVD5icRgim07DrxQ==" + }, + "node_modules/@browserify/envify/node_modules/readable-stream": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/@browserify/envify/node_modules/through2": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/through2/-/through2-4.0.2.tgz", + "integrity": "sha512-iOqSav00cVxEEICeD7TjLB1sueEL+81Wpzp2bY17uZjZN0pWZPuo4suZ/61VujxmqSGFfgOcNuTZ85QJwNZQpw==", + "dependencies": { + "readable-stream": "3" + } + }, + "node_modules/@browserify/uglifyify": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/@browserify/uglifyify/-/uglifyify-6.0.0.tgz", + "integrity": "sha512-48M2a3novsgKhUSo/B3ja10awc7unliK1HfW6aYBJdLFQj3wXDx9BBJVfj6MVYERSQVEVjNHQQ7IK89h4MpCLw==", + "dependencies": { + "convert-source-map": "^1.9.0", + "minimatch": "^3.0.2", + "terser": "^5.15.1", + "through2": "^4.0.2", + "xtend": "^4.0.1" + } + }, + "node_modules/@browserify/uglifyify/node_modules/readable-stream": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/@browserify/uglifyify/node_modules/through2": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/through2/-/through2-4.0.2.tgz", + "integrity": "sha512-iOqSav00cVxEEICeD7TjLB1sueEL+81Wpzp2bY17uZjZN0pWZPuo4suZ/61VujxmqSGFfgOcNuTZ85QJwNZQpw==", + "dependencies": { + "readable-stream": "3" + } + }, + "node_modules/@colors/colors": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@colors/colors/-/colors-1.5.0.tgz", + "integrity": "sha512-ooWCrlZP11i8GImSjTHYHLkvFDP48nS4+204nGb1RiX/WXYHmJA2III9/e2DWVabCESdW7hBAEzHRqUn9OUVvQ==", + "optional": true, + "engines": { + "node": ">=0.1.90" + } + }, + "node_modules/@cspotcode/source-map-support": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz", + "integrity": "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==", + "dev": true, + "dependencies": { + "@jridgewell/trace-mapping": "0.3.9" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@cypress/request": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@cypress/request/-/request-3.0.1.tgz", + "integrity": "sha512-TWivJlJi8ZDx2wGOw1dbLuHJKUYX7bWySw377nlnGOW3hP9/MUKIsEdXT/YngWxVdgNCHRBmFlBipE+5/2ZZlQ==", + "optional": true, + "dependencies": { + "aws-sign2": "~0.7.0", + "aws4": "^1.8.0", + "caseless": "~0.12.0", + "combined-stream": "~1.0.6", + "extend": "~3.0.2", + "forever-agent": "~0.6.1", + "form-data": "~2.3.2", + "http-signature": "~1.3.6", + "is-typedarray": "~1.0.0", + "isstream": "~0.1.2", + "json-stringify-safe": "~5.0.1", + "mime-types": "~2.1.19", + "performance-now": "^2.1.0", + "qs": "6.10.4", + "safe-buffer": "^5.1.2", + "tough-cookie": "^4.1.3", + "tunnel-agent": "^0.6.0", + "uuid": "^8.3.2" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/@cypress/schematic": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/@cypress/schematic/-/schematic-2.5.0.tgz", + "integrity": "sha512-Yt/fQxYIHl9lU8LSoJL92nIwTVyYG5uP4VqW4taTn3viVWvssjK7sRtTI/LRxOoeMYX2RRlXQyUbFEikByn0cQ==", + "optional": true, + "dependencies": { + "jsonc-parser": "^3.0.0", + "rxjs": "~6.6.0" + }, + "peerDependencies": { + "@angular/cli": ">=14", + "@angular/core": ">=14" + } + }, + "node_modules/@cypress/schematic/node_modules/rxjs": { + "version": "6.6.7", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.6.7.tgz", + "integrity": "sha512-hTdwr+7yYNIT5n4AMYp85KA6yw2Va0FLa3Rguvbpa4W3I5xynaBZo41cM3XM+4Q6fRMj3sBYIR1VAmZMXYJvRQ==", + "optional": true, + "dependencies": { + "tslib": "^1.9.0" + }, + "engines": { + "npm": ">=2.0.0" + } + }, + "node_modules/@cypress/schematic/node_modules/tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "optional": true + }, + "node_modules/@cypress/xvfb": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@cypress/xvfb/-/xvfb-1.2.4.tgz", + "integrity": "sha512-skbBzPggOVYCbnGgV+0dmBdW/s77ZkAOXIC1knS8NagwDjBrNC1LuXtQJeiN6l+m7lzmHtaoUw/ctJKdqkG57Q==", + "optional": true, + "dependencies": { + "debug": "^3.1.0", + "lodash.once": "^4.1.1" + } + }, + "node_modules/@cypress/xvfb/node_modules/debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "optional": true, + "dependencies": { + "ms": "^2.1.1" + } + }, + "node_modules/@discoveryjs/json-ext": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/@discoveryjs/json-ext/-/json-ext-0.5.7.tgz", + "integrity": "sha512-dBVuXR082gk3jsFp7Rd/JI4kytwGHecnCoTtXFb7DB6CNHp4rg5k1bhg0nWdLGLnOV71lmDzGQaLMy8iPLY0pw==", + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/@esbuild/aix-ppc64": { + "version": "0.23.0", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.23.0.tgz", + "integrity": "sha512-3sG8Zwa5fMcA9bgqB8AfWPQ+HFke6uD3h1s3RIwUNK8EG7a4buxvuFTs3j1IMs2NXAk9F30C/FF4vxRgQCcmoQ==", + "cpu": [ + "ppc64" + ], + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm": { + "version": "0.23.0", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.23.0.tgz", + "integrity": "sha512-+KuOHTKKyIKgEEqKbGTK8W7mPp+hKinbMBeEnNzjJGyFcWsfrXjSTNluJHCY1RqhxFurdD8uNXQDei7qDlR6+g==", + "cpu": [ + "arm" + ], + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-arm64": { + "version": "0.23.0", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.23.0.tgz", + "integrity": "sha512-EuHFUYkAVfU4qBdyivULuu03FhJO4IJN9PGuABGrFy4vUuzk91P2d+npxHcFdpUnfYKy0PuV+n6bKIpHOB3prQ==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/android-x64": { + "version": "0.23.0", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.23.0.tgz", + "integrity": "sha512-WRrmKidLoKDl56LsbBMhzTTBxrsVwTKdNbKDalbEZr0tcsBgCLbEtoNthOW6PX942YiYq8HzEnb4yWQMLQuipQ==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-arm64": { + "version": "0.23.0", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.23.0.tgz", + "integrity": "sha512-YLntie/IdS31H54Ogdn+v50NuoWF5BDkEUFpiOChVa9UnKpftgwzZRrI4J132ETIi+D8n6xh9IviFV3eXdxfow==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/darwin-x64": { + "version": "0.23.0", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.23.0.tgz", + "integrity": "sha512-IMQ6eme4AfznElesHUPDZ+teuGwoRmVuuixu7sv92ZkdQcPbsNHzutd+rAfaBKo8YK3IrBEi9SLLKWJdEvJniQ==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-arm64": { + "version": "0.23.0", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.23.0.tgz", + "integrity": "sha512-0muYWCng5vqaxobq6LB3YNtevDFSAZGlgtLoAc81PjUfiFz36n4KMpwhtAd4he8ToSI3TGyuhyx5xmiWNYZFyw==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/freebsd-x64": { + "version": "0.23.0", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.23.0.tgz", + "integrity": "sha512-XKDVu8IsD0/q3foBzsXGt/KjD/yTKBCIwOHE1XwiXmrRwrX6Hbnd5Eqn/WvDekddK21tfszBSrE/WMaZh+1buQ==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm": { + "version": "0.23.0", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.23.0.tgz", + "integrity": "sha512-SEELSTEtOFu5LPykzA395Mc+54RMg1EUgXP+iw2SJ72+ooMwVsgfuwXo5Fn0wXNgWZsTVHwY2cg4Vi/bOD88qw==", + "cpu": [ + "arm" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-arm64": { + "version": "0.23.0", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.23.0.tgz", + "integrity": "sha512-j1t5iG8jE7BhonbsEg5d9qOYcVZv/Rv6tghaXM/Ug9xahM0nX/H2gfu6X6z11QRTMT6+aywOMA8TDkhPo8aCGw==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ia32": { + "version": "0.23.0", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.23.0.tgz", + "integrity": "sha512-P7O5Tkh2NbgIm2R6x1zGJJsnacDzTFcRWZyTTMgFdVit6E98LTxO+v8LCCLWRvPrjdzXHx9FEOA8oAZPyApWUA==", + "cpu": [ + "ia32" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-loong64": { + "version": "0.23.0", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.23.0.tgz", + "integrity": "sha512-InQwepswq6urikQiIC/kkx412fqUZudBO4SYKu0N+tGhXRWUqAx+Q+341tFV6QdBifpjYgUndV1hhMq3WeJi7A==", + "cpu": [ + "loong64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-mips64el": { + "version": "0.23.0", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.23.0.tgz", + "integrity": "sha512-J9rflLtqdYrxHv2FqXE2i1ELgNjT+JFURt/uDMoPQLcjWQA5wDKgQA4t/dTqGa88ZVECKaD0TctwsUfHbVoi4w==", + "cpu": [ + "mips64el" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-ppc64": { + "version": "0.23.0", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.23.0.tgz", + "integrity": "sha512-cShCXtEOVc5GxU0fM+dsFD10qZ5UpcQ8AM22bYj0u/yaAykWnqXJDpd77ublcX6vdDsWLuweeuSNZk4yUxZwtw==", + "cpu": [ + "ppc64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-riscv64": { + "version": "0.23.0", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.23.0.tgz", + "integrity": "sha512-HEtaN7Y5UB4tZPeQmgz/UhzoEyYftbMXrBCUjINGjh3uil+rB/QzzpMshz3cNUxqXN7Vr93zzVtpIDL99t9aRw==", + "cpu": [ + "riscv64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-s390x": { + "version": "0.23.0", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.23.0.tgz", + "integrity": "sha512-WDi3+NVAuyjg/Wxi+o5KPqRbZY0QhI9TjrEEm+8dmpY9Xir8+HE/HNx2JoLckhKbFopW0RdO2D72w8trZOV+Wg==", + "cpu": [ + "s390x" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/linux-x64": { + "version": "0.23.0", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.23.0.tgz", + "integrity": "sha512-a3pMQhUEJkITgAw6e0bWA+F+vFtCciMjW/LPtoj99MhVt+Mfb6bbL9hu2wmTZgNd994qTAEw+U/r6k3qHWWaOQ==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/netbsd-x64": { + "version": "0.23.0", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.23.0.tgz", + "integrity": "sha512-cRK+YDem7lFTs2Q5nEv/HHc4LnrfBCbH5+JHu6wm2eP+d8OZNoSMYgPZJq78vqQ9g+9+nMuIsAO7skzphRXHyw==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-arm64": { + "version": "0.23.0", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.23.0.tgz", + "integrity": "sha512-suXjq53gERueVWu0OKxzWqk7NxiUWSUlrxoZK7usiF50C6ipColGR5qie2496iKGYNLhDZkPxBI3erbnYkU0rQ==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/openbsd-x64": { + "version": "0.23.0", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.23.0.tgz", + "integrity": "sha512-6p3nHpby0DM/v15IFKMjAaayFhqnXV52aEmv1whZHX56pdkK+MEaLoQWj+H42ssFarP1PcomVhbsR4pkz09qBg==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/sunos-x64": { + "version": "0.23.0", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.23.0.tgz", + "integrity": "sha512-BFelBGfrBwk6LVrmFzCq1u1dZbG4zy/Kp93w2+y83Q5UGYF1d8sCzeLI9NXjKyujjBBniQa8R8PzLFAUrSM9OA==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-arm64": { + "version": "0.23.0", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.23.0.tgz", + "integrity": "sha512-lY6AC8p4Cnb7xYHuIxQ6iYPe6MfO2CC43XXKo9nBXDb35krYt7KGhQnOkRGar5psxYkircpCqfbNDB4uJbS2jQ==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-ia32": { + "version": "0.23.0", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.23.0.tgz", + "integrity": "sha512-7L1bHlOTcO4ByvI7OXVI5pNN6HSu6pUQq9yodga8izeuB1KcT2UkHaH6118QJwopExPn0rMHIseCTx1CRo/uNA==", + "cpu": [ + "ia32" + ], + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@esbuild/win32-x64": { + "version": "0.23.0", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.23.0.tgz", + "integrity": "sha512-Arm+WgUFLUATuoxCJcahGuk6Yj9Pzxd6l11Zb/2aAuv5kWWvvfhLFo2fni4uSK5vzlUdCGZ/BdV5tH8klj8p8g==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=18" + } + }, + "node_modules/@eslint-community/eslint-utils": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz", + "integrity": "sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==", + "dev": true, + "dependencies": { + "eslint-visitor-keys": "^3.3.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "peerDependencies": { + "eslint": "^6.0.0 || ^7.0.0 || >=8.0.0" + } + }, + "node_modules/@eslint-community/regexpp": { + "version": "4.10.0", + "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.10.0.tgz", + "integrity": "sha512-Cu96Sd2By9mCNTx2iyKOmq10v22jUVQv0lQnlGNy16oE9589yE+QADPbrMGCkA51cKZSg3Pu/aTJVTGfL/qjUA==", + "dev": true, + "engines": { + "node": "^12.0.0 || ^14.0.0 || >=16.0.0" + } + }, + "node_modules/@eslint/eslintrc": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.1.4.tgz", + "integrity": "sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ==", + "dev": true, + "dependencies": { + "ajv": "^6.12.4", + "debug": "^4.3.2", + "espree": "^9.6.0", + "globals": "^13.19.0", + "ignore": "^5.2.0", + "import-fresh": "^3.2.1", + "js-yaml": "^4.1.0", + "minimatch": "^3.1.2", + "strip-json-comments": "^3.1.1" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/@eslint/eslintrc/node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true + }, + "node_modules/@eslint/eslintrc/node_modules/globals": { + "version": "13.24.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.24.0.tgz", + "integrity": "sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==", + "dev": true, + "dependencies": { + "type-fest": "^0.20.2" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@eslint/eslintrc/node_modules/js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "dev": true, + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/@eslint/eslintrc/node_modules/type-fest": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", + "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@eslint/js": { + "version": "8.57.0", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.57.0.tgz", + "integrity": "sha512-Ys+3g2TaW7gADOJzPt83SJtCDhMjndcDMFVQ/Tj9iA1BfJzFKD9mAUXT3OenpuPHbI6P/myECxRJrofUsDx/5g==", + "dev": true, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + } + }, + "node_modules/@fortawesome/angular-fontawesome": { + "version": "0.14.1", + "resolved": "https://registry.npmjs.org/@fortawesome/angular-fontawesome/-/angular-fontawesome-0.14.1.tgz", + "integrity": "sha512-Yb5HLiEOAxjSLEcaOM51CKIrzdfvoDafXVJERm9vufxfZkVZPZJgrZRgqwLVpejgq4/Ez6TqHZ6SqmJwdtRF6g==", + "dependencies": { + "tslib": "^2.6.2" + }, + "peerDependencies": { + "@angular/core": "^17.0.0", + "@fortawesome/fontawesome-svg-core": "~1.2.27 || ~1.3.0-beta2 || ^6.1.0" + } + }, + "node_modules/@fortawesome/fontawesome-common-types": { + "version": "6.6.0", + "resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-common-types/-/fontawesome-common-types-6.6.0.tgz", + "integrity": "sha512-xyX0X9mc0kyz9plIyryrRbl7ngsA9jz77mCZJsUkLl+ZKs0KWObgaEBoSgQiYWAsSmjz/yjl0F++Got0Mdp4Rw==", + "engines": { + "node": ">=6" + } + }, + "node_modules/@fortawesome/fontawesome-svg-core": { + "version": "6.6.0", + "resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-svg-core/-/fontawesome-svg-core-6.6.0.tgz", + "integrity": "sha512-KHwPkCk6oRT4HADE7smhfsKudt9N/9lm6EJ5BVg0tD1yPA5hht837fB87F8pn15D8JfTqQOjhKTktwmLMiD7Kg==", + "dependencies": { + "@fortawesome/fontawesome-common-types": "6.6.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/@fortawesome/free-solid-svg-icons": { + "version": "6.6.0", + "resolved": "https://registry.npmjs.org/@fortawesome/free-solid-svg-icons/-/free-solid-svg-icons-6.6.0.tgz", + "integrity": "sha512-IYv/2skhEDFc2WGUcqvFJkeK39Q+HyPf5GHUrT/l2pKbtgEIv1al1TKd6qStR5OIwQdN1GZP54ci3y4mroJWjA==", + "dependencies": { + "@fortawesome/fontawesome-common-types": "6.6.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/@goto-bus-stop/common-shake": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/@goto-bus-stop/common-shake/-/common-shake-2.4.0.tgz", + "integrity": "sha512-LO+7v+UbxE3IyAS4Suf/KYB7Zq9DEIHibwDe6Wph4apNEfDyyxP7BSxzRS/Qa9lUH5gsm9eL9nF8EE1E0/nQkQ==", + "dependencies": { + "acorn-walk": "^7.0.0", + "debug": "^3.2.6", + "escope": "^3.6.0" + } + }, + "node_modules/@goto-bus-stop/common-shake/node_modules/debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "dependencies": { + "ms": "^2.1.1" + } + }, + "node_modules/@hapi/hoek": { + "version": "9.3.0", + "resolved": "https://registry.npmjs.org/@hapi/hoek/-/hoek-9.3.0.tgz", + "integrity": "sha512-/c6rf4UJlmHlC9b5BaNvzAcFv7HZ2QHaV0D4/HNlBdvFnvQq8RI4kYdhyPCl7Xj+oWvTWQ8ujhqS53LIgAe6KQ==", + "optional": true + }, + "node_modules/@hapi/topo": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/@hapi/topo/-/topo-5.1.0.tgz", + "integrity": "sha512-foQZKJig7Ob0BMAYBfcJk8d77QtOe7Wo4ox7ff1lQYoNNAb6jwcY1ncdoy2e9wQZzvNy7ODZCYJkK8kzmcAnAg==", + "optional": true, + "dependencies": { + "@hapi/hoek": "^9.0.0" + } + }, + "node_modules/@humanwhocodes/config-array": { + "version": "0.11.14", + "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.14.tgz", + "integrity": "sha512-3T8LkOmg45BV5FICb15QQMsyUSWrQ8AygVfC7ZG32zOalnqrilm018ZVCw0eapXux8FtA33q8PSRSstjee3jSg==", + "dev": true, + "dependencies": { + "@humanwhocodes/object-schema": "^2.0.2", + "debug": "^4.3.1", + "minimatch": "^3.0.5" + }, + "engines": { + "node": ">=10.10.0" + } + }, + "node_modules/@humanwhocodes/module-importer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", + "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", + "dev": true, + "engines": { + "node": ">=12.22" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/nzakas" + } + }, + "node_modules/@humanwhocodes/object-schema": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-2.0.2.tgz", + "integrity": "sha512-6EwiSjwWYP7pTckG6I5eyFANjPhmPjUX9JRLUSfNPC7FX7zK9gyZAfUEaECL6ALTpGX5AjnBq3C9XmVWPitNpw==", + "dev": true + }, + "node_modules/@isaacs/cliui": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", + "integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==", + "dependencies": { + "string-width": "^5.1.2", + "string-width-cjs": "npm:string-width@^4.2.0", + "strip-ansi": "^7.0.1", + "strip-ansi-cjs": "npm:strip-ansi@^6.0.1", + "wrap-ansi": "^8.1.0", + "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/@isaacs/cliui/node_modules/ansi-regex": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", + "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-regex?sponsor=1" + } + }, + "node_modules/@isaacs/cliui/node_modules/ansi-styles": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", + "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/@isaacs/cliui/node_modules/emoji-regex": { + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", + "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==" + }, + "node_modules/@isaacs/cliui/node_modules/string-width": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", + "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", + "dependencies": { + "eastasianwidth": "^0.2.0", + "emoji-regex": "^9.2.2", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@isaacs/cliui/node_modules/strip-ansi": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", + "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", + "dependencies": { + "ansi-regex": "^6.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/strip-ansi?sponsor=1" + } + }, + "node_modules/@isaacs/cliui/node_modules/wrap-ansi": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz", + "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==", + "dependencies": { + "ansi-styles": "^6.1.0", + "string-width": "^5.0.1", + "strip-ansi": "^7.0.1" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/@istanbuljs/load-nyc-config": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz", + "integrity": "sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ==", + "dependencies": { + "camelcase": "^5.3.1", + "find-up": "^4.1.0", + "get-package-type": "^0.1.0", + "js-yaml": "^3.13.1", + "resolve-from": "^5.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/@istanbuljs/schema": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.2.tgz", + "integrity": "sha512-tsAQNx32a8CoFhjhijUIhI4kccIAgmGhy8LZMZgGfmXcpMbPRUqn5LWmgRttILi6yeGmBJd2xsPkFMs0PzgPCw==", + "engines": { + "node": ">=8" + } + }, + "node_modules/@jridgewell/gen-mapping": { + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.5.tgz", + "integrity": "sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg==", + "dependencies": { + "@jridgewell/set-array": "^1.2.1", + "@jridgewell/sourcemap-codec": "^1.4.10", + "@jridgewell/trace-mapping": "^0.3.24" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/gen-mapping/node_modules/@jridgewell/trace-mapping": { + "version": "0.3.25", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz", + "integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==", + "dependencies": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, + "node_modules/@jridgewell/resolve-uri": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz", + "integrity": "sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/set-array": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.2.1.tgz", + "integrity": "sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==", + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/@jridgewell/source-map": { + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.5.tgz", + "integrity": "sha512-UTYAUj/wviwdsMfzoSJspJxbkH5o1snzwX0//0ENX1u/55kkZZkcTZP6u9bwKGkv+dkk9at4m1Cpt0uY80kcpQ==", + "dependencies": { + "@jridgewell/gen-mapping": "^0.3.0", + "@jridgewell/trace-mapping": "^0.3.9" + } + }, + "node_modules/@jridgewell/sourcemap-codec": { + "version": "1.4.15", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz", + "integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==" + }, + "node_modules/@jridgewell/trace-mapping": { + "version": "0.3.9", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz", + "integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==", + "dependencies": { + "@jridgewell/resolve-uri": "^3.0.3", + "@jridgewell/sourcemap-codec": "^1.4.10" + } + }, + "node_modules/@leichtgewicht/ip-codec": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/@leichtgewicht/ip-codec/-/ip-codec-2.0.4.tgz", + "integrity": "sha512-Hcv+nVC0kZnQ3tD9GVu5xSMR4VVYOteQIr/hwFPVEvPdlXqgGEuRjiheChHgdM+JyqdgNcmzZOX/tnl0JOiI7A==" + }, + "node_modules/@ljharb/through": { + "version": "2.3.13", + "resolved": "https://registry.npmjs.org/@ljharb/through/-/through-2.3.13.tgz", + "integrity": "sha512-/gKJun8NNiWGZJkGzI/Ragc53cOdcLNdzjLaIa+GEjguQs0ulsurx8WN0jijdK9yPqDvziX995sMRLyLt1uZMQ==", + "dependencies": { + "call-bind": "^1.0.7" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/@mempool/mempool.js": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@mempool/mempool.js/-/mempool.js-2.3.0.tgz", + "integrity": "sha512-FrN9WjZCEyyLodrTPQxmlWDh8B/UGK0jlKfVNzJxqzQ1IMPo/Hpdws8xwYEcsks5JqsaxbjLwaC3GAtJ6Brd0A==", + "dependencies": { + "axios": "0.24.0", + "ws": "8.3.0" + } + }, + "node_modules/@mempool/mempool.js/node_modules/ws": { + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.3.0.tgz", + "integrity": "sha512-Gs5EZtpqZzLvmIM59w4igITU57lrtYVFneaa434VROv4thzJyV6UjIL3D42lslWlI+D4KzLYnxSwtfuiO79sNw==", + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": "^5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, + "node_modules/@ng-bootstrap/ng-bootstrap": { + "version": "16.0.0", + "resolved": "https://registry.npmjs.org/@ng-bootstrap/ng-bootstrap/-/ng-bootstrap-16.0.0.tgz", + "integrity": "sha512-+FJ3e6cX9DW2t7021Ji3oz433rk3+4jLfqzU+Jyx6/vJz1dIOaML3EAY6lYuW4TLiXgMPOMvs6KzPFALGh4Lag==", + "dependencies": { + "tslib": "^2.3.0" + }, + "peerDependencies": { + "@angular/common": "^17.0.0", + "@angular/core": "^17.0.0", + "@angular/forms": "^17.0.0", + "@angular/localize": "^17.0.0", + "@popperjs/core": "^2.11.8", + "rxjs": "^6.5.3 || ^7.4.0" + } + }, + "node_modules/@ngtools/webpack": { + "version": "17.3.1", + "resolved": "https://registry.npmjs.org/@ngtools/webpack/-/webpack-17.3.1.tgz", + "integrity": "sha512-6qRYFN6DqogZK0ZFrSlhg1OsIWm3lL3m+/Ixoj6/MLLjDBrTtHqmI93vg6P1EKYTH4fWChL7jtv7iS/LSZubgw==", + "engines": { + "node": "^18.13.0 || >=20.9.0", + "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", + "yarn": ">= 1.13.0" + }, + "peerDependencies": { + "@angular/compiler-cli": "^17.0.0", + "typescript": ">=5.2 <5.5", + "webpack": "^5.54.0" + } + }, + "node_modules/@nodelib/fs.scandir": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", + "dependencies": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.stat": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.walk": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", + "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", + "dependencies": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@npmcli/agent": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/@npmcli/agent/-/agent-2.2.1.tgz", + "integrity": "sha512-H4FrOVtNyWC8MUwL3UfjOsAihHvT1Pe8POj3JvjXhSTJipsZMtgUALCT4mGyYZNxymkUfOw3PUj6dE4QPp6osQ==", + "dependencies": { + "agent-base": "^7.1.0", + "http-proxy-agent": "^7.0.0", + "https-proxy-agent": "^7.0.1", + "lru-cache": "^10.0.1", + "socks-proxy-agent": "^8.0.1" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "node_modules/@npmcli/agent/node_modules/lru-cache": { + "version": "10.2.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.2.0.tgz", + "integrity": "sha512-2bIM8x+VAf6JT4bKAljS1qUWgMsqZRPGJS6FSahIMPVvctcNhyVp7AJu7quxOW9jwkryBReKZY5tY5JYv2n/7Q==", + "engines": { + "node": "14 || >=16.14" + } + }, + "node_modules/@npmcli/fs": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@npmcli/fs/-/fs-3.1.0.tgz", + "integrity": "sha512-7kZUAaLscfgbwBQRbvdMYaZOWyMEcPTH/tJjnyAWJ/dvvs9Ef+CERx/qJb9GExJpl1qipaDGn7KqHnFGGixd0w==", + "dependencies": { + "semver": "^7.3.5" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/@npmcli/git": { + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/@npmcli/git/-/git-5.0.4.tgz", + "integrity": "sha512-nr6/WezNzuYUppzXRaYu/W4aT5rLxdXqEFupbh6e/ovlYFQ8hpu1UUPV3Ir/YTl+74iXl2ZOMlGzudh9ZPUchQ==", + "dependencies": { + "@npmcli/promise-spawn": "^7.0.0", + "lru-cache": "^10.0.1", + "npm-pick-manifest": "^9.0.0", + "proc-log": "^3.0.0", + "promise-inflight": "^1.0.1", + "promise-retry": "^2.0.1", + "semver": "^7.3.5", + "which": "^4.0.0" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "node_modules/@npmcli/git/node_modules/isexe": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-3.1.1.tgz", + "integrity": "sha512-LpB/54B+/2J5hqQ7imZHfdU31OlgQqx7ZicVlkm9kzg9/w8GKLEcFfJl/t7DCEDueOyBAD6zCCwTO6Fzs0NoEQ==", + "engines": { + "node": ">=16" + } + }, + "node_modules/@npmcli/git/node_modules/lru-cache": { + "version": "10.2.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.2.0.tgz", + "integrity": "sha512-2bIM8x+VAf6JT4bKAljS1qUWgMsqZRPGJS6FSahIMPVvctcNhyVp7AJu7quxOW9jwkryBReKZY5tY5JYv2n/7Q==", + "engines": { + "node": "14 || >=16.14" + } + }, + "node_modules/@npmcli/git/node_modules/which": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/which/-/which-4.0.0.tgz", + "integrity": "sha512-GlaYyEb07DPxYCKhKzplCWBJtvxZcZMrL+4UkrTSJHHPyZU4mYYTv3qaOe77H7EODLSSopAUFAc6W8U4yqvscg==", + "dependencies": { + "isexe": "^3.1.1" + }, + "bin": { + "node-which": "bin/which.js" + }, + "engines": { + "node": "^16.13.0 || >=18.0.0" + } + }, + "node_modules/@npmcli/installed-package-contents": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/@npmcli/installed-package-contents/-/installed-package-contents-2.0.2.tgz", + "integrity": "sha512-xACzLPhnfD51GKvTOOuNX2/V4G4mz9/1I2MfDoye9kBM3RYe5g2YbscsaGoTlaWqkxeiapBWyseULVKpSVHtKQ==", + "dependencies": { + "npm-bundled": "^3.0.0", + "npm-normalize-package-bin": "^3.0.0" + }, + "bin": { + "installed-package-contents": "lib/index.js" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/@npmcli/node-gyp": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@npmcli/node-gyp/-/node-gyp-3.0.0.tgz", + "integrity": "sha512-gp8pRXC2oOxu0DUE1/M3bYtb1b3/DbJ5aM113+XJBgfXdussRAsX0YOrOhdd8WvnAR6auDBvJomGAkLKA5ydxA==", + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/@npmcli/package-json": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/@npmcli/package-json/-/package-json-5.0.0.tgz", + "integrity": "sha512-OI2zdYBLhQ7kpNPaJxiflofYIpkNLi+lnGdzqUOfRmCF3r2l1nadcjtCYMJKv/Utm/ZtlffaUuTiAktPHbc17g==", + "dependencies": { + "@npmcli/git": "^5.0.0", + "glob": "^10.2.2", + "hosted-git-info": "^7.0.0", + "json-parse-even-better-errors": "^3.0.0", + "normalize-package-data": "^6.0.0", + "proc-log": "^3.0.0", + "semver": "^7.5.3" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "node_modules/@npmcli/package-json/node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/@npmcli/package-json/node_modules/glob": { + "version": "10.3.10", + "resolved": "https://registry.npmjs.org/glob/-/glob-10.3.10.tgz", + "integrity": "sha512-fa46+tv1Ak0UPK1TOy/pZrIybNNt4HCv7SDzwyfiOZkvZLEbjsZkJBPtDHVshZjbecAoAGSC20MjLDG/qr679g==", + "dependencies": { + "foreground-child": "^3.1.0", + "jackspeak": "^2.3.5", + "minimatch": "^9.0.1", + "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0", + "path-scurry": "^1.10.1" + }, + "bin": { + "glob": "dist/esm/bin.mjs" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/@npmcli/package-json/node_modules/json-parse-even-better-errors": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-3.0.1.tgz", + "integrity": "sha512-aatBvbL26wVUCLmbWdCpeu9iF5wOyWpagiKkInA+kfws3sWdBrTnsvN2CKcyCYyUrc7rebNBlK6+kteg7ksecg==", + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/@npmcli/package-json/node_modules/minimatch": { + "version": "9.0.3", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.3.tgz", + "integrity": "sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==", + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/@npmcli/promise-spawn": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/@npmcli/promise-spawn/-/promise-spawn-7.0.1.tgz", + "integrity": "sha512-P4KkF9jX3y+7yFUxgcUdDtLy+t4OlDGuEBLNs57AZsfSfg+uV6MLndqGpnl4831ggaEdXwR50XFoZP4VFtHolg==", + "dependencies": { + "which": "^4.0.0" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "node_modules/@npmcli/promise-spawn/node_modules/isexe": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-3.1.1.tgz", + "integrity": "sha512-LpB/54B+/2J5hqQ7imZHfdU31OlgQqx7ZicVlkm9kzg9/w8GKLEcFfJl/t7DCEDueOyBAD6zCCwTO6Fzs0NoEQ==", + "engines": { + "node": ">=16" + } + }, + "node_modules/@npmcli/promise-spawn/node_modules/which": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/which/-/which-4.0.0.tgz", + "integrity": "sha512-GlaYyEb07DPxYCKhKzplCWBJtvxZcZMrL+4UkrTSJHHPyZU4mYYTv3qaOe77H7EODLSSopAUFAc6W8U4yqvscg==", + "dependencies": { + "isexe": "^3.1.1" + }, + "bin": { + "node-which": "bin/which.js" + }, + "engines": { + "node": "^16.13.0 || >=18.0.0" + } + }, + "node_modules/@npmcli/run-script": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/@npmcli/run-script/-/run-script-7.0.4.tgz", + "integrity": "sha512-9ApYM/3+rBt9V80aYg6tZfzj3UWdiYyCt7gJUD1VJKvWF5nwKDSICXbYIQbspFTq6TOpbsEtIC0LArB8d9PFmg==", + "dependencies": { + "@npmcli/node-gyp": "^3.0.0", + "@npmcli/package-json": "^5.0.0", + "@npmcli/promise-spawn": "^7.0.0", + "node-gyp": "^10.0.0", + "which": "^4.0.0" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "node_modules/@npmcli/run-script/node_modules/isexe": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-3.1.1.tgz", + "integrity": "sha512-LpB/54B+/2J5hqQ7imZHfdU31OlgQqx7ZicVlkm9kzg9/w8GKLEcFfJl/t7DCEDueOyBAD6zCCwTO6Fzs0NoEQ==", + "engines": { + "node": ">=16" + } + }, + "node_modules/@npmcli/run-script/node_modules/which": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/which/-/which-4.0.0.tgz", + "integrity": "sha512-GlaYyEb07DPxYCKhKzplCWBJtvxZcZMrL+4UkrTSJHHPyZU4mYYTv3qaOe77H7EODLSSopAUFAc6W8U4yqvscg==", + "dependencies": { + "isexe": "^3.1.1" + }, + "bin": { + "node-which": "bin/which.js" + }, + "engines": { + "node": "^16.13.0 || >=18.0.0" + } + }, + "node_modules/@pkgjs/parseargs": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", + "integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==", + "optional": true, + "engines": { + "node": ">=14" + } + }, + "node_modules/@popperjs/core": { + "version": "2.11.8", + "resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.11.8.tgz", + "integrity": "sha512-P1st0aksCrn9sGZhp8GMYwBnQsbvAWsZAX44oXNNvLHGqAOcoVxmjZiohstwQ7SqKnbR47akdNi+uleWD8+g6A==", + "peer": true, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/popperjs" + } + }, + "node_modules/@rollup/rollup-android-arm-eabi": { + "version": "4.13.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.13.0.tgz", + "integrity": "sha512-5ZYPOuaAqEH/W3gYsRkxQATBW3Ii1MfaT4EQstTnLKViLi2gLSQmlmtTpGucNP3sXEpOiI5tdGhjdE111ekyEg==", + "cpu": [ + "arm" + ], + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-android-arm64": { + "version": "4.13.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.13.0.tgz", + "integrity": "sha512-BSbaCmn8ZadK3UAQdlauSvtaJjhlDEjS5hEVVIN3A4bbl3X+otyf/kOJV08bYiRxfejP3DXFzO2jz3G20107+Q==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "android" + ] + }, + "node_modules/@rollup/rollup-darwin-arm64": { + "version": "4.13.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.13.0.tgz", + "integrity": "sha512-Ovf2evVaP6sW5Ut0GHyUSOqA6tVKfrTHddtmxGQc1CTQa1Cw3/KMCDEEICZBbyppcwnhMwcDce9ZRxdWRpVd6g==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-darwin-x64": { + "version": "4.13.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.13.0.tgz", + "integrity": "sha512-U+Jcxm89UTK592vZ2J9st9ajRv/hrwHdnvyuJpa5A2ngGSVHypigidkQJP+YiGL6JODiUeMzkqQzbCG3At81Gg==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "darwin" + ] + }, + "node_modules/@rollup/rollup-linux-arm-gnueabihf": { + "version": "4.13.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.13.0.tgz", + "integrity": "sha512-8wZidaUJUTIR5T4vRS22VkSMOVooG0F4N+JSwQXWSRiC6yfEsFMLTYRFHvby5mFFuExHa/yAp9juSphQQJAijQ==", + "cpu": [ + "arm" + ], + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-gnu": { + "version": "4.13.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.13.0.tgz", + "integrity": "sha512-Iu0Kno1vrD7zHQDxOmvweqLkAzjxEVqNhUIXBsZ8hu8Oak7/5VTPrxOEZXYC1nmrBVJp0ZcL2E7lSuuOVaE3+w==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-arm64-musl": { + "version": "4.13.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.13.0.tgz", + "integrity": "sha512-C31QrW47llgVyrRjIwiOwsHFcaIwmkKi3PCroQY5aVq4H0A5v/vVVAtFsI1nfBngtoRpeREvZOkIhmRwUKkAdw==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-riscv64-gnu": { + "version": "4.13.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.13.0.tgz", + "integrity": "sha512-Oq90dtMHvthFOPMl7pt7KmxzX7E71AfyIhh+cPhLY9oko97Zf2C9tt/XJD4RgxhaGeAraAXDtqxvKE1y/j35lA==", + "cpu": [ + "riscv64" + ], + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-gnu": { + "version": "4.13.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.13.0.tgz", + "integrity": "sha512-yUD/8wMffnTKuiIsl6xU+4IA8UNhQ/f1sAnQebmE/lyQ8abjsVyDkyRkWop0kdMhKMprpNIhPmYlCxgHrPoXoA==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-linux-x64-musl": { + "version": "4.13.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.13.0.tgz", + "integrity": "sha512-9RyNqoFNdF0vu/qqX63fKotBh43fJQeYC98hCaf89DYQpv+xu0D8QFSOS0biA7cGuqJFOc1bJ+m2rhhsKcw1hw==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "linux" + ] + }, + "node_modules/@rollup/rollup-win32-arm64-msvc": { + "version": "4.13.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.13.0.tgz", + "integrity": "sha512-46ue8ymtm/5PUU6pCvjlic0z82qWkxv54GTJZgHrQUuZnVH+tvvSP0LsozIDsCBFO4VjJ13N68wqrKSeScUKdA==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-ia32-msvc": { + "version": "4.13.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.13.0.tgz", + "integrity": "sha512-P5/MqLdLSlqxbeuJ3YDeX37srC8mCflSyTrUsgbU1c/U9j6l2g2GiIdYaGD9QjdMQPMSgYm7hgg0551wHyIluw==", + "cpu": [ + "ia32" + ], + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@rollup/rollup-win32-x64-msvc": { + "version": "4.13.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.13.0.tgz", + "integrity": "sha512-UKXUQNbO3DOhzLRwHSpa0HnhhCgNODvfoPWv2FCXme8N/ANFfhIPMGuOT+QuKd16+B5yxZ0HdpNlqPvTMS1qfw==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "win32" + ] + }, + "node_modules/@schematics/angular": { + "version": "17.3.1", + "resolved": "https://registry.npmjs.org/@schematics/angular/-/angular-17.3.1.tgz", + "integrity": "sha512-B3TkpjDjZhxX+tUc2ySEHU33x82Da0sssq/EMqQ1PQBHeRMa0ecyCeExjFEs2y57ZuC+QeVTaUt+TW45lLSjQw==", + "dependencies": { + "@angular-devkit/core": "17.3.1", + "@angular-devkit/schematics": "17.3.1", + "jsonc-parser": "3.2.1" + }, + "engines": { + "node": "^18.13.0 || >=20.9.0", + "npm": "^6.11.0 || ^7.5.6 || >=8.0.0", + "yarn": ">= 1.13.0" + } + }, + "node_modules/@sideway/address": { + "version": "4.1.4", + "resolved": "https://registry.npmjs.org/@sideway/address/-/address-4.1.4.tgz", + "integrity": "sha512-7vwq+rOHVWjyXxVlR76Agnvhy8I9rpzjosTESvmhNeXOXdZZB15Fl+TI9x1SiHZH5Jv2wTGduSxFDIaq0m3DUw==", + "optional": true, + "dependencies": { + "@hapi/hoek": "^9.0.0" + } + }, + "node_modules/@sideway/formula": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@sideway/formula/-/formula-3.0.1.tgz", + "integrity": "sha512-/poHZJJVjx3L+zVD6g9KgHfYnb443oi7wLu/XKojDviHy6HOEOA6z1Trk5aR1dGcmPenJEgb2sK2I80LeS3MIg==", + "optional": true + }, + "node_modules/@sideway/pinpoint": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@sideway/pinpoint/-/pinpoint-2.0.0.tgz", + "integrity": "sha512-RNiOoTPkptFtSVzQevY/yWtZwf/RxyVnPy/OcA9HBM3MlGDnBEYL5B41H0MTn0Uec8Hi+2qUtTfG2WWZBmMejQ==", + "optional": true + }, + "node_modules/@sigstore/bundle": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@sigstore/bundle/-/bundle-2.2.0.tgz", + "integrity": "sha512-5VI58qgNs76RDrwXNhpmyN/jKpq9evV/7f1XrcqcAfvxDl5SeVY/I5Rmfe96ULAV7/FK5dge9RBKGBJPhL1WsQ==", + "dependencies": { + "@sigstore/protobuf-specs": "^0.3.0" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "node_modules/@sigstore/core": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@sigstore/core/-/core-1.0.0.tgz", + "integrity": "sha512-dW2qjbWLRKGu6MIDUTBuJwXCnR8zivcSpf5inUzk7y84zqy/dji0/uahppoIgMoKeR+6pUZucrwHfkQQtiG9Rw==", + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "node_modules/@sigstore/protobuf-specs": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/@sigstore/protobuf-specs/-/protobuf-specs-0.3.0.tgz", + "integrity": "sha512-zxiQ66JFOjVvP9hbhGj/F/qNdsZfkGb/dVXSanNRNuAzMlr4MC95voPUBX8//ZNnmv3uSYzdfR/JSkrgvZTGxA==", + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/@sigstore/sign": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/@sigstore/sign/-/sign-2.2.3.tgz", + "integrity": "sha512-LqlA+ffyN02yC7RKszCdMTS6bldZnIodiox+IkT8B2f8oRYXCB3LQ9roXeiEL21m64CVH1wyveYAORfD65WoSw==", + "dependencies": { + "@sigstore/bundle": "^2.2.0", + "@sigstore/core": "^1.0.0", + "@sigstore/protobuf-specs": "^0.3.0", + "make-fetch-happen": "^13.0.0" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "node_modules/@sigstore/tuf": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/@sigstore/tuf/-/tuf-2.3.1.tgz", + "integrity": "sha512-9Iv40z652td/QbV0o5n/x25H9w6IYRt2pIGbTX55yFDYlApDQn/6YZomjz6+KBx69rXHLzHcbtTS586mDdFD+Q==", + "dependencies": { + "@sigstore/protobuf-specs": "^0.3.0", + "tuf-js": "^2.2.0" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "node_modules/@sigstore/verify": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@sigstore/verify/-/verify-1.1.0.tgz", + "integrity": "sha512-1fTqnqyTBWvV7cftUUFtDcHPdSox0N3Ub7C0lRyReYx4zZUlNTZjCV+HPy4Lre+r45dV7Qx5JLKvqqsgxuyYfg==", + "dependencies": { + "@sigstore/bundle": "^2.2.0", + "@sigstore/core": "^1.0.0", + "@sigstore/protobuf-specs": "^0.3.0" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "node_modules/@sinonjs/commons": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-3.0.0.tgz", + "integrity": "sha512-jXBtWAF4vmdNmZgD5FoKsVLv3rPgDnLgPbU84LIJ3otV44vJlDRokVng5v8NFJdCf/da9legHcKaRuZs4L7faA==", + "optional": true, + "dependencies": { + "type-detect": "4.0.8" + } + }, + "node_modules/@sinonjs/fake-timers": { + "version": "11.2.2", + "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-11.2.2.tgz", + "integrity": "sha512-G2piCSxQ7oWOxwGSAyFHfPIsyeJGXYtc6mFbnFA+kRXkiEnTl8c/8jul2S329iFBnDI9HGoeWWAZvuvOkZccgw==", + "optional": true, + "dependencies": { + "@sinonjs/commons": "^3.0.0" + } + }, + "node_modules/@sinonjs/samsam": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/@sinonjs/samsam/-/samsam-8.0.0.tgz", + "integrity": "sha512-Bp8KUVlLp8ibJZrnvq2foVhP0IVX2CIprMJPK0vqGqgrDa0OHVKeZyBykqskkrdxV6yKBPmGasO8LVjAKR3Gew==", + "optional": true, + "dependencies": { + "@sinonjs/commons": "^2.0.0", + "lodash.get": "^4.4.2", + "type-detect": "^4.0.8" + } + }, + "node_modules/@sinonjs/samsam/node_modules/@sinonjs/commons": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-2.0.0.tgz", + "integrity": "sha512-uLa0j859mMrg2slwQYdO/AkrOfmH+X6LTVmNTS9CqexuE2IvVORIkSpJLqePAbEnKJ77aMmCwr1NUZ57120Xcg==", + "optional": true, + "dependencies": { + "type-detect": "4.0.8" + } + }, + "node_modules/@sinonjs/text-encoding": { + "version": "0.7.2", + "resolved": "https://registry.npmjs.org/@sinonjs/text-encoding/-/text-encoding-0.7.2.tgz", + "integrity": "sha512-sXXKG+uL9IrKqViTtao2Ws6dy0znu9sOaP1di/jKGW1M6VssO8vlpXCQcpZ+jisQ1tTFAC5Jo/EOzFbggBagFQ==", + "optional": true + }, + "node_modules/@socket.io/component-emitter": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@socket.io/component-emitter/-/component-emitter-3.1.0.tgz", + "integrity": "sha512-+9jVqKhRSpsc591z5vX+X5Yyw+he/HCB4iQ/RYxw35CEPaY1gnsNE43nf9n9AaYjAQrTiI/mOwKUKdUs9vf7Xg==", + "devOptional": true + }, + "node_modules/@tsconfig/node10": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.9.tgz", + "integrity": "sha512-jNsYVVxU8v5g43Erja32laIDHXeoNvFEpX33OK4d6hljo3jDhCBDhx5dhCCTMWUojscpAagGiRkBKxpdl9fxqA==", + "dev": true + }, + "node_modules/@tsconfig/node12": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.11.tgz", + "integrity": "sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==", + "dev": true + }, + "node_modules/@tsconfig/node14": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.3.tgz", + "integrity": "sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==", + "dev": true + }, + "node_modules/@tsconfig/node16": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.3.tgz", + "integrity": "sha512-yOlFc+7UtL/89t2ZhjPvvB/DeAr3r+Dq58IgzsFkOAvVC6NMJXmCGjbptdXdR9qsX7pKcTL+s87FtYREi2dEEQ==", + "dev": true + }, + "node_modules/@tufjs/canonical-json": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@tufjs/canonical-json/-/canonical-json-2.0.0.tgz", + "integrity": "sha512-yVtV8zsdo8qFHe+/3kw81dSLyF7D576A5cCFCi4X7B39tWT7SekaEFUnvnWJHz+9qO7qJTah1JbrDjWKqFtdWA==", + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "node_modules/@tufjs/models": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@tufjs/models/-/models-2.0.0.tgz", + "integrity": "sha512-c8nj8BaOExmZKO2DXhDfegyhSGcG9E/mPN3U13L+/PsoWm1uaGiHHjxqSHQiasDBQwDA3aHuw9+9spYAP1qvvg==", + "dependencies": { + "@tufjs/canonical-json": "2.0.0", + "minimatch": "^9.0.3" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "node_modules/@tufjs/models/node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/@tufjs/models/node_modules/minimatch": { + "version": "9.0.3", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.3.tgz", + "integrity": "sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==", + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/@types/babel__core": { + "version": "7.20.5", + "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.5.tgz", + "integrity": "sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==", + "dependencies": { + "@babel/parser": "^7.20.7", + "@babel/types": "^7.20.7", + "@types/babel__generator": "*", + "@types/babel__template": "*", + "@types/babel__traverse": "*" + } + }, + "node_modules/@types/babel__generator": { + "version": "7.6.8", + "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.6.8.tgz", + "integrity": "sha512-ASsj+tpEDsEiFr1arWrlN6V3mdfjRMZt6LtK/Vp/kreFLnr5QH5+DhvD5nINYZXzwJvXeGq+05iUXcAzVrqWtw==", + "dependencies": { + "@babel/types": "^7.0.0" + } + }, + "node_modules/@types/babel__template": { + "version": "7.4.4", + "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.4.tgz", + "integrity": "sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==", + "dependencies": { + "@babel/parser": "^7.1.0", + "@babel/types": "^7.0.0" + } + }, + "node_modules/@types/babel__traverse": { + "version": "7.20.5", + "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.20.5.tgz", + "integrity": "sha512-WXCyOcRtH37HAUkpXhUduaxdm82b4GSlyTqajXviN4EfiuPgNYR109xMCKvpl6zPIpua0DGlMEDCq+g8EdoheQ==", + "dependencies": { + "@babel/types": "^7.20.7" + } + }, + "node_modules/@types/body-parser": { + "version": "1.19.0", + "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.0.tgz", + "integrity": "sha512-W98JrE0j2K78swW4ukqMleo8R7h/pFETjM2DQ90MF6XK2i4LO4W3gQ71Lt4w3bfm2EvVSyWHplECvB5sK22yFQ==", + "dependencies": { + "@types/connect": "*", + "@types/node": "*" + } + }, + "node_modules/@types/bonjour": { + "version": "3.5.13", + "resolved": "https://registry.npmjs.org/@types/bonjour/-/bonjour-3.5.13.tgz", + "integrity": "sha512-z9fJ5Im06zvUL548KvYNecEVlA7cVDkGUi6kZusb04mpyEFKCIZJvloCcmpmLaIahDpOQGHaHmG6imtPMmPXGQ==", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/connect": { + "version": "3.4.33", + "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.33.tgz", + "integrity": "sha512-2+FrkXY4zllzTNfJth7jOqEHC+enpLeGslEhpnTAkg21GkRrWV4SsAtqchtT4YS9/nODBU2/ZfsBY2X4J/dX7A==", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/connect-history-api-fallback": { + "version": "1.5.4", + "resolved": "https://registry.npmjs.org/@types/connect-history-api-fallback/-/connect-history-api-fallback-1.5.4.tgz", + "integrity": "sha512-n6Cr2xS1h4uAulPRdlw6Jl6s1oG8KrVilPN2yUITEs+K48EzMJJ3W1xy8K5eWuFvjp3R74AOIGSmp2UfBJ8HFw==", + "dependencies": { + "@types/express-serve-static-core": "*", + "@types/node": "*" + } + }, + "node_modules/@types/cookie": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/@types/cookie/-/cookie-0.4.1.tgz", + "integrity": "sha512-XW/Aa8APYr6jSVVA1y/DEIZX0/GMKLEVekNG727R8cs56ahETkRAy/3DR7+fJyh7oUgGwNQaRfXCun0+KbWY7Q==", + "devOptional": true + }, + "node_modules/@types/cors": { + "version": "2.8.13", + "resolved": "https://registry.npmjs.org/@types/cors/-/cors-2.8.13.tgz", + "integrity": "sha512-RG8AStHlUiV5ysZQKq97copd2UmVYw3/pRMLefISZ3S1hK104Cwm7iLQ3fTKx+lsUH2CE8FlLaYeEA2LSeqYUA==", + "devOptional": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/cypress": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/@types/cypress/-/cypress-1.1.3.tgz", + "integrity": "sha512-OXe0Gw8LeCflkG1oPgFpyrYWJmEKqYncBsD/J0r17r0ETx/TnIGDNLwXt/pFYSYuYTpzcq1q3g62M9DrfsBL4g==", + "deprecated": "This is a stub types definition for cypress (https://cypress.io). cypress provides its own type definitions, so you don't need @types/cypress installed!", + "optional": true, + "dependencies": { + "cypress": "*" + } + }, + "node_modules/@types/eslint": { + "version": "8.4.1", + "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-8.4.1.tgz", + "integrity": "sha512-GE44+DNEyxxh2Kc6ro/VkIj+9ma0pO0bwv9+uHSyBrikYOHr8zYcdPvnBOp1aw8s+CjRvuSx7CyWqRrNFQ59mA==", + "dependencies": { + "@types/estree": "*", + "@types/json-schema": "*" + } + }, + "node_modules/@types/eslint-scope": { + "version": "3.7.3", + "resolved": "https://registry.npmjs.org/@types/eslint-scope/-/eslint-scope-3.7.3.tgz", + "integrity": "sha512-PB3ldyrcnAicT35TWPs5IcwKD8S333HMaa2VVv4+wdvebJkjWuW/xESoB8IwRcog8HYVYamb1g/R31Qv5Bx03g==", + "dependencies": { + "@types/eslint": "*", + "@types/estree": "*" + } + }, + "node_modules/@types/estree": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.5.tgz", + "integrity": "sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==" + }, + "node_modules/@types/express": { + "version": "4.17.13", + "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.13.tgz", + "integrity": "sha512-6bSZTPaTIACxn48l50SR+axgrqm6qXFIxrdAKaG6PaJk3+zuUr35hBlgT7vOmJcum+OEaIBLtHV/qloEAFITeA==", + "dependencies": { + "@types/body-parser": "*", + "@types/express-serve-static-core": "^4.17.18", + "@types/qs": "*", + "@types/serve-static": "*" + } + }, + "node_modules/@types/express-serve-static-core": { + "version": "4.17.28", + "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.17.28.tgz", + "integrity": "sha512-P1BJAEAW3E2DJUlkgq4tOL3RyMunoWXqbSCygWo5ZIWTjUgN1YnaXWW4VWl/oc8vs/XoYibEGBKP0uZyF4AHig==", + "dependencies": { + "@types/node": "*", + "@types/qs": "*", + "@types/range-parser": "*" + } + }, + "node_modules/@types/http-proxy": { + "version": "1.17.8", + "resolved": "https://registry.npmjs.org/@types/http-proxy/-/http-proxy-1.17.8.tgz", + "integrity": "sha512-5kPLG5BKpWYkw/LVOGWpiq3nEVqxiN32rTgI53Sk12/xHFQ2rG3ehI9IO+O3W2QoKeyB92dJkoka8SUm6BX1pA==", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/json-schema": { + "version": "7.0.15", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", + "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==" + }, + "node_modules/@types/mime": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@types/mime/-/mime-2.0.3.tgz", + "integrity": "sha512-Jus9s4CDbqwocc5pOAnh8ShfrnMcPHuJYzVcSUU7lrh8Ni5HuIqX3oilL86p3dlTrk0LzHRCgA/GQ7uNCw6l2Q==" + }, + "node_modules/@types/node": { + "version": "18.17.18", + "resolved": "https://registry.npmjs.org/@types/node/-/node-18.17.18.tgz", + "integrity": "sha512-/4QOuy3ZpV7Ya1GTRz5CYSz3DgkKpyUptXuQ5PPce7uuyJAOR7r9FhkmxJfvcNUXyklbC63a+YvB3jxy7s9ngw==" + }, + "node_modules/@types/node-forge": { + "version": "1.3.11", + "resolved": "https://registry.npmjs.org/@types/node-forge/-/node-forge-1.3.11.tgz", + "integrity": "sha512-FQx220y22OKNTqaByeBGqHWYz4cl94tpcxeFdvBo3wjG6XPBuZ0BNgNZRV5J5TFmmcsJ4IzsLkmGRiQbnYsBEQ==", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/qrcode": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@types/qrcode/-/qrcode-1.5.0.tgz", + "integrity": "sha512-x5ilHXRxUPIMfjtM+1vf/GPTRWZ81nqscursm5gMznJeK9M0YnZ1c3bEvRLQ0zSSgedLx1J6MGL231ObQGGhaA==", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/qs": { + "version": "6.9.5", + "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.5.tgz", + "integrity": "sha512-/JHkVHtx/REVG0VVToGRGH2+23hsYLHdyG+GrvoUGlGAd0ErauXDyvHtRI/7H7mzLm+tBCKA7pfcpkQ1lf58iQ==" + }, + "node_modules/@types/range-parser": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.3.tgz", + "integrity": "sha512-ewFXqrQHlFsgc09MK5jP5iR7vumV/BYayNC6PgJO2LPe8vrnNFyjQjSppfEngITi0qvfKtzFvgKymGheFM9UOA==" + }, + "node_modules/@types/retry": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/@types/retry/-/retry-0.12.0.tgz", + "integrity": "sha512-wWKOClTTiizcZhXnPY4wikVAwmdYHp8q6DmC+EJUzAMsycb7HB32Kh9RN4+0gExjmPmZSAQjgURXIGATPegAvA==" + }, + "node_modules/@types/semver": { + "version": "7.5.8", + "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.5.8.tgz", + "integrity": "sha512-I8EUhyrgfLrcTkzV3TSsGyl1tSuPrEDzr0yd5m90UgNxQkyDXULk3b6MlQqTCpZpNtWe1K0hzclnZkTcLBe2UQ==", + "dev": true + }, + "node_modules/@types/serve-index": { + "version": "1.9.4", + "resolved": "https://registry.npmjs.org/@types/serve-index/-/serve-index-1.9.4.tgz", + "integrity": "sha512-qLpGZ/c2fhSs5gnYsQxtDEq3Oy8SXPClIXkW5ghvAvsNuVSA8k+gCONcUCS/UjLEYvYps+e8uBtfgXgvhwfNug==", + "dependencies": { + "@types/express": "*" + } + }, + "node_modules/@types/serve-static": { + "version": "1.15.0", + "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.15.0.tgz", + "integrity": "sha512-z5xyF6uh8CbjAu9760KDKsH2FcDxZ2tFCsA4HIMWE6IkiYMXfVoa+4f9KX+FN0ZLsaMw1WNG2ETLA6N+/YA+cg==", + "dependencies": { + "@types/mime": "*", + "@types/node": "*" + } + }, + "node_modules/@types/sinonjs__fake-timers": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/@types/sinonjs__fake-timers/-/sinonjs__fake-timers-8.1.1.tgz", + "integrity": "sha512-0kSuKjAS0TrGLJ0M/+8MaFkGsQhZpB6pxOmvS3K8FYI72K//YmdfoW9X2qPsAKh1mkwxGD5zib9s1FIFed6E8g==", + "optional": true + }, + "node_modules/@types/sizzle": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/@types/sizzle/-/sizzle-2.3.2.tgz", + "integrity": "sha512-7EJYyKTL7tFR8+gDbB6Wwz/arpGa0Mywk1TJbNzKzHtzbwVmY4HR9WqS5VV7dsBUKQmPNr192jHr/VpBluj/hg==", + "optional": true + }, + "node_modules/@types/sockjs": { + "version": "0.3.36", + "resolved": "https://registry.npmjs.org/@types/sockjs/-/sockjs-0.3.36.tgz", + "integrity": "sha512-MK9V6NzAS1+Ud7JV9lJLFqW85VbC9dq3LmwZCuBe4wBDgKC0Kj/jd8Xl+nSviU+Qc3+m7umHHyHg//2KSa0a0Q==", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/ws": { + "version": "8.5.10", + "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.5.10.tgz", + "integrity": "sha512-vmQSUcfalpIq0R9q7uTo2lXs6eGIpt9wtnLdMv9LVpIjCA/+ufZRozlVoVelIYixx1ugCBKDhn89vnsEGOCx9A==", + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@types/yauzl": { + "version": "2.10.0", + "resolved": "https://registry.npmjs.org/@types/yauzl/-/yauzl-2.10.0.tgz", + "integrity": "sha512-Cn6WYCm0tXv8p6k+A8PvbDG763EDpBoTzHdA+Q/MF6H3sapGjCm9NzoaJncJS9tUKSuCoDs9XHxYYsQDgxR6kw==", + "optional": true, + "dependencies": { + "@types/node": "*" + } + }, + "node_modules/@typescript-eslint/eslint-plugin": { + "version": "7.4.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-7.4.0.tgz", + "integrity": "sha512-yHMQ/oFaM7HZdVrVm/M2WHaNPgyuJH4WelkSVEWSSsir34kxW2kDJCxlXRhhGWEsMN0WAW/vLpKfKVcm8k+MPw==", + "dev": true, + "dependencies": { + "@eslint-community/regexpp": "^4.5.1", + "@typescript-eslint/scope-manager": "7.4.0", + "@typescript-eslint/type-utils": "7.4.0", + "@typescript-eslint/utils": "7.4.0", + "@typescript-eslint/visitor-keys": "7.4.0", + "debug": "^4.3.4", + "graphemer": "^1.4.0", + "ignore": "^5.2.4", + "natural-compare": "^1.4.0", + "semver": "^7.5.4", + "ts-api-utils": "^1.0.1" + }, + "engines": { + "node": "^18.18.0 || >=20.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "@typescript-eslint/parser": "^7.0.0", + "eslint": "^8.56.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/parser": { + "version": "7.4.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-7.4.0.tgz", + "integrity": "sha512-ZvKHxHLusweEUVwrGRXXUVzFgnWhigo4JurEj0dGF1tbcGh6buL+ejDdjxOQxv6ytcY1uhun1p2sm8iWStlgLQ==", + "dev": true, + "dependencies": { + "@typescript-eslint/scope-manager": "7.4.0", + "@typescript-eslint/types": "7.4.0", + "@typescript-eslint/typescript-estree": "7.4.0", + "@typescript-eslint/visitor-keys": "7.4.0", + "debug": "^4.3.4" + }, + "engines": { + "node": "^18.18.0 || >=20.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.56.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/scope-manager": { + "version": "7.4.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-7.4.0.tgz", + "integrity": "sha512-68VqENG5HK27ypafqLVs8qO+RkNc7TezCduYrx8YJpXq2QGZ30vmNZGJJJC48+MVn4G2dCV8m5ZTVnzRexTVtw==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "7.4.0", + "@typescript-eslint/visitor-keys": "7.4.0" + }, + "engines": { + "node": "^18.18.0 || >=20.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/type-utils": { + "version": "7.4.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-7.4.0.tgz", + "integrity": "sha512-247ETeHgr9WTRMqHbbQdzwzhuyaJ8dPTuyuUEMANqzMRB1rj/9qFIuIXK7l0FX9i9FXbHeBQl/4uz6mYuCE7Aw==", + "dev": true, + "dependencies": { + "@typescript-eslint/typescript-estree": "7.4.0", + "@typescript-eslint/utils": "7.4.0", + "debug": "^4.3.4", + "ts-api-utils": "^1.0.1" + }, + "engines": { + "node": "^18.18.0 || >=20.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.56.0" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/types": { + "version": "7.4.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.4.0.tgz", + "integrity": "sha512-mjQopsbffzJskos5B4HmbsadSJQWaRK0UxqQ7GuNA9Ga4bEKeiO6b2DnB6cM6bpc8lemaPseh0H9B/wyg+J7rw==", + "dev": true, + "engines": { + "node": "^18.18.0 || >=20.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@typescript-eslint/typescript-estree": { + "version": "7.4.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-7.4.0.tgz", + "integrity": "sha512-A99j5AYoME/UBQ1ucEbbMEmGkN7SE0BvZFreSnTd1luq7yulcHdyGamZKizU7canpGDWGJ+Q6ZA9SyQobipePg==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "7.4.0", + "@typescript-eslint/visitor-keys": "7.4.0", + "debug": "^4.3.4", + "globby": "^11.1.0", + "is-glob": "^4.0.3", + "minimatch": "9.0.3", + "semver": "^7.5.4", + "ts-api-utils": "^1.0.1" + }, + "engines": { + "node": "^18.18.0 || >=20.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/globby": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", + "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", + "dev": true, + "dependencies": { + "array-union": "^2.1.0", + "dir-glob": "^3.0.1", + "fast-glob": "^3.2.9", + "ignore": "^5.2.0", + "merge2": "^1.4.1", + "slash": "^3.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/minimatch": { + "version": "9.0.3", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.3.tgz", + "integrity": "sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==", + "dev": true, + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/@typescript-eslint/typescript-estree/node_modules/slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/@typescript-eslint/utils": { + "version": "7.4.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-7.4.0.tgz", + "integrity": "sha512-NQt9QLM4Tt8qrlBVY9lkMYzfYtNz8/6qwZg8pI3cMGlPnj6mOpRxxAm7BMJN9K0AiY+1BwJ5lVC650YJqYOuNg==", + "dev": true, + "dependencies": { + "@eslint-community/eslint-utils": "^4.4.0", + "@types/json-schema": "^7.0.12", + "@types/semver": "^7.5.0", + "@typescript-eslint/scope-manager": "7.4.0", + "@typescript-eslint/types": "7.4.0", + "@typescript-eslint/typescript-estree": "7.4.0", + "semver": "^7.5.4" + }, + "engines": { + "node": "^18.18.0 || >=20.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + }, + "peerDependencies": { + "eslint": "^8.56.0" + } + }, + "node_modules/@typescript-eslint/visitor-keys": { + "version": "7.4.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-7.4.0.tgz", + "integrity": "sha512-0zkC7YM0iX5Y41homUUeW1CHtZR01K3ybjM1l6QczoMuay0XKtrb93kv95AxUGwdjGr64nNqnOCwmEl616N8CA==", + "dev": true, + "dependencies": { + "@typescript-eslint/types": "7.4.0", + "eslint-visitor-keys": "^3.4.1" + }, + "engines": { + "node": "^18.18.0 || >=20.0.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/typescript-eslint" + } + }, + "node_modules/@ungap/structured-clone": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.2.0.tgz", + "integrity": "sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==", + "dev": true + }, + "node_modules/@vitejs/plugin-basic-ssl": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@vitejs/plugin-basic-ssl/-/plugin-basic-ssl-1.1.0.tgz", + "integrity": "sha512-wO4Dk/rm8u7RNhOf95ZzcEmC9rYOncYgvq4z3duaJrCgjN8BxAnDVyndanfcJZ0O6XZzHz6Q0hTimxTg8Y9g/A==", + "engines": { + "node": ">=14.6.0" + }, + "peerDependencies": { + "vite": "^3.0.0 || ^4.0.0 || ^5.0.0" + } + }, + "node_modules/@webassemblyjs/ast": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.11.6.tgz", + "integrity": "sha512-IN1xI7PwOvLPgjcf180gC1bqn3q/QaOCwYUahIOhbYUu8KA/3tw2RT/T0Gidi1l7Hhj5D/INhJxiICObqpMu4Q==", + "dependencies": { + "@webassemblyjs/helper-numbers": "1.11.6", + "@webassemblyjs/helper-wasm-bytecode": "1.11.6" + } + }, + "node_modules/@webassemblyjs/floating-point-hex-parser": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.11.6.tgz", + "integrity": "sha512-ejAj9hfRJ2XMsNHk/v6Fu2dGS+i4UaXBXGemOfQ/JfQ6mdQg/WXtwleQRLLS4OvfDhv8rYnVwH27YJLMyYsxhw==" + }, + "node_modules/@webassemblyjs/helper-api-error": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-api-error/-/helper-api-error-1.11.6.tgz", + "integrity": "sha512-o0YkoP4pVu4rN8aTJgAyj9hC2Sv5UlkzCHhxqWj8butaLvnpdc2jOwh4ewE6CX0txSfLn/UYaV/pheS2Txg//Q==" + }, + "node_modules/@webassemblyjs/helper-buffer": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-buffer/-/helper-buffer-1.11.6.tgz", + "integrity": "sha512-z3nFzdcp1mb8nEOFFk8DrYLpHvhKC3grJD2ardfKOzmbmJvEf/tPIqCY+sNcwZIY8ZD7IkB2l7/pqhUhqm7hLA==" + }, + "node_modules/@webassemblyjs/helper-numbers": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-numbers/-/helper-numbers-1.11.6.tgz", + "integrity": "sha512-vUIhZ8LZoIWHBohiEObxVm6hwP034jwmc9kuq5GdHZH0wiLVLIPcMCdpJzG4C11cHoQ25TFIQj9kaVADVX7N3g==", + "dependencies": { + "@webassemblyjs/floating-point-hex-parser": "1.11.6", + "@webassemblyjs/helper-api-error": "1.11.6", + "@xtuc/long": "4.2.2" + } + }, + "node_modules/@webassemblyjs/helper-wasm-bytecode": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.11.6.tgz", + "integrity": "sha512-sFFHKwcmBprO9e7Icf0+gddyWYDViL8bpPjJJl0WHxCdETktXdmtWLGVzoHbqUcY4Be1LkNfwTmXOJUFZYSJdA==" + }, + "node_modules/@webassemblyjs/helper-wasm-section": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.11.6.tgz", + "integrity": "sha512-LPpZbSOwTpEC2cgn4hTydySy1Ke+XEu+ETXuoyvuyezHO3Kjdu90KK95Sh9xTbmjrCsUwvWwCOQQNta37VrS9g==", + "dependencies": { + "@webassemblyjs/ast": "1.11.6", + "@webassemblyjs/helper-buffer": "1.11.6", + "@webassemblyjs/helper-wasm-bytecode": "1.11.6", + "@webassemblyjs/wasm-gen": "1.11.6" + } + }, + "node_modules/@webassemblyjs/ieee754": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/ieee754/-/ieee754-1.11.6.tgz", + "integrity": "sha512-LM4p2csPNvbij6U1f19v6WR56QZ8JcHg3QIJTlSwzFcmx6WSORicYj6I63f9yU1kEUtrpG+kjkiIAkevHpDXrg==", + "dependencies": { + "@xtuc/ieee754": "^1.2.0" + } + }, + "node_modules/@webassemblyjs/leb128": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/leb128/-/leb128-1.11.6.tgz", + "integrity": "sha512-m7a0FhE67DQXgouf1tbN5XQcdWoNgaAuoULHIfGFIEVKA6tu/edls6XnIlkmS6FrXAquJRPni3ZZKjw6FSPjPQ==", + "dependencies": { + "@xtuc/long": "4.2.2" + } + }, + "node_modules/@webassemblyjs/utf8": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/utf8/-/utf8-1.11.6.tgz", + "integrity": "sha512-vtXf2wTQ3+up9Zsg8sa2yWiQpzSsMyXj0qViVP6xKGCUT8p8YJ6HqI7l5eCnWx1T/FYdsv07HQs2wTFbbof/RA==" + }, + "node_modules/@webassemblyjs/wasm-edit": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-edit/-/wasm-edit-1.11.6.tgz", + "integrity": "sha512-Ybn2I6fnfIGuCR+Faaz7YcvtBKxvoLV3Lebn1tM4o/IAJzmi9AWYIPWpyBfU8cC+JxAO57bk4+zdsTjJR+VTOw==", + "dependencies": { + "@webassemblyjs/ast": "1.11.6", + "@webassemblyjs/helper-buffer": "1.11.6", + "@webassemblyjs/helper-wasm-bytecode": "1.11.6", + "@webassemblyjs/helper-wasm-section": "1.11.6", + "@webassemblyjs/wasm-gen": "1.11.6", + "@webassemblyjs/wasm-opt": "1.11.6", + "@webassemblyjs/wasm-parser": "1.11.6", + "@webassemblyjs/wast-printer": "1.11.6" + } + }, + "node_modules/@webassemblyjs/wasm-gen": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-gen/-/wasm-gen-1.11.6.tgz", + "integrity": "sha512-3XOqkZP/y6B4F0PBAXvI1/bky7GryoogUtfwExeP/v7Nzwo1QLcq5oQmpKlftZLbT+ERUOAZVQjuNVak6UXjPA==", + "dependencies": { + "@webassemblyjs/ast": "1.11.6", + "@webassemblyjs/helper-wasm-bytecode": "1.11.6", + "@webassemblyjs/ieee754": "1.11.6", + "@webassemblyjs/leb128": "1.11.6", + "@webassemblyjs/utf8": "1.11.6" + } + }, + "node_modules/@webassemblyjs/wasm-opt": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-opt/-/wasm-opt-1.11.6.tgz", + "integrity": "sha512-cOrKuLRE7PCe6AsOVl7WasYf3wbSo4CeOk6PkrjS7g57MFfVUF9u6ysQBBODX0LdgSvQqRiGz3CXvIDKcPNy4g==", + "dependencies": { + "@webassemblyjs/ast": "1.11.6", + "@webassemblyjs/helper-buffer": "1.11.6", + "@webassemblyjs/wasm-gen": "1.11.6", + "@webassemblyjs/wasm-parser": "1.11.6" + } + }, + "node_modules/@webassemblyjs/wasm-parser": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-parser/-/wasm-parser-1.11.6.tgz", + "integrity": "sha512-6ZwPeGzMJM3Dqp3hCsLgESxBGtT/OeCvCZ4TA1JUPYgmhAx38tTPR9JaKy0S5H3evQpO/h2uWs2j6Yc/fjkpTQ==", + "dependencies": { + "@webassemblyjs/ast": "1.11.6", + "@webassemblyjs/helper-api-error": "1.11.6", + "@webassemblyjs/helper-wasm-bytecode": "1.11.6", + "@webassemblyjs/ieee754": "1.11.6", + "@webassemblyjs/leb128": "1.11.6", + "@webassemblyjs/utf8": "1.11.6" + } + }, + "node_modules/@webassemblyjs/wast-printer": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-printer/-/wast-printer-1.11.6.tgz", + "integrity": "sha512-JM7AhRcE+yW2GWYaKeHL5vt4xqee5N2WcezptmgyhNS+ScggqcT1OtXykhAb13Sn5Yas0j2uv9tHgrjwvzAP4A==", + "dependencies": { + "@webassemblyjs/ast": "1.11.6", + "@xtuc/long": "4.2.2" + } + }, + "node_modules/@xtuc/ieee754": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@xtuc/ieee754/-/ieee754-1.2.0.tgz", + "integrity": "sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA==" + }, + "node_modules/@xtuc/long": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/@xtuc/long/-/long-4.2.2.tgz", + "integrity": "sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==" + }, + "node_modules/@yarnpkg/lockfile": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@yarnpkg/lockfile/-/lockfile-1.1.0.tgz", + "integrity": "sha512-GpSwvyXOcOOlV70vbnzjj4fW5xW/FdUF6nQEt1ENy7m4ZCczi1+/buVUPAqmGfqznsORNFzUMjctTIp8a9tuCQ==" + }, + "node_modules/abbrev": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-2.0.0.tgz", + "integrity": "sha512-6/mh1E2u2YgEsCHdY0Yx5oW+61gZU+1vXaoiHHrpKeuRNNgFvS+/jrwHiQhB5apAf5oB7UB7E19ol2R2LKH8hQ==", + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/accepts": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", + "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==", + "dependencies": { + "mime-types": "~2.1.34", + "negotiator": "0.6.3" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/acorn": { + "version": "7.4.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz", + "integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==", + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/acorn-jsx": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", + "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", + "dev": true, + "peerDependencies": { + "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" + } + }, + "node_modules/acorn-node": { + "version": "1.8.2", + "resolved": "https://registry.npmjs.org/acorn-node/-/acorn-node-1.8.2.tgz", + "integrity": "sha512-8mt+fslDufLYntIoPAaIMUe/lrbrehIiwmR3t2k9LljIzoigEPF27eLk2hy8zSGzmR/ogr7zbRKINMo1u0yh5A==", + "dependencies": { + "acorn": "^7.0.0", + "acorn-walk": "^7.0.0", + "xtend": "^4.0.2" + } + }, + "node_modules/acorn-walk": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-7.2.0.tgz", + "integrity": "sha512-OPdCF6GsMIP+Az+aWfAAOEt2/+iVDKE7oy6lJ098aoe59oAmK76qV6Gw60SbZ8jHuG2wH058GF4pLFbYamYrVA==", + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/adjust-sourcemap-loader": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/adjust-sourcemap-loader/-/adjust-sourcemap-loader-4.0.0.tgz", + "integrity": "sha512-OXwN5b9pCUXNQHJpwwD2qP40byEmSgzj8B4ydSN0uMNYWiFmJ6x6KwUllMmfk8Rwu/HJDFR7U8ubsWBoN0Xp0A==", + "dependencies": { + "loader-utils": "^2.0.0", + "regex-parser": "^2.2.11" + }, + "engines": { + "node": ">=8.9" + } + }, + "node_modules/agent-base": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.0.tgz", + "integrity": "sha512-o/zjMZRhJxny7OyEF+Op8X+efiELC7k7yOjMzgfzVqOzXqkBkWI79YoTdOtsuWd5BWhAGAuOY/Xa6xpiaWXiNg==", + "dependencies": { + "debug": "^4.3.4" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/aggregate-error": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-3.1.0.tgz", + "integrity": "sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==", + "dependencies": { + "clean-stack": "^2.0.0", + "indent-string": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "dependencies": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/ajv-formats": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-2.1.1.tgz", + "integrity": "sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA==", + "dependencies": { + "ajv": "^8.0.0" + }, + "peerDependencies": { + "ajv": "^8.0.0" + }, + "peerDependenciesMeta": { + "ajv": { + "optional": true + } + } + }, + "node_modules/ajv-formats/node_modules/ajv": { + "version": "8.11.2", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.11.2.tgz", + "integrity": "sha512-E4bfmKAhGiSTvMfL1Myyycaub+cUEU2/IvpylXkUu7CHBkBj1f/ikdzbD7YQ6FKUbixDxeYvB/xY4fvyroDlQg==", + "dependencies": { + "fast-deep-equal": "^3.1.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/ajv-formats/node_modules/json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==" + }, + "node_modules/ajv-keywords": { + "version": "3.5.2", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz", + "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==", + "peerDependencies": { + "ajv": "^6.9.1" + } + }, + "node_modules/amdefine": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/amdefine/-/amdefine-1.0.1.tgz", + "integrity": "sha512-S2Hw0TtNkMJhIabBwIojKL9YHO5T0n5eNqWJ7Lrlel/zDbftQpxpapi8tZs3X1HWa+u+QeydGmzzNU0m09+Rcg==", + "engines": { + "node": ">=0.4.2" + } + }, + "node_modules/ansi-colors": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.3.tgz", + "integrity": "sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw==", + "engines": { + "node": ">=6" + } + }, + "node_modules/ansi-escapes": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", + "integrity": "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==", + "dependencies": { + "type-fest": "^0.21.3" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/ansi-html-community": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/ansi-html-community/-/ansi-html-community-0.0.8.tgz", + "integrity": "sha512-1APHAyr3+PCamwNw3bXCPp4HFLONZt/yIH0sZp0/469KWNTEy+qN5jQ3GVX6DMZ1UXAi34yVwtTeaG/HpBuuzw==", + "engines": [ + "node >= 0.8.0" + ], + "bin": { + "ansi-html": "bin/ansi-html" + } + }, + "node_modules/ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==", + "engines": { + "node": ">=8" + } + }, + "node_modules/ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dependencies": { + "color-convert": "^1.9.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/anymatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.2.tgz", + "integrity": "sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg==", + "dependencies": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/arch": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/arch/-/arch-2.2.0.tgz", + "integrity": "sha512-Of/R0wqp83cgHozfIYLbBMnej79U/SVGOOyuB3VVFv1NRM/PSFMK12x9KVtiYzJqmnU5WR2qp0Z5rHb7sWGnFQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "optional": true + }, + "node_modules/arg": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", + "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==", + "dev": true + }, + "node_modules/argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "dependencies": { + "sprintf-js": "~1.0.2" + } + }, + "node_modules/argparse/node_modules/sprintf-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=" + }, + "node_modules/array-filter": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/array-filter/-/array-filter-1.0.0.tgz", + "integrity": "sha1-uveeYubvTCpMC4MSMtr/7CUfnYM=" + }, + "node_modules/array-flatten": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", + "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==" + }, + "node_modules/array-from": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/array-from/-/array-from-2.1.1.tgz", + "integrity": "sha1-z+nYwmYoudxa7MYqn12PHzUsEZU=" + }, + "node_modules/array-union": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", + "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/asn1": { + "version": "0.2.6", + "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.6.tgz", + "integrity": "sha512-ix/FxPn0MDjeyJ7i/yoHGFt/EX6LyNbxSEhPPXODPL+KB0VPk86UYfL0lMdy+KCnv+fmvIzySwaK5COwqVbWTQ==", + "optional": true, + "dependencies": { + "safer-buffer": "~2.1.0" + } + }, + "node_modules/asn1.js": { + "version": "5.4.1", + "resolved": "https://registry.npmjs.org/asn1.js/-/asn1.js-5.4.1.tgz", + "integrity": "sha512-+I//4cYPccV8LdmBLiX8CYvf9Sp3vQsrqu2QNXRcrbiWvcx/UdlFiqUJJzxRQxgsZmvhXhn4cSKeSmoFjVdupA==", + "dependencies": { + "bn.js": "^4.0.0", + "inherits": "^2.0.1", + "minimalistic-assert": "^1.0.0", + "safer-buffer": "^2.1.0" + } + }, + "node_modules/asn1.js/node_modules/bn.js": { + "version": "4.12.0", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", + "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==" + }, + "node_modules/assert": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/assert/-/assert-1.5.0.tgz", + "integrity": "sha512-EDsgawzwoun2CZkCgtxJbv392v4nbk9XDD06zI+kQYoBM/3RBWLlEyJARDOmhAAosBjWACEkKL6S+lIZtcAubA==", + "dependencies": { + "object-assign": "^4.1.1", + "util": "0.10.3" + } + }, + "node_modules/assert-plus": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", + "integrity": "sha512-NfJ4UzBCcQGLDlQq7nHxH+tv3kyZ0hHQqF5BO6J7tNJeP5do1llPr8dZ8zHonfhAu0PHAdMkSo+8o0wxg9lZWw==", + "optional": true, + "engines": { + "node": ">=0.8" + } + }, + "node_modules/assert/node_modules/inherits": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.1.tgz", + "integrity": "sha1-sX0I0ya0Qj5Wjv9xn5GwscvfafE=" + }, + "node_modules/assert/node_modules/util": { + "version": "0.10.3", + "resolved": "https://registry.npmjs.org/util/-/util-0.10.3.tgz", + "integrity": "sha1-evsa/lCAUkZInj23/g7TeTNqwPk=", + "dependencies": { + "inherits": "2.0.1" + } + }, + "node_modules/assertion-error": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-1.1.0.tgz", + "integrity": "sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==", + "optional": true, + "engines": { + "node": "*" + } + }, + "node_modules/astral-regex": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-2.0.0.tgz", + "integrity": "sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==", + "optional": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/async": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/async/-/async-3.2.4.tgz", + "integrity": "sha512-iAB+JbDEGXhyIUavoDl9WP/Jj106Kz9DEn1DPgYw5ruDn0e3Wgi3sKFm55sASdGBNOQB8F59d9qQ7deqrHA8wQ==", + "optional": true + }, + "node_modules/async-each-series": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/async-each-series/-/async-each-series-0.1.1.tgz", + "integrity": "sha512-p4jj6Fws4Iy2m0iCmI2am2ZNZCgbdgE+P8F/8csmn2vx7ixXrO2zGcuNsD46X5uZSVecmkEy/M06X2vG8KD6dQ==", + "devOptional": true, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", + "optional": true + }, + "node_modules/at-least-node": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/at-least-node/-/at-least-node-1.0.0.tgz", + "integrity": "sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg==", + "optional": true, + "engines": { + "node": ">= 4.0.0" + } + }, + "node_modules/autoprefixer": { + "version": "10.4.18", + "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.18.tgz", + "integrity": "sha512-1DKbDfsr6KUElM6wg+0zRNkB/Q7WcKYAaK+pzXn+Xqmszm/5Xa9coeNdtP88Vi+dPzZnMjhge8GIV49ZQkDa+g==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/autoprefixer" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "dependencies": { + "browserslist": "^4.23.0", + "caniuse-lite": "^1.0.30001591", + "fraction.js": "^4.3.7", + "normalize-range": "^0.1.2", + "picocolors": "^1.0.0", + "postcss-value-parser": "^4.2.0" + }, + "bin": { + "autoprefixer": "bin/autoprefixer" + }, + "engines": { + "node": "^10 || ^12 || >=14" + }, + "peerDependencies": { + "postcss": "^8.1.0" + } + }, + "node_modules/available-typed-arrays": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.2.tgz", + "integrity": "sha512-XWX3OX8Onv97LMk/ftVyBibpGwY5a8SmuxZPzeOxqmuEqUCOM9ZE+uIaD1VNJ5QnvU2UQusvmKbuM1FR8QWGfQ==", + "dependencies": { + "array-filter": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/aws-sign2": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz", + "integrity": "sha512-08kcGqnYf/YmjoRhfxyu+CLxBjUtHLXLXX/vUfx9l2LYzG3c1m61nrpyFUZI6zeS+Li/wWMMidD9KgrqtGq3mA==", + "optional": true, + "engines": { + "node": "*" + } + }, + "node_modules/aws4": { + "version": "1.12.0", + "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.12.0.tgz", + "integrity": "sha512-NmWvPnx0F1SfrQbYwOi7OeaNGokp9XhzNioJ/CSBs8Qa4vxug81mhJEAVZwxXuBmYB5KDRfMq/F3RR0BIU7sWg==", + "optional": true + }, + "node_modules/axios": { + "version": "0.24.0", + "resolved": "https://registry.npmjs.org/axios/-/axios-0.24.0.tgz", + "integrity": "sha512-Q6cWsys88HoPgAaFAVUb0WpPk0O8iTeisR9IMqy9G8AbO4NlpVknrnQS03zzF9PGAWgO3cgletO3VjV/P7VztA==", + "dependencies": { + "follow-redirects": "^1.14.4" + } + }, + "node_modules/babel-loader": { + "version": "9.1.3", + "resolved": "https://registry.npmjs.org/babel-loader/-/babel-loader-9.1.3.tgz", + "integrity": "sha512-xG3ST4DglodGf8qSwv0MdeWLhrDsw/32QMdTO5T1ZIp9gQur0HkCyFs7Awskr10JKXFXwpAhiCuYX5oGXnRGbw==", + "dependencies": { + "find-cache-dir": "^4.0.0", + "schema-utils": "^4.0.0" + }, + "engines": { + "node": ">= 14.15.0" + }, + "peerDependencies": { + "@babel/core": "^7.12.0", + "webpack": ">=5" + } + }, + "node_modules/babel-plugin-istanbul": { + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-6.1.1.tgz", + "integrity": "sha512-Y1IQok9821cC9onCx5otgFfRm7Lm+I+wwxOx738M/WLPZ9Q42m4IG5W0FNX8WLL2gYMZo3JkuXIH2DOpWM+qwA==", + "dependencies": { + "@babel/helper-plugin-utils": "^7.0.0", + "@istanbuljs/load-nyc-config": "^1.0.0", + "@istanbuljs/schema": "^0.1.2", + "istanbul-lib-instrument": "^5.0.4", + "test-exclude": "^6.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/babel-plugin-polyfill-corejs2": { + "version": "0.4.10", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.4.10.tgz", + "integrity": "sha512-rpIuu//y5OX6jVU+a5BCn1R5RSZYWAl2Nar76iwaOdycqb6JPxediskWFMMl7stfwNJR4b7eiQvh5fB5TEQJTQ==", + "dependencies": { + "@babel/compat-data": "^7.22.6", + "@babel/helper-define-polyfill-provider": "^0.6.1", + "semver": "^6.3.1" + }, + "peerDependencies": { + "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" + } + }, + "node_modules/babel-plugin-polyfill-corejs2/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/babel-plugin-polyfill-corejs3": { + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.9.0.tgz", + "integrity": "sha512-7nZPG1uzK2Ymhy/NbaOWTg3uibM2BmGASS4vHS4szRZAIR8R6GwA/xAujpdrXU5iyklrimWnLWU+BLF9suPTqg==", + "dependencies": { + "@babel/helper-define-polyfill-provider": "^0.5.0", + "core-js-compat": "^3.34.0" + }, + "peerDependencies": { + "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" + } + }, + "node_modules/babel-plugin-polyfill-corejs3/node_modules/@babel/helper-define-polyfill-provider": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.5.0.tgz", + "integrity": "sha512-NovQquuQLAQ5HuyjCz7WQP9MjRj7dx++yspwiyUiGl9ZyadHRSql1HZh5ogRd8W8w6YM6EQ/NTB8rgjLt5W65Q==", + "dependencies": { + "@babel/helper-compilation-targets": "^7.22.6", + "@babel/helper-plugin-utils": "^7.22.5", + "debug": "^4.1.1", + "lodash.debounce": "^4.0.8", + "resolve": "^1.14.2" + }, + "peerDependencies": { + "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" + } + }, + "node_modules/babel-plugin-polyfill-regenerator": { + "version": "0.5.5", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.5.5.tgz", + "integrity": "sha512-OJGYZlhLqBh2DDHeqAxWB1XIvr49CxiJ2gIt61/PU55CQK4Z58OzMqjDe1zwQdQk+rBYsRc+1rJmdajM3gimHg==", + "dependencies": { + "@babel/helper-define-polyfill-provider": "^0.5.0" + }, + "peerDependencies": { + "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" + } + }, + "node_modules/babel-plugin-polyfill-regenerator/node_modules/@babel/helper-define-polyfill-provider": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.5.0.tgz", + "integrity": "sha512-NovQquuQLAQ5HuyjCz7WQP9MjRj7dx++yspwiyUiGl9ZyadHRSql1HZh5ogRd8W8w6YM6EQ/NTB8rgjLt5W65Q==", + "dependencies": { + "@babel/helper-compilation-targets": "^7.22.6", + "@babel/helper-plugin-utils": "^7.22.5", + "debug": "^4.1.1", + "lodash.debounce": "^4.0.8", + "resolve": "^1.14.2" + }, + "peerDependencies": { + "@babel/core": "^7.4.0 || ^8.0.0-0 <8.0.0" + } + }, + "node_modules/balanced-match": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", + "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=" + }, + "node_modules/base64-js": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/base64id": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/base64id/-/base64id-2.0.0.tgz", + "integrity": "sha512-lGe34o6EHj9y3Kts9R4ZYs/Gr+6N7MCaMlIFA3F1R2O5/m7K06AxfSeO5530PEERE6/WyEg3lsuyw4GHlPZHog==", + "devOptional": true, + "engines": { + "node": "^4.5.0 || >= 5.9" + } + }, + "node_modules/batch": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/batch/-/batch-0.6.1.tgz", + "integrity": "sha512-x+VAiMRL6UPkx+kudNvxTl6hB2XNNCG2r+7wixVfIYwu/2HKRXimwQyaumLjMveWvT2Hkd/cAJw+QBMfJ/EKVw==" + }, + "node_modules/bcrypt-pbkdf": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz", + "integrity": "sha512-qeFIXtP4MSoi6NLqO12WfqARWWuCKi2Rn/9hJLEmtB5yTNr9DqFWkJRCf2qShWzPeAMRnOgCrq0sg/KLv5ES9w==", + "optional": true, + "dependencies": { + "tweetnacl": "^0.14.3" + } + }, + "node_modules/big.js": { + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/big.js/-/big.js-5.2.2.tgz", + "integrity": "sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ==", + "engines": { + "node": "*" + } + }, + "node_modules/binary-extensions": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.1.0.tgz", + "integrity": "sha512-1Yj8h9Q+QDF5FzhMs/c9+6UntbD5MkRfRwac8DoEm9ZfUBZ7tZ55YcGVAzEe4bXsdQHEk+s9S5wsOKVdZrw0tQ==", + "engines": { + "node": ">=8" + } + }, + "node_modules/bl": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz", + "integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==", + "dependencies": { + "buffer": "^5.5.0", + "inherits": "^2.0.4", + "readable-stream": "^3.4.0" + } + }, + "node_modules/bl/node_modules/readable-stream": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", + "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/blob-util": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/blob-util/-/blob-util-2.0.2.tgz", + "integrity": "sha512-T7JQa+zsXXEa6/8ZhHcQEW1UFfVM49Ts65uBkFL6fz2QmrElqmbajIDJvuA0tEhRe5eIjpV9ZF+0RfZR9voJFQ==", + "optional": true + }, + "node_modules/bluebird": { + "version": "3.7.2", + "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz", + "integrity": "sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==", + "optional": true + }, + "node_modules/bn.js": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-5.2.1.tgz", + "integrity": "sha512-eXRvHzWyYPBuB4NBy0cmYQjGitUrtqwbvlzP3G6VFnNRbsZQIxQ10PbKKHt8gZ/HW/D/747aDl+QkDqg3KQLMQ==" + }, + "node_modules/body-parser": { + "version": "1.20.2", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.2.tgz", + "integrity": "sha512-ml9pReCu3M61kGlqoTm2umSXTlRTuGTx0bfYj+uIUKKYycG5NtSbeetV3faSU6R7ajOPw0g/J1PvK4qNy7s5bA==", + "dependencies": { + "bytes": "3.1.2", + "content-type": "~1.0.5", + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "1.2.0", + "http-errors": "2.0.0", + "iconv-lite": "0.4.24", + "on-finished": "2.4.1", + "qs": "6.11.0", + "raw-body": "2.5.2", + "type-is": "~1.6.18", + "unpipe": "1.0.0" + }, + "engines": { + "node": ">= 0.8", + "npm": "1.2.8000 || >= 1.4.16" + } + }, + "node_modules/body-parser/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/body-parser/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" + }, + "node_modules/body-parser/node_modules/on-finished": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", + "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", + "dependencies": { + "ee-first": "1.1.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/body-parser/node_modules/qs": { + "version": "6.11.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz", + "integrity": "sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==", + "dependencies": { + "side-channel": "^1.0.4" + }, + "engines": { + "node": ">=0.6" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/bonjour-service": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/bonjour-service/-/bonjour-service-1.2.1.tgz", + "integrity": "sha512-oSzCS2zV14bh2kji6vNe7vrpJYCHGvcZnlffFQ1MEoX/WOeQ/teD8SYWKR942OI3INjq8OMNJlbPK5LLLUxFDw==", + "dependencies": { + "fast-deep-equal": "^3.1.3", + "multicast-dns": "^7.2.5" + } + }, + "node_modules/boolbase": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz", + "integrity": "sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==" + }, + "node_modules/bootstrap": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/bootstrap/-/bootstrap-4.6.2.tgz", + "integrity": "sha512-51Bbp/Uxr9aTuy6ca/8FbFloBUJZLHwnhTcnjIeRn2suQWsWzcuJhGjKDB5eppVte/8oCdOL3VuwxvZDUggwGQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/twbs" + }, + { + "type": "opencollective", + "url": "https://opencollective.com/bootstrap" + } + ], + "peerDependencies": { + "jquery": "1.9.1 - 3", + "popper.js": "^1.16.1" + } + }, + "node_modules/brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dependencies": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "node_modules/braces": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", + "dependencies": { + "fill-range": "^7.1.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/brorand": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/brorand/-/brorand-1.1.0.tgz", + "integrity": "sha1-EsJe/kCkXjwyPrhnWgoM5XsiNx8=" + }, + "node_modules/browser-pack": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/browser-pack/-/browser-pack-6.1.0.tgz", + "integrity": "sha512-erYug8XoqzU3IfcU8fUgyHqyOXqIE4tUTTQ+7mqUjQlvnXkOO6OlT9c/ZoJVHYoAaqGxr09CN53G7XIsO4KtWA==", + "dependencies": { + "combine-source-map": "~0.8.0", + "defined": "^1.0.0", + "JSONStream": "^1.0.3", + "safe-buffer": "^5.1.1", + "through2": "^2.0.0", + "umd": "^3.0.0" + }, + "bin": { + "browser-pack": "bin/cmd.js" + } + }, + "node_modules/browser-pack-flat": { + "version": "3.4.2", + "resolved": "https://registry.npmjs.org/browser-pack-flat/-/browser-pack-flat-3.4.2.tgz", + "integrity": "sha512-TrUo6n2fGSOCYFAKkt/EkgenytAuuCI88fmXFA60aNFVHvz3CZEBTXYSvvXVpU6xpjM8lj/6vkC6Exn8KPjtPw==", + "dependencies": { + "combine-source-map": "^0.8.0", + "convert-source-map": "^1.5.1", + "count-lines": "^0.1.2", + "dedent": "^0.7.0", + "estree-is-member-expression": "^1.0.0", + "estree-is-require": "^1.0.0", + "esutils": "^2.0.2", + "JSONStream": "^1.3.2", + "path-parse": "^1.0.5", + "scope-analyzer": "^2.0.0", + "stream-combiner": "^0.2.2", + "through2": "^2.0.3", + "transform-ast": "^2.4.2", + "umd": "^3.0.3", + "wrap-comment": "^1.0.0" + }, + "bin": { + "browser-pack-flat": "cli.js" + } + }, + "node_modules/browser-resolve": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/browser-resolve/-/browser-resolve-2.0.0.tgz", + "integrity": "sha512-7sWsQlYL2rGLy2IWm8WL8DCTJvYLc/qlOnsakDac87SOoCd16WLsaAMdCiAqsTNHIe+SXfaqyxyo6THoWqs8WQ==", + "dependencies": { + "resolve": "^1.17.0" + } + }, + "node_modules/browser-sync": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/browser-sync/-/browser-sync-3.0.2.tgz", + "integrity": "sha512-PC9c7aWJFVR4IFySrJxOqLwB9ENn3/TaXCXtAa0SzLwocLN3qMjN+IatbjvtCX92BjNXsY6YWg9Eb7F3Wy255g==", + "devOptional": true, + "dependencies": { + "browser-sync-client": "^3.0.2", + "browser-sync-ui": "^3.0.2", + "bs-recipes": "1.3.4", + "chalk": "4.1.2", + "chokidar": "^3.5.1", + "connect": "3.6.6", + "connect-history-api-fallback": "^1", + "dev-ip": "^1.0.1", + "easy-extender": "^2.3.4", + "eazy-logger": "^4.0.1", + "etag": "^1.8.1", + "fresh": "^0.5.2", + "fs-extra": "3.0.1", + "http-proxy": "^1.18.1", + "immutable": "^3", + "micromatch": "^4.0.2", + "opn": "5.3.0", + "portscanner": "2.2.0", + "raw-body": "^2.3.2", + "resp-modifier": "6.0.2", + "rx": "4.1.0", + "send": "0.16.2", + "serve-index": "1.9.1", + "serve-static": "1.13.2", + "server-destroy": "1.0.1", + "socket.io": "^4.4.1", + "ua-parser-js": "^1.0.33", + "yargs": "^17.3.1" + }, + "bin": { + "browser-sync": "dist/bin.js" + }, + "engines": { + "node": ">= 8.0.0" + } + }, + "node_modules/browser-sync-client": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/browser-sync-client/-/browser-sync-client-3.0.2.tgz", + "integrity": "sha512-tBWdfn9L0wd2Pjuz/NWHtNEKthVb1Y67vg8/qyGNtCqetNz5lkDkFnrsx5UhPNPYUO8vci50IWC/BhYaQskDiQ==", + "devOptional": true, + "dependencies": { + "etag": "1.8.1", + "fresh": "0.5.2", + "mitt": "^1.1.3" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/browser-sync-ui": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/browser-sync-ui/-/browser-sync-ui-3.0.2.tgz", + "integrity": "sha512-V3FwWAI+abVbFLTyJjXJlCMBwjc3GXf/BPGfwO2fMFACWbIGW9/4SrBOFYEOOtqzCjQE0Di+U3VIb7eES4omNA==", + "devOptional": true, + "dependencies": { + "async-each-series": "0.1.1", + "chalk": "4.1.2", + "connect-history-api-fallback": "^1", + "immutable": "^3", + "server-destroy": "1.0.1", + "socket.io-client": "^4.4.1", + "stream-throttle": "^0.1.3" + } + }, + "node_modules/browser-sync-ui/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "devOptional": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/browser-sync-ui/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "devOptional": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/browser-sync-ui/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "devOptional": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/browser-sync-ui/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "devOptional": true + }, + "node_modules/browser-sync-ui/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "devOptional": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/browser-sync-ui/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "devOptional": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/browser-sync/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "devOptional": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/browser-sync/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "devOptional": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/browser-sync/node_modules/cliui": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", + "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", + "devOptional": true, + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.1", + "wrap-ansi": "^7.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/browser-sync/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "devOptional": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/browser-sync/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "devOptional": true + }, + "node_modules/browser-sync/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "devOptional": true, + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/browser-sync/node_modules/depd": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", + "integrity": "sha512-7emPTl6Dpo6JRXOXjLRxck+FlLRX5847cLKEn00PLAgc3g2hTZZgr+e4c2v6QpSmLeFP3n5yUo7ft6avBK/5jQ==", + "devOptional": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/browser-sync/node_modules/destroy": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz", + "integrity": "sha512-3NdhDuEXnfun/z7x9GOElY49LoqVHoGScmOKwmxhsS8N5Y+Z8KyPPDnaSzqWgYt/ji4mqwfTS34Htrk0zPIXVg==", + "devOptional": true + }, + "node_modules/browser-sync/node_modules/fs-extra": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-3.0.1.tgz", + "integrity": "sha512-V3Z3WZWVUYd8hoCL5xfXJCaHWYzmtwW5XWYSlLgERi8PWd8bx1kUHUk8L1BT57e49oKnDDD180mjfrHc1yA9rg==", + "devOptional": true, + "dependencies": { + "graceful-fs": "^4.1.2", + "jsonfile": "^3.0.0", + "universalify": "^0.1.0" + } + }, + "node_modules/browser-sync/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "devOptional": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/browser-sync/node_modules/http-errors": { + "version": "1.6.3", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.6.3.tgz", + "integrity": "sha512-lks+lVC8dgGyh97jxvxeYTWQFvh4uw4yC12gVl63Cg30sjPX4wuGcdkICVXDAESr6OJGjqGA8Iz5mkeN6zlD7A==", + "devOptional": true, + "dependencies": { + "depd": "~1.1.2", + "inherits": "2.0.3", + "setprototypeof": "1.1.0", + "statuses": ">= 1.4.0 < 2" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/browser-sync/node_modules/inherits": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", + "integrity": "sha512-x00IRNXNy63jwGkJmzPigoySHbaqpNuzKbBOmzK+g2OdZpQ9w+sxCN+VSB3ja7IAge2OP2qpfxTjeNcyjmW1uw==", + "devOptional": true + }, + "node_modules/browser-sync/node_modules/jsonfile": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-3.0.1.tgz", + "integrity": "sha512-oBko6ZHlubVB5mRFkur5vgYR1UyqX+S6Y/oCfLhqNdcc2fYFlDpIoNc7AfKS1KOGcnNAkvsr0grLck9ANM815w==", + "devOptional": true, + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, + "node_modules/browser-sync/node_modules/mime": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.4.1.tgz", + "integrity": "sha512-KI1+qOZu5DcW6wayYHSzR/tXKCDC5Om4s1z2QJjDULzLcmf3DvzS7oluY4HCTrc+9FiKmWUgeNLg7W3uIQvxtQ==", + "devOptional": true, + "bin": { + "mime": "cli.js" + } + }, + "node_modules/browser-sync/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "devOptional": true + }, + "node_modules/browser-sync/node_modules/send": { + "version": "0.16.2", + "resolved": "https://registry.npmjs.org/send/-/send-0.16.2.tgz", + "integrity": "sha512-E64YFPUssFHEFBvpbbjr44NCLtI1AohxQ8ZSiJjQLskAdKuriYEP6VyGEsRDH8ScozGpkaX1BGvhanqCwkcEZw==", + "devOptional": true, + "dependencies": { + "debug": "2.6.9", + "depd": "~1.1.2", + "destroy": "~1.0.4", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "fresh": "0.5.2", + "http-errors": "~1.6.2", + "mime": "1.4.1", + "ms": "2.0.0", + "on-finished": "~2.3.0", + "range-parser": "~1.2.0", + "statuses": "~1.4.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/browser-sync/node_modules/serve-static": { + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.13.2.tgz", + "integrity": "sha512-p/tdJrO4U387R9oMjb1oj7qSMaMfmOyd4j9hOFoxZe2baQszgHcSWjuya/CiT5kgZZKRudHNOA0pYXOl8rQ5nw==", + "devOptional": true, + "dependencies": { + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "parseurl": "~1.3.2", + "send": "0.16.2" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/browser-sync/node_modules/setprototypeof": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.0.tgz", + "integrity": "sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ==", + "devOptional": true + }, + "node_modules/browser-sync/node_modules/statuses": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.4.0.tgz", + "integrity": "sha512-zhSCtt8v2NDrRlPQpCNtw/heZLtfUDqxBM1udqikb/Hbk52LK4nQSwr10u77iopCW5LsyHpuXS0GnEc48mLeew==", + "devOptional": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/browser-sync/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "devOptional": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/browser-sync/node_modules/ua-parser-js": { + "version": "1.0.36", + "resolved": "https://registry.npmjs.org/ua-parser-js/-/ua-parser-js-1.0.36.tgz", + "integrity": "sha512-znuyCIXzl8ciS3+y3fHJI/2OhQIXbXw9MWC/o3qwyR+RGppjZHrM27CGFSKCJXi2Kctiz537iOu2KnXs1lMQhw==", + "devOptional": true, + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/ua-parser-js" + }, + { + "type": "paypal", + "url": "https://paypal.me/faisalman" + }, + { + "type": "github", + "url": "https://github.com/sponsors/faisalman" + } + ], + "engines": { + "node": "*" + } + }, + "node_modules/browser-sync/node_modules/universalify": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", + "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==", + "devOptional": true, + "engines": { + "node": ">= 4.0.0" + } + }, + "node_modules/browser-sync/node_modules/wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "devOptional": true, + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/browser-sync/node_modules/y18n": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", + "devOptional": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/browser-sync/node_modules/yargs": { + "version": "17.7.2", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", + "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==", + "devOptional": true, + "dependencies": { + "cliui": "^8.0.1", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.3", + "y18n": "^5.0.5", + "yargs-parser": "^21.1.1" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/browser-sync/node_modules/yargs-parser": { + "version": "21.1.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", + "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", + "devOptional": true, + "engines": { + "node": ">=12" + } + }, + "node_modules/browser-unpack": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/browser-unpack/-/browser-unpack-1.4.2.tgz", + "integrity": "sha512-uHkiY4bmXjjBBWoKH1aRnEGTQxUUCCcVtoJfH9w1lmGGjETY4u93Zk+GRYkCE/SRMrdoMTINQ/1/manr/3aMVA==", + "dependencies": { + "acorn-node": "^1.5.2", + "concat-stream": "^1.5.0", + "minimist": "^1.1.1" + }, + "bin": { + "browser-unpack": "bin/cmd.js" + } + }, + "node_modules/browserify": { + "version": "17.0.0", + "resolved": "https://registry.npmjs.org/browserify/-/browserify-17.0.0.tgz", + "integrity": "sha512-SaHqzhku9v/j6XsQMRxPyBrSP3gnwmE27gLJYZgMT2GeK3J0+0toN+MnuNYDfHwVGQfLiMZ7KSNSIXHemy905w==", + "dependencies": { + "assert": "^1.4.0", + "browser-pack": "^6.0.1", + "browser-resolve": "^2.0.0", + "browserify-zlib": "~0.2.0", + "buffer": "~5.2.1", + "cached-path-relative": "^1.0.0", + "concat-stream": "^1.6.0", + "console-browserify": "^1.1.0", + "constants-browserify": "~1.0.0", + "crypto-browserify": "^3.0.0", + "defined": "^1.0.0", + "deps-sort": "^2.0.1", + "domain-browser": "^1.2.0", + "duplexer2": "~0.1.2", + "events": "^3.0.0", + "glob": "^7.1.0", + "has": "^1.0.0", + "htmlescape": "^1.1.0", + "https-browserify": "^1.0.0", + "inherits": "~2.0.1", + "insert-module-globals": "^7.2.1", + "JSONStream": "^1.0.3", + "labeled-stream-splicer": "^2.0.0", + "mkdirp-classic": "^0.5.2", + "module-deps": "^6.2.3", + "os-browserify": "~0.3.0", + "parents": "^1.0.1", + "path-browserify": "^1.0.0", + "process": "~0.11.0", + "punycode": "^1.3.2", + "querystring-es3": "~0.2.0", + "read-only-stream": "^2.0.0", + "readable-stream": "^2.0.2", + "resolve": "^1.1.4", + "shasum-object": "^1.0.0", + "shell-quote": "^1.6.1", + "stream-browserify": "^3.0.0", + "stream-http": "^3.0.0", + "string_decoder": "^1.1.1", + "subarg": "^1.0.0", + "syntax-error": "^1.1.1", + "through2": "^2.0.0", + "timers-browserify": "^1.0.1", + "tty-browserify": "0.0.1", + "url": "~0.11.0", + "util": "~0.12.0", + "vm-browserify": "^1.0.0", + "xtend": "^4.0.0" + }, + "bin": { + "browserify": "bin/cmd.js" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/browserify-aes": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/browserify-aes/-/browserify-aes-1.2.0.tgz", + "integrity": "sha512-+7CHXqGuspUn/Sl5aO7Ea0xWGAtETPXNSAjHo48JfLdPWcMng33Xe4znFvQweqc/uzk5zSOI3H52CYnjCfb5hA==", + "dependencies": { + "buffer-xor": "^1.0.3", + "cipher-base": "^1.0.0", + "create-hash": "^1.1.0", + "evp_bytestokey": "^1.0.3", + "inherits": "^2.0.1", + "safe-buffer": "^5.0.1" + } + }, + "node_modules/browserify-cipher": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/browserify-cipher/-/browserify-cipher-1.0.1.tgz", + "integrity": "sha512-sPhkz0ARKbf4rRQt2hTpAHqn47X3llLkUGn+xEJzLjwY8LRs2p0v7ljvI5EyoRO/mexrNunNECisZs+gw2zz1w==", + "dependencies": { + "browserify-aes": "^1.0.4", + "browserify-des": "^1.0.0", + "evp_bytestokey": "^1.0.0" + } + }, + "node_modules/browserify-des": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/browserify-des/-/browserify-des-1.0.2.tgz", + "integrity": "sha512-BioO1xf3hFwz4kc6iBhI3ieDFompMhrMlnDFC4/0/vd5MokpuAc3R+LYbwTA9A5Yc9pq9UYPqffKpW2ObuwX5A==", + "dependencies": { + "cipher-base": "^1.0.1", + "des.js": "^1.0.0", + "inherits": "^2.0.1", + "safe-buffer": "^5.1.2" + } + }, + "node_modules/browserify-rsa": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/browserify-rsa/-/browserify-rsa-4.1.0.tgz", + "integrity": "sha512-AdEER0Hkspgno2aR97SAf6vi0y0k8NuOpGnVH3O99rcA5Q6sh8QxcngtHuJ6uXwnfAXNM4Gn1Gb7/MV1+Ymbog==", + "dependencies": { + "bn.js": "^5.0.0", + "randombytes": "^2.0.1" + } + }, + "node_modules/browserify-sign": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/browserify-sign/-/browserify-sign-4.2.2.tgz", + "integrity": "sha512-1rudGyeYY42Dk6texmv7c4VcQ0EsvVbLwZkA+AQB7SxvXxmcD93jcHie8bzecJ+ChDlmAm2Qyu0+Ccg5uhZXCg==", + "dependencies": { + "bn.js": "^5.2.1", + "browserify-rsa": "^4.1.0", + "create-hash": "^1.2.0", + "create-hmac": "^1.1.7", + "elliptic": "^6.5.4", + "inherits": "^2.0.4", + "parse-asn1": "^5.1.6", + "readable-stream": "^3.6.2", + "safe-buffer": "^5.2.1" + }, + "engines": { + "node": ">= 4" + } + }, + "node_modules/browserify-sign/node_modules/readable-stream": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/browserify-sign/node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/browserify-zlib": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/browserify-zlib/-/browserify-zlib-0.2.0.tgz", + "integrity": "sha512-Z942RysHXmJrhqk88FmKBVq/v5tqmSkDz7p54G/MGyjMnCFFnC79XWNbg+Vta8W6Wb2qtSZTSxIGkJrRpCFEiA==", + "dependencies": { + "pako": "~1.0.5" + } + }, + "node_modules/browserify/node_modules/buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.2.1.tgz", + "integrity": "sha512-c+Ko0loDaFfuPWiL02ls9Xd3GO3cPVmUobQ6t3rXNUk304u6hGq+8N/kFi+QEIKhzK3uwolVhLzszmfLmMLnqg==", + "dependencies": { + "base64-js": "^1.0.2", + "ieee754": "^1.1.4" + } + }, + "node_modules/browserify/node_modules/path-browserify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-browserify/-/path-browserify-1.0.1.tgz", + "integrity": "sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g==" + }, + "node_modules/browserify/node_modules/punycode": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz", + "integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4=" + }, + "node_modules/browserify/node_modules/stream-browserify": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/stream-browserify/-/stream-browserify-3.0.0.tgz", + "integrity": "sha512-H73RAHsVBapbim0tU2JwwOiXUj+fikfiaoYAKHF3VJfA0pe2BCzkhAHBlLG6REzE+2WNZcxOXjK7lkso+9euLA==", + "dependencies": { + "inherits": "~2.0.4", + "readable-stream": "^3.5.0" + } + }, + "node_modules/browserify/node_modules/stream-browserify/node_modules/readable-stream": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", + "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/browserify/node_modules/stream-http": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/stream-http/-/stream-http-3.1.1.tgz", + "integrity": "sha512-S7OqaYu0EkFpgeGFb/NPOoPLxFko7TPqtEeFg5DXPB4v/KETHG0Ln6fRFrNezoelpaDKmycEmmZ81cC9DAwgYg==", + "dependencies": { + "builtin-status-codes": "^3.0.0", + "inherits": "^2.0.4", + "readable-stream": "^3.6.0", + "xtend": "^4.0.2" + } + }, + "node_modules/browserify/node_modules/stream-http/node_modules/readable-stream": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", + "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/browserify/node_modules/timers-browserify": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/timers-browserify/-/timers-browserify-1.4.2.tgz", + "integrity": "sha1-ycWLV1voQHN1y14kYtrO50NZ9B0=", + "dependencies": { + "process": "~0.11.0" + }, + "engines": { + "node": ">=0.6.0" + } + }, + "node_modules/browserify/node_modules/tty-browserify": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/tty-browserify/-/tty-browserify-0.0.1.tgz", + "integrity": "sha512-C3TaO7K81YvjCgQH9Q1S3R3P3BtN3RIM8n+OvX4il1K1zgE8ZhI0op7kClgkxtutIE8hQrcrHBXvIheqKUUCxw==" + }, + "node_modules/browserify/node_modules/util": { + "version": "0.12.3", + "resolved": "https://registry.npmjs.org/util/-/util-0.12.3.tgz", + "integrity": "sha512-I8XkoQwE+fPQEhy9v012V+TSdH2kp9ts29i20TaaDUXsg7x/onePbhFJUExBfv/2ay1ZOp/Vsm3nDlmnFGSAog==", + "dependencies": { + "inherits": "^2.0.3", + "is-arguments": "^1.0.4", + "is-generator-function": "^1.0.7", + "is-typed-array": "^1.1.3", + "safe-buffer": "^5.1.2", + "which-typed-array": "^1.1.2" + } + }, + "node_modules/browserslist": { + "version": "4.23.0", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.23.0.tgz", + "integrity": "sha512-QW8HiM1shhT2GuzkvklfjcKDiWFXHOeFCIA/huJPwHsslwcydgk7X+z2zXpEijP98UCY7HbubZt5J2Zgvf0CaQ==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "dependencies": { + "caniuse-lite": "^1.0.30001587", + "electron-to-chromium": "^1.4.668", + "node-releases": "^2.0.14", + "update-browserslist-db": "^1.0.13" + }, + "bin": { + "browserslist": "cli.js" + }, + "engines": { + "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" + } + }, + "node_modules/bs-recipes": { + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/bs-recipes/-/bs-recipes-1.3.4.tgz", + "integrity": "sha512-BXvDkqhDNxXEjeGM8LFkSbR+jzmP/CYpCiVKYn+soB1dDldeU15EBNDkwVXndKuX35wnNUaPd0qSoQEAkmQtMw==", + "devOptional": true + }, + "node_modules/buffer": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", + "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "dependencies": { + "base64-js": "^1.3.1", + "ieee754": "^1.1.13" + } + }, + "node_modules/buffer-crc32": { + "version": "0.2.13", + "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz", + "integrity": "sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ==", + "optional": true, + "engines": { + "node": "*" + } + }, + "node_modules/buffer-from": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz", + "integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==" + }, + "node_modules/buffer-xor": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/buffer-xor/-/buffer-xor-1.0.3.tgz", + "integrity": "sha1-JuYe0UIvtw3ULm42cp7VHYVf6Nk=" + }, + "node_modules/builtin-status-codes": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/builtin-status-codes/-/builtin-status-codes-3.0.0.tgz", + "integrity": "sha1-hZgoeOIbmOHGZCXgPQF0eI9Wnug=" + }, + "node_modules/builtins": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/builtins/-/builtins-5.0.1.tgz", + "integrity": "sha512-qwVpFEHNfhYJIzNRBvd2C1kyo6jz3ZSMPyyuR47OPdiKWlbYnZNyDWuyR175qDnAJLiCo5fBBqPb3RiXgWlkOQ==", + "dependencies": { + "semver": "^7.0.0" + } + }, + "node_modules/bundle-collapser": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/bundle-collapser/-/bundle-collapser-1.4.0.tgz", + "integrity": "sha512-Gd3K3+3KI1Utuk+gwAvuOVOjT/2XLGL8tU6FwDKk04LlOZkYfT0pwQllsG1Dv8RRhgcjNxZSDmmSXb0AOkwSwg==", + "dependencies": { + "browser-pack": "^6.0.2", + "browser-unpack": "^1.1.0", + "concat-stream": "^1.5.0", + "falafel": "^2.1.0", + "minimist": "^1.1.1", + "through2": "^2.0.0" + }, + "bin": { + "bundle-collapser": "bin/cmd.js" + } + }, + "node_modules/bytes": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", + "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/cacache": { + "version": "18.0.2", + "resolved": "https://registry.npmjs.org/cacache/-/cacache-18.0.2.tgz", + "integrity": "sha512-r3NU8h/P+4lVUHfeRw1dtgQYar3DZMm4/cm2bZgOvrFC/su7budSOeqh52VJIC4U4iG1WWwV6vRW0znqBvxNuw==", + "dependencies": { + "@npmcli/fs": "^3.1.0", + "fs-minipass": "^3.0.0", + "glob": "^10.2.2", + "lru-cache": "^10.0.1", + "minipass": "^7.0.3", + "minipass-collect": "^2.0.1", + "minipass-flush": "^1.0.5", + "minipass-pipeline": "^1.2.4", + "p-map": "^4.0.0", + "ssri": "^10.0.0", + "tar": "^6.1.11", + "unique-filename": "^3.0.0" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "node_modules/cacache/node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/cacache/node_modules/glob": { + "version": "10.3.10", + "resolved": "https://registry.npmjs.org/glob/-/glob-10.3.10.tgz", + "integrity": "sha512-fa46+tv1Ak0UPK1TOy/pZrIybNNt4HCv7SDzwyfiOZkvZLEbjsZkJBPtDHVshZjbecAoAGSC20MjLDG/qr679g==", + "dependencies": { + "foreground-child": "^3.1.0", + "jackspeak": "^2.3.5", + "minimatch": "^9.0.1", + "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0", + "path-scurry": "^1.10.1" + }, + "bin": { + "glob": "dist/esm/bin.mjs" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/cacache/node_modules/lru-cache": { + "version": "10.2.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.2.0.tgz", + "integrity": "sha512-2bIM8x+VAf6JT4bKAljS1qUWgMsqZRPGJS6FSahIMPVvctcNhyVp7AJu7quxOW9jwkryBReKZY5tY5JYv2n/7Q==", + "engines": { + "node": "14 || >=16.14" + } + }, + "node_modules/cacache/node_modules/minimatch": { + "version": "9.0.3", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.3.tgz", + "integrity": "sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==", + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/cached-path-relative": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/cached-path-relative/-/cached-path-relative-1.1.0.tgz", + "integrity": "sha512-WF0LihfemtesFcJgO7xfOoOcnWzY/QHR4qeDqV44jPU3HTI54+LnfXK3SA27AVVGCdZFgjjFFaqUA9Jx7dMJZA==" + }, + "node_modules/cachedir": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/cachedir/-/cachedir-2.3.0.tgz", + "integrity": "sha512-A+Fezp4zxnit6FanDmv9EqXNAi3vt9DWp51/71UEhXukb7QUuvtv9344h91dyAxuTLoSYJFU299qzR3tzwPAhw==", + "optional": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/call-bind": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.7.tgz", + "integrity": "sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w==", + "dependencies": { + "es-define-property": "^1.0.0", + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.4", + "set-function-length": "^1.2.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==", + "engines": { + "node": ">=6" + } + }, + "node_modules/camelcase": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", + "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==", + "engines": { + "node": ">=6" + } + }, + "node_modules/caniuse-lite": { + "version": "1.0.30001600", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001600.tgz", + "integrity": "sha512-+2S9/2JFhYmYaDpZvo0lKkfvuKIglrx68MwOBqMGHhQsNkLjB5xtc/TGoEPs+MxjSyN/72qer2g97nzR641mOQ==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/caniuse-lite" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ] + }, + "node_modules/caseless": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", + "integrity": "sha512-4tYFyifaFfGacoiObjJegolkwSU4xQNGbVgUiNYVUxbQ2x2lUsFvY4hVgVzGiIe6WLOPqycWXA40l+PWsxthUw==", + "optional": true + }, + "node_modules/chai": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/chai/-/chai-4.4.0.tgz", + "integrity": "sha512-x9cHNq1uvkCdU+5xTkNh5WtgD4e4yDFCsp9jVc7N7qVeKeftv3gO/ZrviX5d+3ZfxdYnZXZYujjRInu1RogU6A==", + "optional": true, + "dependencies": { + "assertion-error": "^1.1.0", + "check-error": "^1.0.3", + "deep-eql": "^4.1.3", + "get-func-name": "^2.0.2", + "loupe": "^2.3.6", + "pathval": "^1.1.1", + "type-detect": "^4.0.8" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dependencies": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/chardet": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/chardet/-/chardet-0.7.0.tgz", + "integrity": "sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==" + }, + "node_modules/check-error": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/check-error/-/check-error-1.0.3.tgz", + "integrity": "sha512-iKEoDYaRmd1mxM90a2OEfWhjsjPpYPuQ+lMYsoxB126+t8fw7ySEO48nmDg5COTjxDI65/Y2OWpeEHk3ZOe8zg==", + "optional": true, + "dependencies": { + "get-func-name": "^2.0.2" + }, + "engines": { + "node": "*" + } + }, + "node_modules/check-more-types": { + "version": "2.24.0", + "resolved": "https://registry.npmjs.org/check-more-types/-/check-more-types-2.24.0.tgz", + "integrity": "sha1-FCD/sQ/URNz8ebQ4kbv//TKoRgA=", + "optional": true, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/chokidar": { + "version": "3.5.3", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz", + "integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==", + "funding": [ + { + "type": "individual", + "url": "https://paulmillr.com/funding/" + } + ], + "dependencies": { + "anymatch": "~3.1.2", + "braces": "~3.0.2", + "glob-parent": "~5.1.2", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.6.0" + }, + "engines": { + "node": ">= 8.10.0" + }, + "optionalDependencies": { + "fsevents": "~2.3.2" + } + }, + "node_modules/chownr": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/chownr/-/chownr-2.0.0.tgz", + "integrity": "sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==", + "engines": { + "node": ">=10" + } + }, + "node_modules/chrome-trace-event": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/chrome-trace-event/-/chrome-trace-event-1.0.3.tgz", + "integrity": "sha512-p3KULyQg4S7NIHixdwbGX+nFHkoBiA4YQmyWtjb8XngSKV124nJmRysgAeujbUVb15vh+RvFUfCPqU7rXk+hZg==", + "engines": { + "node": ">=6.0" + } + }, + "node_modules/ci-info": { + "version": "3.8.0", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.8.0.tgz", + "integrity": "sha512-eXTggHWSooYhq49F2opQhuHWgzucfF2YgODK4e1566GQs5BIfP30B0oenwBJHfWxAs2fyPB1s7Mg949zLf61Yw==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/sibiraj-s" + } + ], + "optional": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/cipher-base": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/cipher-base/-/cipher-base-1.0.4.tgz", + "integrity": "sha512-Kkht5ye6ZGmwv40uUDZztayT2ThLQGfnj/T71N/XzeZeo3nf8foyW7zGTsPYkEya3m5f3cAypH+qe7YOrM1U2Q==", + "dependencies": { + "inherits": "^2.0.1", + "safe-buffer": "^5.0.1" + } + }, + "node_modules/clean-stack": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz", + "integrity": "sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==", + "engines": { + "node": ">=6" + } + }, + "node_modules/cli-cursor": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-3.1.0.tgz", + "integrity": "sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==", + "dependencies": { + "restore-cursor": "^3.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/cli-spinners": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/cli-spinners/-/cli-spinners-2.6.0.tgz", + "integrity": "sha512-t+4/y50K/+4xcCRosKkA7W4gTr1MySvLV0q+PxmG7FJ5g+66ChKurYjxBCjHggHH3HA5Hh9cy+lcUGWDqVH+4Q==", + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/cli-table3": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/cli-table3/-/cli-table3-0.6.3.tgz", + "integrity": "sha512-w5Jac5SykAeZJKntOxJCrm63Eg5/4dhMWIcuTbo9rpE+brgaSZo0RuNJZeOyMgsUdhDeojvgyQLmjI+K50ZGyg==", + "optional": true, + "dependencies": { + "string-width": "^4.2.0" + }, + "engines": { + "node": "10.* || >= 12.*" + }, + "optionalDependencies": { + "@colors/colors": "1.5.0" + } + }, + "node_modules/cli-truncate": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/cli-truncate/-/cli-truncate-2.1.0.tgz", + "integrity": "sha512-n8fOixwDD6b/ObinzTrp1ZKFzbgvKZvuz/TvejnLn1aQfC6r52XEx85FmuC+3HI+JM7coBRXUvNqEU2PHVrHpg==", + "optional": true, + "dependencies": { + "slice-ansi": "^3.0.0", + "string-width": "^4.2.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/cli-width": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-4.1.0.tgz", + "integrity": "sha512-ouuZd4/dm2Sw5Gmqy6bGyNNNe1qt9RpmxveLSO7KcgsTnU7RXfsw+/bukWGo1abgBiMAic068rclZsO4IWmmxQ==", + "engines": { + "node": ">= 12" + } + }, + "node_modules/clipboard": { + "version": "2.0.11", + "resolved": "https://registry.npmjs.org/clipboard/-/clipboard-2.0.11.tgz", + "integrity": "sha512-C+0bbOqkezLIsmWSvlsXS0Q0bmkugu7jcfMIACB+RDEntIzQIkdr148we28AfSloQLRdZlYL/QYyrq05j/3Faw==", + "dependencies": { + "good-listener": "^1.2.2", + "select": "^1.1.2", + "tiny-emitter": "^2.0.0" + } + }, + "node_modules/cliui": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-6.0.0.tgz", + "integrity": "sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ==", + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^6.2.0" + } + }, + "node_modules/clone": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/clone/-/clone-1.0.4.tgz", + "integrity": "sha1-2jCcwmPfFZlMaIypAheco8fNfH4=", + "engines": { + "node": ">=0.8" + } + }, + "node_modules/clone-deep": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/clone-deep/-/clone-deep-4.0.1.tgz", + "integrity": "sha512-neHB9xuzh/wk0dIHweyAXv2aPGZIVk3pLMe+/RNzINf17fe0OG96QroktYAUm7SM1PBnzTabaLboqqxDyMU+SQ==", + "dependencies": { + "is-plain-object": "^2.0.4", + "kind-of": "^6.0.2", + "shallow-clone": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dependencies": { + "color-name": "1.1.3" + } + }, + "node_modules/color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==" + }, + "node_modules/colorette": { + "version": "2.0.20", + "resolved": "https://registry.npmjs.org/colorette/-/colorette-2.0.20.tgz", + "integrity": "sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==" + }, + "node_modules/combine-source-map": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/combine-source-map/-/combine-source-map-0.8.0.tgz", + "integrity": "sha1-pY0N8ELBhvz4IqjoAV9UUNLXmos=", + "dependencies": { + "convert-source-map": "~1.1.0", + "inline-source-map": "~0.6.0", + "lodash.memoize": "~3.0.3", + "source-map": "~0.5.3" + } + }, + "node_modules/combine-source-map/node_modules/convert-source-map": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.1.3.tgz", + "integrity": "sha1-SCnId+n+SbMWHzvzZziI4gRpmGA=" + }, + "node_modules/combine-source-map/node_modules/lodash.memoize": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-3.0.4.tgz", + "integrity": "sha1-LcvSwofLwKVcxCMovQxzYVDVPj8=" + }, + "node_modules/combine-source-map/node_modules/source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "optional": true, + "dependencies": { + "delayed-stream": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/commander": { + "version": "2.20.3", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", + "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==" + }, + "node_modules/common-path-prefix": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/common-path-prefix/-/common-path-prefix-3.0.0.tgz", + "integrity": "sha512-QE33hToZseCH3jS0qN96O/bSh3kaw/h+Tq7ngyY9eWDUnTlTNUyqfqvCXioLe5Na5jFsL78ra/wuBU4iuEgd4w==" + }, + "node_modules/common-shakeify": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/common-shakeify/-/common-shakeify-1.1.1.tgz", + "integrity": "sha512-M9hTU14RkpKvNggSU4zJIzgm89inwjnhipxvKxCNms/gM77R7keRqOqGYIM/Jr4BBhtbZB8ZF//raYqAbHk/DA==", + "dependencies": { + "@goto-bus-stop/common-shake": "^2.3.0", + "convert-source-map": "^1.5.1", + "through2": "^2.0.3", + "transform-ast": "^2.4.3", + "wrap-comment": "^1.0.1" + } + }, + "node_modules/common-tags": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/common-tags/-/common-tags-1.8.0.tgz", + "integrity": "sha512-6P6g0uetGpW/sdyUy/iQQCbFF0kWVMSIVSyYz7Zgjcgh8mgw8PQzDNZeyZ5DQ2gM7LBoZPHmnjz8rUthkBG5tw==", + "optional": true, + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/compressible": { + "version": "2.0.18", + "resolved": "https://registry.npmjs.org/compressible/-/compressible-2.0.18.tgz", + "integrity": "sha512-AF3r7P5dWxL8MxyITRMlORQNaOA2IkAFaTr4k7BUumjPtRpGDTZpl0Pb1XCO6JeDCBdp126Cgs9sMxqSjgYyRg==", + "dependencies": { + "mime-db": ">= 1.43.0 < 2" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/compression": { + "version": "1.7.4", + "resolved": "https://registry.npmjs.org/compression/-/compression-1.7.4.tgz", + "integrity": "sha512-jaSIDzP9pZVS4ZfQ+TzvtiWhdpFhE2RDHz8QJkpX9SIpLq88VueF5jJw6t+6CUQcAoA6t+x89MLrWAqpfDE8iQ==", + "dependencies": { + "accepts": "~1.3.5", + "bytes": "3.0.0", + "compressible": "~2.0.16", + "debug": "2.6.9", + "on-headers": "~1.0.2", + "safe-buffer": "5.1.2", + "vary": "~1.1.2" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/compression/node_modules/bytes": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.0.0.tgz", + "integrity": "sha512-pMhOfFDPiv9t5jjIXkHosWmkSyQbvsgEVNkz0ERHbuLh2T/7j4Mqqpz523Fe8MVY89KC6Sh/QfS2sM+SjgFDcw==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/compression/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/compression/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" + }, + "node_modules/concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=" + }, + "node_modules/concat-stream": { + "version": "1.6.2", + "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.2.tgz", + "integrity": "sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==", + "engines": [ + "node >= 0.8" + ], + "dependencies": { + "buffer-from": "^1.0.0", + "inherits": "^2.0.3", + "readable-stream": "^2.2.2", + "typedarray": "^0.0.6" + } + }, + "node_modules/connect": { + "version": "3.6.6", + "resolved": "https://registry.npmjs.org/connect/-/connect-3.6.6.tgz", + "integrity": "sha512-OO7axMmPpu/2XuX1+2Yrg0ddju31B6xLZMWkJ5rYBu4YRmRVlOjvlY6kw2FJKiAzyxGwnrDUAG4s1Pf0sbBMCQ==", + "devOptional": true, + "dependencies": { + "debug": "2.6.9", + "finalhandler": "1.1.0", + "parseurl": "~1.3.2", + "utils-merge": "1.0.1" + }, + "engines": { + "node": ">= 0.10.0" + } + }, + "node_modules/connect-history-api-fallback": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/connect-history-api-fallback/-/connect-history-api-fallback-1.6.0.tgz", + "integrity": "sha512-e54B99q/OUoH64zYYRf3HBP5z24G38h5D3qXu23JGRoigpX5Ss4r9ZnDk3g0Z8uQC2x2lPaJ+UlWBc1ZWBWdLg==", + "devOptional": true, + "engines": { + "node": ">=0.8" + } + }, + "node_modules/connect/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "devOptional": true, + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/connect/node_modules/finalhandler": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.0.tgz", + "integrity": "sha512-ejnvM9ZXYzp6PUPUyQBMBf0Co5VX2gr5H2VQe2Ui2jWXNlxv+PYZo8wpAymJNJdLsG1R4p+M4aynF8KuoUEwRw==", + "devOptional": true, + "dependencies": { + "debug": "2.6.9", + "encodeurl": "~1.0.1", + "escape-html": "~1.0.3", + "on-finished": "~2.3.0", + "parseurl": "~1.3.2", + "statuses": "~1.3.1", + "unpipe": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/connect/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "devOptional": true + }, + "node_modules/connect/node_modules/statuses": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.3.1.tgz", + "integrity": "sha512-wuTCPGlJONk/a1kqZ4fQM2+908lC7fa7nPYpTC1EhnvqLX/IICbeP1OZGDtA374trpSq68YubKUMo8oRhN46yg==", + "devOptional": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/console-browserify": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/console-browserify/-/console-browserify-1.2.0.tgz", + "integrity": "sha512-ZMkYO/LkF17QvCPqM0gxw8yUzigAOZOSWSHg91FH6orS7vcEj5dVZTidN2fQ14yBSdg97RqhSNwLUXInd52OTA==" + }, + "node_modules/constants-browserify": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/constants-browserify/-/constants-browserify-1.0.0.tgz", + "integrity": "sha1-wguW2MYXdIqvHBYCF2DNJ/y4y3U=" + }, + "node_modules/content-disposition": { + "version": "0.5.4", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", + "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==", + "dependencies": { + "safe-buffer": "5.2.1" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/content-disposition/node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/content-type": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz", + "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/convert-source-map": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.9.0.tgz", + "integrity": "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==" + }, + "node_modules/cookie": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.6.0.tgz", + "integrity": "sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/cookie-signature": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", + "integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==" + }, + "node_modules/copy-anything": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/copy-anything/-/copy-anything-2.0.6.tgz", + "integrity": "sha512-1j20GZTsvKNkc4BY3NpMOM8tt///wY3FpIzozTOFO2ffuZcV61nojHXVKIy3WM+7ADCy5FVhdZYHYDdgTU0yJw==", + "dependencies": { + "is-what": "^3.14.1" + }, + "funding": { + "url": "https://github.com/sponsors/mesqueeb" + } + }, + "node_modules/copy-webpack-plugin": { + "version": "11.0.0", + "resolved": "https://registry.npmjs.org/copy-webpack-plugin/-/copy-webpack-plugin-11.0.0.tgz", + "integrity": "sha512-fX2MWpamkW0hZxMEg0+mYnA40LTosOSa5TqZ9GYIBzyJa9C3QUaMPSE2xAi/buNr8u89SfD9wHSQVBzrRa/SOQ==", + "dependencies": { + "fast-glob": "^3.2.11", + "glob-parent": "^6.0.1", + "globby": "^13.1.1", + "normalize-path": "^3.0.0", + "schema-utils": "^4.0.0", + "serialize-javascript": "^6.0.0" + }, + "engines": { + "node": ">= 14.15.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^5.1.0" + } + }, + "node_modules/copy-webpack-plugin/node_modules/glob-parent": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "dependencies": { + "is-glob": "^4.0.3" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/core-js-compat": { + "version": "3.36.1", + "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.36.1.tgz", + "integrity": "sha512-Dk997v9ZCt3X/npqzyGdTlq6t7lDBhZwGvV94PKzDArjp7BTRm7WlDAXYd/OWdeFHO8OChQYRJNJvUCqCbrtKA==", + "dependencies": { + "browserslist": "^4.23.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/core-js" + } + }, + "node_modules/core-util-is": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", + "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=" + }, + "node_modules/cors": { + "version": "2.8.5", + "resolved": "https://registry.npmjs.org/cors/-/cors-2.8.5.tgz", + "integrity": "sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==", + "devOptional": true, + "dependencies": { + "object-assign": "^4", + "vary": "^1" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/cosmiconfig": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-9.0.0.tgz", + "integrity": "sha512-itvL5h8RETACmOTFc4UfIyB2RfEHi71Ax6E/PivVxq9NseKbOWpeyHEOIbmAw1rs8Ak0VursQNww7lf7YtUwzg==", + "dependencies": { + "env-paths": "^2.2.1", + "import-fresh": "^3.3.0", + "js-yaml": "^4.1.0", + "parse-json": "^5.2.0" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/d-fischer" + }, + "peerDependencies": { + "typescript": ">=4.9.5" + }, + "peerDependenciesMeta": { + "typescript": { + "optional": true + } + } + }, + "node_modules/cosmiconfig/node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==" + }, + "node_modules/cosmiconfig/node_modules/js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/count-lines": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/count-lines/-/count-lines-0.1.2.tgz", + "integrity": "sha1-4zST+2hgqC9xWdgjeEP7+u/uWWI=", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/create-ecdh": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/create-ecdh/-/create-ecdh-4.0.4.tgz", + "integrity": "sha512-mf+TCx8wWc9VpuxfP2ht0iSISLZnt0JgWlrOKZiNqyUZWnjIaCIVNQArMHnCZKfEYRg6IM7A+NeJoN8gf/Ws0A==", + "dependencies": { + "bn.js": "^4.1.0", + "elliptic": "^6.5.3" + } + }, + "node_modules/create-ecdh/node_modules/bn.js": { + "version": "4.12.0", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", + "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==" + }, + "node_modules/create-hash": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/create-hash/-/create-hash-1.2.0.tgz", + "integrity": "sha512-z00bCGNHDG8mHAkP7CtT1qVu+bFQUPjYq/4Iv3C3kWjTFV10zIjfSoeqXo9Asws8gwSHDGj/hl2u4OGIjapeCg==", + "dependencies": { + "cipher-base": "^1.0.1", + "inherits": "^2.0.1", + "md5.js": "^1.3.4", + "ripemd160": "^2.0.1", + "sha.js": "^2.4.0" + } + }, + "node_modules/create-hmac": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/create-hmac/-/create-hmac-1.1.7.tgz", + "integrity": "sha512-MJG9liiZ+ogc4TzUwuvbER1JRdgvUFSB5+VR/g5h82fGaIRWMWddtKBHi7/sVhfjQZ6SehlyhvQYrcYkaUIpLg==", + "dependencies": { + "cipher-base": "^1.0.3", + "create-hash": "^1.1.0", + "inherits": "^2.0.1", + "ripemd160": "^2.0.0", + "safe-buffer": "^5.0.1", + "sha.js": "^2.4.8" + } + }, + "node_modules/create-require": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz", + "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==", + "dev": true + }, + "node_modules/critters": { + "version": "0.0.22", + "resolved": "https://registry.npmjs.org/critters/-/critters-0.0.22.tgz", + "integrity": "sha512-NU7DEcQZM2Dy8XTKFHxtdnIM/drE312j2T4PCVaSUcS0oBeyT/NImpRw/Ap0zOr/1SE7SgPK9tGPg1WK/sVakw==", + "dependencies": { + "chalk": "^4.1.0", + "css-select": "^5.1.0", + "dom-serializer": "^2.0.0", + "domhandler": "^5.0.2", + "htmlparser2": "^8.0.2", + "postcss": "^8.4.23", + "postcss-media-query-parser": "^0.2.3" + } + }, + "node_modules/critters/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/critters/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/critters/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/critters/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + }, + "node_modules/critters/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "engines": { + "node": ">=8" + } + }, + "node_modules/critters/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/cross-spawn": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", + "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "dependencies": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/crypto-browserify": { + "version": "3.12.0", + "resolved": "https://registry.npmjs.org/crypto-browserify/-/crypto-browserify-3.12.0.tgz", + "integrity": "sha512-fz4spIh+znjO2VjL+IdhEpRJ3YN6sMzITSBijk6FK2UvTqruSQW+/cCZTSNsMiZNvUeq0CqurF+dAbyiGOY6Wg==", + "dependencies": { + "browserify-cipher": "^1.0.0", + "browserify-sign": "^4.0.0", + "create-ecdh": "^4.0.0", + "create-hash": "^1.1.0", + "create-hmac": "^1.1.0", + "diffie-hellman": "^5.0.0", + "inherits": "^2.0.1", + "pbkdf2": "^3.0.3", + "public-encrypt": "^4.0.0", + "randombytes": "^2.0.0", + "randomfill": "^1.0.3" + }, + "engines": { + "node": "*" + } + }, + "node_modules/css-loader": { + "version": "6.10.0", + "resolved": "https://registry.npmjs.org/css-loader/-/css-loader-6.10.0.tgz", + "integrity": "sha512-LTSA/jWbwdMlk+rhmElbDR2vbtQoTBPr7fkJE+mxrHj+7ru0hUmHafDRzWIjIHTwpitWVaqY2/UWGRca3yUgRw==", + "dependencies": { + "icss-utils": "^5.1.0", + "postcss": "^8.4.33", + "postcss-modules-extract-imports": "^3.0.0", + "postcss-modules-local-by-default": "^4.0.4", + "postcss-modules-scope": "^3.1.1", + "postcss-modules-values": "^4.0.0", + "postcss-value-parser": "^4.2.0", + "semver": "^7.5.4" + }, + "engines": { + "node": ">= 12.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "@rspack/core": "0.x || 1.x", + "webpack": "^5.0.0" + }, + "peerDependenciesMeta": { + "@rspack/core": { + "optional": true + }, + "webpack": { + "optional": true + } + } + }, + "node_modules/css-select": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/css-select/-/css-select-5.1.0.tgz", + "integrity": "sha512-nwoRF1rvRRnnCqqY7updORDsuqKzqYJ28+oSMaJMMgOauh3fvwHqMS7EZpIPqK8GL+g9mKxF1vP/ZjSeNjEVHg==", + "dependencies": { + "boolbase": "^1.0.0", + "css-what": "^6.1.0", + "domhandler": "^5.0.2", + "domutils": "^3.0.1", + "nth-check": "^2.0.1" + }, + "funding": { + "url": "https://github.com/sponsors/fb55" + } + }, + "node_modules/css-what": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/css-what/-/css-what-6.1.0.tgz", + "integrity": "sha512-HTUrgRJ7r4dsZKU6GjmpfRK1O76h97Z8MfS1G0FozR+oF2kG6Vfe8JE6zwrkbxigziPHinCJ+gCPjA9EaBDtRw==", + "engines": { + "node": ">= 6" + }, + "funding": { + "url": "https://github.com/sponsors/fb55" + } + }, + "node_modules/cssesc": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz", + "integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==", + "bin": { + "cssesc": "bin/cssesc" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/custom-event": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/custom-event/-/custom-event-1.0.1.tgz", + "integrity": "sha1-XQKkaFCt8bSjF5RqOSj8y1v9BCU=", + "optional": true, + "peer": true + }, + "node_modules/cypress": { + "version": "13.13.0", + "resolved": "https://registry.npmjs.org/cypress/-/cypress-13.13.0.tgz", + "integrity": "sha512-ou/MQUDq4tcDJI2FsPaod2FZpex4kpIK43JJlcBgWrX8WX7R/05ZxGTuxedOuZBfxjZxja+fbijZGyxiLP6CFA==", + "hasInstallScript": true, + "optional": true, + "dependencies": { + "@cypress/request": "^3.0.0", + "@cypress/xvfb": "^1.2.4", + "@types/sinonjs__fake-timers": "8.1.1", + "@types/sizzle": "^2.3.2", + "arch": "^2.2.0", + "blob-util": "^2.0.2", + "bluebird": "^3.7.2", + "buffer": "^5.7.1", + "cachedir": "^2.3.0", + "chalk": "^4.1.0", + "check-more-types": "^2.24.0", + "cli-cursor": "^3.1.0", + "cli-table3": "~0.6.1", + "commander": "^6.2.1", + "common-tags": "^1.8.0", + "dayjs": "^1.10.4", + "debug": "^4.3.4", + "enquirer": "^2.3.6", + "eventemitter2": "6.4.7", + "execa": "4.1.0", + "executable": "^4.1.1", + "extract-zip": "2.0.1", + "figures": "^3.2.0", + "fs-extra": "^9.1.0", + "getos": "^3.2.1", + "is-ci": "^3.0.1", + "is-installed-globally": "~0.4.0", + "lazy-ass": "^1.6.0", + "listr2": "^3.8.3", + "lodash": "^4.17.21", + "log-symbols": "^4.0.0", + "minimist": "^1.2.8", + "ospath": "^1.2.2", + "pretty-bytes": "^5.6.0", + "process": "^0.11.10", + "proxy-from-env": "1.0.0", + "request-progress": "^3.0.0", + "semver": "^7.5.3", + "supports-color": "^8.1.1", + "tmp": "~0.2.3", + "untildify": "^4.0.0", + "yauzl": "^2.10.0" + }, + "bin": { + "cypress": "bin/cypress" + }, + "engines": { + "node": "^16.0.0 || ^18.0.0 || >=20.0.0" + } + }, + "node_modules/cypress-fail-on-console-error": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/cypress-fail-on-console-error/-/cypress-fail-on-console-error-5.1.0.tgz", + "integrity": "sha512-u/AXLE9obLd9KcGHkGJluJVZeOj1EEOFOs0URxxca4FrftUDJQ3u+IoNfjRUjsrBKmJxgM4vKd0G10D+ZT1uIA==", + "optional": true, + "dependencies": { + "chai": "^4.3.10", + "sinon": "^17.0.0", + "sinon-chai": "^3.7.0", + "type-detect": "^4.0.8" + } + }, + "node_modules/cypress-wait-until": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/cypress-wait-until/-/cypress-wait-until-2.0.1.tgz", + "integrity": "sha512-+IyVnYNiaX1+C+V/LazrJWAi/CqiwfNoRSrFviECQEyolW1gDRy765PZosL2alSSGK8V10Y7BGfOQyZUDgmnjQ==", + "optional": true + }, + "node_modules/cypress/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "optional": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/cypress/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "optional": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/cypress/node_modules/chalk/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "optional": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/cypress/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "optional": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/cypress/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "optional": true + }, + "node_modules/cypress/node_modules/commander": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-6.2.1.tgz", + "integrity": "sha512-U7VdrJFnJgo4xjrHpTzu0yrHPGImdsmD95ZlgYSEajAn2JKzDhDTPG9kBTefmObL2w/ngeZnilk+OV9CG3d7UA==", + "optional": true, + "engines": { + "node": ">= 6" + } + }, + "node_modules/cypress/node_modules/execa": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/execa/-/execa-4.1.0.tgz", + "integrity": "sha512-j5W0//W7f8UxAn8hXVnwG8tLwdiUy4FJLcSupCg6maBYZDpyBvTApK7KyuI4bKj8KOh1r2YH+6ucuYtJv1bTZA==", + "optional": true, + "dependencies": { + "cross-spawn": "^7.0.0", + "get-stream": "^5.0.0", + "human-signals": "^1.1.1", + "is-stream": "^2.0.0", + "merge-stream": "^2.0.0", + "npm-run-path": "^4.0.0", + "onetime": "^5.1.0", + "signal-exit": "^3.0.2", + "strip-final-newline": "^2.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sindresorhus/execa?sponsor=1" + } + }, + "node_modules/cypress/node_modules/fs-extra": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz", + "integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==", + "optional": true, + "dependencies": { + "at-least-node": "^1.0.0", + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/cypress/node_modules/get-stream": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz", + "integrity": "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==", + "optional": true, + "dependencies": { + "pump": "^3.0.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/cypress/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "optional": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/cypress/node_modules/supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "optional": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" + } + }, + "node_modules/cypress/node_modules/tmp": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.2.3.tgz", + "integrity": "sha512-nZD7m9iCPC5g0pYmcaxogYKggSfLsdxl8of3Q/oIbqCqLLIO9IAF0GWjX1z9NZRHPiXv8Wex4yDCaZsgEw0Y8w==", + "optional": true, + "engines": { + "node": ">=14.14" + } + }, + "node_modules/d": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/d/-/d-1.0.1.tgz", + "integrity": "sha512-m62ShEObQ39CfralilEQRjH6oAMtNCV1xJyEx5LpRYUVN+EviphDgUc/F3hnYbADmkiNs67Y+3ylmlG7Lnu+FA==", + "dependencies": { + "es5-ext": "^0.10.50", + "type": "^1.0.1" + } + }, + "node_modules/dash-ast": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/dash-ast/-/dash-ast-1.0.0.tgz", + "integrity": "sha512-Vy4dx7gquTeMcQR/hDkYLGUnwVil6vk4FOOct+djUnHOUWt+zJPJAaRIXaAFkPXtJjvlY7o3rfRu0/3hpnwoUA==" + }, + "node_modules/dashdash": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", + "integrity": "sha512-jRFi8UDGo6j+odZiEpjazZaWqEal3w/basFjQHQEwVtZJGDpxbH1MeYluwCS8Xq5wmLJooDlMgvVarmWfGM44g==", + "optional": true, + "dependencies": { + "assert-plus": "^1.0.0" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/date-format": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/date-format/-/date-format-4.0.3.tgz", + "integrity": "sha512-7P3FyqDcfeznLZp2b+OMitV9Sz2lUnsT87WaTat9nVwqsBkTzPG3lPLNwW3en6F4pHUiWzr6vb8CLhjdK9bcxQ==", + "optional": true, + "peer": true, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/dayjs": { + "version": "1.11.9", + "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.9.tgz", + "integrity": "sha512-QvzAURSbQ0pKdIye2txOzNaHmxtUBXerpY0FJsFXUMKbIZeFm5ht1LS/jFsrncjnmtv8HsG0W2g6c0zUjZWmpA==", + "optional": true + }, + "node_modules/debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "dependencies": { + "ms": "2.1.2" + }, + "engines": { + "node": ">=6.0" + }, + "peerDependenciesMeta": { + "supports-color": { + "optional": true + } + } + }, + "node_modules/decamelize": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", + "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/dedent": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/dedent/-/dedent-0.7.0.tgz", + "integrity": "sha1-JJXduvbrh0q7Dhvp3yLS5aVEMmw=" + }, + "node_modules/deep-eql": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-4.1.3.tgz", + "integrity": "sha512-WaEtAOpRA1MQ0eohqZjpGD8zdI0Ovsm8mmFhaDN8dvDZzyoUMcYDnf5Y6iu7HTXxf8JDS23qWa4a+hKCDyOPzw==", + "optional": true, + "dependencies": { + "type-detect": "^4.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/deep-is": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", + "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", + "dev": true + }, + "node_modules/default-gateway": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/default-gateway/-/default-gateway-6.0.3.tgz", + "integrity": "sha512-fwSOJsbbNzZ/CUFpqFBqYfYNLj1NbMPm8MMCIzHjC83iSJRBEGmDUxU+WP661BaBQImeC2yHwXtz+P/O9o+XEg==", + "dependencies": { + "execa": "^5.0.0" + }, + "engines": { + "node": ">= 10" + } + }, + "node_modules/defaults": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/defaults/-/defaults-1.0.3.tgz", + "integrity": "sha1-xlYFHpgX2f8I7YgUd/P+QBnz730=", + "dependencies": { + "clone": "^1.0.2" + } + }, + "node_modules/define-data-property": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz", + "integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==", + "dependencies": { + "es-define-property": "^1.0.0", + "es-errors": "^1.3.0", + "gopd": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/define-lazy-prop": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/define-lazy-prop/-/define-lazy-prop-2.0.0.tgz", + "integrity": "sha512-Ds09qNh8yw3khSjiJjiUInaGX9xlqZDY7JVryGxdxV7NPeuqQfplOpQ66yJFZut3jLa5zOwkXw1g9EI2uKh4Og==", + "engines": { + "node": ">=8" + } + }, + "node_modules/define-properties": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.2.1.tgz", + "integrity": "sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==", + "dependencies": { + "define-data-property": "^1.0.1", + "has-property-descriptors": "^1.0.0", + "object-keys": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/defined": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/defined/-/defined-1.0.0.tgz", + "integrity": "sha1-yY2bzvdWdBiOEQlpFRGZ45sfppM=" + }, + "node_modules/delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", + "optional": true, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/delegate": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/delegate/-/delegate-3.2.0.tgz", + "integrity": "sha512-IofjkYBZaZivn0V8nnsMJGBr4jVLxHDheKSW88PyxS5QC4Vo9ZbZVvhzlSxY87fVq3STR6r+4cGepyHkcWOQSw==" + }, + "node_modules/depd": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", + "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/deps-sort": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/deps-sort/-/deps-sort-2.0.1.tgz", + "integrity": "sha512-1orqXQr5po+3KI6kQb9A4jnXT1PBwggGl2d7Sq2xsnOeI9GPcE/tGcF9UiSZtZBM7MukY4cAh7MemS6tZYipfw==", + "dependencies": { + "JSONStream": "^1.0.3", + "shasum-object": "^1.0.0", + "subarg": "^1.0.0", + "through2": "^2.0.0" + }, + "bin": { + "deps-sort": "bin/cmd.js" + } + }, + "node_modules/des.js": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/des.js/-/des.js-1.0.1.tgz", + "integrity": "sha512-Q0I4pfFrv2VPd34/vfLrFOoRmlYj3OV50i7fskps1jZWK1kApMWWT9G6RRUeYedLcBDIhnSDaUvJMb3AhUlaEA==", + "dependencies": { + "inherits": "^2.0.1", + "minimalistic-assert": "^1.0.0" + } + }, + "node_modules/destroy": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz", + "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==", + "engines": { + "node": ">= 0.8", + "npm": "1.2.8000 || >= 1.4.16" + } + }, + "node_modules/detect-node": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/detect-node/-/detect-node-2.1.0.tgz", + "integrity": "sha512-T0NIuQpnTvFDATNuHN5roPwSBG83rFsuO+MXXH9/3N1eFbn4wcPjttvjMLEPWJ0RGUYgQE7cGgS3tNxbqCGM7g==" + }, + "node_modules/detective": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/detective/-/detective-5.2.0.tgz", + "integrity": "sha512-6SsIx+nUUbuK0EthKjv0zrdnajCCXVYGmbYYiYjFVpzcjwEs/JMDZ8tPRG29J/HhN56t3GJp2cGSWDRjjot8Pg==", + "dependencies": { + "acorn-node": "^1.6.1", + "defined": "^1.0.0", + "minimist": "^1.1.1" + }, + "bin": { + "detective": "bin/detective.js" + }, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/dev-ip": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/dev-ip/-/dev-ip-1.0.1.tgz", + "integrity": "sha512-LmVkry/oDShEgSZPNgqCIp2/TlqtExeGmymru3uCELnfyjY11IzpAproLYs+1X88fXO6DBoYP3ul2Xo2yz2j6A==", + "devOptional": true, + "bin": { + "dev-ip": "lib/dev-ip.js" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/di": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/di/-/di-0.0.1.tgz", + "integrity": "sha1-gGZJMmzqp8qjMG112YXqJ0i6kTw=", + "optional": true, + "peer": true + }, + "node_modules/diff": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", + "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", + "dev": true, + "engines": { + "node": ">=0.3.1" + } + }, + "node_modules/diffie-hellman": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/diffie-hellman/-/diffie-hellman-5.0.3.tgz", + "integrity": "sha512-kqag/Nl+f3GwyK25fhUMYj81BUOrZ9IuJsjIcDE5icNM9FJHAVm3VcUDxdLPoQtTuUylWm6ZIknYJwwaPxsUzg==", + "dependencies": { + "bn.js": "^4.1.0", + "miller-rabin": "^4.0.0", + "randombytes": "^2.0.0" + } + }, + "node_modules/diffie-hellman/node_modules/bn.js": { + "version": "4.12.0", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", + "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==" + }, + "node_modules/dijkstrajs": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/dijkstrajs/-/dijkstrajs-1.0.1.tgz", + "integrity": "sha1-082BIh4+pAdCz83lVtTpnpjdxxs=" + }, + "node_modules/dir-glob": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", + "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", + "dependencies": { + "path-type": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/dns-packet": { + "version": "5.6.1", + "resolved": "https://registry.npmjs.org/dns-packet/-/dns-packet-5.6.1.tgz", + "integrity": "sha512-l4gcSouhcgIKRvyy99RNVOgxXiicE+2jZoNmaNmZ6JXiGajBOJAesk1OBlJuM5k2c+eudGdLxDqXuPCKIj6kpw==", + "dependencies": { + "@leichtgewicht/ip-codec": "^2.0.1" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/doctrine": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", + "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", + "dev": true, + "dependencies": { + "esutils": "^2.0.2" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/dom-serialize": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/dom-serialize/-/dom-serialize-2.2.1.tgz", + "integrity": "sha1-ViromZ9Evl6jB29UGdzVnrQ6yVs=", + "optional": true, + "peer": true, + "dependencies": { + "custom-event": "~1.0.0", + "ent": "~2.2.0", + "extend": "^3.0.0", + "void-elements": "^2.0.0" + } + }, + "node_modules/dom-serializer": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-2.0.0.tgz", + "integrity": "sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==", + "dependencies": { + "domelementtype": "^2.3.0", + "domhandler": "^5.0.2", + "entities": "^4.2.0" + }, + "funding": { + "url": "https://github.com/cheeriojs/dom-serializer?sponsor=1" + } + }, + "node_modules/domain-browser": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/domain-browser/-/domain-browser-1.2.0.tgz", + "integrity": "sha512-jnjyiM6eRyZl2H+W8Q/zLMA481hzi0eszAaBUzIVnmYVDBbnLxVNnfu1HgEBvCbL+71FrxMl3E6lpKH7Ge3OXA==", + "engines": { + "node": ">=0.4", + "npm": ">=1.2" + } + }, + "node_modules/domelementtype": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz", + "integrity": "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/fb55" + } + ] + }, + "node_modules/domhandler": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-5.0.3.tgz", + "integrity": "sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==", + "dependencies": { + "domelementtype": "^2.3.0" + }, + "engines": { + "node": ">= 4" + }, + "funding": { + "url": "https://github.com/fb55/domhandler?sponsor=1" + } + }, + "node_modules/domino": { + "version": "2.1.6", + "resolved": "https://registry.npmjs.org/domino/-/domino-2.1.6.tgz", + "integrity": "sha512-3VdM/SXBZX2omc9JF9nOPCtDaYQ67BGp5CoLpIQlO2KCAPETs8TcDHacF26jXadGbvUteZzRTeos2fhID5+ucQ==" + }, + "node_modules/domutils": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/domutils/-/domutils-3.1.0.tgz", + "integrity": "sha512-H78uMmQtI2AhgDJjWeQmHwJJ2bLPD3GMmO7Zja/ZZh84wkm+4ut+IUnUdRa8uCGX88DiVx1j6FRe1XfxEgjEZA==", + "dependencies": { + "dom-serializer": "^2.0.0", + "domelementtype": "^2.3.0", + "domhandler": "^5.0.3" + }, + "funding": { + "url": "https://github.com/fb55/domutils?sponsor=1" + } + }, + "node_modules/duplexer": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/duplexer/-/duplexer-0.1.2.tgz", + "integrity": "sha512-jtD6YG370ZCIi/9GTaJKQxWTZD045+4R4hTk/x1UyoqadyJ9x9CgSi1RlVDQF8U2sxLLSnFkCaMihqljHIWgMg==" + }, + "node_modules/duplexer2": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/duplexer2/-/duplexer2-0.1.4.tgz", + "integrity": "sha1-ixLauHjA1p4+eJEFFmKjL8a93ME=", + "dependencies": { + "readable-stream": "^2.0.2" + } + }, + "node_modules/eastasianwidth": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", + "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==" + }, + "node_modules/easy-extender": { + "version": "2.3.4", + "resolved": "https://registry.npmjs.org/easy-extender/-/easy-extender-2.3.4.tgz", + "integrity": "sha512-8cAwm6md1YTiPpOvDULYJL4ZS6WfM5/cTeVVh4JsvyYZAoqlRVUpHL9Gr5Fy7HA6xcSZicUia3DeAgO3Us8E+Q==", + "devOptional": true, + "dependencies": { + "lodash": "^4.17.10" + }, + "engines": { + "node": ">= 4.0.0" + } + }, + "node_modules/eazy-logger": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/eazy-logger/-/eazy-logger-4.0.1.tgz", + "integrity": "sha512-2GSFtnnC6U4IEKhEI7+PvdxrmjJ04mdsj3wHZTFiw0tUtG4HCWzTr13ZYTk8XOGnA1xQMaDljoBOYlk3D/MMSw==", + "devOptional": true, + "dependencies": { + "chalk": "4.1.2" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/eazy-logger/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "devOptional": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/eazy-logger/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "devOptional": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/eazy-logger/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "devOptional": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/eazy-logger/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "devOptional": true + }, + "node_modules/eazy-logger/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "devOptional": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/eazy-logger/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "devOptional": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/ecc-jsbn": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz", + "integrity": "sha512-eh9O+hwRHNbG4BLTjEl3nw044CkGm5X6LoaCf7LPp7UU8Qrt47JYNi6nPX8xjW97TKGKm1ouctg0QSpZe9qrnw==", + "optional": true, + "dependencies": { + "jsbn": "~0.1.0", + "safer-buffer": "^2.1.0" + } + }, + "node_modules/echarts": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/echarts/-/echarts-5.5.0.tgz", + "integrity": "sha512-rNYnNCzqDAPCr4m/fqyUFv7fD9qIsd50S6GDFgO1DxZhncCsNsG7IfUlAlvZe5oSEQxtsjnHiUuppzccry93Xw==", + "dependencies": { + "tslib": "2.3.0", + "zrender": "5.5.0" + } + }, + "node_modules/echarts/node_modules/tslib": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.3.0.tgz", + "integrity": "sha512-N82ooyxVNm6h1riLCoyS9e3fuJ3AMG2zIZs2Gd1ATcSFjSA23Q0fzjjZeh0jbJvWVDZ0cJT8yaNNaaXHzueNjg==" + }, + "node_modules/ee-first": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", + "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=" + }, + "node_modules/electron-to-chromium": { + "version": "1.4.715", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.715.tgz", + "integrity": "sha512-XzWNH4ZSa9BwVUQSDorPWAUQ5WGuYz7zJUNpNif40zFCiCl20t8zgylmreNmn26h5kiyw2lg7RfTmeMBsDklqg==" + }, + "node_modules/elliptic": { + "version": "6.5.4", + "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.5.4.tgz", + "integrity": "sha512-iLhC6ULemrljPZb+QutR5TQGB+pdW6KGD5RSegS+8sorOZT+rdQFbsQFJgvN3eRqNALqJer4oQ16YvJHlU8hzQ==", + "dependencies": { + "bn.js": "^4.11.9", + "brorand": "^1.1.0", + "hash.js": "^1.0.0", + "hmac-drbg": "^1.0.1", + "inherits": "^2.0.4", + "minimalistic-assert": "^1.0.1", + "minimalistic-crypto-utils": "^1.0.1" + } + }, + "node_modules/elliptic/node_modules/bn.js": { + "version": "4.12.0", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", + "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==" + }, + "node_modules/emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==" + }, + "node_modules/emojis-list": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/emojis-list/-/emojis-list-3.0.0.tgz", + "integrity": "sha512-/kyM18EfinwXZbno9FyUGeFh87KC8HRQBQGildHZbEuRyWFOmv1U10o9BBp8XVZDVNNuQKyIGIu5ZYAAXJ0V2Q==", + "engines": { + "node": ">= 4" + } + }, + "node_modules/encode-utf8": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/encode-utf8/-/encode-utf8-1.0.3.tgz", + "integrity": "sha512-ucAnuBEhUK4boH2HjVYG5Q2mQyPorvv0u/ocS+zhdw0S8AlHYY+GOFhP1Gio5z4icpP2ivFSvhtFjQi8+T9ppw==" + }, + "node_modules/encodeurl": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", + "integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k=", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/encoding": { + "version": "0.1.13", + "resolved": "https://registry.npmjs.org/encoding/-/encoding-0.1.13.tgz", + "integrity": "sha512-ETBauow1T35Y/WZMkio9jiM0Z5xjHHmJ4XmjZOq1l/dXz3lr2sRn87nJy20RupqSh1F2m3HHPSp8ShIPQJrJ3A==", + "optional": true, + "dependencies": { + "iconv-lite": "^0.6.2" + } + }, + "node_modules/encoding/node_modules/iconv-lite": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", + "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", + "optional": true, + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/end-of-stream": { + "version": "1.4.4", + "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", + "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", + "dependencies": { + "once": "^1.4.0" + } + }, + "node_modules/engine.io": { + "version": "6.5.1", + "resolved": "https://registry.npmjs.org/engine.io/-/engine.io-6.5.1.tgz", + "integrity": "sha512-mGqhI+D7YxS9KJMppR6Iuo37Ed3abhU8NdfgSvJSDUafQutrN+sPTncJYTyM9+tkhSmWodKtVYGPPHyXJEwEQA==", + "devOptional": true, + "dependencies": { + "@types/cookie": "^0.4.1", + "@types/cors": "^2.8.12", + "@types/node": ">=10.0.0", + "accepts": "~1.3.4", + "base64id": "2.0.0", + "cookie": "~0.4.1", + "cors": "~2.8.5", + "debug": "~4.3.1", + "engine.io-parser": "~5.1.0", + "ws": "~8.11.0" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/engine.io-client": { + "version": "6.5.3", + "resolved": "https://registry.npmjs.org/engine.io-client/-/engine.io-client-6.5.3.tgz", + "integrity": "sha512-9Z0qLB0NIisTRt1DZ/8U2k12RJn8yls/nXMZLn+/N8hANT3TcYjKFKcwbw5zFQiN4NTde3TSY9zb79e1ij6j9Q==", + "devOptional": true, + "dependencies": { + "@socket.io/component-emitter": "~3.1.0", + "debug": "~4.3.1", + "engine.io-parser": "~5.2.1", + "ws": "~8.11.0", + "xmlhttprequest-ssl": "~2.0.0" + } + }, + "node_modules/engine.io-client/node_modules/engine.io-parser": { + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-5.2.2.tgz", + "integrity": "sha512-RcyUFKA93/CXH20l4SoVvzZfrSDMOTUS3bWVpTt2FuFP+XYrL8i8oonHP7WInRyVHXh0n/ORtoeiE1os+8qkSw==", + "devOptional": true, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/engine.io-client/node_modules/ws": { + "version": "8.11.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.11.0.tgz", + "integrity": "sha512-HPG3wQd9sNQoT9xHyNCXoDUa+Xw/VevmY9FoHyQ+g+rrMn4j6FB4np7Z0OhdTgjx6MgQLK7jwSy1YecU1+4Asg==", + "devOptional": true, + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": "^5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, + "node_modules/engine.io-parser": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-5.1.0.tgz", + "integrity": "sha512-enySgNiK5tyZFynt3z7iqBR+Bto9EVVVvDFuTT0ioHCGbzirZVGDGiQjZzEp8hWl6hd5FSVytJGuScX1C1C35w==", + "devOptional": true, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/engine.io/node_modules/cookie": { + "version": "0.4.2", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.2.tgz", + "integrity": "sha512-aSWTXFzaKWkvHO1Ny/s+ePFpvKsPnjc551iI41v3ny/ow6tBG5Vd+FuqGNhh1LxOmVzOlGUriIlOaokOvhaStA==", + "devOptional": true, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/engine.io/node_modules/ws": { + "version": "8.11.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.11.0.tgz", + "integrity": "sha512-HPG3wQd9sNQoT9xHyNCXoDUa+Xw/VevmY9FoHyQ+g+rrMn4j6FB4np7Z0OhdTgjx6MgQLK7jwSy1YecU1+4Asg==", + "devOptional": true, + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": "^5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, + "node_modules/enhanced-resolve": { + "version": "5.15.0", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.15.0.tgz", + "integrity": "sha512-LXYT42KJ7lpIKECr2mAXIaMldcNCh/7E0KBKOu4KSfkHmP+mZmSs+8V5gBAqisWBy0OO4W5Oyys0GO1Y8KtdKg==", + "dependencies": { + "graceful-fs": "^4.2.4", + "tapable": "^2.2.0" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/enquirer": { + "version": "2.3.6", + "resolved": "https://registry.npmjs.org/enquirer/-/enquirer-2.3.6.tgz", + "integrity": "sha512-yjNnPr315/FjS4zIsUxYguYUPP2e1NK4d7E7ZOLiyYCcbFBiTMyID+2wvm2w6+pZ/odMA7cRkjhsPbltwBOrLg==", + "optional": true, + "dependencies": { + "ansi-colors": "^4.1.1" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/ent": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/ent/-/ent-2.2.0.tgz", + "integrity": "sha1-6WQhkyWiHQX0RGai9obtbOX13R0=", + "optional": true, + "peer": true + }, + "node_modules/entities": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", + "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==", + "engines": { + "node": ">=0.12" + }, + "funding": { + "url": "https://github.com/fb55/entities?sponsor=1" + } + }, + "node_modules/env-paths": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/env-paths/-/env-paths-2.2.1.tgz", + "integrity": "sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==", + "engines": { + "node": ">=6" + } + }, + "node_modules/err-code": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/err-code/-/err-code-2.0.3.tgz", + "integrity": "sha512-2bmlRpNKBxT/CRmPOlyISQpNj+qSeYvcym/uT0Jx2bMOlKLtSy1ZmLuVxSEKKyor/N5yhvp/ZiG1oE3DEYMSFA==" + }, + "node_modules/errno": { + "version": "0.1.8", + "resolved": "https://registry.npmjs.org/errno/-/errno-0.1.8.tgz", + "integrity": "sha512-dJ6oBr5SQ1VSd9qkk7ByRgb/1SH4JZjCHSW/mr63/QcXO9zLVxvJ6Oy13nio03rxpSnVDDjFor75SjVeZWPW/A==", + "optional": true, + "dependencies": { + "prr": "~1.0.1" + }, + "bin": { + "errno": "cli.js" + } + }, + "node_modules/error-ex": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", + "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", + "dependencies": { + "is-arrayish": "^0.2.1" + } + }, + "node_modules/es-abstract": { + "version": "1.18.0", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.18.0.tgz", + "integrity": "sha512-LJzK7MrQa8TS0ja2w3YNLzUgJCGPdPOV1yVvezjNnS89D+VR08+Szt2mz3YB2Dck/+w5tfIq/RoUAFqJJGM2yw==", + "dependencies": { + "call-bind": "^1.0.2", + "es-to-primitive": "^1.2.1", + "function-bind": "^1.1.1", + "get-intrinsic": "^1.1.1", + "has": "^1.0.3", + "has-symbols": "^1.0.2", + "is-callable": "^1.2.3", + "is-negative-zero": "^2.0.1", + "is-regex": "^1.1.2", + "is-string": "^1.0.5", + "object-inspect": "^1.9.0", + "object-keys": "^1.1.1", + "object.assign": "^4.1.2", + "string.prototype.trimend": "^1.0.4", + "string.prototype.trimstart": "^1.0.4", + "unbox-primitive": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/es-define-property": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.0.tgz", + "integrity": "sha512-jxayLKShrEqqzJ0eumQbVhTYQM27CfT1T35+gCgDFoL82JLsXqTJ76zv6A0YLOgEnLUMvLzsDsGIrl8NFpT2gQ==", + "dependencies": { + "get-intrinsic": "^1.2.4" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-errors": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", + "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/es-module-lexer": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.3.0.tgz", + "integrity": "sha512-vZK7T0N2CBmBOixhmjdqx2gWVbFZ4DXZ/NyRMZVlJXPa7CyFS+/a4QQsDGDQy9ZfEzxFuNEsMLeQJnKP2p5/JA==" + }, + "node_modules/es-to-primitive": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", + "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", + "dependencies": { + "is-callable": "^1.1.4", + "is-date-object": "^1.0.1", + "is-symbol": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/es5-ext": { + "version": "0.10.64", + "resolved": "https://registry.npmjs.org/es5-ext/-/es5-ext-0.10.64.tgz", + "integrity": "sha512-p2snDhiLaXe6dahss1LddxqEm+SkuDvV8dnIQG0MWjyHpcMNfXKPE+/Cc0y+PhxJX3A4xGNeFCj5oc0BUh6deg==", + "hasInstallScript": true, + "dependencies": { + "es6-iterator": "^2.0.3", + "es6-symbol": "^3.1.3", + "esniff": "^2.0.1", + "next-tick": "^1.1.0" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/es6-iterator": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/es6-iterator/-/es6-iterator-2.0.3.tgz", + "integrity": "sha1-p96IkUGgWpSwhUQDstCg+/qY87c=", + "dependencies": { + "d": "1", + "es5-ext": "^0.10.35", + "es6-symbol": "^3.1.1" + } + }, + "node_modules/es6-map": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/es6-map/-/es6-map-0.1.5.tgz", + "integrity": "sha1-kTbgUD3MBqMBaQ8LsU/042TpSfA=", + "dependencies": { + "d": "1", + "es5-ext": "~0.10.14", + "es6-iterator": "~2.0.1", + "es6-set": "~0.1.5", + "es6-symbol": "~3.1.1", + "event-emitter": "~0.3.5" + } + }, + "node_modules/es6-set": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/es6-set/-/es6-set-0.1.5.tgz", + "integrity": "sha1-0rPsXU2ADO2BjbU40ol02wpzzLE=", + "dependencies": { + "d": "1", + "es5-ext": "~0.10.14", + "es6-iterator": "~2.0.1", + "es6-symbol": "3.1.1", + "event-emitter": "~0.3.5" + } + }, + "node_modules/es6-set/node_modules/es6-symbol": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/es6-symbol/-/es6-symbol-3.1.1.tgz", + "integrity": "sha1-vwDvT9q2uhtG7Le2KbTH7VcVzHc=", + "dependencies": { + "d": "1", + "es5-ext": "~0.10.14" + } + }, + "node_modules/es6-symbol": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/es6-symbol/-/es6-symbol-3.1.3.tgz", + "integrity": "sha512-NJ6Yn3FuDinBaBRWl/q5X/s4koRHBrgKAu+yGI6JCBeiu3qrcbJhwT2GeR/EXVfylRk8dpQVJoLEFhK+Mu31NA==", + "dependencies": { + "d": "^1.0.1", + "ext": "^1.1.2" + } + }, + "node_modules/es6-weak-map": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/es6-weak-map/-/es6-weak-map-2.0.3.tgz", + "integrity": "sha512-p5um32HOTO1kP+w7PRnB+5lQ43Z6muuMuIMffvDN8ZB4GcnjLBV6zGStpbASIMk4DCAvEaamhe2zhyCb/QXXsA==", + "dependencies": { + "d": "1", + "es5-ext": "^0.10.46", + "es6-iterator": "^2.0.3", + "es6-symbol": "^3.1.1" + } + }, + "node_modules/esbuild": { + "version": "0.23.0", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.23.0.tgz", + "integrity": "sha512-1lvV17H2bMYda/WaFb2jLPeHU3zml2k4/yagNMG8Q/YtfMjCwEUZa2eXXMgZTVSL5q1n4H7sQ0X6CdJDqqeCFA==", + "hasInstallScript": true, + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=18" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.23.0", + "@esbuild/android-arm": "0.23.0", + "@esbuild/android-arm64": "0.23.0", + "@esbuild/android-x64": "0.23.0", + "@esbuild/darwin-arm64": "0.23.0", + "@esbuild/darwin-x64": "0.23.0", + "@esbuild/freebsd-arm64": "0.23.0", + "@esbuild/freebsd-x64": "0.23.0", + "@esbuild/linux-arm": "0.23.0", + "@esbuild/linux-arm64": "0.23.0", + "@esbuild/linux-ia32": "0.23.0", + "@esbuild/linux-loong64": "0.23.0", + "@esbuild/linux-mips64el": "0.23.0", + "@esbuild/linux-ppc64": "0.23.0", + "@esbuild/linux-riscv64": "0.23.0", + "@esbuild/linux-s390x": "0.23.0", + "@esbuild/linux-x64": "0.23.0", + "@esbuild/netbsd-x64": "0.23.0", + "@esbuild/openbsd-arm64": "0.23.0", + "@esbuild/openbsd-x64": "0.23.0", + "@esbuild/sunos-x64": "0.23.0", + "@esbuild/win32-arm64": "0.23.0", + "@esbuild/win32-ia32": "0.23.0", + "@esbuild/win32-x64": "0.23.0" + } + }, + "node_modules/esbuild-wasm": { + "version": "0.20.1", + "resolved": "https://registry.npmjs.org/esbuild-wasm/-/esbuild-wasm-0.20.1.tgz", + "integrity": "sha512-6v/WJubRsjxBbQdz6izgvx7LsVFvVaGmSdwrFHmEzoVgfXL89hkKPoQHsnVI2ngOkcBUQT9kmAM1hVL1k/Av4A==", + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/escalade": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", + "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==", + "engines": { + "node": ">=6" + } + }, + "node_modules/escape-html": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", + "integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg=" + }, + "node_modules/escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/escodegen": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-2.1.0.tgz", + "integrity": "sha512-2NlIDTwUWJN0mRPQOdtQBzbUHvdGY2P1VXSyU83Q3xKxM7WHX2Ql8dKq782Q9TgQUNOLEzEYu9bzLNj1q88I5w==", + "dependencies": { + "esprima": "^4.0.1", + "estraverse": "^5.2.0", + "esutils": "^2.0.2" + }, + "bin": { + "escodegen": "bin/escodegen.js", + "esgenerate": "bin/esgenerate.js" + }, + "engines": { + "node": ">=6.0" + }, + "optionalDependencies": { + "source-map": "~0.6.1" + } + }, + "node_modules/escodegen/node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "engines": { + "node": ">=4.0" + } + }, + "node_modules/escodegen/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "optional": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/escope": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/escope/-/escope-3.6.0.tgz", + "integrity": "sha512-75IUQsusDdalQEW/G/2esa87J7raqdJF+Ca0/Xm5C3Q58Nr4yVYjZGp/P1+2xiEVgXRrA39dpRb8LcshajbqDQ==", + "dependencies": { + "es6-map": "^0.1.3", + "es6-weak-map": "^2.0.1", + "esrecurse": "^4.1.0", + "estraverse": "^4.1.1" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/eslint": { + "version": "8.57.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.57.0.tgz", + "integrity": "sha512-dZ6+mexnaTIbSBZWgou51U6OmzIhYM2VcNdtiTtI7qPNZm35Akpr0f6vtw3w1Kmn5PYo+tZVfh13WrhpS6oLqQ==", + "dev": true, + "dependencies": { + "@eslint-community/eslint-utils": "^4.2.0", + "@eslint-community/regexpp": "^4.6.1", + "@eslint/eslintrc": "^2.1.4", + "@eslint/js": "8.57.0", + "@humanwhocodes/config-array": "^0.11.14", + "@humanwhocodes/module-importer": "^1.0.1", + "@nodelib/fs.walk": "^1.2.8", + "@ungap/structured-clone": "^1.2.0", + "ajv": "^6.12.4", + "chalk": "^4.0.0", + "cross-spawn": "^7.0.2", + "debug": "^4.3.2", + "doctrine": "^3.0.0", + "escape-string-regexp": "^4.0.0", + "eslint-scope": "^7.2.2", + "eslint-visitor-keys": "^3.4.3", + "espree": "^9.6.1", + "esquery": "^1.4.2", + "esutils": "^2.0.2", + "fast-deep-equal": "^3.1.3", + "file-entry-cache": "^6.0.1", + "find-up": "^5.0.0", + "glob-parent": "^6.0.2", + "globals": "^13.19.0", + "graphemer": "^1.4.0", + "ignore": "^5.2.0", + "imurmurhash": "^0.1.4", + "is-glob": "^4.0.0", + "is-path-inside": "^3.0.3", + "js-yaml": "^4.1.0", + "json-stable-stringify-without-jsonify": "^1.0.1", + "levn": "^0.4.1", + "lodash.merge": "^4.6.2", + "minimatch": "^3.1.2", + "natural-compare": "^1.4.0", + "optionator": "^0.9.3", + "strip-ansi": "^6.0.1", + "text-table": "^0.2.0" + }, + "bin": { + "eslint": "bin/eslint.js" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint-scope": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", + "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^4.1.1" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/eslint-visitor-keys": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", + "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", + "dev": true, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/eslint/node_modules/argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true + }, + "node_modules/eslint/node_modules/chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/eslint/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/eslint/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "node_modules/eslint/node_modules/escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint/node_modules/eslint-scope": { + "version": "7.2.2", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.2.tgz", + "integrity": "sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==", + "dev": true, + "dependencies": { + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/eslint/node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/eslint/node_modules/find-up": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "dev": true, + "dependencies": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint/node_modules/glob-parent": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "dev": true, + "dependencies": { + "is-glob": "^4.0.3" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/eslint/node_modules/globals": { + "version": "13.24.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.24.0.tgz", + "integrity": "sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==", + "dev": true, + "dependencies": { + "type-fest": "^0.20.2" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/eslint/node_modules/js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "dev": true, + "dependencies": { + "argparse": "^2.0.1" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/eslint/node_modules/locate-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "dev": true, + "dependencies": { + "p-locate": "^5.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint/node_modules/p-locate": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "dev": true, + "dependencies": { + "p-limit": "^3.0.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/eslint/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/eslint/node_modules/type-fest": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", + "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/esniff": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/esniff/-/esniff-2.0.1.tgz", + "integrity": "sha512-kTUIGKQ/mDPFoJ0oVfcmyJn4iBDRptjNVIzwIFR7tqWXdVI9xfA2RMwY/gbSpJG3lkdWNEjLap/NqVHZiJsdfg==", + "dependencies": { + "d": "^1.0.1", + "es5-ext": "^0.10.62", + "event-emitter": "^0.3.5", + "type": "^2.7.2" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/esniff/node_modules/type": { + "version": "2.7.2", + "resolved": "https://registry.npmjs.org/type/-/type-2.7.2.tgz", + "integrity": "sha512-dzlvlNlt6AXU7EBSfpAscydQ7gXB+pPGsPnfJnZpiNJBDj7IaJzQlBZYGdEi4R9HmPdBv2XmWJ6YUtoTa7lmCw==" + }, + "node_modules/espree": { + "version": "9.6.1", + "resolved": "https://registry.npmjs.org/espree/-/espree-9.6.1.tgz", + "integrity": "sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==", + "dev": true, + "dependencies": { + "acorn": "^8.9.0", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^3.4.1" + }, + "engines": { + "node": "^12.22.0 || ^14.17.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint" + } + }, + "node_modules/espree/node_modules/acorn": { + "version": "8.11.3", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.11.3.tgz", + "integrity": "sha512-Y9rRfJG5jcKOE0CLisYbojUjIrIEE7AGMzA/Sm4BslANhbS+cDMpgBdcPT91oJ7OuJ9hYJBx59RjbhxVnrF8Xg==", + "dev": true, + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/esprima": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==", + "bin": { + "esparse": "bin/esparse.js", + "esvalidate": "bin/esvalidate.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/esquery": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.5.0.tgz", + "integrity": "sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg==", + "dev": true, + "dependencies": { + "estraverse": "^5.1.0" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/esquery/node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/esrecurse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "dependencies": { + "estraverse": "^5.2.0" + }, + "engines": { + "node": ">=4.0" + } + }, + "node_modules/esrecurse/node_modules/estraverse": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.2.0.tgz", + "integrity": "sha512-BxbNGGNm0RyRYvUdHpIwv9IWzeM9XClbOxwoATuFdOE7ZE6wHL+HQ5T8hoPM+zHvmKzzsEqhgy0GrQ5X13afiQ==", + "engines": { + "node": ">=4.0" + } + }, + "node_modules/estraverse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", + "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", + "engines": { + "node": ">=4.0" + } + }, + "node_modules/estree-is-function": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/estree-is-function/-/estree-is-function-1.0.0.tgz", + "integrity": "sha512-nSCWn1jkSq2QAtkaVLJZY2ezwcFO161HVc174zL1KPW3RJ+O6C3eJb8Nx7OXzvhoEv+nLgSR1g71oWUHUDTrJA==" + }, + "node_modules/estree-is-identifier": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/estree-is-identifier/-/estree-is-identifier-1.0.0.tgz", + "integrity": "sha512-2BDRGrkQJV/NhCAmmE33A35WAaxq3WQaGHgQuD//7orGWfpFqj8Srkwvx0TH+20yIdOF1yMQwi8anv5ISec2AQ==" + }, + "node_modules/estree-is-member-expression": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/estree-is-member-expression/-/estree-is-member-expression-1.0.0.tgz", + "integrity": "sha512-Ec+X44CapIGExvSZN+pGkmr5p7HwUVQoPQSd458Lqwvaf4/61k/invHSh4BYK8OXnCkfEhWuIoG5hayKLQStIg==" + }, + "node_modules/estree-is-require": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/estree-is-require/-/estree-is-require-1.0.0.tgz", + "integrity": "sha512-oWxQdSEmnUwNZsDQYiBNpVxKEhMmsJQSSxnDrwsr1MWtooCLfhgzsNGzmokdmfK0EzEIS5V4LPvqxv1Kmb1vvA==", + "dependencies": { + "estree-is-identifier": "^1.0.0" + } + }, + "node_modules/esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/etag": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", + "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/event-emitter": { + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/event-emitter/-/event-emitter-0.3.5.tgz", + "integrity": "sha1-34xp7vFkeSPHFXuc6DhAYQsCzDk=", + "dependencies": { + "d": "1", + "es5-ext": "~0.10.14" + } + }, + "node_modules/event-stream": { + "version": "3.3.4", + "resolved": "https://registry.npmjs.org/event-stream/-/event-stream-3.3.4.tgz", + "integrity": "sha1-SrTJoPWlTbkzi0w02Gv86PSzVXE=", + "optional": true, + "dependencies": { + "duplexer": "~0.1.1", + "from": "~0", + "map-stream": "~0.1.0", + "pause-stream": "0.0.11", + "split": "0.3", + "stream-combiner": "~0.0.4", + "through": "~2.3.1" + } + }, + "node_modules/event-stream/node_modules/stream-combiner": { + "version": "0.0.4", + "resolved": "https://registry.npmjs.org/stream-combiner/-/stream-combiner-0.0.4.tgz", + "integrity": "sha1-TV5DPBhSYd3mI8o/RMWGvPXErRQ=", + "optional": true, + "dependencies": { + "duplexer": "~0.1.1" + } + }, + "node_modules/eventemitter2": { + "version": "6.4.7", + "resolved": "https://registry.npmjs.org/eventemitter2/-/eventemitter2-6.4.7.tgz", + "integrity": "sha512-tYUSVOGeQPKt/eC1ABfhHy5Xd96N3oIijJvN3O9+TsC28T5V9yX9oEfEK5faP0EFSNVOG97qtAS68GBrQB2hDg==", + "optional": true + }, + "node_modules/eventemitter3": { + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz", + "integrity": "sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==" + }, + "node_modules/events": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz", + "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==", + "engines": { + "node": ">=0.8.x" + } + }, + "node_modules/evp_bytestokey": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/evp_bytestokey/-/evp_bytestokey-1.0.3.tgz", + "integrity": "sha512-/f2Go4TognH/KvCISP7OUsHn85hT9nUkxxA9BEWxFn+Oj9o8ZNLm/40hdlgSLyuOimsrTKLUMEorQexp/aPQeA==", + "dependencies": { + "md5.js": "^1.3.4", + "safe-buffer": "^5.1.1" + } + }, + "node_modules/execa": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", + "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==", + "dependencies": { + "cross-spawn": "^7.0.3", + "get-stream": "^6.0.0", + "human-signals": "^2.1.0", + "is-stream": "^2.0.0", + "merge-stream": "^2.0.0", + "npm-run-path": "^4.0.1", + "onetime": "^5.1.2", + "signal-exit": "^3.0.3", + "strip-final-newline": "^2.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sindresorhus/execa?sponsor=1" + } + }, + "node_modules/execa/node_modules/human-signals": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz", + "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==", + "engines": { + "node": ">=10.17.0" + } + }, + "node_modules/executable": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/executable/-/executable-4.1.1.tgz", + "integrity": "sha512-8iA79xD3uAch729dUG8xaaBBFGaEa0wdD2VkYLFHwlqosEj/jT66AzcreRDSgV7ehnNLBW2WR5jIXwGKjVdTLg==", + "optional": true, + "dependencies": { + "pify": "^2.2.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/exponential-backoff": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/exponential-backoff/-/exponential-backoff-3.1.1.tgz", + "integrity": "sha512-dX7e/LHVJ6W3DE1MHWi9S1EYzDESENfLrYohG2G++ovZrYOkm4Knwa0mc1cn84xJOR4KEU0WSchhLbd0UklbHw==" + }, + "node_modules/express": { + "version": "4.19.2", + "resolved": "https://registry.npmjs.org/express/-/express-4.19.2.tgz", + "integrity": "sha512-5T6nhjsT+EOMzuck8JjBHARTHfMht0POzlA60WV2pMD3gyXw2LZnZ+ueGdNxG+0calOJcWKbpFcuzLZ91YWq9Q==", + "dependencies": { + "accepts": "~1.3.8", + "array-flatten": "1.1.1", + "body-parser": "1.20.2", + "content-disposition": "0.5.4", + "content-type": "~1.0.4", + "cookie": "0.6.0", + "cookie-signature": "1.0.6", + "debug": "2.6.9", + "depd": "2.0.0", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "finalhandler": "1.2.0", + "fresh": "0.5.2", + "http-errors": "2.0.0", + "merge-descriptors": "1.0.1", + "methods": "~1.1.2", + "on-finished": "2.4.1", + "parseurl": "~1.3.3", + "path-to-regexp": "0.1.7", + "proxy-addr": "~2.0.7", + "qs": "6.11.0", + "range-parser": "~1.2.1", + "safe-buffer": "5.2.1", + "send": "0.18.0", + "serve-static": "1.15.0", + "setprototypeof": "1.2.0", + "statuses": "2.0.1", + "type-is": "~1.6.18", + "utils-merge": "1.0.1", + "vary": "~1.1.2" + }, + "engines": { + "node": ">= 0.10.0" + } + }, + "node_modules/express/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/express/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" + }, + "node_modules/express/node_modules/on-finished": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", + "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", + "dependencies": { + "ee-first": "1.1.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/express/node_modules/qs": { + "version": "6.11.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz", + "integrity": "sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==", + "dependencies": { + "side-channel": "^1.0.4" + }, + "engines": { + "node": ">=0.6" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/express/node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/express/node_modules/statuses": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", + "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/ext": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/ext/-/ext-1.4.0.tgz", + "integrity": "sha512-Key5NIsUxdqKg3vIsdw9dSuXpPCQ297y6wBjL30edxwPgt2E44WcWBZey/ZvUc6sERLTxKdyCu4gZFmUbk1Q7A==", + "dependencies": { + "type": "^2.0.0" + } + }, + "node_modules/ext/node_modules/type": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/type/-/type-2.1.0.tgz", + "integrity": "sha512-G9absDWvhAWCV2gmF1zKud3OyC61nZDwWvBL2DApaVFogI07CprggiQAOOjvp2NRjYWFzPyu7vwtDrQFq8jeSA==" + }, + "node_modules/extend": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", + "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==", + "optional": true + }, + "node_modules/external-editor": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-3.1.0.tgz", + "integrity": "sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew==", + "dependencies": { + "chardet": "^0.7.0", + "iconv-lite": "^0.4.24", + "tmp": "^0.0.33" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/extract-zip": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extract-zip/-/extract-zip-2.0.1.tgz", + "integrity": "sha512-GDhU9ntwuKyGXdZBUgTIe+vXnWj0fppUEtMDL0+idd5Sta8TGpHssn/eusA9mrPr9qNDym6SxAYZjNvCn/9RBg==", + "optional": true, + "dependencies": { + "debug": "^4.1.1", + "get-stream": "^5.1.0", + "yauzl": "^2.10.0" + }, + "bin": { + "extract-zip": "cli.js" + }, + "engines": { + "node": ">= 10.17.0" + }, + "optionalDependencies": { + "@types/yauzl": "^2.9.1" + } + }, + "node_modules/extract-zip/node_modules/get-stream": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz", + "integrity": "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==", + "optional": true, + "dependencies": { + "pump": "^3.0.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/extsprintf": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz", + "integrity": "sha512-11Ndz7Nv+mvAC1j0ktTa7fAb0vLyGGX+rMHNBYQviQDGU0Hw7lhctJANqbPhu9nV9/izT/IntTgZ7Im/9LJs9g==", + "engines": [ + "node >=0.6.0" + ], + "optional": true + }, + "node_modules/falafel": { + "version": "2.2.4", + "resolved": "https://registry.npmjs.org/falafel/-/falafel-2.2.4.tgz", + "integrity": "sha512-0HXjo8XASWRmsS0X1EkhwEMZaD3Qvp7FfURwjLKjG1ghfRm/MGZl2r4cWUTv41KdNghTw4OUMmVtdGQp3+H+uQ==", + "dependencies": { + "acorn": "^7.1.1", + "foreach": "^2.0.5", + "isarray": "^2.0.1", + "object-keys": "^1.0.6" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/fancy-canvas": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/fancy-canvas/-/fancy-canvas-0.2.2.tgz", + "integrity": "sha512-50qi8xA0QkHbjmb8h7XQ6k2fvD7y/yMfiUw9YTarJ7rWrq6o5/3CCXPouYk+XSLASvvxtjyiQLRBFt3qkE3oyA==" + }, + "node_modules/fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==" + }, + "node_modules/fast-glob": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.2.tgz", + "integrity": "sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==", + "dependencies": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.2", + "merge2": "^1.3.0", + "micromatch": "^4.0.4" + }, + "engines": { + "node": ">=8.6.0" + } + }, + "node_modules/fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==" + }, + "node_modules/fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", + "dev": true + }, + "node_modules/fast-safe-stringify": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/fast-safe-stringify/-/fast-safe-stringify-2.0.7.tgz", + "integrity": "sha512-Utm6CdzT+6xsDk2m8S6uL8VHxNwI6Jub+e9NYTcAms28T84pTa25GJQV9j0CY0N1rM8hK4x6grpF2BQf+2qwVA==" + }, + "node_modules/fastq": { + "version": "1.13.0", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.13.0.tgz", + "integrity": "sha512-YpkpUnK8od0o1hmeSc7UUs/eB/vIPWJYjKck2QKIzAf71Vm1AAQ3EbuZB3g2JIy+pg+ERD0vqI79KyZiB2e2Nw==", + "dependencies": { + "reusify": "^1.0.4" + } + }, + "node_modules/faye-websocket": { + "version": "0.11.4", + "resolved": "https://registry.npmjs.org/faye-websocket/-/faye-websocket-0.11.4.tgz", + "integrity": "sha512-CzbClwlXAuiRQAlUyfqPgvPoNKTckTPGfwZV4ZdAhVcP2lh9KUxJg2b5GkE7XbjKQ3YJnQ9z6D9ntLAlB+tP8g==", + "dependencies": { + "websocket-driver": ">=0.5.1" + }, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/fd-slicer": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/fd-slicer/-/fd-slicer-1.1.0.tgz", + "integrity": "sha512-cE1qsB/VwyQozZ+q1dGxR8LBYNZeofhEdUNGSMbQD3Gw2lAzX9Zb3uIU6Ebc/Fmyjo9AWWfnn0AUCHqtevs/8g==", + "optional": true, + "dependencies": { + "pend": "~1.2.0" + } + }, + "node_modules/figures": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/figures/-/figures-3.2.0.tgz", + "integrity": "sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg==", + "dependencies": { + "escape-string-regexp": "^1.0.5" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/file-entry-cache": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", + "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", + "dev": true, + "dependencies": { + "flat-cache": "^3.0.4" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + } + }, + "node_modules/fill-range": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/finalhandler": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.2.0.tgz", + "integrity": "sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg==", + "dependencies": { + "debug": "2.6.9", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "on-finished": "2.4.1", + "parseurl": "~1.3.3", + "statuses": "2.0.1", + "unpipe": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/finalhandler/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/finalhandler/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" + }, + "node_modules/finalhandler/node_modules/on-finished": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", + "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", + "dependencies": { + "ee-first": "1.1.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/finalhandler/node_modules/statuses": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", + "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/find-cache-dir": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-4.0.0.tgz", + "integrity": "sha512-9ZonPT4ZAK4a+1pUPVPZJapbi7O5qbbJPdYw/NOQWZZbVLdDTYM3A4R9z/DpAM08IDaFGsvPgiGZ82WEwUDWjg==", + "dependencies": { + "common-path-prefix": "^3.0.0", + "pkg-dir": "^7.0.0" + }, + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "dependencies": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/flat": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/flat/-/flat-5.0.2.tgz", + "integrity": "sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==", + "bin": { + "flat": "cli.js" + } + }, + "node_modules/flat-cache": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.2.0.tgz", + "integrity": "sha512-CYcENa+FtcUKLmhhqyctpclsq7QF38pKjZHsGNiSQF5r4FtoKDWabFDl3hzaEQMvT1LHEysw5twgLvpYYb4vbw==", + "dev": true, + "dependencies": { + "flatted": "^3.2.9", + "keyv": "^4.5.3", + "rimraf": "^3.0.2" + }, + "engines": { + "node": "^10.12.0 || >=12.0.0" + } + }, + "node_modules/flatted": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.1.tgz", + "integrity": "sha512-X8cqMLLie7KsNUDSdzeN8FYK9rEt4Dt67OsG/DNGnYTSDBG4uFAJFBnUeiV+zCVAvwFy56IjM9sH51jVaEhNxw==", + "devOptional": true + }, + "node_modules/follow-redirects": { + "version": "1.15.6", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.6.tgz", + "integrity": "sha512-wWN62YITEaOpSK584EZXJafH1AGpO8RVgElfkuXbTOrPX4fIfOyEpW/CsiNd8JdYrAoOvafRTOEnvsO++qCqFA==", + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/RubenVerborgh" + } + ], + "engines": { + "node": ">=4.0" + }, + "peerDependenciesMeta": { + "debug": { + "optional": true + } + } + }, + "node_modules/foreach": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/foreach/-/foreach-2.0.5.tgz", + "integrity": "sha1-C+4AUBiusmDQo6865ljdATbsG5k=" + }, + "node_modules/foreground-child": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.1.1.tgz", + "integrity": "sha512-TMKDUnIte6bfb5nWv7V/caI169OHgvwjb7V4WkeUvbQQdjr5rWKqHFiKWb/fcOwB+CzBT+qbWjvj+DVwRskpIg==", + "dependencies": { + "cross-spawn": "^7.0.0", + "signal-exit": "^4.0.1" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/foreground-child/node_modules/signal-exit": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", + "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==", + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/forever-agent": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", + "integrity": "sha512-j0KLYPhm6zeac4lz3oJ3o65qvgQCcPubiyotZrXqEaG4hNagNYO8qdlUrX5vwqv9ohqeT/Z3j6+yW067yWWdUw==", + "optional": true, + "engines": { + "node": "*" + } + }, + "node_modules/form-data": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.3.tgz", + "integrity": "sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==", + "optional": true, + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.6", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 0.12" + } + }, + "node_modules/forwarded": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", + "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/fraction.js": { + "version": "4.3.7", + "resolved": "https://registry.npmjs.org/fraction.js/-/fraction.js-4.3.7.tgz", + "integrity": "sha512-ZsDfxO51wGAXREY55a7la9LScWpwv9RxIrYABrlvOFBlH/ShPnrtsXeuUIfXKKOVicNxQ+o8JTbJvjS4M89yew==", + "engines": { + "node": "*" + }, + "funding": { + "type": "patreon", + "url": "https://github.com/sponsors/rawify" + } + }, + "node_modules/fresh": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", + "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/from": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/from/-/from-0.1.7.tgz", + "integrity": "sha1-g8YK/Fi5xWmXAH7Rp2izqzA6RP4=", + "optional": true + }, + "node_modules/from2": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/from2/-/from2-2.3.0.tgz", + "integrity": "sha1-i/tVAr3kpNNs/e6gB/zKIdfjgq8=", + "dependencies": { + "inherits": "^2.0.1", + "readable-stream": "^2.0.0" + } + }, + "node_modules/from2-string": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/from2-string/-/from2-string-1.1.0.tgz", + "integrity": "sha1-GCgrJ9CKJnyzAwzSuLSw8hKvdSo=", + "dependencies": { + "from2": "^2.0.3" + } + }, + "node_modules/fs-extra": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.0.1.tgz", + "integrity": "sha512-NbdoVMZso2Lsrn/QwLXOy6rm0ufY2zEOKCDzJR/0kBsb0E6qed0P3iYK+Ath3BfvXEeu4JhEtXLgILx5psUfag==", + "optional": true, + "peer": true, + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/fs-minipass": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-3.0.3.tgz", + "integrity": "sha512-XUBA9XClHbnJWSfBzjkm6RvPsyg3sryZt06BEQoXcF7EK/xpGaQYJgQKDJSUH5SGZ76Y7pFx1QBnXz09rU5Fbw==", + "dependencies": { + "minipass": "^7.0.3" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/fs-monkey": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/fs-monkey/-/fs-monkey-1.0.5.tgz", + "integrity": "sha512-8uMbBjrhzW76TYgEV27Y5E//W2f/lTFmx78P2w19FZSxarhI/798APGQyuGCwmkNxgwGRhrLfvWyLBvNtuOmew==" + }, + "node_modules/fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=" + }, + "node_modules/fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "hasInstallScript": true, + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": "^8.16.0 || ^10.6.0 || >=11.0.0" + } + }, + "node_modules/function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/gensync": { + "version": "1.0.0-beta.2", + "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", + "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==", + "engines": { + "node": ">=6.9.0" + } + }, + "node_modules/get-assigned-identifiers": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/get-assigned-identifiers/-/get-assigned-identifiers-1.2.0.tgz", + "integrity": "sha512-mBBwmeGTrxEMO4pMaaf/uUEFHnYtwr8FTe8Y/mer4rcV/bye0qGm6pw1bGZFGStxC5O76c5ZAVBGnqHmOaJpdQ==" + }, + "node_modules/get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==", + "engines": { + "node": "6.* || 8.* || >= 10.*" + } + }, + "node_modules/get-func-name": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/get-func-name/-/get-func-name-2.0.2.tgz", + "integrity": "sha512-8vXOvuE167CtIc3OyItco7N/dpRtBbYOsPsXCz7X/PMnlGjYjSGuZJgM1Y7mmew7BKf9BqvLX2tnOVy1BBUsxQ==", + "optional": true, + "engines": { + "node": "*" + } + }, + "node_modules/get-intrinsic": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.4.tgz", + "integrity": "sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ==", + "dependencies": { + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "has-proto": "^1.0.1", + "has-symbols": "^1.0.3", + "hasown": "^2.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/get-package-type": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/get-package-type/-/get-package-type-0.1.0.tgz", + "integrity": "sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==", + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/get-stream": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", + "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/getos": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/getos/-/getos-3.2.1.tgz", + "integrity": "sha512-U56CfOK17OKgTVqozZjUKNdkfEv6jk5WISBJ8SHoagjE6L69zOwl3Z+O8myjY9MEW3i2HPWQBt/LTbCgcC973Q==", + "optional": true, + "dependencies": { + "async": "^3.2.0" + } + }, + "node_modules/getpass": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz", + "integrity": "sha512-0fzj9JxOLfJ+XGLhR8ze3unN0KZCgZwiSSDz168VERjK8Wl8kVSdcu2kspd4s4wtAa1y/qrVRiAA0WclVsu0ng==", + "optional": true, + "dependencies": { + "assert-plus": "^1.0.0" + } + }, + "node_modules/glob": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.0.tgz", + "integrity": "sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q==", + "dependencies": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + }, + "engines": { + "node": "*" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/glob-to-regexp": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz", + "integrity": "sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==" + }, + "node_modules/global-dirs": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/global-dirs/-/global-dirs-3.0.1.tgz", + "integrity": "sha512-NBcGGFbBA9s1VzD41QXDG+3++t9Mn5t1FpLdhESY6oKY4gYTFpX4wO3sqGUa0Srjtbfj3szX0RnemmrVRUdULA==", + "optional": true, + "dependencies": { + "ini": "2.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/global-dirs/node_modules/ini": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ini/-/ini-2.0.0.tgz", + "integrity": "sha512-7PnF4oN3CvZF23ADhA5wRaYEQpJ8qygSkbtTXWBeXWXmEVRXK+1ITciHWwHhsjv1TmW0MgacIv6hEi5pX5NQdA==", + "optional": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/globals": { + "version": "11.12.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", + "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==", + "engines": { + "node": ">=4" + } + }, + "node_modules/globby": { + "version": "13.1.2", + "resolved": "https://registry.npmjs.org/globby/-/globby-13.1.2.tgz", + "integrity": "sha512-LKSDZXToac40u8Q1PQtZihbNdTYSNMuWe+K5l+oa6KgDzSvVrHXlJy40hUP522RjAIoNLJYBJi7ow+rbFpIhHQ==", + "dependencies": { + "dir-glob": "^3.0.1", + "fast-glob": "^3.2.11", + "ignore": "^5.2.0", + "merge2": "^1.4.1", + "slash": "^4.0.0" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/good-listener": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/good-listener/-/good-listener-1.2.2.tgz", + "integrity": "sha1-1TswzfkxPf+33JoNR3CWqm0UXFA=", + "dependencies": { + "delegate": "^3.1.2" + } + }, + "node_modules/gopd": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz", + "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==", + "dependencies": { + "get-intrinsic": "^1.1.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/graceful-fs": { + "version": "4.2.9", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.9.tgz", + "integrity": "sha512-NtNxqUcXgpW2iMrfqSfR73Glt39K+BLwWsPs94yR63v45T0Wbej7eRmL5cWfwEgqXnmjQp3zaJTshdRW/qC2ZQ==" + }, + "node_modules/graphemer": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz", + "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==", + "dev": true + }, + "node_modules/handle-thing": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/handle-thing/-/handle-thing-2.0.1.tgz", + "integrity": "sha512-9Qn4yBxelxoh2Ow62nP+Ka/kMnOXRi8BXnRaUwezLNhqelnN49xKz4F/dPP8OYLxLxq6JDtZb2i9XznUQbNPTg==" + }, + "node_modules/has": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", + "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", + "dependencies": { + "function-bind": "^1.1.1" + }, + "engines": { + "node": ">= 0.4.0" + } + }, + "node_modules/has-ansi": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz", + "integrity": "sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE=", + "dependencies": { + "ansi-regex": "^2.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/has-ansi/node_modules/ansi-regex": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", + "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/has-bigints": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.1.tgz", + "integrity": "sha512-LSBS2LjbNBTf6287JEbEzvJgftkF5qFkmCo9hDRpAzKhUOlJ+hx8dd4USs00SgsUNwc4617J9ki5YtEClM2ffA==", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==", + "engines": { + "node": ">=4" + } + }, + "node_modules/has-property-descriptors": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz", + "integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==", + "dependencies": { + "es-define-property": "^1.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.1.tgz", + "integrity": "sha512-7qE+iP+O+bgF9clE5+UoBFzE65mlBiVj3tKCrlNQ0Ogwm0BjpT/gK4SlLYDMybDh5I3TCTKnPPa0oMG7JDYrhg==", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-symbols": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", + "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/has-tostringtag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.0.tgz", + "integrity": "sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ==", + "dependencies": { + "has-symbols": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/hash-base": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/hash-base/-/hash-base-3.1.0.tgz", + "integrity": "sha512-1nmYp/rhMDiE7AYkDw+lLwlAzz0AntGIe51F3RfFfEqyQ3feY2eI/NcwC6umIQVOASPMsWJLJScWKSSvzL9IVA==", + "dependencies": { + "inherits": "^2.0.4", + "readable-stream": "^3.6.0", + "safe-buffer": "^5.2.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/hash-base/node_modules/readable-stream": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", + "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/hash-base/node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/hash.js": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/hash.js/-/hash.js-1.1.7.tgz", + "integrity": "sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA==", + "dependencies": { + "inherits": "^2.0.3", + "minimalistic-assert": "^1.0.1" + } + }, + "node_modules/hasown": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.0.tgz", + "integrity": "sha512-vUptKVTpIJhcczKBbgnS+RtcuYMB8+oNzPK2/Hp3hanz8JmpATdmmgLgSaadVREkDm+e2giHwY3ZRkyjSIDDFA==", + "dependencies": { + "function-bind": "^1.1.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/hmac-drbg": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/hmac-drbg/-/hmac-drbg-1.0.1.tgz", + "integrity": "sha1-0nRXAQJabHdabFRXk+1QL8DGSaE=", + "dependencies": { + "hash.js": "^1.0.3", + "minimalistic-assert": "^1.0.0", + "minimalistic-crypto-utils": "^1.0.1" + } + }, + "node_modules/hosted-git-info": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-7.0.1.tgz", + "integrity": "sha512-+K84LB1DYwMHoHSgaOY/Jfhw3ucPmSET5v98Ke/HdNSw4a0UktWzyW1mjhjpuxxTqOOsfWT/7iVshHmVZ4IpOA==", + "dependencies": { + "lru-cache": "^10.0.1" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "node_modules/hosted-git-info/node_modules/lru-cache": { + "version": "10.2.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.2.0.tgz", + "integrity": "sha512-2bIM8x+VAf6JT4bKAljS1qUWgMsqZRPGJS6FSahIMPVvctcNhyVp7AJu7quxOW9jwkryBReKZY5tY5JYv2n/7Q==", + "engines": { + "node": "14 || >=16.14" + } + }, + "node_modules/hpack.js": { + "version": "2.1.6", + "resolved": "https://registry.npmjs.org/hpack.js/-/hpack.js-2.1.6.tgz", + "integrity": "sha512-zJxVehUdMGIKsRaNt7apO2Gqp0BdqW5yaiGHXXmbpvxgBYVZnAql+BJb4RO5ad2MgpbZKn5G6nMnegrH1FcNYQ==", + "dependencies": { + "inherits": "^2.0.1", + "obuf": "^1.0.0", + "readable-stream": "^2.0.1", + "wbuf": "^1.1.0" + } + }, + "node_modules/html-entities": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/html-entities/-/html-entities-2.5.2.tgz", + "integrity": "sha512-K//PSRMQk4FZ78Kyau+mZurHn3FH0Vwr+H36eE0rPbeYkRRi9YxceYPhuN60UwWorxyKHhqoAJl2OFKa4BVtaA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/mdevils" + }, + { + "type": "patreon", + "url": "https://patreon.com/mdevils" + } + ] + }, + "node_modules/htmlescape": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/htmlescape/-/htmlescape-1.1.1.tgz", + "integrity": "sha1-OgPtwiFLyjtmQko+eVk0lQnLA1E=", + "engines": { + "node": ">=0.10" + } + }, + "node_modules/htmlparser2": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-8.0.2.tgz", + "integrity": "sha512-GYdjWKDkbRLkZ5geuHs5NY1puJ+PXwP7+fHPRz06Eirsb9ugf6d8kkXav6ADhcODhFFPMIXyxkxSuMf3D6NCFA==", + "funding": [ + "https://github.com/fb55/htmlparser2?sponsor=1", + { + "type": "github", + "url": "https://github.com/sponsors/fb55" + } + ], + "dependencies": { + "domelementtype": "^2.3.0", + "domhandler": "^5.0.3", + "domutils": "^3.0.1", + "entities": "^4.4.0" + } + }, + "node_modules/http-cache-semantics": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.1.tgz", + "integrity": "sha512-er295DKPVsV82j5kw1Gjt+ADA/XYHsajl82cGNQG2eyoPkvgUhX+nDIyelzhIWbbsXP39EHcI6l5tYs2FYqYXQ==" + }, + "node_modules/http-deceiver": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/http-deceiver/-/http-deceiver-1.2.7.tgz", + "integrity": "sha512-LmpOGxTfbpgtGVxJrj5k7asXHCgNZp5nLfp+hWc8QQRqtb7fUy6kRY3BO1h9ddF6yIPYUARgxGOwB42DnxIaNw==" + }, + "node_modules/http-errors": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", + "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==", + "dependencies": { + "depd": "2.0.0", + "inherits": "2.0.4", + "setprototypeof": "1.2.0", + "statuses": "2.0.1", + "toidentifier": "1.0.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/http-errors/node_modules/statuses": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", + "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/http-parser-js": { + "version": "0.5.8", + "resolved": "https://registry.npmjs.org/http-parser-js/-/http-parser-js-0.5.8.tgz", + "integrity": "sha512-SGeBX54F94Wgu5RH3X5jsDtf4eHyRogWX1XGT3b4HuW3tQPM4AaBzoUji/4AAJNXCEOWZ5O0DgZmJw1947gD5Q==" + }, + "node_modules/http-proxy": { + "version": "1.18.1", + "resolved": "https://registry.npmjs.org/http-proxy/-/http-proxy-1.18.1.tgz", + "integrity": "sha512-7mz/721AbnJwIVbnaSv1Cz3Am0ZLT/UBwkC92VlxhXv/k/BBQfM2fXElQNC27BVGr0uwUpplYPQM9LnaBMR5NQ==", + "dependencies": { + "eventemitter3": "^4.0.0", + "follow-redirects": "^1.0.0", + "requires-port": "^1.0.0" + }, + "engines": { + "node": ">=8.0.0" + } + }, + "node_modules/http-proxy-agent": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-7.0.2.tgz", + "integrity": "sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig==", + "dependencies": { + "agent-base": "^7.1.0", + "debug": "^4.3.4" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/http-proxy-middleware": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/http-proxy-middleware/-/http-proxy-middleware-2.0.6.tgz", + "integrity": "sha512-ya/UeJ6HVBYxrgYotAZo1KvPWlgB48kUJLDePFeneHsVujFaW5WNj2NgWCAE//B1Dl02BIfYlpNgBy8Kf8Rjmw==", + "dependencies": { + "@types/http-proxy": "^1.17.8", + "http-proxy": "^1.18.1", + "is-glob": "^4.0.1", + "is-plain-obj": "^3.0.0", + "micromatch": "^4.0.2" + }, + "engines": { + "node": ">=12.0.0" + }, + "peerDependencies": { + "@types/express": "^4.17.13" + }, + "peerDependenciesMeta": { + "@types/express": { + "optional": true + } + } + }, + "node_modules/http-signature": { + "version": "1.3.6", + "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.3.6.tgz", + "integrity": "sha512-3adrsD6zqo4GsTqtO7FyrejHNv+NgiIfAfv68+jVlFmSr9OGy7zrxONceFRLKvnnZA5jbxQBX1u9PpB6Wi32Gw==", + "optional": true, + "dependencies": { + "assert-plus": "^1.0.0", + "jsprim": "^2.0.2", + "sshpk": "^1.14.1" + }, + "engines": { + "node": ">=0.10" + } + }, + "node_modules/https-browserify": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/https-browserify/-/https-browserify-1.0.0.tgz", + "integrity": "sha1-7AbBDgo0wPL68Zn3/X/Hj//QPHM=" + }, + "node_modules/https-proxy-agent": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.4.tgz", + "integrity": "sha512-wlwpilI7YdjSkWaQ/7omYBMTliDcmCN8OLihO6I9B86g06lMyAoqgoDpV0XqoaPOKj+0DIdAvnsWfyAAhmimcg==", + "dependencies": { + "agent-base": "^7.0.2", + "debug": "4" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/human-signals": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-1.1.1.tgz", + "integrity": "sha512-SEQu7vl8KjNL2eoGBLF3+wAjpsNfA9XMlXAYj/3EdaNfAlxKthD1xjEQfGOUhllCGGJVNY34bRr6lPINhNjyZw==", + "optional": true, + "engines": { + "node": ">=8.12.0" + } + }, + "node_modules/iconv-lite": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/icss-utils": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/icss-utils/-/icss-utils-5.1.0.tgz", + "integrity": "sha512-soFhflCVWLfRNOPU3iv5Z9VUdT44xFRbzjLsEzSr5AQmgqPMTHdU3PMT1Cf1ssx8fLNJDA1juftYl+PUcv3MqA==", + "engines": { + "node": "^10 || ^12 || >= 14" + }, + "peerDependencies": { + "postcss": "^8.1.0" + } + }, + "node_modules/ieee754": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", + "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/ignore": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.1.tgz", + "integrity": "sha512-5Fytz/IraMjqpwfd34ke28PTVMjZjJG2MPn5t7OE4eUCUNf8BAa7b5WUS9/Qvr6mwOQS7Mk6vdsMno5he+T8Xw==", + "engines": { + "node": ">= 4" + } + }, + "node_modules/ignore-walk": { + "version": "6.0.4", + "resolved": "https://registry.npmjs.org/ignore-walk/-/ignore-walk-6.0.4.tgz", + "integrity": "sha512-t7sv42WkwFkyKbivUCglsQW5YWMskWtbEf4MNKX5u/CCWHKSPzN4FtBQGsQZgCLbxOzpVlcbWVK5KB3auIOjSw==", + "dependencies": { + "minimatch": "^9.0.0" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/ignore-walk/node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/ignore-walk/node_modules/minimatch": { + "version": "9.0.3", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.3.tgz", + "integrity": "sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==", + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/image-size": { + "version": "0.5.5", + "resolved": "https://registry.npmjs.org/image-size/-/image-size-0.5.5.tgz", + "integrity": "sha512-6TDAlDPZxUFCv+fuOkIoXT/V/f3Qbq8e37p+YOiYrUv3v9cc3/6x78VdfPgFVaB9dZYeLUfKgHRebpkm/oP2VQ==", + "optional": true, + "bin": { + "image-size": "bin/image-size.js" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/immutable": { + "version": "3.8.2", + "resolved": "https://registry.npmjs.org/immutable/-/immutable-3.8.2.tgz", + "integrity": "sha512-15gZoQ38eYjEjxkorfbcgBKBL6R7T459OuK+CpcWt7O3KF4uPCx2tD0uFETlUDIyo+1789crbMhTvQBSR5yBMg==", + "devOptional": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/import-fresh": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", + "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", + "dependencies": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/import-fresh/node_modules/resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==", + "engines": { + "node": ">=4" + } + }, + "node_modules/imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=", + "engines": { + "node": ">=0.8.19" + } + }, + "node_modules/indent-string": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz", + "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==", + "engines": { + "node": ">=8" + } + }, + "node_modules/inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", + "dependencies": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "node_modules/inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" + }, + "node_modules/ini": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/ini/-/ini-4.1.2.tgz", + "integrity": "sha512-AMB1mvwR1pyBFY/nSevUX6y8nJWS63/SzUKD3JyQn97s4xgIdgQPT75IRouIiBAN4yLQBUShNYVW0+UG25daCw==", + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/inline-source-map": { + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/inline-source-map/-/inline-source-map-0.6.2.tgz", + "integrity": "sha1-+Tk0ccGKedFyT4Y/o4tYY3Ct4qU=", + "dependencies": { + "source-map": "~0.5.3" + } + }, + "node_modules/inline-source-map/node_modules/source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/inquirer": { + "version": "9.2.15", + "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-9.2.15.tgz", + "integrity": "sha512-vI2w4zl/mDluHt9YEQ/543VTCwPKWiHzKtm9dM2V0NdFcqEexDAjUHzO1oA60HRNaVifGXXM1tRRNluLVHa0Kg==", + "dependencies": { + "@ljharb/through": "^2.3.12", + "ansi-escapes": "^4.3.2", + "chalk": "^5.3.0", + "cli-cursor": "^3.1.0", + "cli-width": "^4.1.0", + "external-editor": "^3.1.0", + "figures": "^3.2.0", + "lodash": "^4.17.21", + "mute-stream": "1.0.0", + "ora": "^5.4.1", + "run-async": "^3.0.0", + "rxjs": "^7.8.1", + "string-width": "^4.2.3", + "strip-ansi": "^6.0.1", + "wrap-ansi": "^6.2.0" + }, + "engines": { + "node": ">=18" + } + }, + "node_modules/inquirer/node_modules/chalk": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.3.0.tgz", + "integrity": "sha512-dLitG79d+GV1Nb/VYcCDFivJeK1hiukt9QjRNVOsUtTy1rR1YJsmpGGTZ3qJos+uw7WmWF4wUwBd9jxjocFC2w==", + "engines": { + "node": "^12.17.0 || ^14.13 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/insert-module-globals": { + "version": "7.2.1", + "resolved": "https://registry.npmjs.org/insert-module-globals/-/insert-module-globals-7.2.1.tgz", + "integrity": "sha512-ufS5Qq9RZN+Bu899eA9QCAYThY+gGW7oRkmb0vC93Vlyu/CFGcH0OYPEjVkDXA5FEbTt1+VWzdoOD3Ny9N+8tg==", + "dependencies": { + "acorn-node": "^1.5.2", + "combine-source-map": "^0.8.0", + "concat-stream": "^1.6.1", + "is-buffer": "^1.1.0", + "JSONStream": "^1.0.3", + "path-is-absolute": "^1.0.1", + "process": "~0.11.0", + "through2": "^2.0.0", + "undeclared-identifiers": "^1.1.2", + "xtend": "^4.0.0" + }, + "bin": { + "insert-module-globals": "bin/cmd.js" + } + }, + "node_modules/ip-address": { + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/ip-address/-/ip-address-9.0.5.tgz", + "integrity": "sha512-zHtQzGojZXTwZTHQqra+ETKd4Sn3vgi7uBmlPoXVWZqYvuKmtI0l/VZTjqGmJY9x88GGOaZ9+G9ES8hC4T4X8g==", + "dependencies": { + "jsbn": "1.1.0", + "sprintf-js": "^1.1.3" + }, + "engines": { + "node": ">= 12" + } + }, + "node_modules/ip-address/node_modules/jsbn": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-1.1.0.tgz", + "integrity": "sha512-4bYVV3aAMtDTTu4+xsDYa6sy9GyJ69/amsu9sYF2zqjiEoZA5xJi3BrfX3uY+/IekIu7MwdObdbDWpoZdBv3/A==" + }, + "node_modules/ipaddr.js": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-2.1.0.tgz", + "integrity": "sha512-LlbxQ7xKzfBusov6UMi4MFpEg0m+mAm9xyNGEduwXMEDuf4WfzB/RZwMVYEd7IKGvh4IUkEXYxtAVu9T3OelJQ==", + "engines": { + "node": ">= 10" + } + }, + "node_modules/is-arguments": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-arguments/-/is-arguments-1.1.1.tgz", + "integrity": "sha512-8Q7EARjzEnKpt/PCD7e1cgUS0a6X8u5tdSiMqXhojOdoV9TsMsiO+9VLC5vAmO8N7/GmXn7yjR8qnA6bVAEzfA==", + "dependencies": { + "call-bind": "^1.0.2", + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-arrayish": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", + "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==" + }, + "node_modules/is-bigint": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.0.1.tgz", + "integrity": "sha512-J0ELF4yHFxHy0cmSxZuheDOz2luOdVvqjwmEcj8H/L1JHeuEDSDbeRP+Dk9kFVk5RTFzbucJ2Kb9F7ixY2QaCg==", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-binary-path": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "dependencies": { + "binary-extensions": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-boolean-object": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.1.0.tgz", + "integrity": "sha512-a7Uprx8UtD+HWdyYwnD1+ExtTgqQtD2k/1yJgtXP6wnMm8byhkoTZRl+95LLThpzNZJ5aEvi46cdH+ayMFRwmA==", + "dependencies": { + "call-bind": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-buffer": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", + "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==" + }, + "node_modules/is-callable": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.3.tgz", + "integrity": "sha512-J1DcMe8UYTBSrKezuIUTUwjXsho29693unXM2YhJUTR2txK/eG47bvNa/wipPFmZFgr/N6f1GA66dv0mEyTIyQ==", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-ci": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/is-ci/-/is-ci-3.0.1.tgz", + "integrity": "sha512-ZYvCgrefwqoQ6yTyYUbQu64HsITZ3NfKX1lzaEYdkTDcfKzzCI/wthRRYKkdjHKFVgNiXKAKm65Zo1pk2as/QQ==", + "optional": true, + "dependencies": { + "ci-info": "^3.2.0" + }, + "bin": { + "is-ci": "bin.js" + } + }, + "node_modules/is-core-module": { + "version": "2.13.1", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.13.1.tgz", + "integrity": "sha512-hHrIjvZsftOsvKSn2TRYl63zvxsgE0K+0mYMoH6gD4omR5IWB2KynivBQczo3+wF1cCkjzvptnI9Q0sPU66ilw==", + "dependencies": { + "hasown": "^2.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-date-object": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.5.tgz", + "integrity": "sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==", + "dependencies": { + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-docker": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-2.2.1.tgz", + "integrity": "sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==", + "bin": { + "is-docker": "cli.js" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==", + "engines": { + "node": ">=8" + } + }, + "node_modules/is-generator-function": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/is-generator-function/-/is-generator-function-1.0.8.tgz", + "integrity": "sha512-2Omr/twNtufVZFr1GhxjOMFPAj2sjc/dKaIqBhvo4qciXfJmITGH6ZGd8eZYNHza8t1y0e01AuqRhJwfWp26WQ==", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "dependencies": { + "is-extglob": "^2.1.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-installed-globally": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/is-installed-globally/-/is-installed-globally-0.4.0.tgz", + "integrity": "sha512-iwGqO3J21aaSkC7jWnHP/difazwS7SFeIqxv6wEtLU8Y5KlzFTjyqcSIT0d8s4+dDhKytsk9PJZ2BkS5eZwQRQ==", + "optional": true, + "dependencies": { + "global-dirs": "^3.0.0", + "is-path-inside": "^3.0.2" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-interactive": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-interactive/-/is-interactive-1.0.0.tgz", + "integrity": "sha512-2HvIEKRoqS62guEC+qBjpvRubdX910WCMuJTZ+I9yvqKU2/12eSL549HMwtabb4oupdj2sMP50k+XJfB/8JE6w==", + "engines": { + "node": ">=8" + } + }, + "node_modules/is-lambda": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-lambda/-/is-lambda-1.0.1.tgz", + "integrity": "sha512-z7CMFGNrENq5iFB9Bqo64Xk6Y9sg+epq1myIcdHaGnbMTYOxvzsEtdYqQUylB7LxfkvgrrjP32T6Ywciio9UIQ==" + }, + "node_modules/is-negative-zero": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.1.tgz", + "integrity": "sha512-2z6JzQvZRa9A2Y7xC6dQQm4FSTSTNWjKIYYTt4246eMTJmIo0Q+ZyOsU66X8lxK1AbB92dFeglPLrhwpeRKO6w==", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/is-number-like": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/is-number-like/-/is-number-like-1.0.8.tgz", + "integrity": "sha512-6rZi3ezCyFcn5L71ywzz2bS5b2Igl1En3eTlZlvKjpz1n3IZLAYMbKYAIQgFmEu0GENg92ziU/faEOA/aixjbA==", + "devOptional": true, + "dependencies": { + "lodash.isfinite": "^3.3.2" + } + }, + "node_modules/is-number-object": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.4.tgz", + "integrity": "sha512-zohwelOAur+5uXtk8O3GPQ1eAcu4ZX3UwxQhUlfFFMNpUd83gXgjbhJh6HmB6LUNV/ieOLQuDwJO3dWJosUeMw==", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-path-inside": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", + "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", + "devOptional": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/is-plain-obj": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-3.0.0.tgz", + "integrity": "sha512-gwsOE28k+23GP1B6vFl1oVh/WOzmawBrKwo5Ev6wMKzPkaXaCDIQKzLnvsA42DRlbVTWorkgTKIviAKCWkfUwA==", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-plain-object": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", + "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", + "dependencies": { + "isobject": "^3.0.1" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/is-regex": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz", + "integrity": "sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==", + "dependencies": { + "call-bind": "^1.0.2", + "has-tostringtag": "^1.0.0" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-stream": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", + "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==", + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-string": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.5.tgz", + "integrity": "sha512-buY6VNRjhQMiF1qWDouloZlQbRhDPCebwxSjxMjxgemYT46YMd2NR0/H+fBhEfWX4A/w9TBJ+ol+okqJKFE6vQ==", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-symbol": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.3.tgz", + "integrity": "sha512-OwijhaRSgqvhm/0ZdAcXNZt9lYdKFpcRDT5ULUuYXPoT794UNOdU+gpT6Rzo7b4V2HUl/op6GqY894AZwv9faQ==", + "dependencies": { + "has-symbols": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-typed-array": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.5.tgz", + "integrity": "sha512-S+GRDgJlR3PyEbsX/Fobd9cqpZBuvUS+8asRqYDMLCb2qMzt1oz5m5oxQCxOgUDxiWsOVNi4yaF+/uvdlHlYug==", + "dependencies": { + "available-typed-arrays": "^1.0.2", + "call-bind": "^1.0.2", + "es-abstract": "^1.18.0-next.2", + "foreach": "^2.0.5", + "has-symbols": "^1.0.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/is-typedarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", + "integrity": "sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA==", + "optional": true + }, + "node_modules/is-unicode-supported": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz", + "integrity": "sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/is-what": { + "version": "3.14.1", + "resolved": "https://registry.npmjs.org/is-what/-/is-what-3.14.1.tgz", + "integrity": "sha512-sNxgpk9793nzSs7bA6JQJGeIuRBQhAaNGG77kzYQgMkrID+lS6SlK07K5LaptscDlSaIgH+GPFzf+d75FVxozA==" + }, + "node_modules/is-wsl": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-2.2.0.tgz", + "integrity": "sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==", + "dependencies": { + "is-docker": "^2.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/isarray": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", + "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==" + }, + "node_modules/isbinaryfile": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/isbinaryfile/-/isbinaryfile-4.0.8.tgz", + "integrity": "sha512-53h6XFniq77YdW+spoRrebh0mnmTxRPTlcuIArO57lmMdq4uBKFKaeTjnb92oYWrSn/LVL+LT+Hap2tFQj8V+w==", + "optional": true, + "peer": true, + "engines": { + "node": ">= 8.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/gjtorikian/" + } + }, + "node_modules/isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=" + }, + "node_modules/isobject": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", + "integrity": "sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/isstream": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", + "integrity": "sha512-Yljz7ffyPbrLpLngrMtZ7NduUgVvi6wG9RJ9IUcyCd59YQ911PBJphODUcbOVbqYfxe1wuYf/LJ8PauMRwsM/g==", + "optional": true + }, + "node_modules/istanbul-lib-coverage": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.0.tgz", + "integrity": "sha512-eOeJ5BHCmHYvQK7xt9GkdHuzuCGS1Y6g9Gvnx3Ym33fz/HpLRYxiS0wHNr+m/MBC8B647Xt608vCDEvhl9c6Mw==", + "engines": { + "node": ">=8" + } + }, + "node_modules/istanbul-lib-instrument": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-5.2.0.tgz", + "integrity": "sha512-6Lthe1hqXHBNsqvgDzGO6l03XNeu3CrG4RqQ1KM9+l5+jNGpEJfIELx1NS3SEHmJQA8np/u+E4EPRKRiu6m19A==", + "dependencies": { + "@babel/core": "^7.12.3", + "@babel/parser": "^7.14.7", + "@istanbuljs/schema": "^0.1.2", + "istanbul-lib-coverage": "^3.2.0", + "semver": "^6.3.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/istanbul-lib-instrument/node_modules/semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==", + "bin": { + "semver": "bin/semver.js" + } + }, + "node_modules/jackspeak": { + "version": "2.3.6", + "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-2.3.6.tgz", + "integrity": "sha512-N3yCS/NegsOBokc8GAdM8UcmfsKiSS8cipheD/nivzr700H+nsMOxJjQnvwOcRYVuFkdH0wGUvW2WbXGmrZGbQ==", + "dependencies": { + "@isaacs/cliui": "^8.0.2" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + }, + "optionalDependencies": { + "@pkgjs/parseargs": "^0.11.0" + } + }, + "node_modules/jest-worker": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-27.5.1.tgz", + "integrity": "sha512-7vuh85V5cdDofPyxn58nrPjBktZo0u9x1g8WtjQol+jZDaE+fhN+cIvTj11GndBnMnyfrUOG1sZQxCdjKh+DKg==", + "dependencies": { + "@types/node": "*", + "merge-stream": "^2.0.0", + "supports-color": "^8.0.0" + }, + "engines": { + "node": ">= 10.13.0" + } + }, + "node_modules/jest-worker/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "engines": { + "node": ">=8" + } + }, + "node_modules/jest-worker/node_modules/supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/supports-color?sponsor=1" + } + }, + "node_modules/jiti": { + "version": "1.21.0", + "resolved": "https://registry.npmjs.org/jiti/-/jiti-1.21.0.tgz", + "integrity": "sha512-gFqAIbuKyyso/3G2qhiO2OM6shY6EPP/R0+mkDbyspxKazh8BXDC5FiFsUjlczgdNz/vfra0da2y+aHrusLG/Q==", + "bin": { + "jiti": "bin/jiti.js" + } + }, + "node_modules/joi": { + "version": "17.11.0", + "resolved": "https://registry.npmjs.org/joi/-/joi-17.11.0.tgz", + "integrity": "sha512-NgB+lZLNoqISVy1rZocE9PZI36bL/77ie924Ri43yEvi9GUUMPeyVIr8KdFTMUlby1p0PBYMk9spIxEUQYqrJQ==", + "optional": true, + "dependencies": { + "@hapi/hoek": "^9.0.0", + "@hapi/topo": "^5.0.0", + "@sideway/address": "^4.1.3", + "@sideway/formula": "^3.0.1", + "@sideway/pinpoint": "^2.0.0" + } + }, + "node_modules/jquery": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/jquery/-/jquery-3.6.0.tgz", + "integrity": "sha512-JVzAR/AjBvVt2BmYhxRCSYysDsPcssdmTFnzyLEts9qNwmjmu4JTAMYubEfwVOSwpQ1I1sKKFcxhZCI2buerfw==", + "peer": true + }, + "node_modules/js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==" + }, + "node_modules/js-yaml": { + "version": "3.14.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.0.tgz", + "integrity": "sha512-/4IbIeHcD9VMHFqDR/gQ7EdZdLimOvW2DdcxFjdyyZ9NsbS+ccrXqVWDtab/lRl5AlUqmpBx8EhPaWR+OtY17A==", + "dependencies": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + }, + "bin": { + "js-yaml": "bin/js-yaml.js" + } + }, + "node_modules/jsbn": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", + "integrity": "sha512-UVU9dibq2JcFWxQPA6KCqj5O42VOmAY3zQUfEKxU0KpTGXwNoCjkX1e13eHNvw/xPynt6pU0rZ1htjWTNTSXsg==", + "optional": true + }, + "node_modules/jsesc": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", + "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==", + "bin": { + "jsesc": "bin/jsesc" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/json-buffer": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", + "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", + "dev": true + }, + "node_modules/json-parse-even-better-errors": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", + "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==" + }, + "node_modules/json-schema": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.4.0.tgz", + "integrity": "sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA==", + "optional": true + }, + "node_modules/json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==" + }, + "node_modules/json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", + "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", + "dev": true + }, + "node_modules/json-stringify-safe": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", + "integrity": "sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA==", + "optional": true + }, + "node_modules/json5": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", + "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==", + "bin": { + "json5": "lib/cli.js" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/jsonc-parser": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.2.1.tgz", + "integrity": "sha512-AilxAyFOAcK5wA1+LeaySVBrHsGQvUFCDWXKpZjzaL0PqW+xfBOttn8GNtWKFWqneyMZj41MWF9Kl6iPWLwgOA==" + }, + "node_modules/jsonfile": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", + "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", + "optional": true, + "dependencies": { + "universalify": "^2.0.0" + }, + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, + "node_modules/jsonparse": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/jsonparse/-/jsonparse-1.3.1.tgz", + "integrity": "sha1-P02uSpH6wxX3EGL4UhzCOfE2YoA=", + "engines": [ + "node >= 0.2.0" + ] + }, + "node_modules/JSONStream": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/JSONStream/-/JSONStream-1.3.5.tgz", + "integrity": "sha512-E+iruNOY8VV9s4JEbe1aNEm6MiszPRr/UfcHMz0TQh1BXSxHK+ASV1R6W4HpjBhSeS+54PIsAMCBmwD06LLsqQ==", + "dependencies": { + "jsonparse": "^1.2.0", + "through": ">=2.2.7 <3" + }, + "bin": { + "JSONStream": "bin.js" + }, + "engines": { + "node": "*" + } + }, + "node_modules/jsprim": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-2.0.2.tgz", + "integrity": "sha512-gqXddjPqQ6G40VdnI6T6yObEC+pDNvyP95wdQhkWkg7crHH3km5qP1FsOXEkzEQwnz6gz5qGTn1c2Y52wP3OyQ==", + "engines": [ + "node >=0.6.0" + ], + "optional": true, + "dependencies": { + "assert-plus": "1.0.0", + "extsprintf": "1.3.0", + "json-schema": "0.4.0", + "verror": "1.10.0" + } + }, + "node_modules/just-extend": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/just-extend/-/just-extend-4.2.1.tgz", + "integrity": "sha512-g3UB796vUFIY90VIv/WX3L2c8CS2MdWUww3CNrYmqza1Fg0DURc2K/O4YrnklBdQarSJ/y8JnJYDGc+1iumQjg==", + "optional": true + }, + "node_modules/karma": { + "version": "6.3.19", + "resolved": "https://registry.npmjs.org/karma/-/karma-6.3.19.tgz", + "integrity": "sha512-NDhWckzES/Y9xMiddyU1RzaKL76/scCsu8Mp0vR0Z3lQRvC3p72+Ab4ppoxs36S9tyPNX5V48yvaV++RNEBPZw==", + "optional": true, + "peer": true, + "dependencies": { + "@colors/colors": "1.5.0", + "body-parser": "^1.19.0", + "braces": "^3.0.2", + "chokidar": "^3.5.1", + "connect": "^3.7.0", + "di": "^0.0.1", + "dom-serialize": "^2.2.1", + "glob": "^7.1.7", + "graceful-fs": "^4.2.6", + "http-proxy": "^1.18.1", + "isbinaryfile": "^4.0.8", + "lodash": "^4.17.21", + "log4js": "^6.4.1", + "mime": "^2.5.2", + "minimatch": "^3.0.4", + "mkdirp": "^0.5.5", + "qjobs": "^1.2.0", + "range-parser": "^1.2.1", + "rimraf": "^3.0.2", + "socket.io": "^4.4.1", + "source-map": "^0.6.1", + "tmp": "^0.2.1", + "ua-parser-js": "^0.7.30", + "yargs": "^16.1.1" + }, + "bin": { + "karma": "bin/karma" + }, + "engines": { + "node": ">= 10" + } + }, + "node_modules/karma-source-map-support": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/karma-source-map-support/-/karma-source-map-support-1.4.0.tgz", + "integrity": "sha512-RsBECncGO17KAoJCYXjv+ckIz+Ii9NCi+9enk+rq6XC81ezYkb4/RHE6CTXdA7IOJqoF3wcaLfVG0CPmE5ca6A==", + "dependencies": { + "source-map-support": "^0.5.5" + } + }, + "node_modules/karma/node_modules/connect": { + "version": "3.7.0", + "resolved": "https://registry.npmjs.org/connect/-/connect-3.7.0.tgz", + "integrity": "sha512-ZqRXc+tZukToSNmh5C2iWMSoV3X1YUcPbqEM4DkEG5tNQXrQUZCNVGGv3IuicnkMtPfGf3Xtp8WCXs295iQ1pQ==", + "optional": true, + "peer": true, + "dependencies": { + "debug": "2.6.9", + "finalhandler": "1.1.2", + "parseurl": "~1.3.3", + "utils-merge": "1.0.1" + }, + "engines": { + "node": ">= 0.10.0" + } + }, + "node_modules/karma/node_modules/connect/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "optional": true, + "peer": true, + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/karma/node_modules/finalhandler": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.2.tgz", + "integrity": "sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA==", + "optional": true, + "peer": true, + "dependencies": { + "debug": "2.6.9", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "on-finished": "~2.3.0", + "parseurl": "~1.3.3", + "statuses": "~1.5.0", + "unpipe": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/karma/node_modules/finalhandler/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "optional": true, + "peer": true, + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/karma/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "optional": true, + "peer": true + }, + "node_modules/karma/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "optional": true, + "peer": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/karma/node_modules/tmp": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.2.1.tgz", + "integrity": "sha512-76SUhtfqR2Ijn+xllcI5P1oyannHNHByD80W1q447gU3mp9G9PSpGdWmjUOHRDPiHYacIk66W7ubDTuPF3BEtQ==", + "optional": true, + "peer": true, + "dependencies": { + "rimraf": "^3.0.0" + }, + "engines": { + "node": ">=8.17.0" + } + }, + "node_modules/keyv": { + "version": "4.5.4", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", + "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", + "dev": true, + "dependencies": { + "json-buffer": "3.0.1" + } + }, + "node_modules/kind-of": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", + "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/klona": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/klona/-/klona-2.0.6.tgz", + "integrity": "sha512-dhG34DXATL5hSxJbIexCft8FChFXtmskoZYnoPWjXQuebWYCNkVeV3KkGegCK9CP1oswI/vQibS2GY7Em/sJJA==", + "engines": { + "node": ">= 8" + } + }, + "node_modules/labeled-stream-splicer": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/labeled-stream-splicer/-/labeled-stream-splicer-2.0.2.tgz", + "integrity": "sha512-Ca4LSXFFZUjPScRaqOcFxneA0VpKZr4MMYCljyQr4LIewTLb3Y0IUTIsnBBsVubIeEfxeSZpSjSsRM8APEQaAw==", + "dependencies": { + "inherits": "^2.0.1", + "stream-splicer": "^2.0.0" + } + }, + "node_modules/launch-editor": { + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/launch-editor/-/launch-editor-2.6.1.tgz", + "integrity": "sha512-eB/uXmFVpY4zezmGp5XtU21kwo7GBbKB+EQ+UZeWtGb9yAM5xt/Evk+lYH3eRNAtId+ej4u7TYPFZ07w4s7rRw==", + "dependencies": { + "picocolors": "^1.0.0", + "shell-quote": "^1.8.1" + } + }, + "node_modules/lazy-ass": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/lazy-ass/-/lazy-ass-1.6.0.tgz", + "integrity": "sha1-eZllXoZGwX8In90YfRUNMyTVRRM=", + "optional": true, + "engines": { + "node": "> 0.8" + } + }, + "node_modules/less": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/less/-/less-4.2.0.tgz", + "integrity": "sha512-P3b3HJDBtSzsXUl0im2L7gTO5Ubg8mEN6G8qoTS77iXxXX4Hvu4Qj540PZDvQ8V6DmX6iXo98k7Md0Cm1PrLaA==", + "dependencies": { + "copy-anything": "^2.0.1", + "parse-node-version": "^1.0.1", + "tslib": "^2.3.0" + }, + "bin": { + "lessc": "bin/lessc" + }, + "engines": { + "node": ">=6" + }, + "optionalDependencies": { + "errno": "^0.1.1", + "graceful-fs": "^4.1.2", + "image-size": "~0.5.0", + "make-dir": "^2.1.0", + "mime": "^1.4.1", + "needle": "^3.1.0", + "source-map": "~0.6.0" + } + }, + "node_modules/less-loader": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/less-loader/-/less-loader-11.1.0.tgz", + "integrity": "sha512-C+uDBV7kS7W5fJlUjq5mPBeBVhYpTIm5gB09APT9o3n/ILeaXVsiSFTbZpTJCJwQ/Crczfn3DmfQFwxYusWFug==", + "dependencies": { + "klona": "^2.0.4" + }, + "engines": { + "node": ">= 14.15.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "less": "^3.5.0 || ^4.0.0", + "webpack": "^5.0.0" + } + }, + "node_modules/less/node_modules/make-dir": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-2.1.0.tgz", + "integrity": "sha512-LS9X+dc8KLxXCb8dni79fLIIUA5VyZoyjSMCwTluaXA0o27cCK0bhXkpgw+sTXVpPy/lSO57ilRixqk0vDmtRA==", + "optional": true, + "dependencies": { + "pify": "^4.0.1", + "semver": "^5.6.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/less/node_modules/mime": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", + "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", + "optional": true, + "bin": { + "mime": "cli.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/less/node_modules/pify": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz", + "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==", + "optional": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/less/node_modules/semver": { + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", + "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", + "optional": true, + "bin": { + "semver": "bin/semver" + } + }, + "node_modules/less/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "optional": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/levn": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", + "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", + "dev": true, + "dependencies": { + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/license-webpack-plugin": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/license-webpack-plugin/-/license-webpack-plugin-4.0.2.tgz", + "integrity": "sha512-771TFWFD70G1wLTC4oU2Cw4qvtmNrIw+wRvBtn+okgHl7slJVi7zfNcdmqDL72BojM30VNJ2UHylr1o77U37Jw==", + "dependencies": { + "webpack-sources": "^3.0.0" + }, + "peerDependenciesMeta": { + "webpack": { + "optional": true + }, + "webpack-sources": { + "optional": true + } + } + }, + "node_modules/lightweight-charts": { + "version": "3.8.0", + "resolved": "https://registry.npmjs.org/lightweight-charts/-/lightweight-charts-3.8.0.tgz", + "integrity": "sha512-7yFGnYuE1RjRJG9RwUTBz5wvF1QtjBOSW4FFlikr8Dh+/TDNt4ci+HsWSYmStgQUpawpvkCJ3j5/W25GppGj9Q==", + "dependencies": { + "fancy-canvas": "0.2.2" + } + }, + "node_modules/limiter": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/limiter/-/limiter-1.1.5.tgz", + "integrity": "sha512-FWWMIEOxz3GwUI4Ts/IvgVy6LPvoMPgjMdQ185nN6psJyBJ4yOpzqm695/h5umdLJg2vW3GR5iG11MAkR2AzJA==", + "devOptional": true + }, + "node_modules/lines-and-columns": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", + "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==" + }, + "node_modules/listr2": { + "version": "3.14.0", + "resolved": "https://registry.npmjs.org/listr2/-/listr2-3.14.0.tgz", + "integrity": "sha512-TyWI8G99GX9GjE54cJ+RrNMcIFBfwMPxc3XTFiAYGN4s10hWROGtOg7+O6u6LE3mNkyld7RSLE6nrKBvTfcs3g==", + "optional": true, + "dependencies": { + "cli-truncate": "^2.1.0", + "colorette": "^2.0.16", + "log-update": "^4.0.0", + "p-map": "^4.0.0", + "rfdc": "^1.3.0", + "rxjs": "^7.5.1", + "through": "^2.3.8", + "wrap-ansi": "^7.0.0" + }, + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "enquirer": ">= 2.3.0 < 3" + }, + "peerDependenciesMeta": { + "enquirer": { + "optional": true + } + } + }, + "node_modules/listr2/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "optional": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/listr2/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "optional": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/listr2/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "optional": true + }, + "node_modules/listr2/node_modules/wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "optional": true, + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/loader-runner": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-4.2.0.tgz", + "integrity": "sha512-92+huvxMvYlMzMt0iIOukcwYBFpkYJdpl2xsZ7LrlayO7E8SOv+JJUEK17B/dJIHAOLMfh2dZZ/Y18WgmGtYNw==", + "engines": { + "node": ">=6.11.5" + } + }, + "node_modules/loader-utils": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.4.tgz", + "integrity": "sha512-xXqpXoINfFhgua9xiqD8fPFHgkoq1mmmpE92WlDbm9rNRd/EbRb+Gqf908T2DMfuHjjJlksiK2RbHVOdD/MqSw==", + "dependencies": { + "big.js": "^5.2.2", + "emojis-list": "^3.0.0", + "json5": "^2.1.2" + }, + "engines": { + "node": ">=8.9.0" + } + }, + "node_modules/locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "dependencies": { + "p-locate": "^4.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/lodash": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" + }, + "node_modules/lodash.debounce": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz", + "integrity": "sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow==" + }, + "node_modules/lodash.get": { + "version": "4.4.2", + "resolved": "https://registry.npmjs.org/lodash.get/-/lodash.get-4.4.2.tgz", + "integrity": "sha512-z+Uw/vLuy6gQe8cfaFWD7p0wVv8fJl3mbzXh33RS+0oW2wvUqiRXiQ69gLWSLpgB5/6sU+r6BlQR0MBILadqTQ==", + "optional": true + }, + "node_modules/lodash.isfinite": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/lodash.isfinite/-/lodash.isfinite-3.3.2.tgz", + "integrity": "sha512-7FGG40uhC8Mm633uKW1r58aElFlBlxCrg9JfSi3P6aYiWmfiWF0PgMd86ZUsxE5GwWPdHoS2+48bwTh2VPkIQA==", + "devOptional": true + }, + "node_modules/lodash.merge": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", + "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", + "dev": true + }, + "node_modules/lodash.once": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/lodash.once/-/lodash.once-4.1.1.tgz", + "integrity": "sha1-DdOXEhPHxW34gJd9UEyI+0cal6w=", + "optional": true + }, + "node_modules/log-symbols": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz", + "integrity": "sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==", + "dependencies": { + "chalk": "^4.1.0", + "is-unicode-supported": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/log-symbols/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/log-symbols/node_modules/chalk": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz", + "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/log-symbols/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/log-symbols/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + }, + "node_modules/log-symbols/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "engines": { + "node": ">=8" + } + }, + "node_modules/log-symbols/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/log-update": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/log-update/-/log-update-4.0.0.tgz", + "integrity": "sha512-9fkkDevMefjg0mmzWFBW8YkFP91OrizzkW3diF7CpG+S2EYdy4+TVfGwz1zeF8x7hCx1ovSPTOE9Ngib74qqUg==", + "optional": true, + "dependencies": { + "ansi-escapes": "^4.3.0", + "cli-cursor": "^3.1.0", + "slice-ansi": "^4.0.0", + "wrap-ansi": "^6.2.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/log-update/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "optional": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/log-update/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "optional": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/log-update/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "optional": true + }, + "node_modules/log-update/node_modules/slice-ansi": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-4.0.0.tgz", + "integrity": "sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ==", + "optional": true, + "dependencies": { + "ansi-styles": "^4.0.0", + "astral-regex": "^2.0.0", + "is-fullwidth-code-point": "^3.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/slice-ansi?sponsor=1" + } + }, + "node_modules/log4js": { + "version": "6.4.1", + "resolved": "https://registry.npmjs.org/log4js/-/log4js-6.4.1.tgz", + "integrity": "sha512-iUiYnXqAmNKiIZ1XSAitQ4TmNs8CdZYTAWINARF3LjnsLN8tY5m0vRwd6uuWj/yNY0YHxeZodnbmxKFUOM2rMg==", + "optional": true, + "peer": true, + "dependencies": { + "date-format": "^4.0.3", + "debug": "^4.3.3", + "flatted": "^3.2.4", + "rfdc": "^1.3.0", + "streamroller": "^3.0.2" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/loupe": { + "version": "2.3.7", + "resolved": "https://registry.npmjs.org/loupe/-/loupe-2.3.7.tgz", + "integrity": "sha512-zSMINGVYkdpYSOBmLi0D1Uo7JU9nVdQKrHxC8eYlV+9YKK9WePqAlL7lSlorG/U2Fw1w0hTBmaa/jrQ3UbPHtA==", + "optional": true, + "dependencies": { + "get-func-name": "^2.0.1" + } + }, + "node_modules/lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/magic-string": { + "version": "0.30.8", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.8.tgz", + "integrity": "sha512-ISQTe55T2ao7XtlAStud6qwYPZjE4GK1S/BeVPus4jrq6JuOnQ00YKQC581RWhR122W7msZV263KzVeLoqidyQ==", + "dependencies": { + "@jridgewell/sourcemap-codec": "^1.4.15" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/make-error": { + "version": "1.3.6", + "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", + "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", + "dev": true + }, + "node_modules/make-fetch-happen": { + "version": "13.0.0", + "resolved": "https://registry.npmjs.org/make-fetch-happen/-/make-fetch-happen-13.0.0.tgz", + "integrity": "sha512-7ThobcL8brtGo9CavByQrQi+23aIfgYU++wg4B87AIS8Rb2ZBt/MEaDqzA00Xwv/jUjAjYkLHjVolYuTLKda2A==", + "dependencies": { + "@npmcli/agent": "^2.0.0", + "cacache": "^18.0.0", + "http-cache-semantics": "^4.1.1", + "is-lambda": "^1.0.1", + "minipass": "^7.0.2", + "minipass-fetch": "^3.0.0", + "minipass-flush": "^1.0.5", + "minipass-pipeline": "^1.2.4", + "negotiator": "^0.6.3", + "promise-retry": "^2.0.1", + "ssri": "^10.0.0" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "node_modules/map-stream": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/map-stream/-/map-stream-0.1.0.tgz", + "integrity": "sha1-5WqpTEyAVaFkBKBnS3jyFffI4ZQ=", + "optional": true + }, + "node_modules/md5.js": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/md5.js/-/md5.js-1.3.5.tgz", + "integrity": "sha512-xitP+WxNPcTTOgnTJcrhM0xvdPepipPSf3I8EIpGKeFLjt3PlJLIDG3u8EX53ZIubkb+5U2+3rELYpEhHhzdkg==", + "dependencies": { + "hash-base": "^3.0.0", + "inherits": "^2.0.1", + "safe-buffer": "^5.1.2" + } + }, + "node_modules/media-typer": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", + "integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/memfs": { + "version": "3.5.3", + "resolved": "https://registry.npmjs.org/memfs/-/memfs-3.5.3.tgz", + "integrity": "sha512-UERzLsxzllchadvbPs5aolHh65ISpKpM+ccLbOJ8/vvpBKmAWf+la7dXFy7Mr0ySHbdHrFv5kGFCUHHe6GFEmw==", + "dependencies": { + "fs-monkey": "^1.0.4" + }, + "engines": { + "node": ">= 4.0.0" + } + }, + "node_modules/merge-descriptors": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", + "integrity": "sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w==" + }, + "node_modules/merge-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", + "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==" + }, + "node_modules/merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "engines": { + "node": ">= 8" + } + }, + "node_modules/methods": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", + "integrity": "sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/micromatch": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.4.tgz", + "integrity": "sha512-pRmzw/XUcwXGpD9aI9q/0XOwLNygjETJ8y0ao0wdqprrzDa4YnxLcz7fQRZr8voh8V10kGhABbNcHVk5wHgWwg==", + "dependencies": { + "braces": "^3.0.1", + "picomatch": "^2.2.3" + }, + "engines": { + "node": ">=8.6" + } + }, + "node_modules/miller-rabin": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/miller-rabin/-/miller-rabin-4.0.1.tgz", + "integrity": "sha512-115fLhvZVqWwHPbClyntxEVfVDfl9DLLTuJvq3g2O/Oxi8AiNouAHvDSzHS0viUJc+V5vm3eq91Xwqn9dp4jRA==", + "dependencies": { + "bn.js": "^4.0.0", + "brorand": "^1.0.1" + }, + "bin": { + "miller-rabin": "bin/miller-rabin" + } + }, + "node_modules/miller-rabin/node_modules/bn.js": { + "version": "4.12.0", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", + "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==" + }, + "node_modules/mime": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/mime/-/mime-2.5.2.tgz", + "integrity": "sha512-tqkh47FzKeCPD2PUiPB6pkbMzsCasjxAfC62/Wap5qrUWcb+sFasXUC5I3gYM5iBM8v/Qpn4UK0x+j0iHyFPDg==", + "optional": true, + "peer": true, + "bin": { + "mime": "cli.js" + }, + "engines": { + "node": ">=4.0.0" + } + }, + "node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mimic-fn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", + "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==", + "engines": { + "node": ">=6" + } + }, + "node_modules/mini-css-extract-plugin": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/mini-css-extract-plugin/-/mini-css-extract-plugin-2.8.1.tgz", + "integrity": "sha512-/1HDlyFRxWIZPI1ZpgqlZ8jMw/1Dp/dl3P0L1jtZ+zVcHqwPhGwaJwKL00WVgfnBy6PWCde9W65or7IIETImuA==", + "dependencies": { + "schema-utils": "^4.0.0", + "tapable": "^2.2.1" + }, + "engines": { + "node": ">= 12.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^5.0.0" + } + }, + "node_modules/minify-stream": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/minify-stream/-/minify-stream-2.1.0.tgz", + "integrity": "sha512-P5xE4EQRkn7Td54VGcgfDMFx1jmKPPIXCdcMfrbXS6cNHK4dO1LXwtYFb48hHrSmZfT+jlGImvHgSZEkbpNtCw==", + "dependencies": { + "concat-stream": "^2.0.0", + "convert-source-map": "^1.5.0", + "duplexify": "^4.1.1", + "from2-string": "^1.1.0", + "terser": "^4.7.0", + "xtend": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/minify-stream/node_modules/concat-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-2.0.0.tgz", + "integrity": "sha512-MWufYdFw53ccGjCA+Ol7XJYpAlW6/prSMzuPOTRnJGcGzuhLn4Scrz7qf6o8bROZ514ltazcIFJZevcfbo0x7A==", + "engines": [ + "node >= 6.0" + ], + "dependencies": { + "buffer-from": "^1.0.0", + "inherits": "^2.0.3", + "readable-stream": "^3.0.2", + "typedarray": "^0.0.6" + } + }, + "node_modules/minify-stream/node_modules/duplexify": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/duplexify/-/duplexify-4.1.1.tgz", + "integrity": "sha512-DY3xVEmVHTv1wSzKNbwoU6nVjzI369Y6sPoqfYr0/xlx3IdX2n94xIszTcjPO8W8ZIv0Wb0PXNcjuZyT4wiICA==", + "dependencies": { + "end-of-stream": "^1.4.1", + "inherits": "^2.0.3", + "readable-stream": "^3.1.1", + "stream-shift": "^1.0.0" + } + }, + "node_modules/minify-stream/node_modules/readable-stream": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", + "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/minify-stream/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/minify-stream/node_modules/terser": { + "version": "4.8.1", + "resolved": "https://registry.npmjs.org/terser/-/terser-4.8.1.tgz", + "integrity": "sha512-4GnLC0x667eJG0ewJTa6z/yXrbLGv80D9Ru6HIpCQmO+Q4PfEtBFi0ObSckqwL6VyQv/7ENJieXHo2ANmdQwgw==", + "dependencies": { + "commander": "^2.20.0", + "source-map": "~0.6.1", + "source-map-support": "~0.5.12" + }, + "bin": { + "terser": "bin/terser" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/minimalistic-assert": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz", + "integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==" + }, + "node_modules/minimalistic-crypto-utils": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz", + "integrity": "sha1-9sAMHAsIIkblxNmd+4x8CDsrWCo=" + }, + "node_modules/minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "dependencies": { + "brace-expansion": "^1.1.7" + }, + "engines": { + "node": "*" + } + }, + "node_modules/minimist": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", + "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/minipass": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.0.4.tgz", + "integrity": "sha512-jYofLM5Dam9279rdkWzqHozUo4ybjdZmCsDHePy5V/PbBcVMiSZR97gmAy45aqi8CK1lG2ECd356FU86avfwUQ==", + "engines": { + "node": ">=16 || 14 >=14.17" + } + }, + "node_modules/minipass-collect": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/minipass-collect/-/minipass-collect-2.0.1.tgz", + "integrity": "sha512-D7V8PO9oaz7PWGLbCACuI1qEOsq7UKfLotx/C0Aet43fCUB/wfQ7DYeq2oR/svFJGYDHPr38SHATeaj/ZoKHKw==", + "dependencies": { + "minipass": "^7.0.3" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + } + }, + "node_modules/minipass-fetch": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/minipass-fetch/-/minipass-fetch-3.0.4.tgz", + "integrity": "sha512-jHAqnA728uUpIaFm7NWsCnqKT6UqZz7GcI/bDpPATuwYyKwJwW0remxSCxUlKiEty+eopHGa3oc8WxgQ1FFJqg==", + "dependencies": { + "minipass": "^7.0.3", + "minipass-sized": "^1.0.3", + "minizlib": "^2.1.2" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + }, + "optionalDependencies": { + "encoding": "^0.1.13" + } + }, + "node_modules/minipass-flush": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/minipass-flush/-/minipass-flush-1.0.5.tgz", + "integrity": "sha512-JmQSYYpPUqX5Jyn1mXaRwOda1uQ8HP5KAT/oDSLCzt1BYRhQU0/hDtsB1ufZfEEzMZ9aAVmsBw8+FWsIXlClWw==", + "dependencies": { + "minipass": "^3.0.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/minipass-flush/node_modules/minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/minipass-json-stream": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/minipass-json-stream/-/minipass-json-stream-1.0.1.tgz", + "integrity": "sha512-ODqY18UZt/I8k+b7rl2AENgbWE8IDYam+undIJONvigAz8KR5GWblsFTEfQs0WODsjbSXWlm+JHEv8Gr6Tfdbg==", + "dependencies": { + "jsonparse": "^1.3.1", + "minipass": "^3.0.0" + } + }, + "node_modules/minipass-json-stream/node_modules/minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/minipass-pipeline": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/minipass-pipeline/-/minipass-pipeline-1.2.4.tgz", + "integrity": "sha512-xuIq7cIOt09RPRJ19gdi4b+RiNvDFYe5JH+ggNvBqGqpQXcru3PcRmOZuHBKWK1Txf9+cQ+HMVN4d6z46LZP7A==", + "dependencies": { + "minipass": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/minipass-pipeline/node_modules/minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/minipass-sized": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/minipass-sized/-/minipass-sized-1.0.3.tgz", + "integrity": "sha512-MbkQQ2CTiBMlA2Dm/5cY+9SWFEN8pzzOXi6rlM5Xxq0Yqbda5ZQy9sU75a673FE9ZK0Zsbr6Y5iP6u9nktfg2g==", + "dependencies": { + "minipass": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/minipass-sized/node_modules/minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/minizlib": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-2.1.2.tgz", + "integrity": "sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==", + "dependencies": { + "minipass": "^3.0.0", + "yallist": "^4.0.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/minizlib/node_modules/minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/mitt": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/mitt/-/mitt-1.2.0.tgz", + "integrity": "sha512-r6lj77KlwqLhIUku9UWYes7KJtsczvolZkzp8hbaDPPaE24OmWl5s539Mytlj22siEQKosZ26qCBgda2PKwoJw==", + "devOptional": true + }, + "node_modules/mkdirp": { + "version": "0.5.5", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz", + "integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==", + "optional": true, + "peer": true, + "dependencies": { + "minimist": "^1.2.5" + }, + "bin": { + "mkdirp": "bin/cmd.js" + } + }, + "node_modules/mkdirp-classic": { + "version": "0.5.3", + "resolved": "https://registry.npmjs.org/mkdirp-classic/-/mkdirp-classic-0.5.3.tgz", + "integrity": "sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==" + }, + "node_modules/mock-socket": { + "version": "9.3.1", + "resolved": "https://registry.npmjs.org/mock-socket/-/mock-socket-9.3.1.tgz", + "integrity": "sha512-qxBgB7Qa2sEQgHFjj0dSigq7fX4k6Saisd5Nelwp2q8mlbAFh5dHV9JTTlF8viYJLSSWgMCZFUom8PJcMNBoJw==", + "optional": true, + "engines": { + "node": ">= 8" + } + }, + "node_modules/module-deps": { + "version": "6.2.3", + "resolved": "https://registry.npmjs.org/module-deps/-/module-deps-6.2.3.tgz", + "integrity": "sha512-fg7OZaQBcL4/L+AK5f4iVqf9OMbCclXfy/znXRxTVhJSeW5AIlS9AwheYwDaXM3lVW7OBeaeUEY3gbaC6cLlSA==", + "dependencies": { + "browser-resolve": "^2.0.0", + "cached-path-relative": "^1.0.2", + "concat-stream": "~1.6.0", + "defined": "^1.0.0", + "detective": "^5.2.0", + "duplexer2": "^0.1.2", + "inherits": "^2.0.1", + "JSONStream": "^1.0.3", + "parents": "^1.0.0", + "readable-stream": "^2.0.2", + "resolve": "^1.4.0", + "stream-combiner2": "^1.1.1", + "subarg": "^1.0.0", + "through2": "^2.0.0", + "xtend": "^4.0.0" + }, + "bin": { + "module-deps": "bin/cmd.js" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/mrmime": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/mrmime/-/mrmime-2.0.0.tgz", + "integrity": "sha512-eu38+hdgojoyq63s+yTpN4XMBdt5l8HhMhc4VKLO9KM5caLIBvUm4thi7fFaxyTmCKeNnXZ5pAlBwCUnhA09uw==", + "engines": { + "node": ">=10" + } + }, + "node_modules/ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + }, + "node_modules/multi-stage-sourcemap": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/multi-stage-sourcemap/-/multi-stage-sourcemap-0.3.1.tgz", + "integrity": "sha512-UiTLYjqeIoVnJHyWGskwMKIhtZKK9uXUjSTWuwatarrc0d2H/6MAVFdwvEA/aKOHamIn7z4tfvxjz+FYucFpNQ==", + "dependencies": { + "source-map": "^0.1.34" + } + }, + "node_modules/multi-stage-sourcemap/node_modules/source-map": { + "version": "0.1.43", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.1.43.tgz", + "integrity": "sha512-VtCvB9SIQhk3aF6h+N85EaqIaBFIAfZ9Cu+NJHHVvc8BbEcnvDcFw6sqQ2dQrT6SlOrZq3tIvyD9+EGq/lJryQ==", + "dependencies": { + "amdefine": ">=0.0.4" + }, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/multicast-dns": { + "version": "7.2.5", + "resolved": "https://registry.npmjs.org/multicast-dns/-/multicast-dns-7.2.5.tgz", + "integrity": "sha512-2eznPJP8z2BFLX50tf0LuODrpINqP1RVIm/CObbTcBRITQgmC/TjcREF1NeTBzIcR5XO/ukWo+YHOjBbFwIupg==", + "dependencies": { + "dns-packet": "^5.2.2", + "thunky": "^1.0.2" + }, + "bin": { + "multicast-dns": "cli.js" + } + }, + "node_modules/multisplice": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/multisplice/-/multisplice-1.0.0.tgz", + "integrity": "sha512-KU5tVjIdTGsMb92JlWwEZCGrvtI1ku9G9GuNbWdQT/Ici1ztFXX0L8lWpbbC3pISVMfBNL56wdqplHvva2XSlA==" + }, + "node_modules/mute-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-1.0.0.tgz", + "integrity": "sha512-avsJQhyd+680gKXyG/sQc0nXaC6rBkPOfyHYcFb9+hdkqQkR9bdnkJ0AMZhke0oesPqIO+mFFJ+IdBc7mst4IA==", + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/mutexify": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/mutexify/-/mutexify-1.3.1.tgz", + "integrity": "sha512-nU7mOEuaXiQIB/EgTIjYZJ7g8KqMm2D8l4qp+DqA4jxWOb/tnb1KEoqp+tlbdQIDIAiC1i7j7X/3yHDFXLxr9g==" + }, + "node_modules/nanobench": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/nanobench/-/nanobench-2.1.1.tgz", + "integrity": "sha512-z+Vv7zElcjN+OpzAxAquUayFLGK3JI/ubCl0Oh64YQqsTGG09CGqieJVQw4ui8huDnnAgrvTv93qi5UaOoNj8A==", + "dependencies": { + "browser-process-hrtime": "^0.1.2", + "chalk": "^1.1.3", + "mutexify": "^1.1.0", + "pretty-hrtime": "^1.0.2" + }, + "bin": { + "nanobench": "run.js", + "nanobench-compare": "compare.js" + } + }, + "node_modules/nanobench/node_modules/ansi-regex": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", + "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/nanobench/node_modules/ansi-styles": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", + "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/nanobench/node_modules/browser-process-hrtime": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/browser-process-hrtime/-/browser-process-hrtime-0.1.3.tgz", + "integrity": "sha512-bRFnI4NnjO6cnyLmOV/7PVoDEMJChlcfN0z4s1YMBY989/SvlfMI1lgCnkFUs53e9gQF+w7qu7XdllSTiSl8Aw==" + }, + "node_modules/nanobench/node_modules/chalk": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", + "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", + "dependencies": { + "ansi-styles": "^2.2.1", + "escape-string-regexp": "^1.0.2", + "has-ansi": "^2.0.0", + "strip-ansi": "^3.0.0", + "supports-color": "^2.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/nanobench/node_modules/strip-ansi": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", + "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", + "dependencies": { + "ansi-regex": "^2.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/nanobench/node_modules/supports-color": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", + "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=", + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/nanoid": { + "version": "3.3.7", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.7.tgz", + "integrity": "sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "bin": { + "nanoid": "bin/nanoid.cjs" + }, + "engines": { + "node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1" + } + }, + "node_modules/natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", + "dev": true + }, + "node_modules/needle": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/needle/-/needle-3.2.0.tgz", + "integrity": "sha512-oUvzXnyLiVyVGoianLijF9O/RecZUf7TkBfimjGrLM4eQhXyeJwM6GeAWccwfQ9aa4gMCZKqhAOuLaMIcQxajQ==", + "optional": true, + "dependencies": { + "debug": "^3.2.6", + "iconv-lite": "^0.6.3", + "sax": "^1.2.4" + }, + "bin": { + "needle": "bin/needle" + }, + "engines": { + "node": ">= 4.4.x" + } + }, + "node_modules/needle/node_modules/debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "optional": true, + "dependencies": { + "ms": "^2.1.1" + } + }, + "node_modules/needle/node_modules/iconv-lite": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", + "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", + "optional": true, + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/negotiator": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", + "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/neo-async": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz", + "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==" + }, + "node_modules/next-tick": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/next-tick/-/next-tick-1.1.0.tgz", + "integrity": "sha512-CXdUiJembsNjuToQvxayPZF9Vqht7hewsvy2sOWafLvi2awflj9mOC6bHIg50orX8IJvWKY9wYQ/zB2kogPslQ==" + }, + "node_modules/ngx-echarts": { + "version": "17.2.0", + "resolved": "https://registry.npmjs.org/ngx-echarts/-/ngx-echarts-17.2.0.tgz", + "integrity": "sha512-i3XDE9d53zmJH4bp8RQ/271oPlhBkczO1M3VtWk8nCXdxQq9qx8UckjWEQ7oV1AbSDLGK5sRiFu5EaY5hvdWPA==", + "dependencies": { + "tslib": "^2.3.0" + }, + "peerDependencies": { + "echarts": ">=5.0.0" + } + }, + "node_modules/ngx-infinite-scroll": { + "version": "17.0.0", + "resolved": "https://registry.npmjs.org/ngx-infinite-scroll/-/ngx-infinite-scroll-17.0.0.tgz", + "integrity": "sha512-pQXLuRiuhRuDKD3nmgyW1V08JVNBepmk6nb8qjHc5hgsWNts01+R/p33rYcRDzcut6/PWqGyrZ9o9i8swzMYMA==", + "dependencies": { + "tslib": "^2.3.0" + }, + "peerDependencies": { + "@angular/common": ">=17.0.0 <18.0.0", + "@angular/core": ">=17.0.0 <18.0.0" + } + }, + "node_modules/nice-napi": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/nice-napi/-/nice-napi-1.0.2.tgz", + "integrity": "sha512-px/KnJAJZf5RuBGcfD+Sp2pAKq0ytz8j+1NehvgIGFkvtvFrDM3T8E4x/JJODXK9WZow8RRGrbA9QQ3hs+pDhA==", + "hasInstallScript": true, + "optional": true, + "os": [ + "!win32" + ], + "dependencies": { + "node-addon-api": "^3.0.0", + "node-gyp-build": "^4.2.2" + } + }, + "node_modules/nise": { + "version": "5.1.5", + "resolved": "https://registry.npmjs.org/nise/-/nise-5.1.5.tgz", + "integrity": "sha512-VJuPIfUFaXNRzETTQEEItTOP8Y171ijr+JLq42wHes3DiryR8vT+1TXQW/Rx8JNUhyYYWyIvjXTU6dOhJcs9Nw==", + "optional": true, + "dependencies": { + "@sinonjs/commons": "^2.0.0", + "@sinonjs/fake-timers": "^10.0.2", + "@sinonjs/text-encoding": "^0.7.1", + "just-extend": "^4.0.2", + "path-to-regexp": "^1.7.0" + } + }, + "node_modules/nise/node_modules/@sinonjs/commons": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-2.0.0.tgz", + "integrity": "sha512-uLa0j859mMrg2slwQYdO/AkrOfmH+X6LTVmNTS9CqexuE2IvVORIkSpJLqePAbEnKJ77aMmCwr1NUZ57120Xcg==", + "optional": true, + "dependencies": { + "type-detect": "4.0.8" + } + }, + "node_modules/nise/node_modules/@sinonjs/fake-timers": { + "version": "10.3.0", + "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-10.3.0.tgz", + "integrity": "sha512-V4BG07kuYSUkTCSBHG8G8TNhM+F19jXFWnQtzj+we8DrkpSBCee9Z3Ms8yiGer/dlmhe35/Xdgyo3/0rQKg7YA==", + "optional": true, + "dependencies": { + "@sinonjs/commons": "^3.0.0" + } + }, + "node_modules/nise/node_modules/@sinonjs/fake-timers/node_modules/@sinonjs/commons": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-3.0.0.tgz", + "integrity": "sha512-jXBtWAF4vmdNmZgD5FoKsVLv3rPgDnLgPbU84LIJ3otV44vJlDRokVng5v8NFJdCf/da9legHcKaRuZs4L7faA==", + "optional": true, + "dependencies": { + "type-detect": "4.0.8" + } + }, + "node_modules/nise/node_modules/isarray": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", + "integrity": "sha512-D2S+3GLxWH+uhrNEcoh/fnmYeP8E8/zHl644d/jdA0g2uyXvy3sb0qxotE+ne0LtccHknQzWwZEzhak7oJ0COQ==", + "optional": true + }, + "node_modules/nise/node_modules/path-to-regexp": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-1.8.0.tgz", + "integrity": "sha512-n43JRhlUKUAlibEJhPeir1ncUID16QnEjNpwzNdO3Lm4ywrBpBZ5oLD0I6br9evr1Y9JTqwRtAh7JLoOzAQdVA==", + "optional": true, + "dependencies": { + "isarray": "0.0.1" + } + }, + "node_modules/node-addon-api": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-3.2.1.tgz", + "integrity": "sha512-mmcei9JghVNDYydghQmeDX8KoAm0FAiYyIcUt/N4nhyAipB17pllZQDOJD2fotxABnt4Mdz+dKTO7eftLg4d0A==", + "optional": true + }, + "node_modules/node-forge": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-1.3.1.tgz", + "integrity": "sha512-dPEtOeMvF9VMcYV/1Wb8CPoVAXtp6MKMlcbAt4ddqmGqUJ6fQZFXkNZNkNlfevtNkGtaSoXf/vNNNSvgrdXwtA==", + "engines": { + "node": ">= 6.13.0" + } + }, + "node_modules/node-gyp": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/node-gyp/-/node-gyp-10.0.1.tgz", + "integrity": "sha512-gg3/bHehQfZivQVfqIyy8wTdSymF9yTyP4CJifK73imyNMU8AIGQE2pUa7dNWfmMeG9cDVF2eehiRMv0LC1iAg==", + "dependencies": { + "env-paths": "^2.2.0", + "exponential-backoff": "^3.1.1", + "glob": "^10.3.10", + "graceful-fs": "^4.2.6", + "make-fetch-happen": "^13.0.0", + "nopt": "^7.0.0", + "proc-log": "^3.0.0", + "semver": "^7.3.5", + "tar": "^6.1.2", + "which": "^4.0.0" + }, + "bin": { + "node-gyp": "bin/node-gyp.js" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "node_modules/node-gyp-build": { + "version": "4.8.0", + "resolved": "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-4.8.0.tgz", + "integrity": "sha512-u6fs2AEUljNho3EYTJNBfImO5QTo/J/1Etd+NVdCj7qWKUSN/bSLkZwhDv7I+w/MSC6qJ4cknepkAYykDdK8og==", + "optional": true, + "bin": { + "node-gyp-build": "bin.js", + "node-gyp-build-optional": "optional.js", + "node-gyp-build-test": "build-test.js" + } + }, + "node_modules/node-gyp/node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/node-gyp/node_modules/glob": { + "version": "10.3.10", + "resolved": "https://registry.npmjs.org/glob/-/glob-10.3.10.tgz", + "integrity": "sha512-fa46+tv1Ak0UPK1TOy/pZrIybNNt4HCv7SDzwyfiOZkvZLEbjsZkJBPtDHVshZjbecAoAGSC20MjLDG/qr679g==", + "dependencies": { + "foreground-child": "^3.1.0", + "jackspeak": "^2.3.5", + "minimatch": "^9.0.1", + "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0", + "path-scurry": "^1.10.1" + }, + "bin": { + "glob": "dist/esm/bin.mjs" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/node-gyp/node_modules/isexe": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-3.1.1.tgz", + "integrity": "sha512-LpB/54B+/2J5hqQ7imZHfdU31OlgQqx7ZicVlkm9kzg9/w8GKLEcFfJl/t7DCEDueOyBAD6zCCwTO6Fzs0NoEQ==", + "engines": { + "node": ">=16" + } + }, + "node_modules/node-gyp/node_modules/minimatch": { + "version": "9.0.3", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.3.tgz", + "integrity": "sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==", + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/node-gyp/node_modules/which": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/which/-/which-4.0.0.tgz", + "integrity": "sha512-GlaYyEb07DPxYCKhKzplCWBJtvxZcZMrL+4UkrTSJHHPyZU4mYYTv3qaOe77H7EODLSSopAUFAc6W8U4yqvscg==", + "dependencies": { + "isexe": "^3.1.1" + }, + "bin": { + "node-which": "bin/which.js" + }, + "engines": { + "node": "^16.13.0 || >=18.0.0" + } + }, + "node_modules/node-releases": { + "version": "2.0.14", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.14.tgz", + "integrity": "sha512-y10wOWt8yZpqXmOgRo77WaHEmhYQYGNA6y421PKsKYWEK8aW+cqAphborZDhqfyKrbZEN92CN1X2KbafY2s7Yw==" + }, + "node_modules/nopt": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/nopt/-/nopt-7.2.0.tgz", + "integrity": "sha512-CVDtwCdhYIvnAzFoJ6NJ6dX3oga9/HyciQDnG1vQDjSLMeKLJ4A93ZqYKDrgYSr1FBY5/hMYC+2VCi24pgpkGA==", + "dependencies": { + "abbrev": "^2.0.0" + }, + "bin": { + "nopt": "bin/nopt.js" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/normalize-package-data": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-6.0.0.tgz", + "integrity": "sha512-UL7ELRVxYBHBgYEtZCXjxuD5vPxnmvMGq0jp/dGPKKrN7tfsBh2IY7TlJ15WWwdjRWD3RJbnsygUurTK3xkPkg==", + "dependencies": { + "hosted-git-info": "^7.0.0", + "is-core-module": "^2.8.1", + "semver": "^7.3.5", + "validate-npm-package-license": "^3.0.4" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "node_modules/normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/normalize-range": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/normalize-range/-/normalize-range-0.1.2.tgz", + "integrity": "sha512-bdok/XvKII3nUpklnV6P2hxtMNrCboOjAcyBuQnWEhO665FwrSNRxU+AqpsyvO6LgGYPspN+lu5CLtw4jPRKNA==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/npm-bundled": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/npm-bundled/-/npm-bundled-3.0.0.tgz", + "integrity": "sha512-Vq0eyEQy+elFpzsKjMss9kxqb9tG3YHg4dsyWuUENuzvSUWe1TCnW/vV9FkhvBk/brEDoDiVd+M1Btosa6ImdQ==", + "dependencies": { + "npm-normalize-package-bin": "^3.0.0" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/npm-install-checks": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/npm-install-checks/-/npm-install-checks-6.3.0.tgz", + "integrity": "sha512-W29RiK/xtpCGqn6f3ixfRYGk+zRyr+Ew9F2E20BfXxT5/euLdA/Nm7fO7OeTGuAmTs30cpgInyJ0cYe708YTZw==", + "dependencies": { + "semver": "^7.1.1" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/npm-normalize-package-bin": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/npm-normalize-package-bin/-/npm-normalize-package-bin-3.0.1.tgz", + "integrity": "sha512-dMxCf+zZ+3zeQZXKxmyuCKlIDPGuv8EF940xbkC4kQVDTtqoh6rJFO+JTKSA6/Rwi0getWmtuy4Itup0AMcaDQ==", + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/npm-package-arg": { + "version": "11.0.1", + "resolved": "https://registry.npmjs.org/npm-package-arg/-/npm-package-arg-11.0.1.tgz", + "integrity": "sha512-M7s1BD4NxdAvBKUPqqRW957Xwcl/4Zvo8Aj+ANrzvIPzGJZElrH7Z//rSaec2ORcND6FHHLnZeY8qgTpXDMFQQ==", + "dependencies": { + "hosted-git-info": "^7.0.0", + "proc-log": "^3.0.0", + "semver": "^7.3.5", + "validate-npm-package-name": "^5.0.0" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "node_modules/npm-packlist": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/npm-packlist/-/npm-packlist-8.0.2.tgz", + "integrity": "sha512-shYrPFIS/JLP4oQmAwDyk5HcyysKW8/JLTEA32S0Z5TzvpaeeX2yMFfoK1fjEBnCBvVyIB/Jj/GBFdm0wsgzbA==", + "dependencies": { + "ignore-walk": "^6.0.4" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/npm-pick-manifest": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/npm-pick-manifest/-/npm-pick-manifest-9.0.0.tgz", + "integrity": "sha512-VfvRSs/b6n9ol4Qb+bDwNGUXutpy76x6MARw/XssevE0TnctIKcmklJZM5Z7nqs5z5aW+0S63pgCNbpkUNNXBg==", + "dependencies": { + "npm-install-checks": "^6.0.0", + "npm-normalize-package-bin": "^3.0.0", + "npm-package-arg": "^11.0.0", + "semver": "^7.3.5" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "node_modules/npm-registry-fetch": { + "version": "16.1.0", + "resolved": "https://registry.npmjs.org/npm-registry-fetch/-/npm-registry-fetch-16.1.0.tgz", + "integrity": "sha512-PQCELXKt8Azvxnt5Y85GseQDJJlglTFM9L9U9gkv2y4e9s0k3GVDdOx3YoB6gm2Do0hlkzC39iCGXby+Wve1Bw==", + "dependencies": { + "make-fetch-happen": "^13.0.0", + "minipass": "^7.0.2", + "minipass-fetch": "^3.0.0", + "minipass-json-stream": "^1.0.1", + "minizlib": "^2.1.2", + "npm-package-arg": "^11.0.0", + "proc-log": "^3.0.0" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "node_modules/npm-run-path": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", + "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", + "dependencies": { + "path-key": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/nth-check": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.1.1.tgz", + "integrity": "sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==", + "dependencies": { + "boolbase": "^1.0.0" + }, + "funding": { + "url": "https://github.com/fb55/nth-check?sponsor=1" + } + }, + "node_modules/object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/object-inspect": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.9.0.tgz", + "integrity": "sha512-i3Bp9iTqwhaLZBxGkRfo5ZbE07BQRT7MGu8+nNgwW9ItGp1TzCTw2DLEoWwjClxBjOFI/hWljTAmYGCEwmtnOw==", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/object-keys": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", + "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/object.assign": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.2.tgz", + "integrity": "sha512-ixT2L5THXsApyiUPYKmW+2EHpXXe5Ii3M+f4e+aJFAHao5amFRW6J0OO6c/LU8Be47utCx2GL89hxGB6XSmKuQ==", + "dependencies": { + "call-bind": "^1.0.0", + "define-properties": "^1.1.3", + "has-symbols": "^1.0.1", + "object-keys": "^1.1.1" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/obuf": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/obuf/-/obuf-1.1.2.tgz", + "integrity": "sha512-PX1wu0AmAdPqOL1mWhqmlOd8kOIZQwGZw6rh7uby9fTc5lhaOWFLX3I6R1hrF9k3zUY40e6igsLGkDXK92LJNg==" + }, + "node_modules/on-finished": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", + "integrity": "sha1-IPEzZIGwg811M3mSoWlxqi2QaUc=", + "devOptional": true, + "dependencies": { + "ee-first": "1.1.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/on-headers": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.0.2.tgz", + "integrity": "sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", + "dependencies": { + "wrappy": "1" + } + }, + "node_modules/onetime": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", + "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", + "dependencies": { + "mimic-fn": "^2.1.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/open": { + "version": "8.4.2", + "resolved": "https://registry.npmjs.org/open/-/open-8.4.2.tgz", + "integrity": "sha512-7x81NCL719oNbsq/3mh+hVrAWmFuEYUqrq/Iw3kUzH8ReypT9QQ0BLoJS7/G9k6N81XjW4qHWtjWwe/9eLy1EQ==", + "dependencies": { + "define-lazy-prop": "^2.0.0", + "is-docker": "^2.1.1", + "is-wsl": "^2.2.0" + }, + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/opn": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/opn/-/opn-5.3.0.tgz", + "integrity": "sha512-bYJHo/LOmoTd+pfiYhfZDnf9zekVJrY+cnS2a5F2x+w5ppvTqObojTP7WiFG+kVZs9Inw+qQ/lw7TroWwhdd2g==", + "devOptional": true, + "dependencies": { + "is-wsl": "^1.1.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/opn/node_modules/is-wsl": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-1.1.0.tgz", + "integrity": "sha512-gfygJYZ2gLTDlmbWMI0CE2MwnFzSN/2SZfkMlItC4K/JBlsWVDB0bO6XhqcY13YXE7iMcAJnzTCJjPiTeJJ0Mw==", + "devOptional": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/optionator": { + "version": "0.9.3", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.3.tgz", + "integrity": "sha512-JjCoypp+jKn1ttEFExxhetCKeJt9zhAgAve5FXHixTvFDW/5aEktX9bufBKLRRMdU7bNtpLfcGu94B3cdEJgjg==", + "dev": true, + "dependencies": { + "@aashutoshrathi/word-wrap": "^1.2.3", + "deep-is": "^0.1.3", + "fast-levenshtein": "^2.0.6", + "levn": "^0.4.1", + "prelude-ls": "^1.2.1", + "type-check": "^0.4.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/ora": { + "version": "5.4.1", + "resolved": "https://registry.npmjs.org/ora/-/ora-5.4.1.tgz", + "integrity": "sha512-5b6Y85tPxZZ7QytO+BQzysW31HJku27cRIlkbAXaNx+BdcVi+LlRFmVXzeF6a7JCwJpyw5c4b+YSVImQIrBpuQ==", + "dependencies": { + "bl": "^4.1.0", + "chalk": "^4.1.0", + "cli-cursor": "^3.1.0", + "cli-spinners": "^2.5.0", + "is-interactive": "^1.0.0", + "is-unicode-supported": "^0.1.0", + "log-symbols": "^4.1.0", + "strip-ansi": "^6.0.0", + "wcwidth": "^1.0.1" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/ora/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/ora/node_modules/chalk": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz", + "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==", + "dependencies": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/chalk?sponsor=1" + } + }, + "node_modules/ora/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/ora/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + }, + "node_modules/ora/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "engines": { + "node": ">=8" + } + }, + "node_modules/ora/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/os-browserify": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/os-browserify/-/os-browserify-0.3.0.tgz", + "integrity": "sha1-hUNzx/XCMVkU/Jv8a9gjj92h7Cc=" + }, + "node_modules/os-tmpdir": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", + "integrity": "sha512-D2FR03Vir7FIu45XBY20mTb+/ZSWB00sjU9jdQXt83gDrI4Ztz5Fs7/yy74g2N5SVQY4xY1qDr4rNddwYRVX0g==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/ospath": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/ospath/-/ospath-1.2.2.tgz", + "integrity": "sha1-EnZjl3Sj+O8lcvf+QoDg6kVQwHs=", + "optional": true + }, + "node_modules/p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "dev": true, + "dependencies": { + "yocto-queue": "^0.1.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "dependencies": { + "p-limit": "^2.2.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/p-locate/node_modules/p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "dependencies": { + "p-try": "^2.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-map": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/p-map/-/p-map-4.0.0.tgz", + "integrity": "sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ==", + "dependencies": { + "aggregate-error": "^3.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/p-retry": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/p-retry/-/p-retry-4.6.2.tgz", + "integrity": "sha512-312Id396EbJdvRONlngUx0NydfrIQ5lsYu0znKVUzVvArzEIt08V1qhtyESbGVd1FGX7UKtiFp5uwKZdM8wIuQ==", + "dependencies": { + "@types/retry": "0.12.0", + "retry": "^0.13.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/p-retry/node_modules/retry": { + "version": "0.13.1", + "resolved": "https://registry.npmjs.org/retry/-/retry-0.13.1.tgz", + "integrity": "sha512-XQBQ3I8W1Cge0Seh+6gjj03LbmRFWuoszgK9ooCpwYIrhhoO80pfq4cUkU5DkknwfOfFteRwlZ56PYOGYyFWdg==", + "engines": { + "node": ">= 4" + } + }, + "node_modules/p-try": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", + "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", + "engines": { + "node": ">=6" + } + }, + "node_modules/pacote": { + "version": "17.0.6", + "resolved": "https://registry.npmjs.org/pacote/-/pacote-17.0.6.tgz", + "integrity": "sha512-cJKrW21VRE8vVTRskJo78c/RCvwJCn1f4qgfxL4w77SOWrTCRcmfkYHlHtS0gqpgjv3zhXflRtgsrUCX5xwNnQ==", + "dependencies": { + "@npmcli/git": "^5.0.0", + "@npmcli/installed-package-contents": "^2.0.1", + "@npmcli/promise-spawn": "^7.0.0", + "@npmcli/run-script": "^7.0.0", + "cacache": "^18.0.0", + "fs-minipass": "^3.0.0", + "minipass": "^7.0.2", + "npm-package-arg": "^11.0.0", + "npm-packlist": "^8.0.0", + "npm-pick-manifest": "^9.0.0", + "npm-registry-fetch": "^16.0.0", + "proc-log": "^3.0.0", + "promise-retry": "^2.0.1", + "read-package-json": "^7.0.0", + "read-package-json-fast": "^3.0.0", + "sigstore": "^2.2.0", + "ssri": "^10.0.0", + "tar": "^6.1.11" + }, + "bin": { + "pacote": "lib/bin.js" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "node_modules/pako": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/pako/-/pako-1.0.11.tgz", + "integrity": "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==" + }, + "node_modules/parent-module": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "dependencies": { + "callsites": "^3.0.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/parents": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parents/-/parents-1.0.1.tgz", + "integrity": "sha1-/t1NK/GTp3dF/nHjcdc8MwfZx1E=", + "dependencies": { + "path-platform": "~0.11.15" + } + }, + "node_modules/parse-asn1": { + "version": "5.1.6", + "resolved": "https://registry.npmjs.org/parse-asn1/-/parse-asn1-5.1.6.tgz", + "integrity": "sha512-RnZRo1EPU6JBnra2vGHj0yhp6ebyjBZpmUCLHWiFhxlzvBCCpAuZ7elsBp1PVAbQN0/04VD/19rfzlBSwLstMw==", + "dependencies": { + "asn1.js": "^5.2.0", + "browserify-aes": "^1.0.0", + "evp_bytestokey": "^1.0.0", + "pbkdf2": "^3.0.3", + "safe-buffer": "^5.1.1" + } + }, + "node_modules/parse-json": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", + "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", + "dependencies": { + "@babel/code-frame": "^7.0.0", + "error-ex": "^1.3.1", + "json-parse-even-better-errors": "^2.3.0", + "lines-and-columns": "^1.1.6" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/parse-node-version": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parse-node-version/-/parse-node-version-1.0.1.tgz", + "integrity": "sha512-3YHlOa/JgH6Mnpr05jP9eDG254US9ek25LyIxZlDItp2iJtwyaXQb57lBYLdT3MowkUFYEV2XXNAYIPlESvJlA==", + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/parse5": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-7.1.2.tgz", + "integrity": "sha512-Czj1WaSVpaoj0wbhMzLmWD69anp2WH7FXMB9n1Sy8/ZFF9jolSQVMu1Ij5WIyGmcBmhk7EOndpO4mIpihVqAXw==", + "dependencies": { + "entities": "^4.4.0" + }, + "funding": { + "url": "https://github.com/inikulin/parse5?sponsor=1" + } + }, + "node_modules/parse5-html-rewriting-stream": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/parse5-html-rewriting-stream/-/parse5-html-rewriting-stream-7.0.0.tgz", + "integrity": "sha512-mazCyGWkmCRWDI15Zp+UiCqMp/0dgEmkZRvhlsqqKYr4SsVm/TvnSpD9fCvqCA2zoWJcfRym846ejWBBHRiYEg==", + "dependencies": { + "entities": "^4.3.0", + "parse5": "^7.0.0", + "parse5-sax-parser": "^7.0.0" + }, + "funding": { + "url": "https://github.com/inikulin/parse5?sponsor=1" + } + }, + "node_modules/parse5-sax-parser": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/parse5-sax-parser/-/parse5-sax-parser-7.0.0.tgz", + "integrity": "sha512-5A+v2SNsq8T6/mG3ahcz8ZtQ0OUFTatxPbeidoMB7tkJSGDY3tdfl4MHovtLQHkEn5CGxijNWRQHhRQ6IRpXKg==", + "dependencies": { + "parse5": "^7.0.0" + }, + "funding": { + "url": "https://github.com/inikulin/parse5?sponsor=1" + } + }, + "node_modules/parseurl": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", + "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==", + "engines": { + "node": ">=8" + } + }, + "node_modules/path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==", + "engines": { + "node": ">=8" + } + }, + "node_modules/path-parse": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==" + }, + "node_modules/path-platform": { + "version": "0.11.15", + "resolved": "https://registry.npmjs.org/path-platform/-/path-platform-0.11.15.tgz", + "integrity": "sha1-6GQhf3TDaFDwhSt43Hv31KVyG/I=", + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/path-scurry": { + "version": "1.10.1", + "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.10.1.tgz", + "integrity": "sha512-MkhCqzzBEpPvxxQ71Md0b1Kk51W01lrYvlMzSUaIzNsODdd7mqhiimSZlr+VegAz5Z6Vzt9Xg2ttE//XBhH3EQ==", + "dependencies": { + "lru-cache": "^9.1.1 || ^10.0.0", + "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/path-scurry/node_modules/lru-cache": { + "version": "10.2.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.2.0.tgz", + "integrity": "sha512-2bIM8x+VAf6JT4bKAljS1qUWgMsqZRPGJS6FSahIMPVvctcNhyVp7AJu7quxOW9jwkryBReKZY5tY5JYv2n/7Q==", + "engines": { + "node": "14 || >=16.14" + } + }, + "node_modules/path-to-regexp": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", + "integrity": "sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ==" + }, + "node_modules/path-type": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", + "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", + "engines": { + "node": ">=8" + } + }, + "node_modules/pathval": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/pathval/-/pathval-1.1.1.tgz", + "integrity": "sha512-Dp6zGqpTdETdR63lehJYPeIOqpiNBNtc7BpWSLrOje7UaIsE5aY92r/AunQA7rsXvet3lrJ3JnZX29UPTKXyKQ==", + "optional": true, + "engines": { + "node": "*" + } + }, + "node_modules/pause-stream": { + "version": "0.0.11", + "resolved": "https://registry.npmjs.org/pause-stream/-/pause-stream-0.0.11.tgz", + "integrity": "sha1-/lo0sMvOErWqaitAPuLnO2AvFEU=", + "optional": true, + "dependencies": { + "through": "~2.3" + } + }, + "node_modules/pbkdf2": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/pbkdf2/-/pbkdf2-3.1.1.tgz", + "integrity": "sha512-4Ejy1OPxi9f2tt1rRV7Go7zmfDQ+ZectEQz3VGUQhgq62HtIRPDyG/JtnwIxs6x3uNMwo2V7q1fMvKjb+Tnpqg==", + "dependencies": { + "create-hash": "^1.1.2", + "create-hmac": "^1.1.4", + "ripemd160": "^2.0.1", + "safe-buffer": "^5.0.1", + "sha.js": "^2.4.8" + }, + "engines": { + "node": ">=0.12" + } + }, + "node_modules/pend": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz", + "integrity": "sha512-F3asv42UuXchdzt+xXqfW1OGlVBe+mxa2mqI0pg5yAHZPvFmY3Y6drSf/GQ1A86WgWEN9Kzh/WrgKa6iGcHXLg==", + "optional": true + }, + "node_modules/performance-now": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", + "integrity": "sha512-7EAHlyLHI56VEIdK57uwHdHKIaAGbnXPiw0yWbarQZOKaKpvUIgW0jWRVLiatnM+XXlSwsanIBH/hzGMJulMow==", + "optional": true + }, + "node_modules/picocolors": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", + "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==" + }, + "node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/pify": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "integrity": "sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==", + "optional": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/piscina": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/piscina/-/piscina-4.4.0.tgz", + "integrity": "sha512-+AQduEJefrOApE4bV7KRmp3N2JnnyErlVqq4P/jmko4FPz9Z877BCccl/iB3FdrWSUkvbGV9Kan/KllJgat3Vg==", + "optionalDependencies": { + "nice-napi": "^1.0.2" + } + }, + "node_modules/pkg-dir": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-7.0.0.tgz", + "integrity": "sha512-Ie9z/WINcxxLp27BKOCHGde4ITq9UklYKDzVo1nhk5sqGEXU3FpkwP5GM2voTGJkGd9B3Otl+Q4uwSOeSUtOBA==", + "dependencies": { + "find-up": "^6.3.0" + }, + "engines": { + "node": ">=14.16" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/pkg-dir/node_modules/find-up": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-6.3.0.tgz", + "integrity": "sha512-v2ZsoEuVHYy8ZIlYqwPe/39Cy+cFDzp4dXPaxNvkEuouymu+2Jbz0PxpKarJHYJTmv2HWT3O382qY8l4jMWthw==", + "dependencies": { + "locate-path": "^7.1.0", + "path-exists": "^5.0.0" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/pkg-dir/node_modules/locate-path": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-7.2.0.tgz", + "integrity": "sha512-gvVijfZvn7R+2qyPX8mAuKcFGDf6Nc61GdvGafQsHL0sBIxfKzA+usWn4GFC/bk+QdwPUD4kWFJLhElipq+0VA==", + "dependencies": { + "p-locate": "^6.0.0" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/pkg-dir/node_modules/p-limit": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-4.0.0.tgz", + "integrity": "sha512-5b0R4txpzjPWVw/cXXUResoD4hb6U/x9BH08L7nw+GN1sezDzPdxeRvpc9c433fZhBan/wusjbCsqwqm4EIBIQ==", + "dependencies": { + "yocto-queue": "^1.0.0" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/pkg-dir/node_modules/p-locate": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-6.0.0.tgz", + "integrity": "sha512-wPrq66Llhl7/4AGC6I+cqxT07LhXvWL08LNXz1fENOw0Ap4sRZZ/gZpTTJ5jpurzzzfS2W/Ge9BY3LgLjCShcw==", + "dependencies": { + "p-limit": "^4.0.0" + }, + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/pkg-dir/node_modules/path-exists": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-5.0.0.tgz", + "integrity": "sha512-RjhtfwJOxzcFmNOi6ltcbcu4Iu+FL3zEj83dk4kAS+fVpTxXLO1b38RvJgT/0QwvV/L3aY9TAnyv0EOqW4GoMQ==", + "engines": { + "node": "^12.20.0 || ^14.13.1 || >=16.0.0" + } + }, + "node_modules/pkg-dir/node_modules/yocto-queue": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-1.0.0.tgz", + "integrity": "sha512-9bnSc/HEW2uRy67wc+T8UwauLuPJVn28jb+GtJY16iiKWyvmYJRXVT4UamsAEGQfPohgr2q4Tq0sQbQlxTfi1g==", + "engines": { + "node": ">=12.20" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/pngjs": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/pngjs/-/pngjs-5.0.0.tgz", + "integrity": "sha512-40QW5YalBNfQo5yRYmiw7Yz6TKKVr3h6970B2YE+3fQpsWcrbj1PzJgxeJ19DRQjhMbKPIuMY8rFaXc8moolVw==", + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/popper.js": { + "version": "1.16.1", + "resolved": "https://registry.npmjs.org/popper.js/-/popper.js-1.16.1.tgz", + "integrity": "sha512-Wb4p1J4zyFTbM+u6WuO4XstYx4Ky9Cewe4DWrel7B0w6VVICvPwdOpotjzcf6eD8TsckVnIMNONQyPIUFOUbCQ==", + "deprecated": "You can find the new Popper v2 at @popperjs/core, this package is dedicated to the legacy v1", + "peer": true, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/popperjs" + } + }, + "node_modules/portscanner": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/portscanner/-/portscanner-2.2.0.tgz", + "integrity": "sha512-IFroCz/59Lqa2uBvzK3bKDbDDIEaAY8XJ1jFxcLWTqosrsc32//P4VuSB2vZXoHiHqOmx8B5L5hnKOxL/7FlPw==", + "devOptional": true, + "dependencies": { + "async": "^2.6.0", + "is-number-like": "^1.0.3" + }, + "engines": { + "node": ">=0.4", + "npm": ">=1.0.0" + } + }, + "node_modules/portscanner/node_modules/async": { + "version": "2.6.4", + "resolved": "https://registry.npmjs.org/async/-/async-2.6.4.tgz", + "integrity": "sha512-mzo5dfJYwAn29PeiJ0zvwTo04zj8HDJj0Mn8TD7sno7q12prdbnasKJHhkm2c1LgrhlJ0teaea8860oxi51mGA==", + "devOptional": true, + "dependencies": { + "lodash": "^4.17.14" + } + }, + "node_modules/postcss": { + "version": "8.4.35", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.35.tgz", + "integrity": "sha512-u5U8qYpBCpN13BsiEB0CbR1Hhh4Gc0zLFuedrHJKMctHCHAGrMdG0PRM/KErzAL3CU6/eckEtmHNB3x6e3c0vA==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/postcss/" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/postcss" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "dependencies": { + "nanoid": "^3.3.7", + "picocolors": "^1.0.0", + "source-map-js": "^1.0.2" + }, + "engines": { + "node": "^10 || ^12 || >=14" + } + }, + "node_modules/postcss-loader": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/postcss-loader/-/postcss-loader-8.1.1.tgz", + "integrity": "sha512-0IeqyAsG6tYiDRCYKQJLAmgQr47DX6N7sFSWvQxt6AcupX8DIdmykuk/o/tx0Lze3ErGHJEp5OSRxrelC6+NdQ==", + "dependencies": { + "cosmiconfig": "^9.0.0", + "jiti": "^1.20.0", + "semver": "^7.5.4" + }, + "engines": { + "node": ">= 18.12.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "@rspack/core": "0.x || 1.x", + "postcss": "^7.0.0 || ^8.0.1", + "webpack": "^5.0.0" + }, + "peerDependenciesMeta": { + "@rspack/core": { + "optional": true + }, + "webpack": { + "optional": true + } + } + }, + "node_modules/postcss-media-query-parser": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/postcss-media-query-parser/-/postcss-media-query-parser-0.2.3.tgz", + "integrity": "sha512-3sOlxmbKcSHMjlUXQZKQ06jOswE7oVkXPxmZdoB1r5l0q6gTFTQSHxNxOrCccElbW7dxNytifNEo8qidX2Vsig==" + }, + "node_modules/postcss-modules-extract-imports": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/postcss-modules-extract-imports/-/postcss-modules-extract-imports-3.0.0.tgz", + "integrity": "sha512-bdHleFnP3kZ4NYDhuGlVK+CMrQ/pqUm8bx/oGL93K6gVwiclvX5x0n76fYMKuIGKzlABOy13zsvqjb0f92TEXw==", + "engines": { + "node": "^10 || ^12 || >= 14" + }, + "peerDependencies": { + "postcss": "^8.1.0" + } + }, + "node_modules/postcss-modules-local-by-default": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/postcss-modules-local-by-default/-/postcss-modules-local-by-default-4.0.4.tgz", + "integrity": "sha512-L4QzMnOdVwRm1Qb8m4x8jsZzKAaPAgrUF1r/hjDR2Xj7R+8Zsf97jAlSQzWtKx5YNiNGN8QxmPFIc/sh+RQl+Q==", + "dependencies": { + "icss-utils": "^5.0.0", + "postcss-selector-parser": "^6.0.2", + "postcss-value-parser": "^4.1.0" + }, + "engines": { + "node": "^10 || ^12 || >= 14" + }, + "peerDependencies": { + "postcss": "^8.1.0" + } + }, + "node_modules/postcss-modules-scope": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/postcss-modules-scope/-/postcss-modules-scope-3.1.1.tgz", + "integrity": "sha512-uZgqzdTleelWjzJY+Fhti6F3C9iF1JR/dODLs/JDefozYcKTBCdD8BIl6nNPbTbcLnGrk56hzwZC2DaGNvYjzA==", + "dependencies": { + "postcss-selector-parser": "^6.0.4" + }, + "engines": { + "node": "^10 || ^12 || >= 14" + }, + "peerDependencies": { + "postcss": "^8.1.0" + } + }, + "node_modules/postcss-modules-values": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/postcss-modules-values/-/postcss-modules-values-4.0.0.tgz", + "integrity": "sha512-RDxHkAiEGI78gS2ofyvCsu7iycRv7oqw5xMWn9iMoR0N/7mf9D50ecQqUo5BZ9Zh2vH4bCUR/ktCqbB9m8vJjQ==", + "dependencies": { + "icss-utils": "^5.0.0" + }, + "engines": { + "node": "^10 || ^12 || >= 14" + }, + "peerDependencies": { + "postcss": "^8.1.0" + } + }, + "node_modules/postcss-selector-parser": { + "version": "6.0.16", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.16.tgz", + "integrity": "sha512-A0RVJrX+IUkVZbW3ClroRWurercFhieevHB38sr2+l9eUClMqome3LmEmnhlNy+5Mr2EYN6B2Kaw9wYdd+VHiw==", + "dependencies": { + "cssesc": "^3.0.0", + "util-deprecate": "^1.0.2" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/postcss-value-parser": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz", + "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==" + }, + "node_modules/prelude-ls": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", + "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", + "dev": true, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/prettier": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.0.0.tgz", + "integrity": "sha512-zBf5eHpwHOGPC47h0zrPyNn+eAEIdEzfywMoYn2XPi0P44Zp0tSq64rq0xAREh4auw2cJZHo9QUob+NqCQky4g==", + "dev": true, + "bin": { + "prettier": "bin/prettier.cjs" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/prettier/prettier?sponsor=1" + } + }, + "node_modules/pretty-bytes": { + "version": "5.6.0", + "resolved": "https://registry.npmjs.org/pretty-bytes/-/pretty-bytes-5.6.0.tgz", + "integrity": "sha512-FFw039TmrBqFK8ma/7OL3sDz/VytdtJr044/QUJtH0wK9lb9jLq9tJyIxUwtQJHwar2BqtiA4iCWSwo9JLkzFg==", + "optional": true, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/pretty-hrtime": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/pretty-hrtime/-/pretty-hrtime-1.0.3.tgz", + "integrity": "sha1-t+PqQkNaTJsnWdmeDyAesZWALuE=", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/proc-log": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/proc-log/-/proc-log-3.0.0.tgz", + "integrity": "sha512-++Vn7NS4Xf9NacaU9Xq3URUuqZETPsf8L4j5/ckhaRYsfPeRyzGw+iDjFhV/Jr3uNmTvvddEJFWh5R1gRgUH8A==", + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/process": { + "version": "0.11.10", + "resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz", + "integrity": "sha1-czIwDoQBYb2j5podHZGn1LwW8YI=", + "engines": { + "node": ">= 0.6.0" + } + }, + "node_modules/process-nextick-args": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", + "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==" + }, + "node_modules/promise-inflight": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/promise-inflight/-/promise-inflight-1.0.1.tgz", + "integrity": "sha512-6zWPyEOFaQBJYcGMHBKTKJ3u6TBsnMFOIZSa6ce1e/ZrrsOlnHRHbabMjLiBYKp+n44X9eUI6VUPaukCXHuG4g==" + }, + "node_modules/promise-retry": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/promise-retry/-/promise-retry-2.0.1.tgz", + "integrity": "sha512-y+WKFlBR8BGXnsNlIHFGPZmyDf3DFMoLhaflAnyZgV6rG6xu+JwesTo2Q9R6XwYmtmwAFCkAk3e35jEdoeh/3g==", + "dependencies": { + "err-code": "^2.0.2", + "retry": "^0.12.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/proxy-addr": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", + "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==", + "dependencies": { + "forwarded": "0.2.0", + "ipaddr.js": "1.9.1" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/proxy-addr/node_modules/ipaddr.js": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", + "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==", + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/proxy-from-env": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.0.0.tgz", + "integrity": "sha512-F2JHgJQ1iqwnHDcQjVBsq3n/uoaFL+iPW/eAeL7kVxy/2RrWaN4WroKjjvbsoRtv0ftelNyC01bjRhn/bhcf4A==", + "optional": true + }, + "node_modules/prr": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/prr/-/prr-1.0.1.tgz", + "integrity": "sha512-yPw4Sng1gWghHQWj0B3ZggWUm4qVbPwPFcRG8KyxiU7J2OHFSoEHKS+EZ3fv5l1t9CyCiop6l/ZYeWbrgoQejw==", + "optional": true + }, + "node_modules/ps-tree": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/ps-tree/-/ps-tree-1.2.0.tgz", + "integrity": "sha512-0VnamPPYHl4uaU/nSFeZZpR21QAWRz+sRv4iW9+v/GS/J5U5iZB5BNN6J0RMoOvdx2gWM2+ZFMIm58q24e4UYA==", + "optional": true, + "dependencies": { + "event-stream": "=3.3.4" + }, + "bin": { + "ps-tree": "bin/ps-tree.js" + }, + "engines": { + "node": ">= 0.10" + } + }, + "node_modules/psl": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/psl/-/psl-1.9.0.tgz", + "integrity": "sha512-E/ZsdU4HLs/68gYzgGTkMicWTLPdAftJLfJFlLUAAKZGkStNU72sZjT66SnMDVOfOWY/YAoiD7Jxa9iHvngcag==", + "optional": true + }, + "node_modules/public-encrypt": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/public-encrypt/-/public-encrypt-4.0.3.tgz", + "integrity": "sha512-zVpa8oKZSz5bTMTFClc1fQOnyyEzpl5ozpi1B5YcvBrdohMjH2rfsBtyXcuNuwjsDIXmBYlF2N5FlJYhR29t8Q==", + "dependencies": { + "bn.js": "^4.1.0", + "browserify-rsa": "^4.0.0", + "create-hash": "^1.1.0", + "parse-asn1": "^5.0.0", + "randombytes": "^2.0.1", + "safe-buffer": "^5.1.2" + } + }, + "node_modules/public-encrypt/node_modules/bn.js": { + "version": "4.12.0", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", + "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==" + }, + "node_modules/pump": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", + "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", + "optional": true, + "dependencies": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + }, + "node_modules/punycode": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.0.tgz", + "integrity": "sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA==", + "engines": { + "node": ">=6" + } + }, + "node_modules/qjobs": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/qjobs/-/qjobs-1.2.0.tgz", + "integrity": "sha512-8YOJEHtxpySA3fFDyCRxA+UUV+fA+rTWnuWvylOK/NCjhY+b4ocCtmu8TtsWb+mYeU+GCHf/S66KZF/AsteKHg==", + "optional": true, + "peer": true, + "engines": { + "node": ">=0.9" + } + }, + "node_modules/qrcode": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/qrcode/-/qrcode-1.5.1.tgz", + "integrity": "sha512-nS8NJ1Z3md8uTjKtP+SGGhfqmTCs5flU/xR623oI0JX+Wepz9R8UrRVCTBTJm3qGw3rH6jJ6MUHjkDx15cxSSg==", + "dependencies": { + "dijkstrajs": "^1.0.1", + "encode-utf8": "^1.0.3", + "pngjs": "^5.0.0", + "yargs": "^15.3.1" + }, + "bin": { + "qrcode": "bin/qrcode" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/qrcode/node_modules/yargs": { + "version": "15.4.1", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-15.4.1.tgz", + "integrity": "sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A==", + "dependencies": { + "cliui": "^6.0.0", + "decamelize": "^1.2.0", + "find-up": "^4.1.0", + "get-caller-file": "^2.0.1", + "require-directory": "^2.1.1", + "require-main-filename": "^2.0.0", + "set-blocking": "^2.0.0", + "string-width": "^4.2.0", + "which-module": "^2.0.0", + "y18n": "^4.0.0", + "yargs-parser": "^18.1.2" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/qs": { + "version": "6.10.4", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.10.4.tgz", + "integrity": "sha512-OQiU+C+Ds5qiH91qh/mg0w+8nwQuLjM4F4M/PbmhDOoYehPh+Fb0bDjtR1sOvy7YKxvj28Y/M0PhP5uVX0kB+g==", + "optional": true, + "dependencies": { + "side-channel": "^1.0.4" + }, + "engines": { + "node": ">=0.6" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/querystring": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/querystring/-/querystring-0.2.0.tgz", + "integrity": "sha1-sgmEkgO7Jd+CDadW50cAWHhSFiA=", + "deprecated": "The querystring API is considered Legacy. new code should use the URLSearchParams API instead.", + "engines": { + "node": ">=0.4.x" + } + }, + "node_modules/querystring-es3": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/querystring-es3/-/querystring-es3-0.2.1.tgz", + "integrity": "sha1-nsYfeQSYdXB9aUFFlv2Qek1xHnM=", + "engines": { + "node": ">=0.4.x" + } + }, + "node_modules/querystringify": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/querystringify/-/querystringify-2.2.0.tgz", + "integrity": "sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ==", + "optional": true + }, + "node_modules/queue-microtask": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/randombytes": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", + "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", + "dependencies": { + "safe-buffer": "^5.1.0" + } + }, + "node_modules/randomfill": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/randomfill/-/randomfill-1.0.4.tgz", + "integrity": "sha512-87lcbR8+MhcWcUiQ+9e+Rwx8MyR2P7qnt15ynUlbm3TU/fjbgz4GsvfSUDTemtCCtVCqb4ZcEFlyPNTh9bBTLw==", + "dependencies": { + "randombytes": "^2.0.5", + "safe-buffer": "^5.1.0" + } + }, + "node_modules/range-parser": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", + "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/raw-body": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.2.tgz", + "integrity": "sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA==", + "dependencies": { + "bytes": "3.1.2", + "http-errors": "2.0.0", + "iconv-lite": "0.4.24", + "unpipe": "1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/read-only-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/read-only-stream/-/read-only-stream-2.0.0.tgz", + "integrity": "sha1-JyT9aoET1zdkrCiNQ4YnDB2/F/A=", + "dependencies": { + "readable-stream": "^2.0.2" + } + }, + "node_modules/read-package-json": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/read-package-json/-/read-package-json-7.0.0.tgz", + "integrity": "sha512-uL4Z10OKV4p6vbdvIXB+OzhInYtIozl/VxUBPgNkBuUi2DeRonnuspmaVAMcrkmfjKGNmRndyQAbE7/AmzGwFg==", + "dependencies": { + "glob": "^10.2.2", + "json-parse-even-better-errors": "^3.0.0", + "normalize-package-data": "^6.0.0", + "npm-normalize-package-bin": "^3.0.0" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "node_modules/read-package-json-fast": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/read-package-json-fast/-/read-package-json-fast-3.0.2.tgz", + "integrity": "sha512-0J+Msgym3vrLOUB3hzQCuZHII0xkNGCtz/HJH9xZshwv9DbDwkw1KaE3gx/e2J5rpEY5rtOy6cyhKOPrkP7FZw==", + "dependencies": { + "json-parse-even-better-errors": "^3.0.0", + "npm-normalize-package-bin": "^3.0.0" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/read-package-json-fast/node_modules/json-parse-even-better-errors": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-3.0.1.tgz", + "integrity": "sha512-aatBvbL26wVUCLmbWdCpeu9iF5wOyWpagiKkInA+kfws3sWdBrTnsvN2CKcyCYyUrc7rebNBlK6+kteg7ksecg==", + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/read-package-json/node_modules/brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dependencies": { + "balanced-match": "^1.0.0" + } + }, + "node_modules/read-package-json/node_modules/glob": { + "version": "10.3.10", + "resolved": "https://registry.npmjs.org/glob/-/glob-10.3.10.tgz", + "integrity": "sha512-fa46+tv1Ak0UPK1TOy/pZrIybNNt4HCv7SDzwyfiOZkvZLEbjsZkJBPtDHVshZjbecAoAGSC20MjLDG/qr679g==", + "dependencies": { + "foreground-child": "^3.1.0", + "jackspeak": "^2.3.5", + "minimatch": "^9.0.1", + "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0", + "path-scurry": "^1.10.1" + }, + "bin": { + "glob": "dist/esm/bin.mjs" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/read-package-json/node_modules/json-parse-even-better-errors": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-3.0.1.tgz", + "integrity": "sha512-aatBvbL26wVUCLmbWdCpeu9iF5wOyWpagiKkInA+kfws3sWdBrTnsvN2CKcyCYyUrc7rebNBlK6+kteg7ksecg==", + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/read-package-json/node_modules/minimatch": { + "version": "9.0.3", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.3.tgz", + "integrity": "sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==", + "dependencies": { + "brace-expansion": "^2.0.1" + }, + "engines": { + "node": ">=16 || 14 >=14.17" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/readable-stream": { + "version": "2.3.7", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", + "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", + "dependencies": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "node_modules/readable-stream/node_modules/isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=" + }, + "node_modules/readdirp": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", + "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "dependencies": { + "picomatch": "^2.2.1" + }, + "engines": { + "node": ">=8.10.0" + } + }, + "node_modules/reflect-metadata": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/reflect-metadata/-/reflect-metadata-0.2.1.tgz", + "integrity": "sha512-i5lLI6iw9AU3Uu4szRNPPEkomnkjRTaVt9hy/bn5g/oSzekBSMeLZblcjP74AW0vBabqERLLIrz+gR8QYR54Tw==" + }, + "node_modules/regenerate": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.2.tgz", + "integrity": "sha512-zrceR/XhGYU/d/opr2EKO7aRHUeiBI8qjtfHqADTwZd6Szfy16la6kqD0MIUs5z5hx6AaKa+PixpPrR289+I0A==" + }, + "node_modules/regenerate-unicode-properties": { + "version": "10.1.1", + "resolved": "https://registry.npmjs.org/regenerate-unicode-properties/-/regenerate-unicode-properties-10.1.1.tgz", + "integrity": "sha512-X007RyZLsCJVVrjgEFVpLUTZwyOZk3oiL75ZcuYjlIWd6rNJtOjkBwQc5AsRrpbKVkxN6sklw/k/9m2jJYOf8Q==", + "dependencies": { + "regenerate": "^1.4.2" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/regenerator-runtime": { + "version": "0.14.1", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz", + "integrity": "sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==" + }, + "node_modules/regenerator-transform": { + "version": "0.15.2", + "resolved": "https://registry.npmjs.org/regenerator-transform/-/regenerator-transform-0.15.2.tgz", + "integrity": "sha512-hfMp2BoF0qOk3uc5V20ALGDS2ddjQaLrdl7xrGXvAIow7qeWRM2VA2HuCHkUKk9slq3VwEwLNK3DFBqDfPGYtg==", + "dependencies": { + "@babel/runtime": "^7.8.4" + } + }, + "node_modules/regex-parser": { + "version": "2.2.11", + "resolved": "https://registry.npmjs.org/regex-parser/-/regex-parser-2.2.11.tgz", + "integrity": "sha512-jbD/FT0+9MBU2XAZluI7w2OBs1RBi6p9M83nkoZayQXXU9e8Robt69FcZc7wU4eJD/YFTjn1JdCk3rbMJajz8Q==" + }, + "node_modules/regexpu-core": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-5.3.2.tgz", + "integrity": "sha512-RAM5FlZz+Lhmo7db9L298p2vHP5ZywrVXmVXpmAD9GuL5MPH6t9ROw1iA/wfHkQ76Qe7AaPF0nGuim96/IrQMQ==", + "dependencies": { + "@babel/regjsgen": "^0.8.0", + "regenerate": "^1.4.2", + "regenerate-unicode-properties": "^10.1.0", + "regjsparser": "^0.9.1", + "unicode-match-property-ecmascript": "^2.0.0", + "unicode-match-property-value-ecmascript": "^2.1.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/regjsparser": { + "version": "0.9.1", + "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.9.1.tgz", + "integrity": "sha512-dQUtn90WanSNl+7mQKcXAgZxvUe7Z0SqXlgzv0za4LwiUhyzBC58yQO3liFoUgu8GiJVInAhJjkj1N0EtQ5nkQ==", + "dependencies": { + "jsesc": "~0.5.0" + }, + "bin": { + "regjsparser": "bin/parser" + } + }, + "node_modules/regjsparser/node_modules/jsesc": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-0.5.0.tgz", + "integrity": "sha512-uZz5UnB7u4T9LvwmFqXii7pZSouaRPorGs5who1Ip7VO0wxanFvBL7GkM6dTHlgX+jhBApRetaWpnDabOeTcnA==", + "bin": { + "jsesc": "bin/jsesc" + } + }, + "node_modules/request-progress": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/request-progress/-/request-progress-3.0.0.tgz", + "integrity": "sha1-TKdUCBx/7GP1BeT6qCWqBs1mnb4=", + "optional": true, + "dependencies": { + "throttleit": "^1.0.0" + } + }, + "node_modules/require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/require-from-string": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", + "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/require-main-filename": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz", + "integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==" + }, + "node_modules/requires-port": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", + "integrity": "sha1-kl0mAdOaxIXgkc8NpcbmlNw9yv8=" + }, + "node_modules/resolve": { + "version": "1.22.8", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.8.tgz", + "integrity": "sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==", + "dependencies": { + "is-core-module": "^2.13.0", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + }, + "bin": { + "resolve": "bin/resolve" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/resolve-from": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", + "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==", + "engines": { + "node": ">=8" + } + }, + "node_modules/resolve-url-loader": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/resolve-url-loader/-/resolve-url-loader-5.0.0.tgz", + "integrity": "sha512-uZtduh8/8srhBoMx//5bwqjQ+rfYOUq8zC9NrMUGtjBiGTtFJM42s58/36+hTqeqINcnYe08Nj3LkK9lW4N8Xg==", + "dependencies": { + "adjust-sourcemap-loader": "^4.0.0", + "convert-source-map": "^1.7.0", + "loader-utils": "^2.0.0", + "postcss": "^8.2.14", + "source-map": "0.6.1" + }, + "engines": { + "node": ">=12" + } + }, + "node_modules/resolve-url-loader/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/resp-modifier": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/resp-modifier/-/resp-modifier-6.0.2.tgz", + "integrity": "sha512-U1+0kWC/+4ncRFYqQWTx/3qkfE6a4B/h3XXgmXypfa0SPZ3t7cbbaFk297PjQS/yov24R18h6OZe6iZwj3NSLw==", + "devOptional": true, + "dependencies": { + "debug": "^2.2.0", + "minimatch": "^3.0.2" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/resp-modifier/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "devOptional": true, + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/resp-modifier/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "devOptional": true + }, + "node_modules/restore-cursor": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-3.1.0.tgz", + "integrity": "sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==", + "dependencies": { + "onetime": "^5.1.0", + "signal-exit": "^3.0.2" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/retry": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/retry/-/retry-0.12.0.tgz", + "integrity": "sha512-9LkiTwjUh6rT555DtE9rTX+BKByPfrMzEAtnlEtdEwr3Nkffwiihqe2bWADg+OQRjt9gl6ICdmB/ZFDCGAtSow==", + "engines": { + "node": ">= 4" + } + }, + "node_modules/reusify": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", + "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==", + "engines": { + "iojs": ">=1.0.0", + "node": ">=0.10.0" + } + }, + "node_modules/rfdc": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/rfdc/-/rfdc-1.3.0.tgz", + "integrity": "sha512-V2hovdzFbOi77/WajaSMXk2OLm+xNIeQdMMuB7icj7bk6zi2F8GGAxigcnDFpJHbNyNcgyJDiP+8nOrY5cZGrA==", + "optional": true + }, + "node_modules/rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "dependencies": { + "glob": "^7.1.3" + }, + "bin": { + "rimraf": "bin.js" + }, + "funding": { + "url": "https://github.com/sponsors/isaacs" + } + }, + "node_modules/ripemd160": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/ripemd160/-/ripemd160-2.0.2.tgz", + "integrity": "sha512-ii4iagi25WusVoiC4B4lq7pbXfAp3D9v5CwfkY33vffw2+pkDjY1D8GaN7spsxvCSx8dkPqOZCEZyfxcmJG2IA==", + "dependencies": { + "hash-base": "^3.0.0", + "inherits": "^2.0.1" + } + }, + "node_modules/rollup": { + "version": "4.13.0", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.13.0.tgz", + "integrity": "sha512-3YegKemjoQnYKmsBlOHfMLVPPA5xLkQ8MHLLSw/fBrFaVkEayL51DilPpNNLq1exr98F2B1TzrV0FUlN3gWRPg==", + "dependencies": { + "@types/estree": "1.0.5" + }, + "bin": { + "rollup": "dist/bin/rollup" + }, + "engines": { + "node": ">=18.0.0", + "npm": ">=8.0.0" + }, + "optionalDependencies": { + "@rollup/rollup-android-arm-eabi": "4.13.0", + "@rollup/rollup-android-arm64": "4.13.0", + "@rollup/rollup-darwin-arm64": "4.13.0", + "@rollup/rollup-darwin-x64": "4.13.0", + "@rollup/rollup-linux-arm-gnueabihf": "4.13.0", + "@rollup/rollup-linux-arm64-gnu": "4.13.0", + "@rollup/rollup-linux-arm64-musl": "4.13.0", + "@rollup/rollup-linux-riscv64-gnu": "4.13.0", + "@rollup/rollup-linux-x64-gnu": "4.13.0", + "@rollup/rollup-linux-x64-musl": "4.13.0", + "@rollup/rollup-win32-arm64-msvc": "4.13.0", + "@rollup/rollup-win32-ia32-msvc": "4.13.0", + "@rollup/rollup-win32-x64-msvc": "4.13.0", + "fsevents": "~2.3.2" + } + }, + "node_modules/run-async": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/run-async/-/run-async-3.0.0.tgz", + "integrity": "sha512-540WwVDOMxA6dN6We19EcT9sc3hkXPw5mzRNGM3FkdN/vtE9NFvj5lFAPNwUDmJjXidm3v7TC1cTE7t17Ulm1Q==", + "engines": { + "node": ">=0.12.0" + } + }, + "node_modules/run-parallel": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "dependencies": { + "queue-microtask": "^1.2.2" + } + }, + "node_modules/rx": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/rx/-/rx-4.1.0.tgz", + "integrity": "sha512-CiaiuN6gapkdl+cZUr67W6I8jquN4lkak3vtIsIWCl4XIPP8ffsoyN6/+PuGXnQy8Cu8W2y9Xxh31Rq4M6wUug==", + "devOptional": true + }, + "node_modules/rxjs": { + "version": "7.8.1", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.1.tgz", + "integrity": "sha512-AA3TVj+0A2iuIoQkWEK/tqFjBq2j+6PO6Y0zJcvzLAFhEFIO3HL0vls9hWLncZbAAbK0mar7oZ4V079I/qPMxg==", + "dependencies": { + "tslib": "^2.1.0" + } + }, + "node_modules/safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + }, + "node_modules/safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" + }, + "node_modules/sass": { + "version": "1.71.1", + "resolved": "https://registry.npmjs.org/sass/-/sass-1.71.1.tgz", + "integrity": "sha512-wovtnV2PxzteLlfNzbgm1tFXPLoZILYAMJtvoXXkD7/+1uP41eKkIt1ypWq5/q2uT94qHjXehEYfmjKOvjL9sg==", + "dependencies": { + "chokidar": ">=3.0.0 <4.0.0", + "immutable": "^4.0.0", + "source-map-js": ">=0.6.2 <2.0.0" + }, + "bin": { + "sass": "sass.js" + }, + "engines": { + "node": ">=14.0.0" + } + }, + "node_modules/sass-loader": { + "version": "14.1.1", + "resolved": "https://registry.npmjs.org/sass-loader/-/sass-loader-14.1.1.tgz", + "integrity": "sha512-QX8AasDg75monlybel38BZ49JP5Z+uSKfKwF2rO7S74BywaRmGQMUBw9dtkS+ekyM/QnP+NOrRYq8ABMZ9G8jw==", + "dependencies": { + "neo-async": "^2.6.2" + }, + "engines": { + "node": ">= 18.12.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "@rspack/core": "0.x || 1.x", + "node-sass": "^4.0.0 || ^5.0.0 || ^6.0.0 || ^7.0.0 || ^8.0.0 || ^9.0.0", + "sass": "^1.3.0", + "sass-embedded": "*", + "webpack": "^5.0.0" + }, + "peerDependenciesMeta": { + "@rspack/core": { + "optional": true + }, + "node-sass": { + "optional": true + }, + "sass": { + "optional": true + }, + "sass-embedded": { + "optional": true + }, + "webpack": { + "optional": true + } + } + }, + "node_modules/sass/node_modules/immutable": { + "version": "4.3.5", + "resolved": "https://registry.npmjs.org/immutable/-/immutable-4.3.5.tgz", + "integrity": "sha512-8eabxkth9gZatlwl5TBuJnCsoTADlL6ftEr7A4qgdaTsPyreilDSnUk57SO+jfKcNtxPa22U5KK6DSeAYhpBJw==" + }, + "node_modules/sax": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz", + "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==", + "optional": true + }, + "node_modules/schema-utils": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.2.0.tgz", + "integrity": "sha512-L0jRsrPpjdckP3oPug3/VxNKt2trR8TcabrM6FOAAlvC/9Phcmm+cuAgTlxBqdBR1WJx7Naj9WHw+aOmheSVbw==", + "dependencies": { + "@types/json-schema": "^7.0.9", + "ajv": "^8.9.0", + "ajv-formats": "^2.1.1", + "ajv-keywords": "^5.1.0" + }, + "engines": { + "node": ">= 12.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "node_modules/schema-utils/node_modules/ajv": { + "version": "8.12.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.12.0.tgz", + "integrity": "sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==", + "dependencies": { + "fast-deep-equal": "^3.1.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2", + "uri-js": "^4.2.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/epoberezkin" + } + }, + "node_modules/schema-utils/node_modules/ajv-keywords": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-5.1.0.tgz", + "integrity": "sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==", + "dependencies": { + "fast-deep-equal": "^3.1.3" + }, + "peerDependencies": { + "ajv": "^8.8.2" + } + }, + "node_modules/schema-utils/node_modules/json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==" + }, + "node_modules/scope-analyzer": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/scope-analyzer/-/scope-analyzer-2.1.1.tgz", + "integrity": "sha512-azEAihtQ9mEyZGhfgTJy3IbOWEzeOrYbg7NcYEshPKnKd+LZmC3TNd5dmDxbLBsTG/JVWmCp+vDJ03vJjeXMHg==", + "dependencies": { + "array-from": "^2.1.1", + "dash-ast": "^1.0.0", + "es6-map": "^0.1.5", + "es6-set": "^0.1.5", + "es6-symbol": "^3.1.1", + "estree-is-function": "^1.0.0", + "get-assigned-identifiers": "^1.1.0" + } + }, + "node_modules/select": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/select/-/select-1.1.2.tgz", + "integrity": "sha1-DnNQrN7ICxEIUoeG7B1EGNEbOW0=" + }, + "node_modules/select-hose": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/select-hose/-/select-hose-2.0.0.tgz", + "integrity": "sha512-mEugaLK+YfkijB4fx0e6kImuJdCIt2LxCRcbEYPqRGCs4F2ogyfZU5IAZRdjCP8JPq2AtdNoC/Dux63d9Kiryg==" + }, + "node_modules/selfsigned": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/selfsigned/-/selfsigned-2.4.1.tgz", + "integrity": "sha512-th5B4L2U+eGLq1TVh7zNRGBapioSORUeymIydxgFpwww9d2qyKvtuPU2jJuHvYAwwqi2Y596QBL3eEqcPEYL8Q==", + "dependencies": { + "@types/node-forge": "^1.3.0", + "node-forge": "^1" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/semver": { + "version": "7.5.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", + "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", + "dependencies": { + "lru-cache": "^6.0.0" + }, + "bin": { + "semver": "bin/semver.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/send": { + "version": "0.18.0", + "resolved": "https://registry.npmjs.org/send/-/send-0.18.0.tgz", + "integrity": "sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==", + "dependencies": { + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "1.2.0", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "fresh": "0.5.2", + "http-errors": "2.0.0", + "mime": "1.6.0", + "ms": "2.1.3", + "on-finished": "2.4.1", + "range-parser": "~1.2.1", + "statuses": "2.0.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/send/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/send/node_modules/debug/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" + }, + "node_modules/send/node_modules/mime": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", + "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", + "bin": { + "mime": "cli.js" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/send/node_modules/ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" + }, + "node_modules/send/node_modules/on-finished": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", + "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", + "dependencies": { + "ee-first": "1.1.1" + }, + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/send/node_modules/statuses": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", + "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/serialize-javascript": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.1.tgz", + "integrity": "sha512-owoXEFjWRllis8/M1Q+Cw5k8ZH40e3zhp/ovX+Xr/vi1qj6QesbyXXViFbpNvWvPNAD62SutwEXavefrLJWj7w==", + "dependencies": { + "randombytes": "^2.1.0" + } + }, + "node_modules/serve-index": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/serve-index/-/serve-index-1.9.1.tgz", + "integrity": "sha512-pXHfKNP4qujrtteMrSBb0rc8HJ9Ms/GrXwcUtUtD5s4ewDJI8bT3Cz2zTVRMKtri49pLx2e0Ya8ziP5Ya2pZZw==", + "dependencies": { + "accepts": "~1.3.4", + "batch": "0.6.1", + "debug": "2.6.9", + "escape-html": "~1.0.3", + "http-errors": "~1.6.2", + "mime-types": "~2.1.17", + "parseurl": "~1.3.2" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/serve-index/node_modules/debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dependencies": { + "ms": "2.0.0" + } + }, + "node_modules/serve-index/node_modules/depd": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", + "integrity": "sha512-7emPTl6Dpo6JRXOXjLRxck+FlLRX5847cLKEn00PLAgc3g2hTZZgr+e4c2v6QpSmLeFP3n5yUo7ft6avBK/5jQ==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/serve-index/node_modules/http-errors": { + "version": "1.6.3", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.6.3.tgz", + "integrity": "sha512-lks+lVC8dgGyh97jxvxeYTWQFvh4uw4yC12gVl63Cg30sjPX4wuGcdkICVXDAESr6OJGjqGA8Iz5mkeN6zlD7A==", + "dependencies": { + "depd": "~1.1.2", + "inherits": "2.0.3", + "setprototypeof": "1.1.0", + "statuses": ">= 1.4.0 < 2" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/serve-index/node_modules/inherits": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", + "integrity": "sha512-x00IRNXNy63jwGkJmzPigoySHbaqpNuzKbBOmzK+g2OdZpQ9w+sxCN+VSB3ja7IAge2OP2qpfxTjeNcyjmW1uw==" + }, + "node_modules/serve-index/node_modules/ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" + }, + "node_modules/serve-index/node_modules/setprototypeof": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.0.tgz", + "integrity": "sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ==" + }, + "node_modules/serve-static": { + "version": "1.15.0", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.15.0.tgz", + "integrity": "sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g==", + "dependencies": { + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "parseurl": "~1.3.3", + "send": "0.18.0" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/server-destroy": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/server-destroy/-/server-destroy-1.0.1.tgz", + "integrity": "sha512-rb+9B5YBIEzYcD6x2VKidaa+cqYBJQKnU4oe4E3ANwRRN56yk/ua1YCJT1n21NTS8w6CcOclAKNP3PhdCXKYtQ==", + "devOptional": true + }, + "node_modules/set-blocking": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", + "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=" + }, + "node_modules/set-function-length": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz", + "integrity": "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==", + "dependencies": { + "define-data-property": "^1.1.4", + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.4", + "gopd": "^1.0.1", + "has-property-descriptors": "^1.0.2" + }, + "engines": { + "node": ">= 0.4" + } + }, + "node_modules/setprototypeof": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", + "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==" + }, + "node_modules/sha.js": { + "version": "2.4.11", + "resolved": "https://registry.npmjs.org/sha.js/-/sha.js-2.4.11.tgz", + "integrity": "sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ==", + "dependencies": { + "inherits": "^2.0.1", + "safe-buffer": "^5.0.1" + }, + "bin": { + "sha.js": "bin.js" + } + }, + "node_modules/shallow-clone": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/shallow-clone/-/shallow-clone-3.0.1.tgz", + "integrity": "sha512-/6KqX+GVUdqPuPPd2LxDDxzX6CAbjJehAAOKlNpqqUpAqPM6HeL8f+o3a+JsyGjn2lv0WY8UsTgUJjU9Ok55NA==", + "dependencies": { + "kind-of": "^6.0.2" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shasum-object": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/shasum-object/-/shasum-object-1.0.0.tgz", + "integrity": "sha512-Iqo5rp/3xVi6M4YheapzZhhGPVs0yZwHj7wvwQ1B9z8H6zk+FEnI7y3Teq7qwnekfEhu8WmG2z0z4iWZaxLWVg==", + "dependencies": { + "fast-safe-stringify": "^2.0.7" + } + }, + "node_modules/shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "dependencies": { + "shebang-regex": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==", + "engines": { + "node": ">=8" + } + }, + "node_modules/shell-quote": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.8.1.tgz", + "integrity": "sha512-6j1W9l1iAs/4xYBI1SYOVZyFcCis9b4KCLQ8fgAGG07QvzaRLVVRQvAy85yNmmZSjYjg4MWh4gNvlPujU/5LpA==", + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/side-channel": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz", + "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==", + "dependencies": { + "call-bind": "^1.0.0", + "get-intrinsic": "^1.0.2", + "object-inspect": "^1.9.0" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/signal-exit": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==" + }, + "node_modules/sigstore": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/sigstore/-/sigstore-2.2.2.tgz", + "integrity": "sha512-2A3WvXkQurhuMgORgT60r6pOWiCOO5LlEqY2ADxGBDGVYLSo5HN0uLtb68YpVpuL/Vi8mLTe7+0Dx2Fq8lLqEg==", + "dependencies": { + "@sigstore/bundle": "^2.2.0", + "@sigstore/core": "^1.0.0", + "@sigstore/protobuf-specs": "^0.3.0", + "@sigstore/sign": "^2.2.3", + "@sigstore/tuf": "^2.3.1", + "@sigstore/verify": "^1.1.0" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "node_modules/simple-concat": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/simple-concat/-/simple-concat-1.0.1.tgz", + "integrity": "sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, + "node_modules/sinon": { + "version": "17.0.1", + "resolved": "https://registry.npmjs.org/sinon/-/sinon-17.0.1.tgz", + "integrity": "sha512-wmwE19Lie0MLT+ZYNpDymasPHUKTaZHUH/pKEubRXIzySv9Atnlw+BUMGCzWgV7b7wO+Hw6f1TEOr0IUnmU8/g==", + "optional": true, + "dependencies": { + "@sinonjs/commons": "^3.0.0", + "@sinonjs/fake-timers": "^11.2.2", + "@sinonjs/samsam": "^8.0.0", + "diff": "^5.1.0", + "nise": "^5.1.5", + "supports-color": "^7.2.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/sinon" + } + }, + "node_modules/sinon-chai": { + "version": "3.7.0", + "resolved": "https://registry.npmjs.org/sinon-chai/-/sinon-chai-3.7.0.tgz", + "integrity": "sha512-mf5NURdUaSdnatJx3uhoBOrY9dtL19fiOtAdT1Azxg3+lNJFiuN0uzaU3xX1LeAfL17kHQhTAJgpsfhbMJMY2g==", + "optional": true, + "peerDependencies": { + "chai": "^4.0.0", + "sinon": ">=4.0.0" + } + }, + "node_modules/sinon/node_modules/diff": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/diff/-/diff-5.1.0.tgz", + "integrity": "sha512-D+mk+qE8VC/PAUrlAU34N+VfXev0ghe5ywmpqrawphmVZc1bEfn56uo9qpyGp1p4xpzOHkSW4ztBd6L7Xx4ACw==", + "optional": true, + "engines": { + "node": ">=0.3.1" + } + }, + "node_modules/sinon/node_modules/has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "optional": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/sinon/node_modules/supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "optional": true, + "dependencies": { + "has-flag": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/slash": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-4.0.0.tgz", + "integrity": "sha512-3dOsAHXXUkQTpOYcoAxLIorMTp4gIQr5IW3iVb7A7lFIp0VHhnynm9izx6TssdrIcVIESAlVjtnO2K8bg+Coew==", + "engines": { + "node": ">=12" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/slice-ansi": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-3.0.0.tgz", + "integrity": "sha512-pSyv7bSTC7ig9Dcgbw9AuRNUb5k5V6oDudjZoMBSr13qpLBG7tB+zgCkARjq7xIUgdz5P1Qe8u+rSGdouOOIyQ==", + "optional": true, + "dependencies": { + "ansi-styles": "^4.0.0", + "astral-regex": "^2.0.0", + "is-fullwidth-code-point": "^3.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/slice-ansi/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "optional": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/slice-ansi/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "optional": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/slice-ansi/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "optional": true + }, + "node_modules/smart-buffer": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/smart-buffer/-/smart-buffer-4.2.0.tgz", + "integrity": "sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==", + "engines": { + "node": ">= 6.0.0", + "npm": ">= 3.0.0" + } + }, + "node_modules/socket.io": { + "version": "4.7.1", + "resolved": "https://registry.npmjs.org/socket.io/-/socket.io-4.7.1.tgz", + "integrity": "sha512-W+utHys2w//dhFjy7iQQu9sGd3eokCjGbl2r59tyLqNiJJBdIebn3GAKEXBr3osqHTObJi2die/25bCx2zsaaw==", + "devOptional": true, + "dependencies": { + "accepts": "~1.3.4", + "base64id": "~2.0.0", + "cors": "~2.8.5", + "debug": "~4.3.2", + "engine.io": "~6.5.0", + "socket.io-adapter": "~2.5.2", + "socket.io-parser": "~4.2.4" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/socket.io-adapter": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/socket.io-adapter/-/socket.io-adapter-2.5.2.tgz", + "integrity": "sha512-87C3LO/NOMc+eMcpcxUBebGjkpMDkNBS9tf7KJqcDsmL936EChtVva71Dw2q4tQcuVC+hAUy4an2NO/sYXmwRA==", + "devOptional": true, + "dependencies": { + "ws": "~8.11.0" + } + }, + "node_modules/socket.io-adapter/node_modules/ws": { + "version": "8.11.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.11.0.tgz", + "integrity": "sha512-HPG3wQd9sNQoT9xHyNCXoDUa+Xw/VevmY9FoHyQ+g+rrMn4j6FB4np7Z0OhdTgjx6MgQLK7jwSy1YecU1+4Asg==", + "devOptional": true, + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": "^5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, + "node_modules/socket.io-client": { + "version": "4.7.5", + "resolved": "https://registry.npmjs.org/socket.io-client/-/socket.io-client-4.7.5.tgz", + "integrity": "sha512-sJ/tqHOCe7Z50JCBCXrsY3I2k03iOiUe+tj1OmKeD2lXPiGH/RUCdTZFoqVyN7l1MnpIzPrGtLcijffmeouNlQ==", + "devOptional": true, + "dependencies": { + "@socket.io/component-emitter": "~3.1.0", + "debug": "~4.3.2", + "engine.io-client": "~6.5.2", + "socket.io-parser": "~4.2.4" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/socket.io-parser": { + "version": "4.2.4", + "resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-4.2.4.tgz", + "integrity": "sha512-/GbIKmo8ioc+NIWIhwdecY0ge+qVBSMdgxGygevmdHj24bsfgtCmcUUcQ5ZzcylGFHsN3k4HB4Cgkl96KVnuew==", + "devOptional": true, + "dependencies": { + "@socket.io/component-emitter": "~3.1.0", + "debug": "~4.3.1" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/sockjs": { + "version": "0.3.24", + "resolved": "https://registry.npmjs.org/sockjs/-/sockjs-0.3.24.tgz", + "integrity": "sha512-GJgLTZ7vYb/JtPSSZ10hsOYIvEYsjbNU+zPdIHcUaWVNUEPivzxku31865sSSud0Da0W4lEeOPlmw93zLQchuQ==", + "dependencies": { + "faye-websocket": "^0.11.3", + "uuid": "^8.3.2", + "websocket-driver": "^0.7.4" + } + }, + "node_modules/socks": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/socks/-/socks-2.8.1.tgz", + "integrity": "sha512-B6w7tkwNid7ToxjZ08rQMT8M9BJAf8DKx8Ft4NivzH0zBUfd6jldGcisJn/RLgxcX3FPNDdNQCUEMMT79b+oCQ==", + "dependencies": { + "ip-address": "^9.0.5", + "smart-buffer": "^4.2.0" + }, + "engines": { + "node": ">= 10.0.0", + "npm": ">= 3.0.0" + } + }, + "node_modules/socks-proxy-agent": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/socks-proxy-agent/-/socks-proxy-agent-8.0.2.tgz", + "integrity": "sha512-8zuqoLv1aP/66PHF5TqwJ7Czm3Yv32urJQHrVyhD7mmA6d61Zv8cIXQYPTWwmg6qlupnPvs/QKDmfa4P/qct2g==", + "dependencies": { + "agent-base": "^7.0.2", + "debug": "^4.3.4", + "socks": "^2.7.1" + }, + "engines": { + "node": ">= 14" + } + }, + "node_modules/source-map": { + "version": "0.7.4", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.4.tgz", + "integrity": "sha512-l3BikUxvPOcn5E74dZiq5BGsTb5yEwhaTSzccU6t4sDOH8NWJCstKO5QT2CvtFoK6F0saL7p9xHAqHOlCPJygA==", + "engines": { + "node": ">= 8" + } + }, + "node_modules/source-map-js": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz", + "integrity": "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/source-map-loader": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/source-map-loader/-/source-map-loader-5.0.0.tgz", + "integrity": "sha512-k2Dur7CbSLcAH73sBcIkV5xjPV4SzqO1NJ7+XaQl8if3VODDUj3FNchNGpqgJSKbvUfJuhVdv8K2Eu8/TNl2eA==", + "dependencies": { + "iconv-lite": "^0.6.3", + "source-map-js": "^1.0.2" + }, + "engines": { + "node": ">= 18.12.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^5.72.1" + } + }, + "node_modules/source-map-loader/node_modules/iconv-lite": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", + "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", + "dependencies": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/source-map-support": { + "version": "0.5.21", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", + "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", + "dependencies": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + } + }, + "node_modules/source-map-support/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/sourcemap-codec": { + "version": "1.4.8", + "resolved": "https://registry.npmjs.org/sourcemap-codec/-/sourcemap-codec-1.4.8.tgz", + "integrity": "sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA==" + }, + "node_modules/spdx-correct": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.2.0.tgz", + "integrity": "sha512-kN9dJbvnySHULIluDHy32WHRUu3Og7B9sbY7tsFLctQkIqnMh3hErYgdMjTYuqmcXX+lK5T1lnUt3G7zNswmZA==", + "dependencies": { + "spdx-expression-parse": "^3.0.0", + "spdx-license-ids": "^3.0.0" + } + }, + "node_modules/spdx-exceptions": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.5.0.tgz", + "integrity": "sha512-PiU42r+xO4UbUS1buo3LPJkjlO7430Xn5SVAhdpzzsPHsjbYVflnnFdATgabnLude+Cqu25p6N+g2lw/PFsa4w==" + }, + "node_modules/spdx-expression-parse": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz", + "integrity": "sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==", + "dependencies": { + "spdx-exceptions": "^2.1.0", + "spdx-license-ids": "^3.0.0" + } + }, + "node_modules/spdx-license-ids": { + "version": "3.0.17", + "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.17.tgz", + "integrity": "sha512-sh8PWc/ftMqAAdFiBu6Fy6JUOYjqDJBJvIhpfDMyHrr0Rbp5liZqd4TjtQ/RgfLjKFZb+LMx5hpml5qOWy0qvg==" + }, + "node_modules/spdy": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/spdy/-/spdy-4.0.2.tgz", + "integrity": "sha512-r46gZQZQV+Kl9oItvl1JZZqJKGr+oEkB08A6BzkiR7593/7IbtuncXHd2YoYeTsG4157ZssMu9KYvUHLcjcDoA==", + "dependencies": { + "debug": "^4.1.0", + "handle-thing": "^2.0.0", + "http-deceiver": "^1.2.7", + "select-hose": "^2.0.0", + "spdy-transport": "^3.0.0" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/spdy-transport": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/spdy-transport/-/spdy-transport-3.0.0.tgz", + "integrity": "sha512-hsLVFE5SjA6TCisWeJXFKniGGOpBgMLmerfO2aCyCU5s7nJ/rpAepqmFifv/GCbSbueEeAJJnmSQ2rKC/g8Fcw==", + "dependencies": { + "debug": "^4.1.0", + "detect-node": "^2.0.4", + "hpack.js": "^2.1.6", + "obuf": "^1.1.2", + "readable-stream": "^3.0.6", + "wbuf": "^1.7.3" + } + }, + "node_modules/spdy-transport/node_modules/readable-stream": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/split": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/split/-/split-0.3.3.tgz", + "integrity": "sha1-zQ7qXmOiEd//frDwkcQTPi0N0o8=", + "optional": true, + "dependencies": { + "through": "2" + }, + "engines": { + "node": "*" + } + }, + "node_modules/sprintf-js": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.1.3.tgz", + "integrity": "sha512-Oo+0REFV59/rz3gfJNKQiBlwfHaSESl1pcGyABQsnnIfWOFt6JNj5gCog2U6MLZ//IGYD+nA8nI+mTShREReaA==" + }, + "node_modules/sshpk": { + "version": "1.17.0", + "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.17.0.tgz", + "integrity": "sha512-/9HIEs1ZXGhSPE8X6Ccm7Nam1z8KcoCqPdI7ecm1N33EzAetWahvQWVqLZtaZQ+IDKX4IyA2o0gBzqIMkAagHQ==", + "optional": true, + "dependencies": { + "asn1": "~0.2.3", + "assert-plus": "^1.0.0", + "bcrypt-pbkdf": "^1.0.0", + "dashdash": "^1.12.0", + "ecc-jsbn": "~0.1.1", + "getpass": "^0.1.1", + "jsbn": "~0.1.0", + "safer-buffer": "^2.0.2", + "tweetnacl": "~0.14.0" + }, + "bin": { + "sshpk-conv": "bin/sshpk-conv", + "sshpk-sign": "bin/sshpk-sign", + "sshpk-verify": "bin/sshpk-verify" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/ssri": { + "version": "10.0.5", + "resolved": "https://registry.npmjs.org/ssri/-/ssri-10.0.5.tgz", + "integrity": "sha512-bSf16tAFkGeRlUNDjXu8FzaMQt6g2HZJrun7mtMbIPOddxt3GLMSz5VWUWcqTJUPfLEaDIepGxv+bYQW49596A==", + "dependencies": { + "minipass": "^7.0.3" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/start-server-and-test": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/start-server-and-test/-/start-server-and-test-2.0.3.tgz", + "integrity": "sha512-QsVObjfjFZKJE6CS6bSKNwWZCKBG6975/jKRPPGFfFh+yOQglSeGXiNWjzgQNXdphcBI9nXbyso9tPfX4YAUhg==", + "optional": true, + "dependencies": { + "arg": "^5.0.2", + "bluebird": "3.7.2", + "check-more-types": "2.24.0", + "debug": "4.3.4", + "execa": "5.1.1", + "lazy-ass": "1.6.0", + "ps-tree": "1.2.0", + "wait-on": "7.2.0" + }, + "bin": { + "server-test": "src/bin/start.js", + "start-server-and-test": "src/bin/start.js", + "start-test": "src/bin/start.js" + }, + "engines": { + "node": ">=16" + } + }, + "node_modules/start-server-and-test/node_modules/arg": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/arg/-/arg-5.0.2.tgz", + "integrity": "sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg==", + "optional": true + }, + "node_modules/statuses": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", + "integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow=", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/stream-combiner": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/stream-combiner/-/stream-combiner-0.2.2.tgz", + "integrity": "sha1-rsjLrBd7Vrb0+kec7YwZEs7lKFg=", + "dependencies": { + "duplexer": "~0.1.1", + "through": "~2.3.4" + } + }, + "node_modules/stream-combiner2": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/stream-combiner2/-/stream-combiner2-1.1.1.tgz", + "integrity": "sha1-+02KFCDqNidk4hrUeAOXvry0HL4=", + "dependencies": { + "duplexer2": "~0.1.0", + "readable-stream": "^2.0.2" + } + }, + "node_modules/stream-shift": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/stream-shift/-/stream-shift-1.0.1.tgz", + "integrity": "sha512-AiisoFqQ0vbGcZgQPY1cdP2I76glaVA/RauYR4G4thNFgkTqr90yXTo4LYX60Jl+sIlPNHHdGSwo01AvbKUSVQ==" + }, + "node_modules/stream-splicer": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/stream-splicer/-/stream-splicer-2.0.1.tgz", + "integrity": "sha512-Xizh4/NPuYSyAXyT7g8IvdJ9HJpxIGL9PjyhtywCZvvP0OPIdqyrr4dMikeuvY8xahpdKEBlBTySe583totajg==", + "dependencies": { + "inherits": "^2.0.1", + "readable-stream": "^2.0.2" + } + }, + "node_modules/stream-throttle": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/stream-throttle/-/stream-throttle-0.1.3.tgz", + "integrity": "sha512-889+B9vN9dq7/vLbGyuHeZ6/ctf5sNuGWsDy89uNxkFTAgzy0eK7+w5fL3KLNRTkLle7EgZGvHUphZW0Q26MnQ==", + "devOptional": true, + "dependencies": { + "commander": "^2.2.0", + "limiter": "^1.0.5" + }, + "bin": { + "throttleproxy": "bin/throttleproxy.js" + }, + "engines": { + "node": ">= 0.10.0" + } + }, + "node_modules/streamroller": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/streamroller/-/streamroller-3.0.2.tgz", + "integrity": "sha512-ur6y5S5dopOaRXBuRIZ1u6GC5bcEXHRZKgfBjfCglMhmIf+roVCECjvkEYzNQOXIN2/JPnkMPW/8B3CZoKaEPA==", + "optional": true, + "peer": true, + "dependencies": { + "date-format": "^4.0.3", + "debug": "^4.1.1", + "fs-extra": "^10.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dependencies": { + "safe-buffer": "~5.1.0" + } + }, + "node_modules/string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/string-width-cjs": { + "name": "string-width", + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "dependencies": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/string.prototype.trimend": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.4.tgz", + "integrity": "sha512-y9xCjw1P23Awk8EvTpcyL2NIr1j7wJ39f+k6lvRnSMz+mz9CGz9NYPelDk42kOz6+ql8xjfK8oYzy3jAP5QU5A==", + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/string.prototype.trimstart": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.4.tgz", + "integrity": "sha512-jh6e984OBfvxS50tdY2nRZnoC5/mLFKOREQfw8t5yytkoUsJRNxvI/E39qu1sD0OtWI3OC0XgKSmcWwziwYuZw==", + "dependencies": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-ansi-cjs": { + "name": "strip-ansi", + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "dependencies": { + "ansi-regex": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/strip-final-newline": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz", + "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==", + "engines": { + "node": ">=6" + } + }, + "node_modules/strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "dev": true, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/subarg": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/subarg/-/subarg-1.0.0.tgz", + "integrity": "sha1-9izxdYHplrSPyWVpn1TAauJouNI=", + "dependencies": { + "minimist": "^1.1.0" + } + }, + "node_modules/supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dependencies": { + "has-flag": "^3.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/supports-preserve-symlinks-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", + "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/symbol-observable": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/symbol-observable/-/symbol-observable-4.0.0.tgz", + "integrity": "sha512-b19dMThMV4HVFynSAM1++gBHAbk2Tc/osgLIBZMKsyqh34jb2e8Os7T6ZW/Bt3pJFdBTd2JwAnAAEQV7rSNvcQ==", + "engines": { + "node": ">=0.10" + } + }, + "node_modules/syntax-error": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/syntax-error/-/syntax-error-1.4.0.tgz", + "integrity": "sha512-YPPlu67mdnHGTup2A8ff7BC2Pjq0e0Yp/IyTFN03zWO0RcK07uLcbi7C2KpGR2FvWbaB0+bfE27a+sBKebSo7w==", + "dependencies": { + "acorn-node": "^1.2.0" + } + }, + "node_modules/tapable": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.2.1.tgz", + "integrity": "sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==", + "engines": { + "node": ">=6" + } + }, + "node_modules/tar": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/tar/-/tar-6.2.1.tgz", + "integrity": "sha512-DZ4yORTwrbTj/7MZYq2w+/ZFdI6OZ/f9SFHR+71gIVUZhOQPHzVCLpvRnPgyaMpfWxxk/4ONva3GQSyNIKRv6A==", + "dependencies": { + "chownr": "^2.0.0", + "fs-minipass": "^2.0.0", + "minipass": "^5.0.0", + "minizlib": "^2.1.1", + "mkdirp": "^1.0.3", + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/tar/node_modules/fs-minipass": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-2.1.0.tgz", + "integrity": "sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==", + "dependencies": { + "minipass": "^3.0.0" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/tar/node_modules/fs-minipass/node_modules/minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "dependencies": { + "yallist": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/tar/node_modules/minipass": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-5.0.0.tgz", + "integrity": "sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ==", + "engines": { + "node": ">=8" + } + }, + "node_modules/tar/node_modules/mkdirp": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", + "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==", + "bin": { + "mkdirp": "bin/cmd.js" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/terser": { + "version": "5.29.1", + "resolved": "https://registry.npmjs.org/terser/-/terser-5.29.1.tgz", + "integrity": "sha512-lZQ/fyaIGxsbGxApKmoPTODIzELy3++mXhS5hOqaAWZjQtpq/hFHAc+rm29NND1rYRxRWKcjuARNwULNXa5RtQ==", + "dependencies": { + "@jridgewell/source-map": "^0.3.3", + "acorn": "^8.8.2", + "commander": "^2.20.0", + "source-map-support": "~0.5.20" + }, + "bin": { + "terser": "bin/terser" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/terser-webpack-plugin": { + "version": "5.3.10", + "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-5.3.10.tgz", + "integrity": "sha512-BKFPWlPDndPs+NGGCr1U59t0XScL5317Y0UReNrHaw9/FwhPENlq6bfgs+4yPfyP51vqC1bQ4rp1EfXW5ZSH9w==", + "dependencies": { + "@jridgewell/trace-mapping": "^0.3.20", + "jest-worker": "^27.4.5", + "schema-utils": "^3.1.1", + "serialize-javascript": "^6.0.1", + "terser": "^5.26.0" + }, + "engines": { + "node": ">= 10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^5.1.0" + }, + "peerDependenciesMeta": { + "@swc/core": { + "optional": true + }, + "esbuild": { + "optional": true + }, + "uglify-js": { + "optional": true + } + } + }, + "node_modules/terser-webpack-plugin/node_modules/@jridgewell/trace-mapping": { + "version": "0.3.25", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz", + "integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==", + "dependencies": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, + "node_modules/terser-webpack-plugin/node_modules/schema-utils": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.3.0.tgz", + "integrity": "sha512-pN/yOAvcC+5rQ5nERGuwrjLlYvLTbCibnZ1I7B1LaiAz9BRBlE9GMgE/eqV30P7aJQUf7Ddimy/RsbYO/GrVGg==", + "dependencies": { + "@types/json-schema": "^7.0.8", + "ajv": "^6.12.5", + "ajv-keywords": "^3.5.2" + }, + "engines": { + "node": ">= 10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "node_modules/terser/node_modules/acorn": { + "version": "8.10.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.10.0.tgz", + "integrity": "sha512-F0SAmZ8iUtS//m8DmCTA0jlh6TDKkHQyK6xc6V4KDTyZKA9dnvX9/3sRTVQrWm79glUAZbnmmNcdYwUIHWVybw==", + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/test-exclude": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-6.0.0.tgz", + "integrity": "sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==", + "dependencies": { + "@istanbuljs/schema": "^0.1.2", + "glob": "^7.1.4", + "minimatch": "^3.0.4" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/text-table": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", + "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", + "dev": true + }, + "node_modules/throttleit": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/throttleit/-/throttleit-1.0.0.tgz", + "integrity": "sha1-nnhYNtr0Z0MUWlmEtiaNgoUorGw=", + "optional": true + }, + "node_modules/through": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", + "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=" + }, + "node_modules/through2": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.5.tgz", + "integrity": "sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==", + "dependencies": { + "readable-stream": "~2.3.6", + "xtend": "~4.0.1" + } + }, + "node_modules/thunky": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/thunky/-/thunky-1.1.0.tgz", + "integrity": "sha512-eHY7nBftgThBqOyHGVN+l8gF0BucP09fMo0oO/Lb0w1OF80dJv+lDVpXG60WMQvkcxAkNybKsrEIE3ZtKGmPrA==" + }, + "node_modules/tiny-emitter": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/tiny-emitter/-/tiny-emitter-2.1.0.tgz", + "integrity": "sha512-NB6Dk1A9xgQPMoGqC5CVXn123gWyte215ONT5Pp5a0yt4nlEoO1ZWeCwpncaekPHXO60i47ihFnZPiRPjRMq4Q==" + }, + "node_modules/tinyify": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/tinyify/-/tinyify-4.0.0.tgz", + "integrity": "sha512-jNDxImwUrJJAU2NyGG144J8aWx2ni39UuBo7ppCXFRmhSH0CbpWL4HgjNvrsAW05WQAgNZePwAlEemNuB+byaA==", + "dependencies": { + "@browserify/envify": "^6.0.0", + "@browserify/uglifyify": "^6.0.0", + "browser-pack-flat": "^3.0.9", + "bundle-collapser": "^1.3.0", + "common-shakeify": "^1.1.1", + "minify-stream": "^2.0.1", + "multisplice": "^1.0.0", + "terser": "3.16.1", + "through2": "^4.0.2", + "unassertify": "^3.0.1" + } + }, + "node_modules/tinyify/node_modules/commander": { + "version": "2.17.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.17.1.tgz", + "integrity": "sha512-wPMUt6FnH2yzG95SA6mzjQOEKUU3aLaDEmzs1ti+1E9h+CsrZghRlqEM/EJ4KscsQVG8uNN4uVreUeT8+drlgg==" + }, + "node_modules/tinyify/node_modules/readable-stream": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "dependencies": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/tinyify/node_modules/source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/tinyify/node_modules/terser": { + "version": "3.16.1", + "resolved": "https://registry.npmjs.org/terser/-/terser-3.16.1.tgz", + "integrity": "sha512-JDJjgleBROeek2iBcSNzOHLKsB/MdDf+E/BOAJ0Tk9r7p9/fVobfv7LMJ/g/k3v9SXdmjZnIlFd5nfn/Rt0Xow==", + "dependencies": { + "commander": "~2.17.1", + "source-map": "~0.6.1", + "source-map-support": "~0.5.9" + }, + "bin": { + "terser": "bin/uglifyjs" + }, + "engines": { + "node": ">=6.0.0" + } + }, + "node_modules/tinyify/node_modules/through2": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/through2/-/through2-4.0.2.tgz", + "integrity": "sha512-iOqSav00cVxEEICeD7TjLB1sueEL+81Wpzp2bY17uZjZN0pWZPuo4suZ/61VujxmqSGFfgOcNuTZ85QJwNZQpw==", + "dependencies": { + "readable-stream": "3" + } + }, + "node_modules/tlite": { + "version": "0.1.9", + "resolved": "https://registry.npmjs.org/tlite/-/tlite-0.1.9.tgz", + "integrity": "sha512-5QOBAvDxZZwW1i+2YXMgF6/PuV/KhA0LyE9PyVi8Ywr3bfIPziZcQD+RpdJaQurCU8zIGtBo/XuPCEHdvyeFuQ==" + }, + "node_modules/tmp": { + "version": "0.0.33", + "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", + "integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==", + "dependencies": { + "os-tmpdir": "~1.0.2" + }, + "engines": { + "node": ">=0.6.0" + } + }, + "node_modules/to-fast-properties": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", + "integrity": "sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==", + "engines": { + "node": ">=4" + } + }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, + "node_modules/toidentifier": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", + "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==", + "engines": { + "node": ">=0.6" + } + }, + "node_modules/tough-cookie": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-4.1.3.tgz", + "integrity": "sha512-aX/y5pVRkfRnfmuX+OdbSdXvPe6ieKX/G2s7e98f4poJHnqH3281gDPm/metm6E/WRamfx7WC4HUqkWHfQHprw==", + "optional": true, + "dependencies": { + "psl": "^1.1.33", + "punycode": "^2.1.1", + "universalify": "^0.2.0", + "url-parse": "^1.5.3" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/tough-cookie/node_modules/universalify": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.2.0.tgz", + "integrity": "sha512-CJ1QgKmNg3CwvAv/kOFmtnEN05f0D/cn9QntgNOQlQF9dgvVTHj3t+8JPdjqawCHk7V/KA+fbUqzZ9XWhcqPUg==", + "optional": true, + "engines": { + "node": ">= 4.0.0" + } + }, + "node_modules/transform-ast": { + "version": "2.4.4", + "resolved": "https://registry.npmjs.org/transform-ast/-/transform-ast-2.4.4.tgz", + "integrity": "sha512-AxjeZAcIOUO2lev2GDe3/xZ1Q0cVGjIMk5IsriTy8zbWlsEnjeB025AhkhBJHoy997mXpLd4R+kRbvnnQVuQHQ==", + "dependencies": { + "acorn-node": "^1.3.0", + "convert-source-map": "^1.5.1", + "dash-ast": "^1.0.0", + "is-buffer": "^2.0.0", + "magic-string": "^0.23.2", + "merge-source-map": "1.0.4", + "nanobench": "^2.1.1" + } + }, + "node_modules/transform-ast/node_modules/is-buffer": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-2.0.5.tgz", + "integrity": "sha512-i2R6zNFDwgEHJyQUtJEk0XFi1i0dPFn/oqjK3/vPCcDeJvW5NQ83V8QbicfF1SupOaB0h8ntgBC2YiE7dfyctQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "engines": { + "node": ">=4" + } + }, + "node_modules/transform-ast/node_modules/magic-string": { + "version": "0.23.2", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.23.2.tgz", + "integrity": "sha512-oIUZaAxbcxYIp4AyLafV6OVKoB3YouZs0UTCJ8mOKBHNyJgGDaMJ4TgA+VylJh6fx7EQCC52XkbURxxG9IoJXA==", + "dependencies": { + "sourcemap-codec": "^1.4.1" + } + }, + "node_modules/transform-ast/node_modules/merge-source-map": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/merge-source-map/-/merge-source-map-1.0.4.tgz", + "integrity": "sha1-pd5GU42uhNQRTMXqArR3KmNGcB8=", + "dependencies": { + "source-map": "^0.5.6" + } + }, + "node_modules/transform-ast/node_modules/source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/tree-kill": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/tree-kill/-/tree-kill-1.2.2.tgz", + "integrity": "sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==", + "bin": { + "tree-kill": "cli.js" + } + }, + "node_modules/ts-api-utils": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-1.3.0.tgz", + "integrity": "sha512-UQMIo7pb8WRomKR1/+MFVLTroIvDVtMX3K6OUir8ynLyzB8Jeriont2bTAtmNPa1ekAgN7YPDyf6V+ygrdU+eQ==", + "dev": true, + "engines": { + "node": ">=16" + }, + "peerDependencies": { + "typescript": ">=4.2.0" + } + }, + "node_modules/ts-node": { + "version": "10.9.1", + "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.1.tgz", + "integrity": "sha512-NtVysVPkxxrwFGUUxGYhfux8k78pQB3JqYBXlLRZgdGUqTO5wU/UyHop5p70iEbGhB7q5KmiZiU0Y3KlJrScEw==", + "dev": true, + "dependencies": { + "@cspotcode/source-map-support": "^0.8.0", + "@tsconfig/node10": "^1.0.7", + "@tsconfig/node12": "^1.0.7", + "@tsconfig/node14": "^1.0.0", + "@tsconfig/node16": "^1.0.2", + "acorn": "^8.4.1", + "acorn-walk": "^8.1.1", + "arg": "^4.1.0", + "create-require": "^1.1.0", + "diff": "^4.0.1", + "make-error": "^1.1.1", + "v8-compile-cache-lib": "^3.0.1", + "yn": "3.1.1" + }, + "bin": { + "ts-node": "dist/bin.js", + "ts-node-cwd": "dist/bin-cwd.js", + "ts-node-esm": "dist/bin-esm.js", + "ts-node-script": "dist/bin-script.js", + "ts-node-transpile-only": "dist/bin-transpile.js", + "ts-script": "dist/bin-script-deprecated.js" + }, + "peerDependencies": { + "@swc/core": ">=1.2.50", + "@swc/wasm": ">=1.2.50", + "@types/node": "*", + "typescript": ">=2.7" + }, + "peerDependenciesMeta": { + "@swc/core": { + "optional": true + }, + "@swc/wasm": { + "optional": true + } + } + }, + "node_modules/ts-node/node_modules/acorn": { + "version": "8.7.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.7.1.tgz", + "integrity": "sha512-Xx54uLJQZ19lKygFXOWsscKUbsBZW0CPykPhVQdhIeIwrbPmJzqeASDInc8nKBnp/JT6igTs82qPXz069H8I/A==", + "dev": true, + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/ts-node/node_modules/acorn-walk": { + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.2.0.tgz", + "integrity": "sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA==", + "dev": true, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/tslib": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz", + "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==" + }, + "node_modules/tuf-js": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/tuf-js/-/tuf-js-2.2.0.tgz", + "integrity": "sha512-ZSDngmP1z6zw+FIkIBjvOp/II/mIub/O7Pp12j1WNsiCpg5R5wAc//i555bBQsE44O94btLt0xM/Zr2LQjwdCg==", + "dependencies": { + "@tufjs/models": "2.0.0", + "debug": "^4.3.4", + "make-fetch-happen": "^13.0.0" + }, + "engines": { + "node": "^16.14.0 || >=18.0.0" + } + }, + "node_modules/tunnel-agent": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", + "integrity": "sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==", + "optional": true, + "dependencies": { + "safe-buffer": "^5.0.1" + }, + "engines": { + "node": "*" + } + }, + "node_modules/tweetnacl": { + "version": "0.14.5", + "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz", + "integrity": "sha512-KXXFFdAbFXY4geFIwoyNK+f5Z1b7swfXABfL7HXCmoIWMKU3dmS26672A4EeQtDzLKy7SXmfBu51JolvEKwtGA==", + "optional": true + }, + "node_modules/type": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/type/-/type-1.2.0.tgz", + "integrity": "sha512-+5nt5AAniqsCnu2cEQQdpzCAh33kVx8n0VoFidKpB1dVVLAN/F+bgVOqOJqOnEnrhp222clB5p3vUlD+1QAnfg==" + }, + "node_modules/type-check": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", + "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", + "dev": true, + "dependencies": { + "prelude-ls": "^1.2.1" + }, + "engines": { + "node": ">= 0.8.0" + } + }, + "node_modules/type-detect": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", + "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==", + "optional": true, + "engines": { + "node": ">=4" + } + }, + "node_modules/type-fest": { + "version": "0.21.3", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz", + "integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==", + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/type-is": { + "version": "1.6.18", + "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", + "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", + "dependencies": { + "media-typer": "0.3.0", + "mime-types": "~2.1.24" + }, + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/typed-assert": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/typed-assert/-/typed-assert-1.0.9.tgz", + "integrity": "sha512-KNNZtayBCtmnNmbo5mG47p1XsCyrx6iVqomjcZnec/1Y5GGARaxPs6r49RnSPeUP3YjNYiU9sQHAtY4BBvnZwg==" + }, + "node_modules/typedarray": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", + "integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=" + }, + "node_modules/typescript": { + "version": "5.4.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.4.3.tgz", + "integrity": "sha512-KrPd3PKaCLr78MalgiwJnA25Nm8HAmdwN3mYUYZgG/wizIo9EainNVQI9/yDavtVFRN2h3k8uf3GLHuhDMgEHg==", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, + "node_modules/ua-parser-js": { + "version": "0.7.35", + "resolved": "https://registry.npmjs.org/ua-parser-js/-/ua-parser-js-0.7.35.tgz", + "integrity": "sha512-veRf7dawaj9xaWEu9HoTVn5Pggtc/qj+kqTOFvNiN1l0YdxwC1kvel57UCjThjGa3BHBihE8/UJAHI+uQHmd/g==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/ua-parser-js" + }, + { + "type": "paypal", + "url": "https://paypal.me/faisalman" + } + ], + "optional": true, + "peer": true, + "engines": { + "node": "*" + } + }, + "node_modules/umd": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/umd/-/umd-3.0.3.tgz", + "integrity": "sha512-4IcGSufhFshvLNcMCV80UnQVlZ5pMOC8mvNPForqwA4+lzYQuetTESLDQkeLmihq8bRcnpbQa48Wb8Lh16/xow==", + "bin": { + "umd": "bin/cli.js" + } + }, + "node_modules/unassert": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/unassert/-/unassert-2.0.2.tgz", + "integrity": "sha512-P6OOg/aRdQmWH+b0g+T4U+9MgL+DG7w6oQPG+N3F2IMuvvd1WfZ5alT/Rjik2lMFVyhfACUxF7PGP1VCwSHlQA==", + "dependencies": { + "estraverse": "^5.0.0" + } + }, + "node_modules/unassert/node_modules/estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "engines": { + "node": ">=4.0" + } + }, + "node_modules/unassertify": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/unassertify/-/unassertify-3.0.1.tgz", + "integrity": "sha512-461ykSPY3oWU+39J5haiq7S/hcYy1oGJ2nHU92lqdL3jft+pSU6oAbb7o6VVmM7nZGLqppszgyzfpCnRBFgFtw==", + "dependencies": { + "acorn": "^8.0.0", + "convert-source-map": "^1.1.1", + "escodegen": "^2.0.0", + "multi-stage-sourcemap": "^0.3.1", + "through": "^2.3.7", + "unassert": "^2.0.0" + } + }, + "node_modules/unassertify/node_modules/acorn": { + "version": "8.11.3", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.11.3.tgz", + "integrity": "sha512-Y9rRfJG5jcKOE0CLisYbojUjIrIEE7AGMzA/Sm4BslANhbS+cDMpgBdcPT91oJ7OuJ9hYJBx59RjbhxVnrF8Xg==", + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/unbox-primitive": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.1.tgz", + "integrity": "sha512-tZU/3NqK3dA5gpE1KtyiJUrEB0lxnGkMFHptJ7q6ewdZ8s12QrODwNbhIJStmJkd1QDXa1NRA8aF2A1zk/Ypyw==", + "dependencies": { + "function-bind": "^1.1.1", + "has-bigints": "^1.0.1", + "has-symbols": "^1.0.2", + "which-boxed-primitive": "^1.0.2" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/undeclared-identifiers": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/undeclared-identifiers/-/undeclared-identifiers-1.1.3.tgz", + "integrity": "sha512-pJOW4nxjlmfwKApE4zvxLScM/njmwj/DiUBv7EabwE4O8kRUy+HIwxQtZLBPll/jx1LJyBcqNfB3/cpv9EZwOw==", + "dependencies": { + "acorn-node": "^1.3.0", + "dash-ast": "^1.0.0", + "get-assigned-identifiers": "^1.2.0", + "simple-concat": "^1.0.0", + "xtend": "^4.0.1" + }, + "bin": { + "undeclared-identifiers": "bin.js" + } + }, + "node_modules/undici": { + "version": "6.7.1", + "resolved": "https://registry.npmjs.org/undici/-/undici-6.7.1.tgz", + "integrity": "sha512-+Wtb9bAQw6HYWzCnxrPTMVEV3Q1QjYanI0E4q02ehReMuquQdLTEFEYbfs7hcImVYKcQkWSwT6buEmSVIiDDtQ==", + "engines": { + "node": ">=18.0" + } + }, + "node_modules/unicode-canonical-property-names-ecmascript": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-2.0.0.tgz", + "integrity": "sha512-yY5PpDlfVIU5+y/BSCxAJRBIS1Zc2dDG3Ujq+sR0U+JjUevW2JhocOF+soROYDSaAezOzOKuyyixhD6mBknSmQ==", + "engines": { + "node": ">=4" + } + }, + "node_modules/unicode-match-property-ecmascript": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/unicode-match-property-ecmascript/-/unicode-match-property-ecmascript-2.0.0.tgz", + "integrity": "sha512-5kaZCrbp5mmbz5ulBkDkbY0SsPOjKqVS35VpL9ulMPfSl0J0Xsm+9Evphv9CoIZFwre7aJoa94AY6seMKGVN5Q==", + "dependencies": { + "unicode-canonical-property-names-ecmascript": "^2.0.0", + "unicode-property-aliases-ecmascript": "^2.0.0" + }, + "engines": { + "node": ">=4" + } + }, + "node_modules/unicode-match-property-value-ecmascript": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-2.1.0.tgz", + "integrity": "sha512-qxkjQt6qjg/mYscYMC0XKRn3Rh0wFPlfxB0xkt9CfyTvpX1Ra0+rAmdX2QyAobptSEvuy4RtpPRui6XkV+8wjA==", + "engines": { + "node": ">=4" + } + }, + "node_modules/unicode-property-aliases-ecmascript": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-2.1.0.tgz", + "integrity": "sha512-6t3foTQI9qne+OZoVQB/8x8rk2k1eVy1gRXhV3oFQ5T6R1dqQ1xtin3XqSlx3+ATBkliTaR/hHyJBm+LVPNM8w==", + "engines": { + "node": ">=4" + } + }, + "node_modules/unique-filename": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/unique-filename/-/unique-filename-3.0.0.tgz", + "integrity": "sha512-afXhuC55wkAmZ0P18QsVE6kp8JaxrEokN2HGIoIVv2ijHQd419H0+6EigAFcIzXeMIkcIkNBpB3L/DXB3cTS/g==", + "dependencies": { + "unique-slug": "^4.0.0" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/unique-slug": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/unique-slug/-/unique-slug-4.0.0.tgz", + "integrity": "sha512-WrcA6AyEfqDX5bWige/4NQfPZMtASNVxdmWR76WESYQVAACSgWcR6e9i0mofqqBxYFtL4oAxPIptY73/0YE1DQ==", + "dependencies": { + "imurmurhash": "^0.1.4" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/universalify": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz", + "integrity": "sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==", + "optional": true, + "engines": { + "node": ">= 10.0.0" + } + }, + "node_modules/unpipe": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", + "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/untildify": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/untildify/-/untildify-4.0.0.tgz", + "integrity": "sha512-KK8xQ1mkzZeg9inewmFVDNkg3l5LUhoq9kN6iWYB/CC9YMG8HA+c1Q8HwDe6dEX7kErrEVNVBO3fWsVq5iDgtw==", + "optional": true, + "engines": { + "node": ">=8" + } + }, + "node_modules/update-browserslist-db": { + "version": "1.0.13", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.13.tgz", + "integrity": "sha512-xebP81SNcPuNpPP3uzeW1NYXxI3rxyJzF3pD6sH4jE7o/IX+WtSpwnVU+qIsDPyk0d3hmFQ7mjqc6AtV604hbg==", + "funding": [ + { + "type": "opencollective", + "url": "https://opencollective.com/browserslist" + }, + { + "type": "tidelift", + "url": "https://tidelift.com/funding/github/npm/browserslist" + }, + { + "type": "github", + "url": "https://github.com/sponsors/ai" + } + ], + "dependencies": { + "escalade": "^3.1.1", + "picocolors": "^1.0.0" + }, + "bin": { + "update-browserslist-db": "cli.js" + }, + "peerDependencies": { + "browserslist": ">= 4.21.0" + } + }, + "node_modules/uri-js": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.0.tgz", + "integrity": "sha512-B0yRTzYdUCCn9n+F4+Gh4yIDtMQcaJsmYBDsTSG8g/OejKBodLQ2IHfN3bM7jUsRXndopT7OIXWdYqc1fjmV6g==", + "dependencies": { + "punycode": "^2.1.0" + } + }, + "node_modules/url": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/url/-/url-0.11.0.tgz", + "integrity": "sha1-ODjpfPxgUh63PFJajlW/3Z4uKPE=", + "dependencies": { + "punycode": "1.3.2", + "querystring": "0.2.0" + } + }, + "node_modules/url-parse": { + "version": "1.5.10", + "resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.5.10.tgz", + "integrity": "sha512-WypcfiRhfeUP9vvF0j6rw0J3hrWrw6iZv3+22h6iRMJ/8z1Tj6XfLP4DsUix5MhMPnXpiHDoKyoZ/bdCkwBCiQ==", + "optional": true, + "dependencies": { + "querystringify": "^2.1.1", + "requires-port": "^1.0.0" + } + }, + "node_modules/url/node_modules/punycode": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.3.2.tgz", + "integrity": "sha1-llOgNvt8HuQjQvIyXM7v6jkmxI0=" + }, + "node_modules/util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=" + }, + "node_modules/utils-merge": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", + "integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=", + "engines": { + "node": ">= 0.4.0" + } + }, + "node_modules/uuid": { + "version": "8.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", + "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==", + "bin": { + "uuid": "dist/bin/uuid" + } + }, + "node_modules/v8-compile-cache-lib": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz", + "integrity": "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==", + "dev": true + }, + "node_modules/validate-npm-package-license": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", + "integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==", + "dependencies": { + "spdx-correct": "^3.0.0", + "spdx-expression-parse": "^3.0.0" + } + }, + "node_modules/validate-npm-package-name": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/validate-npm-package-name/-/validate-npm-package-name-5.0.0.tgz", + "integrity": "sha512-YuKoXDAhBYxY7SfOKxHBDoSyENFeW5VvIIQp2TGQuit8gpK6MnWaQelBKxso72DoxTZfZdcP3W90LqpSkgPzLQ==", + "dependencies": { + "builtins": "^5.0.0" + }, + "engines": { + "node": "^14.17.0 || ^16.13.0 || >=18.0.0" + } + }, + "node_modules/vary": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", + "integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=", + "engines": { + "node": ">= 0.8" + } + }, + "node_modules/verror": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz", + "integrity": "sha512-ZZKSmDAEFOijERBLkmYfJ+vmk3w+7hOLYDNkRCuRuMJGEmqYNCNLyBBFwWKVMhfwaEF3WOd0Zlw86U/WC/+nYw==", + "engines": [ + "node >=0.6.0" + ], + "optional": true, + "dependencies": { + "assert-plus": "^1.0.0", + "core-util-is": "1.0.2", + "extsprintf": "^1.2.0" + } + }, + "node_modules/vite": { + "version": "5.1.5", + "resolved": "https://registry.npmjs.org/vite/-/vite-5.1.5.tgz", + "integrity": "sha512-BdN1xh0Of/oQafhU+FvopafUp6WaYenLU/NFoL5WyJL++GxkNfieKzBhM24H3HVsPQrlAqB7iJYTHabzaRed5Q==", + "dependencies": { + "esbuild": "^0.19.3", + "postcss": "^8.4.35", + "rollup": "^4.2.0" + }, + "bin": { + "vite": "bin/vite.js" + }, + "engines": { + "node": "^18.0.0 || >=20.0.0" + }, + "funding": { + "url": "https://github.com/vitejs/vite?sponsor=1" + }, + "optionalDependencies": { + "fsevents": "~2.3.3" + }, + "peerDependencies": { + "@types/node": "^18.0.0 || >=20.0.0", + "less": "*", + "lightningcss": "^1.21.0", + "sass": "*", + "stylus": "*", + "sugarss": "*", + "terser": "^5.4.0" + }, + "peerDependenciesMeta": { + "@types/node": { + "optional": true + }, + "less": { + "optional": true + }, + "lightningcss": { + "optional": true + }, + "sass": { + "optional": true + }, + "stylus": { + "optional": true + }, + "sugarss": { + "optional": true + }, + "terser": { + "optional": true + } + } + }, + "node_modules/vite/node_modules/@esbuild/aix-ppc64": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.19.12.tgz", + "integrity": "sha512-bmoCYyWdEL3wDQIVbcyzRyeKLgk2WtWLTWz1ZIAZF/EGbNOwSA6ew3PftJ1PqMiOOGu0OyFMzG53L0zqIpPeNA==", + "cpu": [ + "ppc64" + ], + "optional": true, + "os": [ + "aix" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vite/node_modules/@esbuild/android-arm": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.19.12.tgz", + "integrity": "sha512-qg/Lj1mu3CdQlDEEiWrlC4eaPZ1KztwGJ9B6J+/6G+/4ewxJg7gqj8eVYWvao1bXrqGiW2rsBZFSX3q2lcW05w==", + "cpu": [ + "arm" + ], + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vite/node_modules/@esbuild/android-arm64": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.19.12.tgz", + "integrity": "sha512-P0UVNGIienjZv3f5zq0DP3Nt2IE/3plFzuaS96vihvD0Hd6H/q4WXUGpCxD/E8YrSXfNyRPbpTq+T8ZQioSuPA==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vite/node_modules/@esbuild/android-x64": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.19.12.tgz", + "integrity": "sha512-3k7ZoUW6Q6YqhdhIaq/WZ7HwBpnFBlW905Fa4s4qWJyiNOgT1dOqDiVAQFwBH7gBRZr17gLrlFCRzF6jFh7Kew==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "android" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vite/node_modules/@esbuild/darwin-arm64": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.19.12.tgz", + "integrity": "sha512-B6IeSgZgtEzGC42jsI+YYu9Z3HKRxp8ZT3cqhvliEHovq8HSX2YX8lNocDn79gCKJXOSaEot9MVYky7AKjCs8g==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vite/node_modules/@esbuild/darwin-x64": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.19.12.tgz", + "integrity": "sha512-hKoVkKzFiToTgn+41qGhsUJXFlIjxI/jSYeZf3ugemDYZldIXIxhvwN6erJGlX4t5h417iFuheZ7l+YVn05N3A==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "darwin" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vite/node_modules/@esbuild/freebsd-arm64": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.19.12.tgz", + "integrity": "sha512-4aRvFIXmwAcDBw9AueDQ2YnGmz5L6obe5kmPT8Vd+/+x/JMVKCgdcRwH6APrbpNXsPz+K653Qg8HB/oXvXVukA==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vite/node_modules/@esbuild/freebsd-x64": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.19.12.tgz", + "integrity": "sha512-EYoXZ4d8xtBoVN7CEwWY2IN4ho76xjYXqSXMNccFSx2lgqOG/1TBPW0yPx1bJZk94qu3tX0fycJeeQsKovA8gg==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "freebsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vite/node_modules/@esbuild/linux-arm": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.19.12.tgz", + "integrity": "sha512-J5jPms//KhSNv+LO1S1TX1UWp1ucM6N6XuL6ITdKWElCu8wXP72l9MM0zDTzzeikVyqFE6U8YAV9/tFyj0ti+w==", + "cpu": [ + "arm" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vite/node_modules/@esbuild/linux-arm64": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.19.12.tgz", + "integrity": "sha512-EoTjyYyLuVPfdPLsGVVVC8a0p1BFFvtpQDB/YLEhaXyf/5bczaGeN15QkR+O4S5LeJ92Tqotve7i1jn35qwvdA==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vite/node_modules/@esbuild/linux-ia32": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.19.12.tgz", + "integrity": "sha512-Thsa42rrP1+UIGaWz47uydHSBOgTUnwBwNq59khgIwktK6x60Hivfbux9iNR0eHCHzOLjLMLfUMLCypBkZXMHA==", + "cpu": [ + "ia32" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vite/node_modules/@esbuild/linux-loong64": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.19.12.tgz", + "integrity": "sha512-LiXdXA0s3IqRRjm6rV6XaWATScKAXjI4R4LoDlvO7+yQqFdlr1Bax62sRwkVvRIrwXxvtYEHHI4dm50jAXkuAA==", + "cpu": [ + "loong64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vite/node_modules/@esbuild/linux-mips64el": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.19.12.tgz", + "integrity": "sha512-fEnAuj5VGTanfJ07ff0gOA6IPsvrVHLVb6Lyd1g2/ed67oU1eFzL0r9WL7ZzscD+/N6i3dWumGE1Un4f7Amf+w==", + "cpu": [ + "mips64el" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vite/node_modules/@esbuild/linux-ppc64": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.19.12.tgz", + "integrity": "sha512-nYJA2/QPimDQOh1rKWedNOe3Gfc8PabU7HT3iXWtNUbRzXS9+vgB0Fjaqr//XNbd82mCxHzik2qotuI89cfixg==", + "cpu": [ + "ppc64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vite/node_modules/@esbuild/linux-riscv64": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.19.12.tgz", + "integrity": "sha512-2MueBrlPQCw5dVJJpQdUYgeqIzDQgw3QtiAHUC4RBz9FXPrskyyU3VI1hw7C0BSKB9OduwSJ79FTCqtGMWqJHg==", + "cpu": [ + "riscv64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vite/node_modules/@esbuild/linux-s390x": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.19.12.tgz", + "integrity": "sha512-+Pil1Nv3Umes4m3AZKqA2anfhJiVmNCYkPchwFJNEJN5QxmTs1uzyy4TvmDrCRNT2ApwSari7ZIgrPeUx4UZDg==", + "cpu": [ + "s390x" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vite/node_modules/@esbuild/linux-x64": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.19.12.tgz", + "integrity": "sha512-B71g1QpxfwBvNrfyJdVDexenDIt1CiDN1TIXLbhOw0KhJzE78KIFGX6OJ9MrtC0oOqMWf+0xop4qEU8JrJTwCg==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "linux" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vite/node_modules/@esbuild/netbsd-x64": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.19.12.tgz", + "integrity": "sha512-3ltjQ7n1owJgFbuC61Oj++XhtzmymoCihNFgT84UAmJnxJfm4sYCiSLTXZtE00VWYpPMYc+ZQmB6xbSdVh0JWA==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "netbsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vite/node_modules/@esbuild/openbsd-x64": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.19.12.tgz", + "integrity": "sha512-RbrfTB9SWsr0kWmb9srfF+L933uMDdu9BIzdA7os2t0TXhCRjrQyCeOt6wVxr79CKD4c+p+YhCj31HBkYcXebw==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "openbsd" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vite/node_modules/@esbuild/sunos-x64": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.19.12.tgz", + "integrity": "sha512-HKjJwRrW8uWtCQnQOz9qcU3mUZhTUQvi56Q8DPTLLB+DawoiQdjsYq+j+D3s9I8VFtDr+F9CjgXKKC4ss89IeA==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "sunos" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vite/node_modules/@esbuild/win32-arm64": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.19.12.tgz", + "integrity": "sha512-URgtR1dJnmGvX864pn1B2YUYNzjmXkuJOIqG2HdU62MVS4EHpU2946OZoTMnRUHklGtJdJZ33QfzdjGACXhn1A==", + "cpu": [ + "arm64" + ], + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vite/node_modules/@esbuild/win32-ia32": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.19.12.tgz", + "integrity": "sha512-+ZOE6pUkMOJfmxmBZElNOx72NKpIa/HFOMGzu8fqzQJ5kgf6aTGrcJaFsNiVMH4JKpMipyK+7k0n2UXN7a8YKQ==", + "cpu": [ + "ia32" + ], + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vite/node_modules/@esbuild/win32-x64": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.19.12.tgz", + "integrity": "sha512-T1QyPSDCyMXaO3pzBkF96E8xMkiRYbUEZADd29SyPGabqxMViNoii+NcK7eWJAEoU6RZyEm5lVSIjTmcdoB9HA==", + "cpu": [ + "x64" + ], + "optional": true, + "os": [ + "win32" + ], + "engines": { + "node": ">=12" + } + }, + "node_modules/vite/node_modules/esbuild": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.19.12.tgz", + "integrity": "sha512-aARqgq8roFBj054KvQr5f1sFu0D65G+miZRCuJyJ0G13Zwx7vRar5Zhn2tkQNzIXcBrNVsv/8stehpj+GAjgbg==", + "hasInstallScript": true, + "bin": { + "esbuild": "bin/esbuild" + }, + "engines": { + "node": ">=12" + }, + "optionalDependencies": { + "@esbuild/aix-ppc64": "0.19.12", + "@esbuild/android-arm": "0.19.12", + "@esbuild/android-arm64": "0.19.12", + "@esbuild/android-x64": "0.19.12", + "@esbuild/darwin-arm64": "0.19.12", + "@esbuild/darwin-x64": "0.19.12", + "@esbuild/freebsd-arm64": "0.19.12", + "@esbuild/freebsd-x64": "0.19.12", + "@esbuild/linux-arm": "0.19.12", + "@esbuild/linux-arm64": "0.19.12", + "@esbuild/linux-ia32": "0.19.12", + "@esbuild/linux-loong64": "0.19.12", + "@esbuild/linux-mips64el": "0.19.12", + "@esbuild/linux-ppc64": "0.19.12", + "@esbuild/linux-riscv64": "0.19.12", + "@esbuild/linux-s390x": "0.19.12", + "@esbuild/linux-x64": "0.19.12", + "@esbuild/netbsd-x64": "0.19.12", + "@esbuild/openbsd-x64": "0.19.12", + "@esbuild/sunos-x64": "0.19.12", + "@esbuild/win32-arm64": "0.19.12", + "@esbuild/win32-ia32": "0.19.12", + "@esbuild/win32-x64": "0.19.12" + } + }, + "node_modules/vm-browserify": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/vm-browserify/-/vm-browserify-1.1.2.tgz", + "integrity": "sha512-2ham8XPWTONajOR0ohOKOHXkm3+gaBmGut3SRuu75xLd/RRaY6vqgh8NBYYk7+RW3u5AtzPQZG8F10LHkl0lAQ==" + }, + "node_modules/void-elements": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/void-elements/-/void-elements-2.0.1.tgz", + "integrity": "sha1-wGavtYK7HLQSjWDqkjkulNXp2+w=", + "optional": true, + "peer": true, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/wait-on": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/wait-on/-/wait-on-7.2.0.tgz", + "integrity": "sha512-wCQcHkRazgjG5XoAq9jbTMLpNIjoSlZslrJ2+N9MxDsGEv1HnFoVjOCexL0ESva7Y9cu350j+DWADdk54s4AFQ==", + "optional": true, + "dependencies": { + "axios": "^1.6.1", + "joi": "^17.11.0", + "lodash": "^4.17.21", + "minimist": "^1.2.8", + "rxjs": "^7.8.1" + }, + "bin": { + "wait-on": "bin/wait-on" + }, + "engines": { + "node": ">=12.0.0" + } + }, + "node_modules/wait-on/node_modules/axios": { + "version": "1.6.2", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.6.2.tgz", + "integrity": "sha512-7i24Ri4pmDRfJTR7LDBhsOTtcm+9kjX5WiY1X3wIisx6G9So3pfMkEiU7emUBe46oceVImccTEM3k6C5dbVW8A==", + "optional": true, + "dependencies": { + "follow-redirects": "^1.15.0", + "form-data": "^4.0.0", + "proxy-from-env": "^1.1.0" + } + }, + "node_modules/wait-on/node_modules/form-data": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz", + "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==", + "optional": true, + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 6" + } + }, + "node_modules/wait-on/node_modules/proxy-from-env": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", + "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==", + "optional": true + }, + "node_modules/watchpack": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.4.0.tgz", + "integrity": "sha512-Lcvm7MGST/4fup+ifyKi2hjyIAwcdI4HRgtvTpIUxBRhB+RFtUh8XtDOxUfctVCnhVi+QQj49i91OyvzkJl6cg==", + "dependencies": { + "glob-to-regexp": "^0.4.1", + "graceful-fs": "^4.1.2" + }, + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/wbuf": { + "version": "1.7.3", + "resolved": "https://registry.npmjs.org/wbuf/-/wbuf-1.7.3.tgz", + "integrity": "sha512-O84QOnr0icsbFGLS0O3bI5FswxzRr8/gHwWkDlQFskhSPryQXvrTMxjxGP4+iWYoauLoBvfDpkrOauZ+0iZpDA==", + "dependencies": { + "minimalistic-assert": "^1.0.0" + } + }, + "node_modules/wcwidth": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/wcwidth/-/wcwidth-1.0.1.tgz", + "integrity": "sha1-8LDc+RW8X/FSivrbLA4XtTLaL+g=", + "dependencies": { + "defaults": "^1.0.3" + } + }, + "node_modules/webpack": { + "version": "5.90.3", + "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.90.3.tgz", + "integrity": "sha512-h6uDYlWCctQRuXBs1oYpVe6sFcWedl0dpcVaTf/YF67J9bKvwJajFulMVSYKHrksMB3I/pIagRzDxwxkebuzKA==", + "dependencies": { + "@types/eslint-scope": "^3.7.3", + "@types/estree": "^1.0.5", + "@webassemblyjs/ast": "^1.11.5", + "@webassemblyjs/wasm-edit": "^1.11.5", + "@webassemblyjs/wasm-parser": "^1.11.5", + "acorn": "^8.7.1", + "acorn-import-assertions": "^1.9.0", + "browserslist": "^4.21.10", + "chrome-trace-event": "^1.0.2", + "enhanced-resolve": "^5.15.0", + "es-module-lexer": "^1.2.1", + "eslint-scope": "5.1.1", + "events": "^3.2.0", + "glob-to-regexp": "^0.4.1", + "graceful-fs": "^4.2.9", + "json-parse-even-better-errors": "^2.3.1", + "loader-runner": "^4.2.0", + "mime-types": "^2.1.27", + "neo-async": "^2.6.2", + "schema-utils": "^3.2.0", + "tapable": "^2.1.1", + "terser-webpack-plugin": "^5.3.10", + "watchpack": "^2.4.0", + "webpack-sources": "^3.2.3" + }, + "bin": { + "webpack": "bin/webpack.js" + }, + "engines": { + "node": ">=10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependenciesMeta": { + "webpack-cli": { + "optional": true + } + } + }, + "node_modules/webpack-dev-middleware": { + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/webpack-dev-middleware/-/webpack-dev-middleware-6.1.1.tgz", + "integrity": "sha512-y51HrHaFeeWir0YO4f0g+9GwZawuigzcAdRNon6jErXy/SqV/+O6eaVAzDqE6t3e3NpGeR5CS+cCDaTC+V3yEQ==", + "dependencies": { + "colorette": "^2.0.10", + "memfs": "^3.4.12", + "mime-types": "^2.1.31", + "range-parser": "^1.2.1", + "schema-utils": "^4.0.0" + }, + "engines": { + "node": ">= 14.15.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^5.0.0" + }, + "peerDependenciesMeta": { + "webpack": { + "optional": true + } + } + }, + "node_modules/webpack-dev-server": { + "version": "4.15.1", + "resolved": "https://registry.npmjs.org/webpack-dev-server/-/webpack-dev-server-4.15.1.tgz", + "integrity": "sha512-5hbAst3h3C3L8w6W4P96L5vaV0PxSmJhxZvWKYIdgxOQm8pNZ5dEOmmSLBVpP85ReeyRt6AS1QJNyo/oFFPeVA==", + "dependencies": { + "@types/bonjour": "^3.5.9", + "@types/connect-history-api-fallback": "^1.3.5", + "@types/express": "^4.17.13", + "@types/serve-index": "^1.9.1", + "@types/serve-static": "^1.13.10", + "@types/sockjs": "^0.3.33", + "@types/ws": "^8.5.5", + "ansi-html-community": "^0.0.8", + "bonjour-service": "^1.0.11", + "chokidar": "^3.5.3", + "colorette": "^2.0.10", + "compression": "^1.7.4", + "connect-history-api-fallback": "^2.0.0", + "default-gateway": "^6.0.3", + "express": "^4.17.3", + "graceful-fs": "^4.2.6", + "html-entities": "^2.3.2", + "http-proxy-middleware": "^2.0.3", + "ipaddr.js": "^2.0.1", + "launch-editor": "^2.6.0", + "open": "^8.0.9", + "p-retry": "^4.5.0", + "rimraf": "^3.0.2", + "schema-utils": "^4.0.0", + "selfsigned": "^2.1.1", + "serve-index": "^1.9.1", + "sockjs": "^0.3.24", + "spdy": "^4.0.2", + "webpack-dev-middleware": "^5.3.1", + "ws": "^8.13.0" + }, + "bin": { + "webpack-dev-server": "bin/webpack-dev-server.js" + }, + "engines": { + "node": ">= 12.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^4.37.0 || ^5.0.0" + }, + "peerDependenciesMeta": { + "webpack": { + "optional": true + }, + "webpack-cli": { + "optional": true + } + } + }, + "node_modules/webpack-dev-server/node_modules/connect-history-api-fallback": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/connect-history-api-fallback/-/connect-history-api-fallback-2.0.0.tgz", + "integrity": "sha512-U73+6lQFmfiNPrYbXqr6kZ1i1wiRqXnp2nhMsINseWXO8lDau0LGEffJ8kQi4EjLZympVgRdvqjAgiZ1tgzDDA==", + "engines": { + "node": ">=0.8" + } + }, + "node_modules/webpack-dev-server/node_modules/webpack-dev-middleware": { + "version": "5.3.4", + "resolved": "https://registry.npmjs.org/webpack-dev-middleware/-/webpack-dev-middleware-5.3.4.tgz", + "integrity": "sha512-BVdTqhhs+0IfoeAf7EoH5WE+exCmqGerHfDM0IL096Px60Tq2Mn9MAbnaGUe6HiMa41KMCYF19gyzZmBcq/o4Q==", + "dependencies": { + "colorette": "^2.0.10", + "memfs": "^3.4.3", + "mime-types": "^2.1.31", + "range-parser": "^1.2.1", + "schema-utils": "^4.0.0" + }, + "engines": { + "node": ">= 12.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + }, + "peerDependencies": { + "webpack": "^4.0.0 || ^5.0.0" + } + }, + "node_modules/webpack-merge": { + "version": "5.10.0", + "resolved": "https://registry.npmjs.org/webpack-merge/-/webpack-merge-5.10.0.tgz", + "integrity": "sha512-+4zXKdx7UnO+1jaN4l2lHVD+mFvnlZQP/6ljaJVb4SZiwIKeUnrT5l0gkT8z+n4hKpC+jpOv6O9R+gLtag7pSA==", + "dependencies": { + "clone-deep": "^4.0.1", + "flat": "^5.0.2", + "wildcard": "^2.0.0" + }, + "engines": { + "node": ">=10.0.0" + } + }, + "node_modules/webpack-sources": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-3.2.3.tgz", + "integrity": "sha512-/DyMEOrDgLKKIG0fmvtz+4dUX/3Ghozwgm6iPp8KRhvn+eQf9+Q7GWxVNMk3+uCPWfdXYC4ExGBckIXdFEfH1w==", + "engines": { + "node": ">=10.13.0" + } + }, + "node_modules/webpack-subresource-integrity": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/webpack-subresource-integrity/-/webpack-subresource-integrity-5.1.0.tgz", + "integrity": "sha512-sacXoX+xd8r4WKsy9MvH/q/vBtEHr86cpImXwyg74pFIpERKt6FmB8cXpeuh0ZLgclOlHI4Wcll7+R5L02xk9Q==", + "dependencies": { + "typed-assert": "^1.0.8" + }, + "engines": { + "node": ">= 12" + }, + "peerDependencies": { + "html-webpack-plugin": ">= 5.0.0-beta.1 < 6", + "webpack": "^5.12.0" + }, + "peerDependenciesMeta": { + "html-webpack-plugin": { + "optional": true + } + } + }, + "node_modules/webpack/node_modules/acorn": { + "version": "8.10.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.10.0.tgz", + "integrity": "sha512-F0SAmZ8iUtS//m8DmCTA0jlh6TDKkHQyK6xc6V4KDTyZKA9dnvX9/3sRTVQrWm79glUAZbnmmNcdYwUIHWVybw==", + "bin": { + "acorn": "bin/acorn" + }, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/webpack/node_modules/acorn-import-assertions": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/acorn-import-assertions/-/acorn-import-assertions-1.9.0.tgz", + "integrity": "sha512-cmMwop9x+8KFhxvKrKfPYmN6/pKTYYHBqLa0DfvVZcKMJWNyWLnaqND7dx/qn66R7ewM1UX5XMaDVP5wlVTaVA==", + "peerDependencies": { + "acorn": "^8" + } + }, + "node_modules/webpack/node_modules/schema-utils": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.3.0.tgz", + "integrity": "sha512-pN/yOAvcC+5rQ5nERGuwrjLlYvLTbCibnZ1I7B1LaiAz9BRBlE9GMgE/eqV30P7aJQUf7Ddimy/RsbYO/GrVGg==", + "dependencies": { + "@types/json-schema": "^7.0.8", + "ajv": "^6.12.5", + "ajv-keywords": "^3.5.2" + }, + "engines": { + "node": ">= 10.13.0" + }, + "funding": { + "type": "opencollective", + "url": "https://opencollective.com/webpack" + } + }, + "node_modules/websocket-driver": { + "version": "0.7.4", + "resolved": "https://registry.npmjs.org/websocket-driver/-/websocket-driver-0.7.4.tgz", + "integrity": "sha512-b17KeDIQVjvb0ssuSDF2cYXSg2iztliJ4B9WdsuB6J952qCPKmnVq4DyW5motImXHDC1cBT/1UezrJVsKw5zjg==", + "dependencies": { + "http-parser-js": ">=0.5.1", + "safe-buffer": ">=5.1.0", + "websocket-extensions": ">=0.1.1" + }, + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/websocket-extensions": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/websocket-extensions/-/websocket-extensions-0.1.4.tgz", + "integrity": "sha512-OqedPIGOfsDlo31UNwYbCFMSaO9m9G/0faIHj5/dZFDMFqPTcx6UwqyOy3COEaEOg/9VsGIpdqn62W5KhoKSpg==", + "engines": { + "node": ">=0.8.0" + } + }, + "node_modules/which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "dependencies": { + "isexe": "^2.0.0" + }, + "bin": { + "node-which": "bin/node-which" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/which-boxed-primitive": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz", + "integrity": "sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==", + "dependencies": { + "is-bigint": "^1.0.1", + "is-boolean-object": "^1.1.0", + "is-number-object": "^1.0.4", + "is-string": "^1.0.5", + "is-symbol": "^1.0.3" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/which-module": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.0.tgz", + "integrity": "sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho=" + }, + "node_modules/which-typed-array": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.4.tgz", + "integrity": "sha512-49E0SpUe90cjpoc7BOJwyPHRqSAd12c10Qm2amdEZrJPCY2NDxaW01zHITrem+rnETY3dwrbH3UUrUwagfCYDA==", + "dependencies": { + "available-typed-arrays": "^1.0.2", + "call-bind": "^1.0.0", + "es-abstract": "^1.18.0-next.1", + "foreach": "^2.0.5", + "function-bind": "^1.1.1", + "has-symbols": "^1.0.1", + "is-typed-array": "^1.1.3" + }, + "engines": { + "node": ">= 0.4" + }, + "funding": { + "url": "https://github.com/sponsors/ljharb" + } + }, + "node_modules/wildcard": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/wildcard/-/wildcard-2.0.1.tgz", + "integrity": "sha512-CC1bOL87PIWSBhDcTrdeLo6eGT7mCFtrg0uIJtqJUFyK+eJnzl8A1niH56uu7KMa5XFrtiV+AQuHO3n7DsHnLQ==" + }, + "node_modules/wrap-ansi": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz", + "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/wrap-ansi-cjs": { + "name": "wrap-ansi", + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/wrap-ansi-cjs/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/wrap-ansi-cjs/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/wrap-ansi-cjs/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + }, + "node_modules/wrap-ansi/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/wrap-ansi/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/wrap-ansi/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + }, + "node_modules/wrap-comment": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/wrap-comment/-/wrap-comment-1.0.1.tgz", + "integrity": "sha512-APccrMwl/ont0RHFTXNAQfM647duYYEfs6cngrIyTByTI0xbWnDnPSptFZhS68L4WCjt2ZxuhCFwuY6Pe88KZQ==" + }, + "node_modules/wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" + }, + "node_modules/ws": { + "version": "8.16.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.16.0.tgz", + "integrity": "sha512-HS0c//TP7Ina87TfiPUz1rQzMhHrl/SG2guqRcTOIUYD2q8uhUdNHZYJUaQ8aTGPzCh+c6oawMKW35nFl1dxyQ==", + "engines": { + "node": ">=10.0.0" + }, + "peerDependencies": { + "bufferutil": "^4.0.1", + "utf-8-validate": ">=5.0.2" + }, + "peerDependenciesMeta": { + "bufferutil": { + "optional": true + }, + "utf-8-validate": { + "optional": true + } + } + }, + "node_modules/xhr2": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/xhr2/-/xhr2-0.2.1.tgz", + "integrity": "sha512-sID0rrVCqkVNUn8t6xuv9+6FViXjUVXq8H5rWOH2rz9fDNQEd4g0EA2XlcEdJXRz5BMEn4O1pJFdT+z4YHhoWw==", + "engines": { + "node": ">= 6" + } + }, + "node_modules/xmlhttprequest-ssl": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/xmlhttprequest-ssl/-/xmlhttprequest-ssl-2.0.0.tgz", + "integrity": "sha512-QKxVRxiRACQcVuQEYFsI1hhkrMlrXHPegbbd1yn9UHOmRxY+si12nQYzri3vbzt8VdTTRviqcKxcyllFas5z2A==", + "devOptional": true, + "engines": { + "node": ">=0.4.0" + } + }, + "node_modules/xtend": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", + "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==", + "engines": { + "node": ">=0.4" + } + }, + "node_modules/y18n": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.1.tgz", + "integrity": "sha512-wNcy4NvjMYL8gogWWYAO7ZFWFfHcbdbE57tZO8e4cbpj8tfUcwrwqSl3ad8HxpYWCdXcJUCeKKZS62Av1affwQ==" + }, + "node_modules/yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" + }, + "node_modules/yargs": { + "version": "16.2.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", + "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==", + "optional": true, + "peer": true, + "dependencies": { + "cliui": "^7.0.2", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.0", + "y18n": "^5.0.5", + "yargs-parser": "^20.2.2" + }, + "engines": { + "node": ">=10" + } + }, + "node_modules/yargs-parser": { + "version": "18.1.3", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-18.1.3.tgz", + "integrity": "sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ==", + "dependencies": { + "camelcase": "^5.0.0", + "decamelize": "^1.2.0" + }, + "engines": { + "node": ">=6" + } + }, + "node_modules/yargs/node_modules/ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "optional": true, + "peer": true, + "dependencies": { + "color-convert": "^2.0.1" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/chalk/ansi-styles?sponsor=1" + } + }, + "node_modules/yargs/node_modules/cliui": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", + "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", + "optional": true, + "peer": true, + "dependencies": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^7.0.0" + } + }, + "node_modules/yargs/node_modules/color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "optional": true, + "peer": true, + "dependencies": { + "color-name": "~1.1.4" + }, + "engines": { + "node": ">=7.0.0" + } + }, + "node_modules/yargs/node_modules/color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "optional": true, + "peer": true + }, + "node_modules/yargs/node_modules/wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "optional": true, + "peer": true, + "dependencies": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/chalk/wrap-ansi?sponsor=1" + } + }, + "node_modules/yargs/node_modules/y18n": { + "version": "5.0.6", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.6.tgz", + "integrity": "sha512-PlVX4Y0lDTN6E2V4ES2tEdyvXkeKzxa8c/vo0pxPr/TqbztddTP0yn7zZylIyiAuxerqj0Q5GhpJ1YJCP8LaZQ==", + "optional": true, + "peer": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/yargs/node_modules/yargs-parser": { + "version": "20.2.7", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.7.tgz", + "integrity": "sha512-FiNkvbeHzB/syOjIUxFDCnhSfzAL8R5vs40MgLFBorXACCOAEaWu0gRZl14vG8MR9AOJIZbmkjhusqBYZ3HTHw==", + "optional": true, + "peer": true, + "engines": { + "node": ">=10" + } + }, + "node_modules/yauzl": { + "version": "2.10.0", + "resolved": "https://registry.npmjs.org/yauzl/-/yauzl-2.10.0.tgz", + "integrity": "sha512-p4a9I6X6nu6IhoGmBqAcbJy1mlC4j27vEPZX9F4L4/vZT3Lyq1VkFHw/V/PUcB9Buo+DG3iHkT0x3Qya58zc3g==", + "optional": true, + "dependencies": { + "buffer-crc32": "~0.2.3", + "fd-slicer": "~1.1.0" + } + }, + "node_modules/yn": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", + "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==", + "dev": true, + "engines": { + "node": ">=6" + } + }, + "node_modules/yocto-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", + "dev": true, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/zone.js": { + "version": "0.14.4", + "resolved": "https://registry.npmjs.org/zone.js/-/zone.js-0.14.4.tgz", + "integrity": "sha512-NtTUvIlNELez7Q1DzKVIFZBzNb646boQMgpATo9z3Ftuu/gWvzxCW7jdjcUDoRGxRikrhVHB/zLXh1hxeJawvw==", + "dependencies": { + "tslib": "^2.3.0" + } + }, + "node_modules/zrender": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/zrender/-/zrender-5.5.0.tgz", + "integrity": "sha512-O3MilSi/9mwoovx77m6ROZM7sXShR/O/JIanvzTwjN3FORfLSr81PsUGd7jlaYOeds9d8tw82oP44+3YucVo+w==", + "dependencies": { + "tslib": "2.3.0" + } + }, + "node_modules/zrender/node_modules/tslib": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.3.0.tgz", + "integrity": "sha512-N82ooyxVNm6h1riLCoyS9e3fuJ3AMG2zIZs2Gd1ATcSFjSA23Q0fzjjZeh0jbJvWVDZ0cJT8yaNNaaXHzueNjg==" + } + }, + "dependencies": { + "@aashutoshrathi/word-wrap": { + "version": "1.2.6", + "resolved": "https://registry.npmjs.org/@aashutoshrathi/word-wrap/-/word-wrap-1.2.6.tgz", + "integrity": "sha512-1Yjs2SvM8TflER/OD3cOjhWWOZb58A2t7wpE2S9XfBYTiIl+XFhQG2bjy4Pu1I+EAlCNUzRDYDdFwFYUKvXcIA==", + "dev": true + }, + "@ampproject/remapping": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@ampproject/remapping/-/remapping-2.3.0.tgz", + "integrity": "sha512-30iZtAPgz+LTIYoeivqYo853f02jBYSd5uGnGpkFV0M3xOt9aN73erkgYAmZU43x4VfqcnLxW9Kpg3R5LC4YYw==", + "requires": { + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.24" + }, + "dependencies": { + "@jridgewell/trace-mapping": { + "version": "0.3.25", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz", + "integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==", + "requires": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + } + } + }, + "@angular-devkit/architect": { + "version": "0.1703.1", + "resolved": "https://registry.npmjs.org/@angular-devkit/architect/-/architect-0.1703.1.tgz", + "integrity": "sha512-vkfvURv7O+3fHMTE9K+yUEiFS0v4JNYKsDP0LE1ChH5Ocy0bJXGcH2Cyz2W8qdJGDG/tKe41VzvOLpu88Xv3zQ==", + "requires": { + "@angular-devkit/core": "17.3.1", + "rxjs": "7.8.1" + } + }, + "@angular-devkit/build-angular": { + "version": "17.3.1", + "resolved": "https://registry.npmjs.org/@angular-devkit/build-angular/-/build-angular-17.3.1.tgz", + "integrity": "sha512-e+hZvLVH5AvHCFbVtKRd5oJeFsEmjg7kK1V6hsVxH4YE2f2x399TSr+AGxwV+R3jnjZ67ujIeXXd0Uuf1RwcSg==", + "requires": { + "@ampproject/remapping": "2.3.0", + "@angular-devkit/architect": "0.1703.1", + "@angular-devkit/build-webpack": "0.1703.1", + "@angular-devkit/core": "17.3.1", + "@babel/core": "7.24.0", + "@babel/generator": "7.23.6", + "@babel/helper-annotate-as-pure": "7.22.5", + "@babel/helper-split-export-declaration": "7.22.6", + "@babel/plugin-transform-async-generator-functions": "7.23.9", + "@babel/plugin-transform-async-to-generator": "7.23.3", + "@babel/plugin-transform-runtime": "7.24.0", + "@babel/preset-env": "7.24.0", + "@babel/runtime": "7.24.0", + "@discoveryjs/json-ext": "0.5.7", + "@ngtools/webpack": "17.3.1", + "@vitejs/plugin-basic-ssl": "1.1.0", + "ansi-colors": "4.1.3", + "autoprefixer": "10.4.18", + "babel-loader": "9.1.3", + "babel-plugin-istanbul": "6.1.1", + "browserslist": "^4.21.5", + "copy-webpack-plugin": "11.0.0", + "critters": "0.0.22", + "css-loader": "6.10.0", + "esbuild": "0.20.1", + "esbuild-wasm": "0.20.1", + "fast-glob": "3.3.2", + "http-proxy-middleware": "2.0.6", + "https-proxy-agent": "7.0.4", + "inquirer": "9.2.15", + "jsonc-parser": "3.2.1", + "karma-source-map-support": "1.4.0", + "less": "4.2.0", + "less-loader": "11.1.0", + "license-webpack-plugin": "4.0.2", + "loader-utils": "3.2.1", + "magic-string": "0.30.8", + "mini-css-extract-plugin": "2.8.1", + "mrmime": "2.0.0", + "open": "8.4.2", + "ora": "5.4.1", + "parse5-html-rewriting-stream": "7.0.0", + "picomatch": "4.0.1", + "piscina": "4.4.0", + "postcss": "8.4.35", + "postcss-loader": "8.1.1", + "resolve-url-loader": "5.0.0", + "rxjs": "7.8.1", + "sass": "1.71.1", + "sass-loader": "14.1.1", + "semver": "7.6.0", + "source-map-loader": "5.0.0", + "source-map-support": "0.5.21", + "terser": "5.29.1", + "tree-kill": "1.2.2", + "tslib": "2.6.2", + "undici": "6.7.1", + "vite": "5.1.5", + "watchpack": "2.4.0", + "webpack": "5.90.3", + "webpack-dev-middleware": "6.1.1", + "webpack-dev-server": "4.15.1", + "webpack-merge": "5.10.0", + "webpack-subresource-integrity": "5.1.0" + }, + "dependencies": { + "@babel/core": { + "version": "7.24.0", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.24.0.tgz", + "integrity": "sha512-fQfkg0Gjkza3nf0c7/w6Xf34BW4YvzNfACRLmmb7XRLa6XHdR+K9AlJlxneFfWYf6uhOzuzZVTjF/8KfndZANw==", + "requires": { + "@ampproject/remapping": "^2.2.0", + "@babel/code-frame": "^7.23.5", + "@babel/generator": "^7.23.6", + "@babel/helper-compilation-targets": "^7.23.6", + "@babel/helper-module-transforms": "^7.23.3", + "@babel/helpers": "^7.24.0", + "@babel/parser": "^7.24.0", + "@babel/template": "^7.24.0", + "@babel/traverse": "^7.24.0", + "@babel/types": "^7.24.0", + "convert-source-map": "^2.0.0", + "debug": "^4.1.0", + "gensync": "^1.0.0-beta.2", + "json5": "^2.2.3", + "semver": "^6.3.1" + }, + "dependencies": { + "semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==" + } + } + }, + "@esbuild/aix-ppc64": { + "version": "0.20.1", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.20.1.tgz", + "integrity": "sha512-m55cpeupQ2DbuRGQMMZDzbv9J9PgVelPjlcmM5kxHnrBdBx6REaEd7LamYV7Dm8N7rCyR/XwU6rVP8ploKtIkA==", + "optional": true + }, + "@esbuild/android-arm": { + "version": "0.20.1", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.20.1.tgz", + "integrity": "sha512-4j0+G27/2ZXGWR5okcJi7pQYhmkVgb4D7UKwxcqrjhvp5TKWx3cUjgB1CGj1mfdmJBQ9VnUGgUhign+FPF2Zgw==", + "optional": true + }, + "@esbuild/android-arm64": { + "version": "0.20.1", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.20.1.tgz", + "integrity": "sha512-hCnXNF0HM6AjowP+Zou0ZJMWWa1VkD77BXe959zERgGJBBxB+sV+J9f/rcjeg2c5bsukD/n17RKWXGFCO5dD5A==", + "optional": true + }, + "@esbuild/android-x64": { + "version": "0.20.1", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.20.1.tgz", + "integrity": "sha512-MSfZMBoAsnhpS+2yMFYIQUPs8Z19ajwfuaSZx+tSl09xrHZCjbeXXMsUF/0oq7ojxYEpsSo4c0SfjxOYXRbpaA==", + "optional": true + }, + "@esbuild/darwin-arm64": { + "version": "0.20.1", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.20.1.tgz", + "integrity": "sha512-Ylk6rzgMD8klUklGPzS414UQLa5NPXZD5tf8JmQU8GQrj6BrFA/Ic9tb2zRe1kOZyCbGl+e8VMbDRazCEBqPvA==", + "optional": true + }, + "@esbuild/darwin-x64": { + "version": "0.20.1", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.20.1.tgz", + "integrity": "sha512-pFIfj7U2w5sMp52wTY1XVOdoxw+GDwy9FsK3OFz4BpMAjvZVs0dT1VXs8aQm22nhwoIWUmIRaE+4xow8xfIDZA==", + "optional": true + }, + "@esbuild/freebsd-arm64": { + "version": "0.20.1", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.20.1.tgz", + "integrity": "sha512-UyW1WZvHDuM4xDz0jWun4qtQFauNdXjXOtIy7SYdf7pbxSWWVlqhnR/T2TpX6LX5NI62spt0a3ldIIEkPM6RHw==", + "optional": true + }, + "@esbuild/freebsd-x64": { + "version": "0.20.1", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.20.1.tgz", + "integrity": "sha512-itPwCw5C+Jh/c624vcDd9kRCCZVpzpQn8dtwoYIt2TJF3S9xJLiRohnnNrKwREvcZYx0n8sCSbvGH349XkcQeg==", + "optional": true + }, + "@esbuild/linux-arm": { + "version": "0.20.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.20.1.tgz", + "integrity": "sha512-LojC28v3+IhIbfQ+Vu4Ut5n3wKcgTu6POKIHN9Wpt0HnfgUGlBuyDDQR4jWZUZFyYLiz4RBBBmfU6sNfn6RhLw==", + "optional": true + }, + "@esbuild/linux-arm64": { + "version": "0.20.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.20.1.tgz", + "integrity": "sha512-cX8WdlF6Cnvw/DO9/X7XLH2J6CkBnz7Twjpk56cshk9sjYVcuh4sXQBy5bmTwzBjNVZze2yaV1vtcJS04LbN8w==", + "optional": true + }, + "@esbuild/linux-ia32": { + "version": "0.20.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.20.1.tgz", + "integrity": "sha512-4H/sQCy1mnnGkUt/xszaLlYJVTz3W9ep52xEefGtd6yXDQbz/5fZE5dFLUgsPdbUOQANcVUa5iO6g3nyy5BJiw==", + "optional": true + }, + "@esbuild/linux-loong64": { + "version": "0.20.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.20.1.tgz", + "integrity": "sha512-c0jgtB+sRHCciVXlyjDcWb2FUuzlGVRwGXgI+3WqKOIuoo8AmZAddzeOHeYLtD+dmtHw3B4Xo9wAUdjlfW5yYA==", + "optional": true + }, + "@esbuild/linux-mips64el": { + "version": "0.20.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.20.1.tgz", + "integrity": "sha512-TgFyCfIxSujyuqdZKDZ3yTwWiGv+KnlOeXXitCQ+trDODJ+ZtGOzLkSWngynP0HZnTsDyBbPy7GWVXWaEl6lhA==", + "optional": true + }, + "@esbuild/linux-ppc64": { + "version": "0.20.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.20.1.tgz", + "integrity": "sha512-b+yuD1IUeL+Y93PmFZDZFIElwbmFfIKLKlYI8M6tRyzE6u7oEP7onGk0vZRh8wfVGC2dZoy0EqX1V8qok4qHaw==", + "optional": true + }, + "@esbuild/linux-riscv64": { + "version": "0.20.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.20.1.tgz", + "integrity": "sha512-wpDlpE0oRKZwX+GfomcALcouqjjV8MIX8DyTrxfyCfXxoKQSDm45CZr9fanJ4F6ckD4yDEPT98SrjvLwIqUCgg==", + "optional": true + }, + "@esbuild/linux-s390x": { + "version": "0.20.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.20.1.tgz", + "integrity": "sha512-5BepC2Au80EohQ2dBpyTquqGCES7++p7G+7lXe1bAIvMdXm4YYcEfZtQrP4gaoZ96Wv1Ute61CEHFU7h4FMueQ==", + "optional": true + }, + "@esbuild/linux-x64": { + "version": "0.20.1", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.20.1.tgz", + "integrity": "sha512-5gRPk7pKuaIB+tmH+yKd2aQTRpqlf1E4f/mC+tawIm/CGJemZcHZpp2ic8oD83nKgUPMEd0fNanrnFljiruuyA==", + "optional": true + }, + "@esbuild/netbsd-x64": { + "version": "0.20.1", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.20.1.tgz", + "integrity": "sha512-4fL68JdrLV2nVW2AaWZBv3XEm3Ae3NZn/7qy2KGAt3dexAgSVT+Hc97JKSZnqezgMlv9x6KV0ZkZY7UO5cNLCg==", + "optional": true + }, + "@esbuild/openbsd-x64": { + "version": "0.20.1", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.20.1.tgz", + "integrity": "sha512-GhRuXlvRE+twf2ES+8REbeCb/zeikNqwD3+6S5y5/x+DYbAQUNl0HNBs4RQJqrechS4v4MruEr8ZtAin/hK5iw==", + "optional": true + }, + "@esbuild/sunos-x64": { + "version": "0.20.1", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.20.1.tgz", + "integrity": "sha512-ZnWEyCM0G1Ex6JtsygvC3KUUrlDXqOihw8RicRuQAzw+c4f1D66YlPNNV3rkjVW90zXVsHwZYWbJh3v+oQFM9Q==", + "optional": true + }, + "@esbuild/win32-arm64": { + "version": "0.20.1", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.20.1.tgz", + "integrity": "sha512-QZ6gXue0vVQY2Oon9WyLFCdSuYbXSoxaZrPuJ4c20j6ICedfsDilNPYfHLlMH7vGfU5DQR0czHLmJvH4Nzis/A==", + "optional": true + }, + "@esbuild/win32-ia32": { + "version": "0.20.1", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.20.1.tgz", + "integrity": "sha512-HzcJa1NcSWTAU0MJIxOho8JftNp9YALui3o+Ny7hCh0v5f90nprly1U3Sj1Ldj/CvKKdvvFsCRvDkpsEMp4DNw==", + "optional": true + }, + "@esbuild/win32-x64": { + "version": "0.20.1", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.20.1.tgz", + "integrity": "sha512-0MBh53o6XtI6ctDnRMeQ+xoCN8kD2qI1rY1KgF/xdWQwoFeKou7puvDfV8/Wv4Ctx2rRpET/gGdz3YlNtNACSA==", + "optional": true + }, + "convert-source-map": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", + "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==" + }, + "esbuild": { + "version": "0.20.1", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.20.1.tgz", + "integrity": "sha512-OJwEgrpWm/PCMsLVWXKqvcjme3bHNpOgN7Tb6cQnR5n0TPbQx1/Xrn7rqM+wn17bYeT6MGB5sn1Bh5YiGi70nA==", + "optional": true, + "requires": { + "@esbuild/aix-ppc64": "0.20.1", + "@esbuild/android-arm": "0.20.1", + "@esbuild/android-arm64": "0.20.1", + "@esbuild/android-x64": "0.20.1", + "@esbuild/darwin-arm64": "0.20.1", + "@esbuild/darwin-x64": "0.20.1", + "@esbuild/freebsd-arm64": "0.20.1", + "@esbuild/freebsd-x64": "0.20.1", + "@esbuild/linux-arm": "0.20.1", + "@esbuild/linux-arm64": "0.20.1", + "@esbuild/linux-ia32": "0.20.1", + "@esbuild/linux-loong64": "0.20.1", + "@esbuild/linux-mips64el": "0.20.1", + "@esbuild/linux-ppc64": "0.20.1", + "@esbuild/linux-riscv64": "0.20.1", + "@esbuild/linux-s390x": "0.20.1", + "@esbuild/linux-x64": "0.20.1", + "@esbuild/netbsd-x64": "0.20.1", + "@esbuild/openbsd-x64": "0.20.1", + "@esbuild/sunos-x64": "0.20.1", + "@esbuild/win32-arm64": "0.20.1", + "@esbuild/win32-ia32": "0.20.1", + "@esbuild/win32-x64": "0.20.1" + } + }, + "loader-utils": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-3.2.1.tgz", + "integrity": "sha512-ZvFw1KWS3GVyYBYb7qkmRM/WwL2TQQBxgCK62rlvm4WpVQ23Nb4tYjApUlfjrEGvOs7KHEsmyUn75OHZrJMWPw==" + }, + "picomatch": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.1.tgz", + "integrity": "sha512-xUXwsxNjwTQ8K3GnT4pCJm+xq3RUPQbmkYJTP5aFIfNIvbcc/4MUxgBaaRSZJ6yGJZiGSyYlM6MzwTsRk8SYCg==" + }, + "semver": { + "version": "7.6.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.0.tgz", + "integrity": "sha512-EnwXhrlwXMk9gKu5/flx5sv/an57AkRplG3hTK68W7FRDN+k+OWBj65M7719OkA82XLBxrcX0KSHj+X5COhOVg==", + "requires": { + "lru-cache": "^6.0.0" + } + } + } + }, + "@angular-devkit/build-webpack": { + "version": "0.1703.1", + "resolved": "https://registry.npmjs.org/@angular-devkit/build-webpack/-/build-webpack-0.1703.1.tgz", + "integrity": "sha512-nVUzewX8RCzaEPQZ1JQpE42wpsYchKQwfXUSCkoUsuCMB2c6zuEz0Jt94nzJg3UjSEEV4ZqCH8v5MDOvB49Rlw==", + "requires": { + "@angular-devkit/architect": "0.1703.1", + "rxjs": "7.8.1" + } + }, + "@angular-devkit/core": { + "version": "17.3.1", + "resolved": "https://registry.npmjs.org/@angular-devkit/core/-/core-17.3.1.tgz", + "integrity": "sha512-EP7zwqBEaOPuBJwzKmh2abfgNFITGX178BOyTG6zTymeMzEbrvy2OdeQXSslkJ/RGLCpx60GT+0CFW7wGlQR6Q==", + "requires": { + "ajv": "8.12.0", + "ajv-formats": "2.1.1", + "jsonc-parser": "3.2.1", + "picomatch": "4.0.1", + "rxjs": "7.8.1", + "source-map": "0.7.4" + }, + "dependencies": { + "ajv": { + "version": "8.12.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.12.0.tgz", + "integrity": "sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==", + "requires": { + "fast-deep-equal": "^3.1.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2", + "uri-js": "^4.2.2" + } + }, + "json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==" + }, + "picomatch": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-4.0.1.tgz", + "integrity": "sha512-xUXwsxNjwTQ8K3GnT4pCJm+xq3RUPQbmkYJTP5aFIfNIvbcc/4MUxgBaaRSZJ6yGJZiGSyYlM6MzwTsRk8SYCg==" + } + } + }, + "@angular-devkit/schematics": { + "version": "17.3.1", + "resolved": "https://registry.npmjs.org/@angular-devkit/schematics/-/schematics-17.3.1.tgz", + "integrity": "sha512-c3tp5zC5zp6XpK9w8wJf3d4Dyw9BNbmg/VEoXtePGivp4hzks6zuMAFknNRwdK7roOlH0HyM5No4WUZHBFpOmw==", + "requires": { + "@angular-devkit/core": "17.3.1", + "jsonc-parser": "3.2.1", + "magic-string": "0.30.8", + "ora": "5.4.1", + "rxjs": "7.8.1" + } + }, + "@angular/animations": { + "version": "17.3.1", + "resolved": "https://registry.npmjs.org/@angular/animations/-/animations-17.3.1.tgz", + "integrity": "sha512-2TZ0M5J0IizhHpb404DeqArlv8Ki9BFz5ZUuET2uFROpKW8IMDCht8fSrn/DKHpjB9lvzPUhNFaRxNWEY6klnA==", + "requires": { + "tslib": "^2.3.0" + } + }, + "@angular/cli": { + "version": "17.3.1", + "resolved": "https://registry.npmjs.org/@angular/cli/-/cli-17.3.1.tgz", + "integrity": "sha512-IVnnbRi53BZvZ3LE0PCfFefoB2uHlO1sHtilZf/xCpdV4E1Mkz0/hHln5CRHwAXErdSiY57VoMsF5tffxAfaBQ==", + "requires": { + "@angular-devkit/architect": "0.1703.1", + "@angular-devkit/core": "17.3.1", + "@angular-devkit/schematics": "17.3.1", + "@schematics/angular": "17.3.1", + "@yarnpkg/lockfile": "1.1.0", + "ansi-colors": "4.1.3", + "ini": "4.1.2", + "inquirer": "9.2.15", + "jsonc-parser": "3.2.1", + "npm-package-arg": "11.0.1", + "npm-pick-manifest": "9.0.0", + "open": "8.4.2", + "ora": "5.4.1", + "pacote": "17.0.6", + "resolve": "1.22.8", + "semver": "7.6.0", + "symbol-observable": "4.0.0", + "yargs": "17.7.2" + }, + "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "requires": { + "color-convert": "^2.0.1" + } + }, + "cliui": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", + "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", + "requires": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.1", + "wrap-ansi": "^7.0.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + }, + "semver": { + "version": "7.6.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.6.0.tgz", + "integrity": "sha512-EnwXhrlwXMk9gKu5/flx5sv/an57AkRplG3hTK68W7FRDN+k+OWBj65M7719OkA82XLBxrcX0KSHj+X5COhOVg==", + "requires": { + "lru-cache": "^6.0.0" + } + }, + "wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "requires": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + } + }, + "y18n": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==" + }, + "yargs": { + "version": "17.7.2", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", + "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==", + "requires": { + "cliui": "^8.0.1", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.3", + "y18n": "^5.0.5", + "yargs-parser": "^21.1.1" + } + }, + "yargs-parser": { + "version": "21.1.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", + "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==" + } + } + }, + "@angular/common": { + "version": "17.3.1", + "resolved": "https://registry.npmjs.org/@angular/common/-/common-17.3.1.tgz", + "integrity": "sha512-HyUTJ4RxhE3bOmFRV6Fv2y01ixbrUb8Hd4MxPm8REbNMGKsWCfXhR3FfxFL18Sc03SAF+o0Md0wwekjFKTNKfQ==", + "requires": { + "tslib": "^2.3.0" + } + }, + "@angular/compiler": { + "version": "17.3.1", + "resolved": "https://registry.npmjs.org/@angular/compiler/-/compiler-17.3.1.tgz", + "integrity": "sha512-8qqlWPGZEyD2FY5losOW3Aocro+lFysPDzsf0LHgQUM6Ub1b+pq4jUOjH6w0vzaxG3TfxkgzOQ9aNdWtSV67Rg==", + "requires": { + "tslib": "^2.3.0" + } + }, + "@angular/compiler-cli": { + "version": "17.3.1", + "resolved": "https://registry.npmjs.org/@angular/compiler-cli/-/compiler-cli-17.3.1.tgz", + "integrity": "sha512-xLV9KU+zOpe57/2rQ59ku21EaStNpLSlR9+qkDYf8JR09fB+W9vY3UYbpi5RjHxAFIZBM5D9SFQjjll8rch26g==", + "requires": { + "@babel/core": "7.23.9", + "@jridgewell/sourcemap-codec": "^1.4.14", + "chokidar": "^3.0.0", + "convert-source-map": "^1.5.1", + "reflect-metadata": "^0.2.0", + "semver": "^7.0.0", + "tslib": "^2.3.0", + "yargs": "^17.2.1" + }, + "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "requires": { + "color-convert": "^2.0.1" + } + }, + "cliui": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", + "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", + "requires": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^7.0.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + }, + "wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "requires": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + } + }, + "y18n": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==" + }, + "yargs": { + "version": "17.3.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.3.0.tgz", + "integrity": "sha512-GQl1pWyDoGptFPJx9b9L6kmR33TGusZvXIZUT+BOz9f7X2L94oeAskFYLEg/FkhV06zZPBYLvLZRWeYId29lew==", + "requires": { + "cliui": "^7.0.2", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.3", + "y18n": "^5.0.5", + "yargs-parser": "^21.0.0" + } + }, + "yargs-parser": { + "version": "21.0.0", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.0.0.tgz", + "integrity": "sha512-z9kApYUOCwoeZ78rfRYYWdiU/iNL6mwwYlkkZfJoyMR1xps+NEBX5X7XmRpxkZHhXJ6+Ey00IwKxBBSW9FIjyA==" + } + } + }, + "@angular/core": { + "version": "17.3.1", + "resolved": "https://registry.npmjs.org/@angular/core/-/core-17.3.1.tgz", + "integrity": "sha512-Qf3/sgkXS1LHwOTtqAVYprySrn0YpPIZqerPc0tK+hyQfwAz5BQlpcBhbH8RWKlfCY8eO0cqo/j0+e8DQOgYfg==", + "requires": { + "tslib": "^2.3.0" + } + }, + "@angular/forms": { + "version": "17.3.1", + "resolved": "https://registry.npmjs.org/@angular/forms/-/forms-17.3.1.tgz", + "integrity": "sha512-HndsO90k67sFHzd+sII+rhAUksffBvquFuAUCc6QR9WVjILxVg2fY7oBidgS1gKNqu0mptPG0GvuORnaW/0gSg==", + "requires": { + "tslib": "^2.3.0" + } + }, + "@angular/language-service": { + "version": "17.3.1", + "resolved": "https://registry.npmjs.org/@angular/language-service/-/language-service-17.3.1.tgz", + "integrity": "sha512-awC+KHwIRXZ7biQz0Q7q+UZuuyeWHcxjxyQtvv0n1jwwyRpUo8WAXcduKRxl/wMOrxfZkB/tpGcd1/Eeql9CCw==", + "dev": true + }, + "@angular/localize": { + "version": "17.3.1", + "resolved": "https://registry.npmjs.org/@angular/localize/-/localize-17.3.1.tgz", + "integrity": "sha512-ma8PD+DWv68OKgvbmxw7rVohT5HvIYgbmPnVg8lyEz/YkUa9lua0zzrgA+3HUComqv16oVrIaQr00oWxn/9lXQ==", + "requires": { + "@babel/core": "7.23.9", + "@types/babel__core": "7.20.5", + "fast-glob": "3.3.2", + "yargs": "^17.2.1" + }, + "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "requires": { + "color-convert": "^2.0.1" + } + }, + "cliui": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", + "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", + "requires": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^7.0.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + }, + "wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "requires": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + } + }, + "y18n": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==" + }, + "yargs": { + "version": "17.3.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.3.0.tgz", + "integrity": "sha512-GQl1pWyDoGptFPJx9b9L6kmR33TGusZvXIZUT+BOz9f7X2L94oeAskFYLEg/FkhV06zZPBYLvLZRWeYId29lew==", + "requires": { + "cliui": "^7.0.2", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.3", + "y18n": "^5.0.5", + "yargs-parser": "^21.0.0" + } + }, + "yargs-parser": { + "version": "21.0.0", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.0.0.tgz", + "integrity": "sha512-z9kApYUOCwoeZ78rfRYYWdiU/iNL6mwwYlkkZfJoyMR1xps+NEBX5X7XmRpxkZHhXJ6+Ey00IwKxBBSW9FIjyA==" + } + } + }, + "@angular/platform-browser": { + "version": "17.3.1", + "resolved": "https://registry.npmjs.org/@angular/platform-browser/-/platform-browser-17.3.1.tgz", + "integrity": "sha512-8ABAL8PElSGzkIparVwifsU0NSu0DdqnWYw9YvLhhZQ6lOuWbG+dTUo/DXzmWhA6ezQWJGNakEZPJJytFIIy+A==", + "requires": { + "tslib": "^2.3.0" + } + }, + "@angular/platform-browser-dynamic": { + "version": "17.3.1", + "resolved": "https://registry.npmjs.org/@angular/platform-browser-dynamic/-/platform-browser-dynamic-17.3.1.tgz", + "integrity": "sha512-ACW/npNaDxUNQtEomjjv/KIBY8jHEinePff5qosnAxLE0IpA4qE9eDp36zG35xoJqrPJPYjXbZCBRqqrzM7U7Q==", + "requires": { + "tslib": "^2.3.0" + } + }, + "@angular/platform-server": { + "version": "17.3.1", + "resolved": "https://registry.npmjs.org/@angular/platform-server/-/platform-server-17.3.1.tgz", + "integrity": "sha512-yC1WgUquIac8qFCPMLjRio2ViR3XHexlXKlZpFhqpWAFPsWSHjoCHTEW+KTUFZmOPhUEFR2W8fWOChur8mjthw==", + "requires": { + "tslib": "^2.3.0", + "xhr2": "^0.2.0" + } + }, + "@angular/router": { + "version": "17.3.1", + "resolved": "https://registry.npmjs.org/@angular/router/-/router-17.3.1.tgz", + "integrity": "sha512-H6H7lY9i5Ppu0SFwwpeWqJbCFw8cILOj8Rd1+AGoCN5m3ivPtjD2Ltz62PI2zZkqx+WhQdk19l61Wm3oRqg70A==", + "requires": { + "tslib": "^2.3.0" + } + }, + "@angular/ssr": { + "version": "17.3.1", + "resolved": "https://registry.npmjs.org/@angular/ssr/-/ssr-17.3.1.tgz", + "integrity": "sha512-K/2FGTSC3xJOUJEvqRNVhhhoNGMDFMXUKJqnLXe6cNE8xNkOzO52tWTc0ZZr4ZYvFSwtVMuFY4E65HUxbhGTvA==", + "requires": { + "critters": "0.0.22", + "tslib": "^2.3.0" + } + }, + "@babel/code-frame": { + "version": "7.24.2", + "resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.24.2.tgz", + "integrity": "sha512-y5+tLQyV8pg3fsiln67BVLD1P13Eg4lh5RW9mF0zUuvLrv9uIQ4MCL+CRT+FTsBlBjcIan6PGsLcBN0m3ClUyQ==", + "requires": { + "@babel/highlight": "^7.24.2", + "picocolors": "^1.0.0" + } + }, + "@babel/compat-data": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/compat-data/-/compat-data-7.24.1.tgz", + "integrity": "sha512-Pc65opHDliVpRHuKfzI+gSA4zcgr65O4cl64fFJIWEEh8JoHIHh0Oez1Eo8Arz8zq/JhgKodQaxEwUPRtZylVA==" + }, + "@babel/core": { + "version": "7.23.9", + "resolved": "https://registry.npmjs.org/@babel/core/-/core-7.23.9.tgz", + "integrity": "sha512-5q0175NOjddqpvvzU+kDiSOAk4PfdO6FvwCWoQ6RO7rTzEe8vlo+4HVfcnAREhD4npMs0e9uZypjTwzZPCf/cw==", + "requires": { + "@ampproject/remapping": "^2.2.0", + "@babel/code-frame": "^7.23.5", + "@babel/generator": "^7.23.6", + "@babel/helper-compilation-targets": "^7.23.6", + "@babel/helper-module-transforms": "^7.23.3", + "@babel/helpers": "^7.23.9", + "@babel/parser": "^7.23.9", + "@babel/template": "^7.23.9", + "@babel/traverse": "^7.23.9", + "@babel/types": "^7.23.9", + "convert-source-map": "^2.0.0", + "debug": "^4.1.0", + "gensync": "^1.0.0-beta.2", + "json5": "^2.2.3", + "semver": "^6.3.1" + }, + "dependencies": { + "convert-source-map": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz", + "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==" + }, + "semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==" + } + } + }, + "@babel/generator": { + "version": "7.23.6", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.23.6.tgz", + "integrity": "sha512-qrSfCYxYQB5owCmGLbl8XRpX1ytXlpueOb0N0UmQwA073KZxejgQTzAmJezxvpwQD9uGtK2shHdi55QT+MbjIw==", + "requires": { + "@babel/types": "^7.23.6", + "@jridgewell/gen-mapping": "^0.3.2", + "@jridgewell/trace-mapping": "^0.3.17", + "jsesc": "^2.5.1" + }, + "dependencies": { + "@jridgewell/sourcemap-codec": { + "version": "1.4.14", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.14.tgz", + "integrity": "sha512-XPSJHWmi394fuUuzDnGz1wiKqWfo1yXecHQMRf2l6hztTO+nPru658AyDngaBe7isIxEkRsPR3FZh+s7iVa4Uw==" + }, + "@jridgewell/trace-mapping": { + "version": "0.3.18", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.18.tgz", + "integrity": "sha512-w+niJYzMHdd7USdiH2U6869nqhD2nbfZXND5Yp93qIbEmnDNk7PD48o+YchRVpzMU7M6jVCbenTR7PA1FLQ9pA==", + "requires": { + "@jridgewell/resolve-uri": "3.1.0", + "@jridgewell/sourcemap-codec": "1.4.14" + } + } + } + }, + "@babel/helper-annotate-as-pure": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-annotate-as-pure/-/helper-annotate-as-pure-7.22.5.tgz", + "integrity": "sha512-LvBTxu8bQSQkcyKOU+a1btnNFQ1dMAd0R6PyW3arXes06F6QLWLIrd681bxRPIXlrMGR3XYnW9JyML7dP3qgxg==", + "requires": { + "@babel/types": "^7.22.5" + } + }, + "@babel/helper-builder-binary-assignment-operator-visitor": { + "version": "7.22.15", + "resolved": "https://registry.npmjs.org/@babel/helper-builder-binary-assignment-operator-visitor/-/helper-builder-binary-assignment-operator-visitor-7.22.15.tgz", + "integrity": "sha512-QkBXwGgaoC2GtGZRoma6kv7Szfv06khvhFav67ZExau2RaXzy8MpHSMO2PNoP2XtmQphJQRHFfg77Bq731Yizw==", + "requires": { + "@babel/types": "^7.22.15" + } + }, + "@babel/helper-compilation-targets": { + "version": "7.23.6", + "resolved": "https://registry.npmjs.org/@babel/helper-compilation-targets/-/helper-compilation-targets-7.23.6.tgz", + "integrity": "sha512-9JB548GZoQVmzrFgp8o7KxdgkTGm6xs9DW0o/Pim72UDjzr5ObUQ6ZzYPqA+g9OTS2bBQoctLJrky0RDCAWRgQ==", + "requires": { + "@babel/compat-data": "^7.23.5", + "@babel/helper-validator-option": "^7.23.5", + "browserslist": "^4.22.2", + "lru-cache": "^5.1.1", + "semver": "^6.3.1" + }, + "dependencies": { + "lru-cache": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", + "requires": { + "yallist": "^3.0.2" + } + }, + "semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==" + }, + "yallist": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==" + } + } + }, + "@babel/helper-create-class-features-plugin": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/helper-create-class-features-plugin/-/helper-create-class-features-plugin-7.24.1.tgz", + "integrity": "sha512-1yJa9dX9g//V6fDebXoEfEsxkZHk3Hcbm+zLhyu6qVgYFLvmTALTeV+jNU9e5RnYtioBrGEOdoI2joMSNQ/+aA==", + "requires": { + "@babel/helper-annotate-as-pure": "^7.22.5", + "@babel/helper-environment-visitor": "^7.22.20", + "@babel/helper-function-name": "^7.23.0", + "@babel/helper-member-expression-to-functions": "^7.23.0", + "@babel/helper-optimise-call-expression": "^7.22.5", + "@babel/helper-replace-supers": "^7.24.1", + "@babel/helper-skip-transparent-expression-wrappers": "^7.22.5", + "@babel/helper-split-export-declaration": "^7.22.6", + "semver": "^6.3.1" + }, + "dependencies": { + "semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==" + } + } + }, + "@babel/helper-create-regexp-features-plugin": { + "version": "7.22.15", + "resolved": "https://registry.npmjs.org/@babel/helper-create-regexp-features-plugin/-/helper-create-regexp-features-plugin-7.22.15.tgz", + "integrity": "sha512-29FkPLFjn4TPEa3RE7GpW+qbE8tlsu3jntNYNfcGsc49LphF1PQIiD+vMZ1z1xVOKt+93khA9tc2JBs3kBjA7w==", + "requires": { + "@babel/helper-annotate-as-pure": "^7.22.5", + "regexpu-core": "^5.3.1", + "semver": "^6.3.1" + }, + "dependencies": { + "semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==" + } + } + }, + "@babel/helper-define-polyfill-provider": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.6.1.tgz", + "integrity": "sha512-o7SDgTJuvx5vLKD6SFvkydkSMBvahDKGiNJzG22IZYXhiqoe9efY7zocICBgzHV4IRg5wdgl2nEL/tulKIEIbA==", + "requires": { + "@babel/helper-compilation-targets": "^7.22.6", + "@babel/helper-plugin-utils": "^7.22.5", + "debug": "^4.1.1", + "lodash.debounce": "^4.0.8", + "resolve": "^1.14.2" + } + }, + "@babel/helper-environment-visitor": { + "version": "7.22.20", + "resolved": "https://registry.npmjs.org/@babel/helper-environment-visitor/-/helper-environment-visitor-7.22.20.tgz", + "integrity": "sha512-zfedSIzFhat/gFhWfHtgWvlec0nqB9YEIVrpuwjruLlXfUSnA8cJB0miHKwqDnQ7d32aKo2xt88/xZptwxbfhA==" + }, + "@babel/helper-function-name": { + "version": "7.23.0", + "resolved": "https://registry.npmjs.org/@babel/helper-function-name/-/helper-function-name-7.23.0.tgz", + "integrity": "sha512-OErEqsrxjZTJciZ4Oo+eoZqeW9UIiOcuYKRJA4ZAgV9myA+pOXhhmpfNCKjEH/auVfEYVFJ6y1Tc4r0eIApqiw==", + "requires": { + "@babel/template": "^7.22.15", + "@babel/types": "^7.23.0" + } + }, + "@babel/helper-hoist-variables": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-hoist-variables/-/helper-hoist-variables-7.22.5.tgz", + "integrity": "sha512-wGjk9QZVzvknA6yKIUURb8zY3grXCcOZt+/7Wcy8O2uctxhplmUPkOdlgoNhmdVee2c92JXbf1xpMtVNbfoxRw==", + "requires": { + "@babel/types": "^7.22.5" + } + }, + "@babel/helper-member-expression-to-functions": { + "version": "7.23.0", + "resolved": "https://registry.npmjs.org/@babel/helper-member-expression-to-functions/-/helper-member-expression-to-functions-7.23.0.tgz", + "integrity": "sha512-6gfrPwh7OuT6gZyJZvd6WbTfrqAo7vm4xCzAXOusKqq/vWdKXphTpj5klHKNmRUU6/QRGlBsyU9mAIPaWHlqJA==", + "requires": { + "@babel/types": "^7.23.0" + } + }, + "@babel/helper-module-imports": { + "version": "7.24.3", + "resolved": "https://registry.npmjs.org/@babel/helper-module-imports/-/helper-module-imports-7.24.3.tgz", + "integrity": "sha512-viKb0F9f2s0BCS22QSF308z/+1YWKV/76mwt61NBzS5izMzDPwdq1pTrzf+Li3npBWX9KdQbkeCt1jSAM7lZqg==", + "requires": { + "@babel/types": "^7.24.0" + } + }, + "@babel/helper-module-transforms": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/helper-module-transforms/-/helper-module-transforms-7.23.3.tgz", + "integrity": "sha512-7bBs4ED9OmswdfDzpz4MpWgSrV7FXlc3zIagvLFjS5H+Mk7Snr21vQ6QwrsoCGMfNC4e4LQPdoULEt4ykz0SRQ==", + "requires": { + "@babel/helper-environment-visitor": "^7.22.20", + "@babel/helper-module-imports": "^7.22.15", + "@babel/helper-simple-access": "^7.22.5", + "@babel/helper-split-export-declaration": "^7.22.6", + "@babel/helper-validator-identifier": "^7.22.20" + } + }, + "@babel/helper-optimise-call-expression": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-optimise-call-expression/-/helper-optimise-call-expression-7.22.5.tgz", + "integrity": "sha512-HBwaojN0xFRx4yIvpwGqxiV2tUfl7401jlok564NgB9EHS1y6QT17FmKWm4ztqjeVdXLuC4fSvHc5ePpQjoTbw==", + "requires": { + "@babel/types": "^7.22.5" + } + }, + "@babel/helper-plugin-utils": { + "version": "7.24.0", + "resolved": "https://registry.npmjs.org/@babel/helper-plugin-utils/-/helper-plugin-utils-7.24.0.tgz", + "integrity": "sha512-9cUznXMG0+FxRuJfvL82QlTqIzhVW9sL0KjMPHhAOOvpQGL8QtdxnBKILjBqxlHyliz0yCa1G903ZXI/FuHy2w==" + }, + "@babel/helper-remap-async-to-generator": { + "version": "7.22.20", + "resolved": "https://registry.npmjs.org/@babel/helper-remap-async-to-generator/-/helper-remap-async-to-generator-7.22.20.tgz", + "integrity": "sha512-pBGyV4uBqOns+0UvhsTO8qgl8hO89PmiDYv+/COyp1aeMcmfrfruz+/nCMFiYyFF/Knn0yfrC85ZzNFjembFTw==", + "requires": { + "@babel/helper-annotate-as-pure": "^7.22.5", + "@babel/helper-environment-visitor": "^7.22.20", + "@babel/helper-wrap-function": "^7.22.20" + } + }, + "@babel/helper-replace-supers": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/helper-replace-supers/-/helper-replace-supers-7.24.1.tgz", + "integrity": "sha512-QCR1UqC9BzG5vZl8BMicmZ28RuUBnHhAMddD8yHFHDRH9lLTZ9uUPehX8ctVPT8l0TKblJidqcgUUKGVrePleQ==", + "requires": { + "@babel/helper-environment-visitor": "^7.22.20", + "@babel/helper-member-expression-to-functions": "^7.23.0", + "@babel/helper-optimise-call-expression": "^7.22.5" + } + }, + "@babel/helper-simple-access": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-simple-access/-/helper-simple-access-7.22.5.tgz", + "integrity": "sha512-n0H99E/K+Bika3++WNL17POvo4rKWZ7lZEp1Q+fStVbUi8nxPQEBOlTmCOxW/0JsS56SKKQ+ojAe2pHKJHN35w==", + "requires": { + "@babel/types": "^7.22.5" + } + }, + "@babel/helper-skip-transparent-expression-wrappers": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/helper-skip-transparent-expression-wrappers/-/helper-skip-transparent-expression-wrappers-7.22.5.tgz", + "integrity": "sha512-tK14r66JZKiC43p8Ki33yLBVJKlQDFoA8GYN67lWCDCqoL6EMMSuM9b+Iff2jHaM/RRFYl7K+iiru7hbRqNx8Q==", + "requires": { + "@babel/types": "^7.22.5" + } + }, + "@babel/helper-split-export-declaration": { + "version": "7.22.6", + "resolved": "https://registry.npmjs.org/@babel/helper-split-export-declaration/-/helper-split-export-declaration-7.22.6.tgz", + "integrity": "sha512-AsUnxuLhRYsisFiaJwvp1QF+I3KjD5FOxut14q/GzovUe6orHLesW2C7d754kRm53h5gqrz6sFl6sxc4BVtE/g==", + "requires": { + "@babel/types": "^7.22.5" + } + }, + "@babel/helper-string-parser": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/helper-string-parser/-/helper-string-parser-7.24.1.tgz", + "integrity": "sha512-2ofRCjnnA9y+wk8b9IAREroeUP02KHp431N2mhKniy2yKIDKpbrHv9eXwm8cBeWQYcJmzv5qKCu65P47eCF7CQ==" + }, + "@babel/helper-validator-identifier": { + "version": "7.22.20", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-identifier/-/helper-validator-identifier-7.22.20.tgz", + "integrity": "sha512-Y4OZ+ytlatR8AI+8KZfKuL5urKp7qey08ha31L8b3BwewJAoJamTzyvxPR/5D+KkdJCGPq/+8TukHBlY10FX9A==" + }, + "@babel/helper-validator-option": { + "version": "7.23.5", + "resolved": "https://registry.npmjs.org/@babel/helper-validator-option/-/helper-validator-option-7.23.5.tgz", + "integrity": "sha512-85ttAOMLsr53VgXkTbkx8oA6YTfT4q7/HzXSLEYmjcSTJPMPQtvq1BD79Byep5xMUYbGRzEpDsjUf3dyp54IKw==" + }, + "@babel/helper-wrap-function": { + "version": "7.22.20", + "resolved": "https://registry.npmjs.org/@babel/helper-wrap-function/-/helper-wrap-function-7.22.20.tgz", + "integrity": "sha512-pms/UwkOpnQe/PDAEdV/d7dVCoBbB+R4FvYoHGZz+4VPcg7RtYy2KP7S2lbuWM6FCSgob5wshfGESbC/hzNXZw==", + "requires": { + "@babel/helper-function-name": "^7.22.5", + "@babel/template": "^7.22.15", + "@babel/types": "^7.22.19" + } + }, + "@babel/helpers": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/helpers/-/helpers-7.24.1.tgz", + "integrity": "sha512-BpU09QqEe6ZCHuIHFphEFgvNSrubve1FtyMton26ekZ85gRGi6LrTF7zArARp2YvyFxloeiRmtSCq5sjh1WqIg==", + "requires": { + "@babel/template": "^7.24.0", + "@babel/traverse": "^7.24.1", + "@babel/types": "^7.24.0" + } + }, + "@babel/highlight": { + "version": "7.24.2", + "resolved": "https://registry.npmjs.org/@babel/highlight/-/highlight-7.24.2.tgz", + "integrity": "sha512-Yac1ao4flkTxTteCDZLEvdxg2fZfz1v8M4QpaGypq/WPDqg3ijHYbDfs+LG5hvzSoqaSZ9/Z9lKSP3CjZjv+pA==", + "requires": { + "@babel/helper-validator-identifier": "^7.22.20", + "chalk": "^2.4.2", + "js-tokens": "^4.0.0", + "picocolors": "^1.0.0" + } + }, + "@babel/parser": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/parser/-/parser-7.24.1.tgz", + "integrity": "sha512-Zo9c7N3xdOIQrNip7Lc9wvRPzlRtovHVE4lkz8WEDr7uYh/GMQhSiIgFxGIArRHYdJE5kxtZjAf8rT0xhdLCzg==" + }, + "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression/-/plugin-bugfix-safari-id-destructuring-collision-in-function-expression-7.24.1.tgz", + "integrity": "sha512-y4HqEnkelJIOQGd+3g1bTeKsA5c6qM7eOn7VggGVbBc0y8MLSKHacwcIE2PplNlQSj0PqS9rrXL/nkPVK+kUNg==", + "requires": { + "@babel/helper-plugin-utils": "^7.24.0" + } + }, + "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining/-/plugin-bugfix-v8-spread-parameters-in-optional-chaining-7.24.1.tgz", + "integrity": "sha512-Hj791Ii4ci8HqnaKHAlLNs+zaLXb0EzSDhiAWp5VNlyvCNymYfacs64pxTxbH1znW/NcArSmwpmG9IKE/TUVVQ==", + "requires": { + "@babel/helper-plugin-utils": "^7.24.0", + "@babel/helper-skip-transparent-expression-wrappers": "^7.22.5", + "@babel/plugin-transform-optional-chaining": "^7.24.1" + } + }, + "@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly/-/plugin-bugfix-v8-static-class-fields-redefine-readonly-7.24.1.tgz", + "integrity": "sha512-m9m/fXsXLiHfwdgydIFnpk+7jlVbnvlK5B2EKiPdLUb6WX654ZaaEWJUjk8TftRbZpK0XibovlLWX4KIZhV6jw==", + "requires": { + "@babel/helper-environment-visitor": "^7.22.20", + "@babel/helper-plugin-utils": "^7.24.0" + } + }, + "@babel/plugin-proposal-private-property-in-object": { + "version": "7.21.0-placeholder-for-preset-env.2", + "resolved": "https://registry.npmjs.org/@babel/plugin-proposal-private-property-in-object/-/plugin-proposal-private-property-in-object-7.21.0-placeholder-for-preset-env.2.tgz", + "integrity": "sha512-SOSkfJDddaM7mak6cPEpswyTRnuRltl429hMraQEglW+OkovnCzsiszTmsrlY//qLFjCpQDFRvjdm2wA5pPm9w==", + "requires": {} + }, + "@babel/plugin-syntax-async-generators": { + "version": "7.8.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-async-generators/-/plugin-syntax-async-generators-7.8.4.tgz", + "integrity": "sha512-tycmZxkGfZaxhMRbXlPXuVFpdWlXpir2W4AMhSJgRKzk/eDlIXOhb2LHWoLpDF7TEHylV5zNhykX6KAgHJmTNw==", + "requires": { + "@babel/helper-plugin-utils": "^7.8.0" + } + }, + "@babel/plugin-syntax-class-properties": { + "version": "7.12.13", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-properties/-/plugin-syntax-class-properties-7.12.13.tgz", + "integrity": "sha512-fm4idjKla0YahUNgFNLCB0qySdsoPiZP3iQE3rky0mBUtMZ23yDJ9SJdg6dXTSDnulOVqiF3Hgr9nbXvXTQZYA==", + "requires": { + "@babel/helper-plugin-utils": "^7.12.13" + } + }, + "@babel/plugin-syntax-class-static-block": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-class-static-block/-/plugin-syntax-class-static-block-7.14.5.tgz", + "integrity": "sha512-b+YyPmr6ldyNnM6sqYeMWE+bgJcJpO6yS4QD7ymxgH34GBPNDM/THBh8iunyvKIZztiwLH4CJZ0RxTk9emgpjw==", + "requires": { + "@babel/helper-plugin-utils": "^7.14.5" + } + }, + "@babel/plugin-syntax-dynamic-import": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-dynamic-import/-/plugin-syntax-dynamic-import-7.8.3.tgz", + "integrity": "sha512-5gdGbFon+PszYzqs83S3E5mpi7/y/8M9eC90MRTZfduQOYW76ig6SOSPNe41IG5LoP3FGBn2N0RjVDSQiS94kQ==", + "requires": { + "@babel/helper-plugin-utils": "^7.8.0" + } + }, + "@babel/plugin-syntax-export-namespace-from": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-export-namespace-from/-/plugin-syntax-export-namespace-from-7.8.3.tgz", + "integrity": "sha512-MXf5laXo6c1IbEbegDmzGPwGNTsHZmEy6QGznu5Sh2UCWvueywb2ee+CCE4zQiZstxU9BMoQO9i6zUFSY0Kj0Q==", + "requires": { + "@babel/helper-plugin-utils": "^7.8.3" + } + }, + "@babel/plugin-syntax-import-assertions": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-assertions/-/plugin-syntax-import-assertions-7.24.1.tgz", + "integrity": "sha512-IuwnI5XnuF189t91XbxmXeCDz3qs6iDRO7GJ++wcfgeXNs/8FmIlKcpDSXNVyuLQxlwvskmI3Ct73wUODkJBlQ==", + "requires": { + "@babel/helper-plugin-utils": "^7.24.0" + } + }, + "@babel/plugin-syntax-import-attributes": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-attributes/-/plugin-syntax-import-attributes-7.24.1.tgz", + "integrity": "sha512-zhQTMH0X2nVLnb04tz+s7AMuasX8U0FnpE+nHTOhSOINjWMnopoZTxtIKsd45n4GQ/HIZLyfIpoul8e2m0DnRA==", + "requires": { + "@babel/helper-plugin-utils": "^7.24.0" + } + }, + "@babel/plugin-syntax-import-meta": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-import-meta/-/plugin-syntax-import-meta-7.10.4.tgz", + "integrity": "sha512-Yqfm+XDx0+Prh3VSeEQCPU81yC+JWZ2pDPFSS4ZdpfZhp4MkFMaDC1UqseovEKwSUpnIL7+vK+Clp7bfh0iD7g==", + "requires": { + "@babel/helper-plugin-utils": "^7.10.4" + } + }, + "@babel/plugin-syntax-json-strings": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-json-strings/-/plugin-syntax-json-strings-7.8.3.tgz", + "integrity": "sha512-lY6kdGpWHvjoe2vk4WrAapEuBR69EMxZl+RoGRhrFGNYVK8mOPAW8VfbT/ZgrFbXlDNiiaxQnAtgVCZ6jv30EA==", + "requires": { + "@babel/helper-plugin-utils": "^7.8.0" + } + }, + "@babel/plugin-syntax-logical-assignment-operators": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-logical-assignment-operators/-/plugin-syntax-logical-assignment-operators-7.10.4.tgz", + "integrity": "sha512-d8waShlpFDinQ5MtvGU9xDAOzKH47+FFoney2baFIoMr952hKOLp1HR7VszoZvOsV/4+RRszNY7D17ba0te0ig==", + "requires": { + "@babel/helper-plugin-utils": "^7.10.4" + } + }, + "@babel/plugin-syntax-nullish-coalescing-operator": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-nullish-coalescing-operator/-/plugin-syntax-nullish-coalescing-operator-7.8.3.tgz", + "integrity": "sha512-aSff4zPII1u2QD7y+F8oDsz19ew4IGEJg9SVW+bqwpwtfFleiQDMdzA/R+UlWDzfnHFCxxleFT0PMIrR36XLNQ==", + "requires": { + "@babel/helper-plugin-utils": "^7.8.0" + } + }, + "@babel/plugin-syntax-numeric-separator": { + "version": "7.10.4", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-numeric-separator/-/plugin-syntax-numeric-separator-7.10.4.tgz", + "integrity": "sha512-9H6YdfkcK/uOnY/K7/aA2xpzaAgkQn37yzWUMRK7OaPOqOpGS1+n0H5hxT9AUw9EsSjPW8SVyMJwYRtWs3X3ug==", + "requires": { + "@babel/helper-plugin-utils": "^7.10.4" + } + }, + "@babel/plugin-syntax-object-rest-spread": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-object-rest-spread/-/plugin-syntax-object-rest-spread-7.8.3.tgz", + "integrity": "sha512-XoqMijGZb9y3y2XskN+P1wUGiVwWZ5JmoDRwx5+3GmEplNyVM2s2Dg8ILFQm8rWM48orGy5YpI5Bl8U1y7ydlA==", + "requires": { + "@babel/helper-plugin-utils": "^7.8.0" + } + }, + "@babel/plugin-syntax-optional-catch-binding": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-catch-binding/-/plugin-syntax-optional-catch-binding-7.8.3.tgz", + "integrity": "sha512-6VPD0Pc1lpTqw0aKoeRTMiB+kWhAoT24PA+ksWSBrFtl5SIRVpZlwN3NNPQjehA2E/91FV3RjLWoVTglWcSV3Q==", + "requires": { + "@babel/helper-plugin-utils": "^7.8.0" + } + }, + "@babel/plugin-syntax-optional-chaining": { + "version": "7.8.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-optional-chaining/-/plugin-syntax-optional-chaining-7.8.3.tgz", + "integrity": "sha512-KoK9ErH1MBlCPxV0VANkXW2/dw4vlbGDrFgz8bmUsBGYkFRcbRwMh6cIJubdPrkxRwuGdtCk0v/wPTKbQgBjkg==", + "requires": { + "@babel/helper-plugin-utils": "^7.8.0" + } + }, + "@babel/plugin-syntax-private-property-in-object": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-private-property-in-object/-/plugin-syntax-private-property-in-object-7.14.5.tgz", + "integrity": "sha512-0wVnp9dxJ72ZUJDV27ZfbSj6iHLoytYZmh3rFcxNnvsJF3ktkzLDZPy/mA17HGsaQT3/DQsWYX1f1QGWkCoVUg==", + "requires": { + "@babel/helper-plugin-utils": "^7.14.5" + } + }, + "@babel/plugin-syntax-top-level-await": { + "version": "7.14.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-top-level-await/-/plugin-syntax-top-level-await-7.14.5.tgz", + "integrity": "sha512-hx++upLv5U1rgYfwe1xBQUhRmU41NEvpUvrp8jkrSCdvGSnM5/qdRMtylJ6PG5OFkBaHkbTAKTnd3/YyESRHFw==", + "requires": { + "@babel/helper-plugin-utils": "^7.14.5" + } + }, + "@babel/plugin-syntax-unicode-sets-regex": { + "version": "7.18.6", + "resolved": "https://registry.npmjs.org/@babel/plugin-syntax-unicode-sets-regex/-/plugin-syntax-unicode-sets-regex-7.18.6.tgz", + "integrity": "sha512-727YkEAPwSIQTv5im8QHz3upqp92JTWhidIC81Tdx4VJYIte/VndKf1qKrfnnhPLiPghStWfvC/iFaMCQu7Nqg==", + "requires": { + "@babel/helper-create-regexp-features-plugin": "^7.18.6", + "@babel/helper-plugin-utils": "^7.18.6" + } + }, + "@babel/plugin-transform-arrow-functions": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-arrow-functions/-/plugin-transform-arrow-functions-7.24.1.tgz", + "integrity": "sha512-ngT/3NkRhsaep9ck9uj2Xhv9+xB1zShY3tM3g6om4xxCELwCDN4g4Aq5dRn48+0hasAql7s2hdBOysCfNpr4fw==", + "requires": { + "@babel/helper-plugin-utils": "^7.24.0" + } + }, + "@babel/plugin-transform-async-generator-functions": { + "version": "7.23.9", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-generator-functions/-/plugin-transform-async-generator-functions-7.23.9.tgz", + "integrity": "sha512-8Q3veQEDGe14dTYuwagbRtwxQDnytyg1JFu4/HwEMETeofocrB0U0ejBJIXoeG/t2oXZ8kzCyI0ZZfbT80VFNQ==", + "requires": { + "@babel/helper-environment-visitor": "^7.22.20", + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/helper-remap-async-to-generator": "^7.22.20", + "@babel/plugin-syntax-async-generators": "^7.8.4" + } + }, + "@babel/plugin-transform-async-to-generator": { + "version": "7.23.3", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-async-to-generator/-/plugin-transform-async-to-generator-7.23.3.tgz", + "integrity": "sha512-A7LFsKi4U4fomjqXJlZg/u0ft/n8/7n7lpffUP/ZULx/DtV9SGlNKZolHH6PE8Xl1ngCc0M11OaeZptXVkfKSw==", + "requires": { + "@babel/helper-module-imports": "^7.22.15", + "@babel/helper-plugin-utils": "^7.22.5", + "@babel/helper-remap-async-to-generator": "^7.22.20" + } + }, + "@babel/plugin-transform-block-scoped-functions": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoped-functions/-/plugin-transform-block-scoped-functions-7.24.1.tgz", + "integrity": "sha512-TWWC18OShZutrv9C6mye1xwtam+uNi2bnTOCBUd5sZxyHOiWbU6ztSROofIMrK84uweEZC219POICK/sTYwfgg==", + "requires": { + "@babel/helper-plugin-utils": "^7.24.0" + } + }, + "@babel/plugin-transform-block-scoping": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-block-scoping/-/plugin-transform-block-scoping-7.24.1.tgz", + "integrity": "sha512-h71T2QQvDgM2SmT29UYU6ozjMlAt7s7CSs5Hvy8f8cf/GM/Z4a2zMfN+fjVGaieeCrXR3EdQl6C4gQG+OgmbKw==", + "requires": { + "@babel/helper-plugin-utils": "^7.24.0" + } + }, + "@babel/plugin-transform-class-properties": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-class-properties/-/plugin-transform-class-properties-7.24.1.tgz", + "integrity": "sha512-OMLCXi0NqvJfORTaPQBwqLXHhb93wkBKZ4aNwMl6WtehO7ar+cmp+89iPEQPqxAnxsOKTaMcs3POz3rKayJ72g==", + "requires": { + "@babel/helper-create-class-features-plugin": "^7.24.1", + "@babel/helper-plugin-utils": "^7.24.0" + } + }, + "@babel/plugin-transform-class-static-block": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-class-static-block/-/plugin-transform-class-static-block-7.24.1.tgz", + "integrity": "sha512-FUHlKCn6J3ERiu8Dv+4eoz7w8+kFLSyeVG4vDAikwADGjUCoHw/JHokyGtr8OR4UjpwPVivyF+h8Q5iv/JmrtA==", + "requires": { + "@babel/helper-create-class-features-plugin": "^7.24.1", + "@babel/helper-plugin-utils": "^7.24.0", + "@babel/plugin-syntax-class-static-block": "^7.14.5" + } + }, + "@babel/plugin-transform-classes": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-classes/-/plugin-transform-classes-7.24.1.tgz", + "integrity": "sha512-ZTIe3W7UejJd3/3R4p7ScyyOoafetUShSf4kCqV0O7F/RiHxVj/wRaRnQlrGwflvcehNA8M42HkAiEDYZu2F1Q==", + "requires": { + "@babel/helper-annotate-as-pure": "^7.22.5", + "@babel/helper-compilation-targets": "^7.23.6", + "@babel/helper-environment-visitor": "^7.22.20", + "@babel/helper-function-name": "^7.23.0", + "@babel/helper-plugin-utils": "^7.24.0", + "@babel/helper-replace-supers": "^7.24.1", + "@babel/helper-split-export-declaration": "^7.22.6", + "globals": "^11.1.0" + } + }, + "@babel/plugin-transform-computed-properties": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-computed-properties/-/plugin-transform-computed-properties-7.24.1.tgz", + "integrity": "sha512-5pJGVIUfJpOS+pAqBQd+QMaTD2vCL/HcePooON6pDpHgRp4gNRmzyHTPIkXntwKsq3ayUFVfJaIKPw2pOkOcTw==", + "requires": { + "@babel/helper-plugin-utils": "^7.24.0", + "@babel/template": "^7.24.0" + } + }, + "@babel/plugin-transform-destructuring": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-destructuring/-/plugin-transform-destructuring-7.24.1.tgz", + "integrity": "sha512-ow8jciWqNxR3RYbSNVuF4U2Jx130nwnBnhRw6N6h1bOejNkABmcI5X5oz29K4alWX7vf1C+o6gtKXikzRKkVdw==", + "requires": { + "@babel/helper-plugin-utils": "^7.24.0" + } + }, + "@babel/plugin-transform-dotall-regex": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dotall-regex/-/plugin-transform-dotall-regex-7.24.1.tgz", + "integrity": "sha512-p7uUxgSoZwZ2lPNMzUkqCts3xlp8n+o05ikjy7gbtFJSt9gdU88jAmtfmOxHM14noQXBxfgzf2yRWECiNVhTCw==", + "requires": { + "@babel/helper-create-regexp-features-plugin": "^7.22.15", + "@babel/helper-plugin-utils": "^7.24.0" + } + }, + "@babel/plugin-transform-duplicate-keys": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-duplicate-keys/-/plugin-transform-duplicate-keys-7.24.1.tgz", + "integrity": "sha512-msyzuUnvsjsaSaocV6L7ErfNsa5nDWL1XKNnDePLgmz+WdU4w/J8+AxBMrWfi9m4IxfL5sZQKUPQKDQeeAT6lA==", + "requires": { + "@babel/helper-plugin-utils": "^7.24.0" + } + }, + "@babel/plugin-transform-dynamic-import": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-dynamic-import/-/plugin-transform-dynamic-import-7.24.1.tgz", + "integrity": "sha512-av2gdSTyXcJVdI+8aFZsCAtR29xJt0S5tas+Ef8NvBNmD1a+N/3ecMLeMBgfcK+xzsjdLDT6oHt+DFPyeqUbDA==", + "requires": { + "@babel/helper-plugin-utils": "^7.24.0", + "@babel/plugin-syntax-dynamic-import": "^7.8.3" + } + }, + "@babel/plugin-transform-exponentiation-operator": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-exponentiation-operator/-/plugin-transform-exponentiation-operator-7.24.1.tgz", + "integrity": "sha512-U1yX13dVBSwS23DEAqU+Z/PkwE9/m7QQy8Y9/+Tdb8UWYaGNDYwTLi19wqIAiROr8sXVum9A/rtiH5H0boUcTw==", + "requires": { + "@babel/helper-builder-binary-assignment-operator-visitor": "^7.22.15", + "@babel/helper-plugin-utils": "^7.24.0" + } + }, + "@babel/plugin-transform-export-namespace-from": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-export-namespace-from/-/plugin-transform-export-namespace-from-7.24.1.tgz", + "integrity": "sha512-Ft38m/KFOyzKw2UaJFkWG9QnHPG/Q/2SkOrRk4pNBPg5IPZ+dOxcmkK5IyuBcxiNPyyYowPGUReyBvrvZs7IlQ==", + "requires": { + "@babel/helper-plugin-utils": "^7.24.0", + "@babel/plugin-syntax-export-namespace-from": "^7.8.3" + } + }, + "@babel/plugin-transform-for-of": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-for-of/-/plugin-transform-for-of-7.24.1.tgz", + "integrity": "sha512-OxBdcnF04bpdQdR3i4giHZNZQn7cm8RQKcSwA17wAAqEELo1ZOwp5FFgeptWUQXFyT9kwHo10aqqauYkRZPCAg==", + "requires": { + "@babel/helper-plugin-utils": "^7.24.0", + "@babel/helper-skip-transparent-expression-wrappers": "^7.22.5" + } + }, + "@babel/plugin-transform-function-name": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-function-name/-/plugin-transform-function-name-7.24.1.tgz", + "integrity": "sha512-BXmDZpPlh7jwicKArQASrj8n22/w6iymRnvHYYd2zO30DbE277JO20/7yXJT3QxDPtiQiOxQBbZH4TpivNXIxA==", + "requires": { + "@babel/helper-compilation-targets": "^7.23.6", + "@babel/helper-function-name": "^7.23.0", + "@babel/helper-plugin-utils": "^7.24.0" + } + }, + "@babel/plugin-transform-json-strings": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-json-strings/-/plugin-transform-json-strings-7.24.1.tgz", + "integrity": "sha512-U7RMFmRvoasscrIFy5xA4gIp8iWnWubnKkKuUGJjsuOH7GfbMkB+XZzeslx2kLdEGdOJDamEmCqOks6e8nv8DQ==", + "requires": { + "@babel/helper-plugin-utils": "^7.24.0", + "@babel/plugin-syntax-json-strings": "^7.8.3" + } + }, + "@babel/plugin-transform-literals": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-literals/-/plugin-transform-literals-7.24.1.tgz", + "integrity": "sha512-zn9pwz8U7nCqOYIiBaOxoQOtYmMODXTJnkxG4AtX8fPmnCRYWBOHD0qcpwS9e2VDSp1zNJYpdnFMIKb8jmwu6g==", + "requires": { + "@babel/helper-plugin-utils": "^7.24.0" + } + }, + "@babel/plugin-transform-logical-assignment-operators": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-logical-assignment-operators/-/plugin-transform-logical-assignment-operators-7.24.1.tgz", + "integrity": "sha512-OhN6J4Bpz+hIBqItTeWJujDOfNP+unqv/NJgyhlpSqgBTPm37KkMmZV6SYcOj+pnDbdcl1qRGV/ZiIjX9Iy34w==", + "requires": { + "@babel/helper-plugin-utils": "^7.24.0", + "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4" + } + }, + "@babel/plugin-transform-member-expression-literals": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-member-expression-literals/-/plugin-transform-member-expression-literals-7.24.1.tgz", + "integrity": "sha512-4ojai0KysTWXzHseJKa1XPNXKRbuUrhkOPY4rEGeR+7ChlJVKxFa3H3Bz+7tWaGKgJAXUWKOGmltN+u9B3+CVg==", + "requires": { + "@babel/helper-plugin-utils": "^7.24.0" + } + }, + "@babel/plugin-transform-modules-amd": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-amd/-/plugin-transform-modules-amd-7.24.1.tgz", + "integrity": "sha512-lAxNHi4HVtjnHd5Rxg3D5t99Xm6H7b04hUS7EHIXcUl2EV4yl1gWdqZrNzXnSrHveL9qMdbODlLF55mvgjAfaQ==", + "requires": { + "@babel/helper-module-transforms": "^7.23.3", + "@babel/helper-plugin-utils": "^7.24.0" + } + }, + "@babel/plugin-transform-modules-commonjs": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-commonjs/-/plugin-transform-modules-commonjs-7.24.1.tgz", + "integrity": "sha512-szog8fFTUxBfw0b98gEWPaEqF42ZUD/T3bkynW/wtgx2p/XCP55WEsb+VosKceRSd6njipdZvNogqdtI4Q0chw==", + "requires": { + "@babel/helper-module-transforms": "^7.23.3", + "@babel/helper-plugin-utils": "^7.24.0", + "@babel/helper-simple-access": "^7.22.5" + } + }, + "@babel/plugin-transform-modules-systemjs": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-systemjs/-/plugin-transform-modules-systemjs-7.24.1.tgz", + "integrity": "sha512-mqQ3Zh9vFO1Tpmlt8QPnbwGHzNz3lpNEMxQb1kAemn/erstyqw1r9KeOlOfo3y6xAnFEcOv2tSyrXfmMk+/YZA==", + "requires": { + "@babel/helper-hoist-variables": "^7.22.5", + "@babel/helper-module-transforms": "^7.23.3", + "@babel/helper-plugin-utils": "^7.24.0", + "@babel/helper-validator-identifier": "^7.22.20" + } + }, + "@babel/plugin-transform-modules-umd": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-modules-umd/-/plugin-transform-modules-umd-7.24.1.tgz", + "integrity": "sha512-tuA3lpPj+5ITfcCluy6nWonSL7RvaG0AOTeAuvXqEKS34lnLzXpDb0dcP6K8jD0zWZFNDVly90AGFJPnm4fOYg==", + "requires": { + "@babel/helper-module-transforms": "^7.23.3", + "@babel/helper-plugin-utils": "^7.24.0" + } + }, + "@babel/plugin-transform-named-capturing-groups-regex": { + "version": "7.22.5", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-named-capturing-groups-regex/-/plugin-transform-named-capturing-groups-regex-7.22.5.tgz", + "integrity": "sha512-YgLLKmS3aUBhHaxp5hi1WJTgOUb/NCuDHzGT9z9WTt3YG+CPRhJs6nprbStx6DnWM4dh6gt7SU3sZodbZ08adQ==", + "requires": { + "@babel/helper-create-regexp-features-plugin": "^7.22.5", + "@babel/helper-plugin-utils": "^7.22.5" + } + }, + "@babel/plugin-transform-new-target": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-new-target/-/plugin-transform-new-target-7.24.1.tgz", + "integrity": "sha512-/rurytBM34hYy0HKZQyA0nHbQgQNFm4Q/BOc9Hflxi2X3twRof7NaE5W46j4kQitm7SvACVRXsa6N/tSZxvPug==", + "requires": { + "@babel/helper-plugin-utils": "^7.24.0" + } + }, + "@babel/plugin-transform-nullish-coalescing-operator": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-nullish-coalescing-operator/-/plugin-transform-nullish-coalescing-operator-7.24.1.tgz", + "integrity": "sha512-iQ+caew8wRrhCikO5DrUYx0mrmdhkaELgFa+7baMcVuhxIkN7oxt06CZ51D65ugIb1UWRQ8oQe+HXAVM6qHFjw==", + "requires": { + "@babel/helper-plugin-utils": "^7.24.0", + "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3" + } + }, + "@babel/plugin-transform-numeric-separator": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-numeric-separator/-/plugin-transform-numeric-separator-7.24.1.tgz", + "integrity": "sha512-7GAsGlK4cNL2OExJH1DzmDeKnRv/LXq0eLUSvudrehVA5Rgg4bIrqEUW29FbKMBRT0ztSqisv7kjP+XIC4ZMNw==", + "requires": { + "@babel/helper-plugin-utils": "^7.24.0", + "@babel/plugin-syntax-numeric-separator": "^7.10.4" + } + }, + "@babel/plugin-transform-object-rest-spread": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-rest-spread/-/plugin-transform-object-rest-spread-7.24.1.tgz", + "integrity": "sha512-XjD5f0YqOtebto4HGISLNfiNMTTs6tbkFf2TOqJlYKYmbo+mN9Dnpl4SRoofiziuOWMIyq3sZEUqLo3hLITFEA==", + "requires": { + "@babel/helper-compilation-targets": "^7.23.6", + "@babel/helper-plugin-utils": "^7.24.0", + "@babel/plugin-syntax-object-rest-spread": "^7.8.3", + "@babel/plugin-transform-parameters": "^7.24.1" + } + }, + "@babel/plugin-transform-object-super": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-object-super/-/plugin-transform-object-super-7.24.1.tgz", + "integrity": "sha512-oKJqR3TeI5hSLRxudMjFQ9re9fBVUU0GICqM3J1mi8MqlhVr6hC/ZN4ttAyMuQR6EZZIY6h/exe5swqGNNIkWQ==", + "requires": { + "@babel/helper-plugin-utils": "^7.24.0", + "@babel/helper-replace-supers": "^7.24.1" + } + }, + "@babel/plugin-transform-optional-catch-binding": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-catch-binding/-/plugin-transform-optional-catch-binding-7.24.1.tgz", + "integrity": "sha512-oBTH7oURV4Y+3EUrf6cWn1OHio3qG/PVwO5J03iSJmBg6m2EhKjkAu/xuaXaYwWW9miYtvbWv4LNf0AmR43LUA==", + "requires": { + "@babel/helper-plugin-utils": "^7.24.0", + "@babel/plugin-syntax-optional-catch-binding": "^7.8.3" + } + }, + "@babel/plugin-transform-optional-chaining": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-optional-chaining/-/plugin-transform-optional-chaining-7.24.1.tgz", + "integrity": "sha512-n03wmDt+987qXwAgcBlnUUivrZBPZ8z1plL0YvgQalLm+ZE5BMhGm94jhxXtA1wzv1Cu2aaOv1BM9vbVttrzSg==", + "requires": { + "@babel/helper-plugin-utils": "^7.24.0", + "@babel/helper-skip-transparent-expression-wrappers": "^7.22.5", + "@babel/plugin-syntax-optional-chaining": "^7.8.3" + } + }, + "@babel/plugin-transform-parameters": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-parameters/-/plugin-transform-parameters-7.24.1.tgz", + "integrity": "sha512-8Jl6V24g+Uw5OGPeWNKrKqXPDw2YDjLc53ojwfMcKwlEoETKU9rU0mHUtcg9JntWI/QYzGAXNWEcVHZ+fR+XXg==", + "requires": { + "@babel/helper-plugin-utils": "^7.24.0" + } + }, + "@babel/plugin-transform-private-methods": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-private-methods/-/plugin-transform-private-methods-7.24.1.tgz", + "integrity": "sha512-tGvisebwBO5em4PaYNqt4fkw56K2VALsAbAakY0FjTYqJp7gfdrgr7YX76Or8/cpik0W6+tj3rZ0uHU9Oil4tw==", + "requires": { + "@babel/helper-create-class-features-plugin": "^7.24.1", + "@babel/helper-plugin-utils": "^7.24.0" + } + }, + "@babel/plugin-transform-private-property-in-object": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-private-property-in-object/-/plugin-transform-private-property-in-object-7.24.1.tgz", + "integrity": "sha512-pTHxDVa0BpUbvAgX3Gat+7cSciXqUcY9j2VZKTbSB6+VQGpNgNO9ailxTGHSXlqOnX1Hcx1Enme2+yv7VqP9bg==", + "requires": { + "@babel/helper-annotate-as-pure": "^7.22.5", + "@babel/helper-create-class-features-plugin": "^7.24.1", + "@babel/helper-plugin-utils": "^7.24.0", + "@babel/plugin-syntax-private-property-in-object": "^7.14.5" + } + }, + "@babel/plugin-transform-property-literals": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-property-literals/-/plugin-transform-property-literals-7.24.1.tgz", + "integrity": "sha512-LetvD7CrHmEx0G442gOomRr66d7q8HzzGGr4PMHGr+5YIm6++Yke+jxj246rpvsbyhJwCLxcTn6zW1P1BSenqA==", + "requires": { + "@babel/helper-plugin-utils": "^7.24.0" + } + }, + "@babel/plugin-transform-regenerator": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-regenerator/-/plugin-transform-regenerator-7.24.1.tgz", + "integrity": "sha512-sJwZBCzIBE4t+5Q4IGLaaun5ExVMRY0lYwos/jNecjMrVCygCdph3IKv0tkP5Fc87e/1+bebAmEAGBfnRD+cnw==", + "requires": { + "@babel/helper-plugin-utils": "^7.24.0", + "regenerator-transform": "^0.15.2" + } + }, + "@babel/plugin-transform-reserved-words": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-reserved-words/-/plugin-transform-reserved-words-7.24.1.tgz", + "integrity": "sha512-JAclqStUfIwKN15HrsQADFgeZt+wexNQ0uLhuqvqAUFoqPMjEcFCYZBhq0LUdz6dZK/mD+rErhW71fbx8RYElg==", + "requires": { + "@babel/helper-plugin-utils": "^7.24.0" + } + }, + "@babel/plugin-transform-runtime": { + "version": "7.24.0", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-runtime/-/plugin-transform-runtime-7.24.0.tgz", + "integrity": "sha512-zc0GA5IitLKJrSfXlXmp8KDqLrnGECK7YRfQBmEKg1NmBOQ7e+KuclBEKJgzifQeUYLdNiAw4B4bjyvzWVLiSA==", + "requires": { + "@babel/helper-module-imports": "^7.22.15", + "@babel/helper-plugin-utils": "^7.24.0", + "babel-plugin-polyfill-corejs2": "^0.4.8", + "babel-plugin-polyfill-corejs3": "^0.9.0", + "babel-plugin-polyfill-regenerator": "^0.5.5", + "semver": "^6.3.1" + }, + "dependencies": { + "semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==" + } + } + }, + "@babel/plugin-transform-shorthand-properties": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-shorthand-properties/-/plugin-transform-shorthand-properties-7.24.1.tgz", + "integrity": "sha512-LyjVB1nsJ6gTTUKRjRWx9C1s9hE7dLfP/knKdrfeH9UPtAGjYGgxIbFfx7xyLIEWs7Xe1Gnf8EWiUqfjLhInZA==", + "requires": { + "@babel/helper-plugin-utils": "^7.24.0" + } + }, + "@babel/plugin-transform-spread": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-spread/-/plugin-transform-spread-7.24.1.tgz", + "integrity": "sha512-KjmcIM+fxgY+KxPVbjelJC6hrH1CgtPmTvdXAfn3/a9CnWGSTY7nH4zm5+cjmWJybdcPSsD0++QssDsjcpe47g==", + "requires": { + "@babel/helper-plugin-utils": "^7.24.0", + "@babel/helper-skip-transparent-expression-wrappers": "^7.22.5" + } + }, + "@babel/plugin-transform-sticky-regex": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-sticky-regex/-/plugin-transform-sticky-regex-7.24.1.tgz", + "integrity": "sha512-9v0f1bRXgPVcPrngOQvLXeGNNVLc8UjMVfebo9ka0WF3/7+aVUHmaJVT3sa0XCzEFioPfPHZiOcYG9qOsH63cw==", + "requires": { + "@babel/helper-plugin-utils": "^7.24.0" + } + }, + "@babel/plugin-transform-template-literals": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-template-literals/-/plugin-transform-template-literals-7.24.1.tgz", + "integrity": "sha512-WRkhROsNzriarqECASCNu/nojeXCDTE/F2HmRgOzi7NGvyfYGq1NEjKBK3ckLfRgGc6/lPAqP0vDOSw3YtG34g==", + "requires": { + "@babel/helper-plugin-utils": "^7.24.0" + } + }, + "@babel/plugin-transform-typeof-symbol": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-typeof-symbol/-/plugin-transform-typeof-symbol-7.24.1.tgz", + "integrity": "sha512-CBfU4l/A+KruSUoW+vTQthwcAdwuqbpRNB8HQKlZABwHRhsdHZ9fezp4Sn18PeAlYxTNiLMlx4xUBV3AWfg1BA==", + "requires": { + "@babel/helper-plugin-utils": "^7.24.0" + } + }, + "@babel/plugin-transform-unicode-escapes": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-escapes/-/plugin-transform-unicode-escapes-7.24.1.tgz", + "integrity": "sha512-RlkVIcWT4TLI96zM660S877E7beKlQw7Ig+wqkKBiWfj0zH5Q4h50q6er4wzZKRNSYpfo6ILJ+hrJAGSX2qcNw==", + "requires": { + "@babel/helper-plugin-utils": "^7.24.0" + } + }, + "@babel/plugin-transform-unicode-property-regex": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-property-regex/-/plugin-transform-unicode-property-regex-7.24.1.tgz", + "integrity": "sha512-Ss4VvlfYV5huWApFsF8/Sq0oXnGO+jB+rijFEFugTd3cwSObUSnUi88djgR5528Csl0uKlrI331kRqe56Ov2Ng==", + "requires": { + "@babel/helper-create-regexp-features-plugin": "^7.22.15", + "@babel/helper-plugin-utils": "^7.24.0" + } + }, + "@babel/plugin-transform-unicode-regex": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-regex/-/plugin-transform-unicode-regex-7.24.1.tgz", + "integrity": "sha512-2A/94wgZgxfTsiLaQ2E36XAOdcZmGAaEEgVmxQWwZXWkGhvoHbaqXcKnU8zny4ycpu3vNqg0L/PcCiYtHtA13g==", + "requires": { + "@babel/helper-create-regexp-features-plugin": "^7.22.15", + "@babel/helper-plugin-utils": "^7.24.0" + } + }, + "@babel/plugin-transform-unicode-sets-regex": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/plugin-transform-unicode-sets-regex/-/plugin-transform-unicode-sets-regex-7.24.1.tgz", + "integrity": "sha512-fqj4WuzzS+ukpgerpAoOnMfQXwUHFxXUZUE84oL2Kao2N8uSlvcpnAidKASgsNgzZHBsHWvcm8s9FPWUhAb8fA==", + "requires": { + "@babel/helper-create-regexp-features-plugin": "^7.22.15", + "@babel/helper-plugin-utils": "^7.24.0" + } + }, + "@babel/preset-env": { + "version": "7.24.0", + "resolved": "https://registry.npmjs.org/@babel/preset-env/-/preset-env-7.24.0.tgz", + "integrity": "sha512-ZxPEzV9IgvGn73iK0E6VB9/95Nd7aMFpbE0l8KQFDG70cOV9IxRP7Y2FUPmlK0v6ImlLqYX50iuZ3ZTVhOF2lA==", + "requires": { + "@babel/compat-data": "^7.23.5", + "@babel/helper-compilation-targets": "^7.23.6", + "@babel/helper-plugin-utils": "^7.24.0", + "@babel/helper-validator-option": "^7.23.5", + "@babel/plugin-bugfix-safari-id-destructuring-collision-in-function-expression": "^7.23.3", + "@babel/plugin-bugfix-v8-spread-parameters-in-optional-chaining": "^7.23.3", + "@babel/plugin-bugfix-v8-static-class-fields-redefine-readonly": "^7.23.7", + "@babel/plugin-proposal-private-property-in-object": "7.21.0-placeholder-for-preset-env.2", + "@babel/plugin-syntax-async-generators": "^7.8.4", + "@babel/plugin-syntax-class-properties": "^7.12.13", + "@babel/plugin-syntax-class-static-block": "^7.14.5", + "@babel/plugin-syntax-dynamic-import": "^7.8.3", + "@babel/plugin-syntax-export-namespace-from": "^7.8.3", + "@babel/plugin-syntax-import-assertions": "^7.23.3", + "@babel/plugin-syntax-import-attributes": "^7.23.3", + "@babel/plugin-syntax-import-meta": "^7.10.4", + "@babel/plugin-syntax-json-strings": "^7.8.3", + "@babel/plugin-syntax-logical-assignment-operators": "^7.10.4", + "@babel/plugin-syntax-nullish-coalescing-operator": "^7.8.3", + "@babel/plugin-syntax-numeric-separator": "^7.10.4", + "@babel/plugin-syntax-object-rest-spread": "^7.8.3", + "@babel/plugin-syntax-optional-catch-binding": "^7.8.3", + "@babel/plugin-syntax-optional-chaining": "^7.8.3", + "@babel/plugin-syntax-private-property-in-object": "^7.14.5", + "@babel/plugin-syntax-top-level-await": "^7.14.5", + "@babel/plugin-syntax-unicode-sets-regex": "^7.18.6", + "@babel/plugin-transform-arrow-functions": "^7.23.3", + "@babel/plugin-transform-async-generator-functions": "^7.23.9", + "@babel/plugin-transform-async-to-generator": "^7.23.3", + "@babel/plugin-transform-block-scoped-functions": "^7.23.3", + "@babel/plugin-transform-block-scoping": "^7.23.4", + "@babel/plugin-transform-class-properties": "^7.23.3", + "@babel/plugin-transform-class-static-block": "^7.23.4", + "@babel/plugin-transform-classes": "^7.23.8", + "@babel/plugin-transform-computed-properties": "^7.23.3", + "@babel/plugin-transform-destructuring": "^7.23.3", + "@babel/plugin-transform-dotall-regex": "^7.23.3", + "@babel/plugin-transform-duplicate-keys": "^7.23.3", + "@babel/plugin-transform-dynamic-import": "^7.23.4", + "@babel/plugin-transform-exponentiation-operator": "^7.23.3", + "@babel/plugin-transform-export-namespace-from": "^7.23.4", + "@babel/plugin-transform-for-of": "^7.23.6", + "@babel/plugin-transform-function-name": "^7.23.3", + "@babel/plugin-transform-json-strings": "^7.23.4", + "@babel/plugin-transform-literals": "^7.23.3", + "@babel/plugin-transform-logical-assignment-operators": "^7.23.4", + "@babel/plugin-transform-member-expression-literals": "^7.23.3", + "@babel/plugin-transform-modules-amd": "^7.23.3", + "@babel/plugin-transform-modules-commonjs": "^7.23.3", + "@babel/plugin-transform-modules-systemjs": "^7.23.9", + "@babel/plugin-transform-modules-umd": "^7.23.3", + "@babel/plugin-transform-named-capturing-groups-regex": "^7.22.5", + "@babel/plugin-transform-new-target": "^7.23.3", + "@babel/plugin-transform-nullish-coalescing-operator": "^7.23.4", + "@babel/plugin-transform-numeric-separator": "^7.23.4", + "@babel/plugin-transform-object-rest-spread": "^7.24.0", + "@babel/plugin-transform-object-super": "^7.23.3", + "@babel/plugin-transform-optional-catch-binding": "^7.23.4", + "@babel/plugin-transform-optional-chaining": "^7.23.4", + "@babel/plugin-transform-parameters": "^7.23.3", + "@babel/plugin-transform-private-methods": "^7.23.3", + "@babel/plugin-transform-private-property-in-object": "^7.23.4", + "@babel/plugin-transform-property-literals": "^7.23.3", + "@babel/plugin-transform-regenerator": "^7.23.3", + "@babel/plugin-transform-reserved-words": "^7.23.3", + "@babel/plugin-transform-shorthand-properties": "^7.23.3", + "@babel/plugin-transform-spread": "^7.23.3", + "@babel/plugin-transform-sticky-regex": "^7.23.3", + "@babel/plugin-transform-template-literals": "^7.23.3", + "@babel/plugin-transform-typeof-symbol": "^7.23.3", + "@babel/plugin-transform-unicode-escapes": "^7.23.3", + "@babel/plugin-transform-unicode-property-regex": "^7.23.3", + "@babel/plugin-transform-unicode-regex": "^7.23.3", + "@babel/plugin-transform-unicode-sets-regex": "^7.23.3", + "@babel/preset-modules": "0.1.6-no-external-plugins", + "babel-plugin-polyfill-corejs2": "^0.4.8", + "babel-plugin-polyfill-corejs3": "^0.9.0", + "babel-plugin-polyfill-regenerator": "^0.5.5", + "core-js-compat": "^3.31.0", + "semver": "^6.3.1" + }, + "dependencies": { + "semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==" + } + } + }, + "@babel/preset-modules": { + "version": "0.1.6-no-external-plugins", + "resolved": "https://registry.npmjs.org/@babel/preset-modules/-/preset-modules-0.1.6-no-external-plugins.tgz", + "integrity": "sha512-HrcgcIESLm9aIR842yhJ5RWan/gebQUJ6E/E5+rf0y9o6oj7w0Br+sWuL6kEQ/o/AdfvR1Je9jG18/gnpwjEyA==", + "requires": { + "@babel/helper-plugin-utils": "^7.0.0", + "@babel/types": "^7.4.4", + "esutils": "^2.0.2" + } + }, + "@babel/regjsgen": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/@babel/regjsgen/-/regjsgen-0.8.0.tgz", + "integrity": "sha512-x/rqGMdzj+fWZvCOYForTghzbtqPDZ5gPwaoNGHdgDfF2QA/XZbCBp4Moo5scrkAMPhB7z26XM/AaHuIJdgauA==" + }, + "@babel/runtime": { + "version": "7.24.0", + "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.24.0.tgz", + "integrity": "sha512-Chk32uHMg6TnQdvw2e9IlqPpFX/6NLuK0Ys2PqLb7/gL5uFn9mXvK715FGLlOLQrcO4qIkNHkvPGktzzXexsFw==", + "requires": { + "regenerator-runtime": "^0.14.0" + } + }, + "@babel/template": { + "version": "7.24.0", + "resolved": "https://registry.npmjs.org/@babel/template/-/template-7.24.0.tgz", + "integrity": "sha512-Bkf2q8lMB0AFpX0NFEqSbx1OkTHf0f+0j82mkw+ZpzBnkk7e9Ql0891vlfgi+kHwOk8tQjiQHpqh4LaSa0fKEA==", + "requires": { + "@babel/code-frame": "^7.23.5", + "@babel/parser": "^7.24.0", + "@babel/types": "^7.24.0" + } + }, + "@babel/traverse": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/traverse/-/traverse-7.24.1.tgz", + "integrity": "sha512-xuU6o9m68KeqZbQuDt2TcKSxUw/mrsvavlEqQ1leZ/B+C9tk6E4sRWy97WaXgvq5E+nU3cXMxv3WKOCanVMCmQ==", + "requires": { + "@babel/code-frame": "^7.24.1", + "@babel/generator": "^7.24.1", + "@babel/helper-environment-visitor": "^7.22.20", + "@babel/helper-function-name": "^7.23.0", + "@babel/helper-hoist-variables": "^7.22.5", + "@babel/helper-split-export-declaration": "^7.22.6", + "@babel/parser": "^7.24.1", + "@babel/types": "^7.24.0", + "debug": "^4.3.1", + "globals": "^11.1.0" + }, + "dependencies": { + "@babel/generator": { + "version": "7.24.1", + "resolved": "https://registry.npmjs.org/@babel/generator/-/generator-7.24.1.tgz", + "integrity": "sha512-DfCRfZsBcrPEHUfuBMgbJ1Ut01Y/itOs+hY2nFLgqsqXd52/iSiVq5TITtUasIUgm+IIKdY2/1I7auiQOEeC9A==", + "requires": { + "@babel/types": "^7.24.0", + "@jridgewell/gen-mapping": "^0.3.5", + "@jridgewell/trace-mapping": "^0.3.25", + "jsesc": "^2.5.1" + } + }, + "@jridgewell/trace-mapping": { + "version": "0.3.25", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz", + "integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==", + "requires": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + } + } + }, + "@babel/types": { + "version": "7.24.0", + "resolved": "https://registry.npmjs.org/@babel/types/-/types-7.24.0.tgz", + "integrity": "sha512-+j7a5c253RfKh8iABBhywc8NSfP5LURe7Uh4qpsh6jc+aLJguvmIUBdjSdEMQv2bENrCR5MfRdjGo7vzS/ob7w==", + "requires": { + "@babel/helper-string-parser": "^7.23.4", + "@babel/helper-validator-identifier": "^7.22.20", + "to-fast-properties": "^2.0.0" + } + }, + "@browserify/envify": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/@browserify/envify/-/envify-6.0.0.tgz", + "integrity": "sha512-ovxHR0KTsRCyMNwD7MGV0+VCU1sT6Ds+itC4DaQHM41eUId+w5Jd0qlhLVoDkkIVBnkY3BAAM8yb2QfpBlHkPw==", + "requires": { + "acorn-node": "^2.0.1", + "dash-ast": "^2.0.1", + "multisplice": "^1.0.0", + "through2": "^4.0.2" + }, + "dependencies": { + "acorn-node": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/acorn-node/-/acorn-node-2.0.1.tgz", + "integrity": "sha512-VLR5sHqjk+8c5hrKeP2fWaIHb8eewsoxnZ8r2qpwRHXMHuC7KyOPflnOx9dLssVQUurzJ7rO0OzIFjHcndafWw==", + "requires": { + "acorn": "^7.0.0", + "acorn-walk": "^7.0.0", + "xtend": "^4.0.2" + } + }, + "dash-ast": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/dash-ast/-/dash-ast-2.0.1.tgz", + "integrity": "sha512-5TXltWJGc+RdnabUGzhRae1TRq6m4gr+3K2wQX0is5/F2yS6MJXJvLyI3ErAnsAXuJoGqvfVD5icRgim07DrxQ==" + }, + "readable-stream": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "requires": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + } + }, + "through2": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/through2/-/through2-4.0.2.tgz", + "integrity": "sha512-iOqSav00cVxEEICeD7TjLB1sueEL+81Wpzp2bY17uZjZN0pWZPuo4suZ/61VujxmqSGFfgOcNuTZ85QJwNZQpw==", + "requires": { + "readable-stream": "3" + } + } + } + }, + "@browserify/uglifyify": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/@browserify/uglifyify/-/uglifyify-6.0.0.tgz", + "integrity": "sha512-48M2a3novsgKhUSo/B3ja10awc7unliK1HfW6aYBJdLFQj3wXDx9BBJVfj6MVYERSQVEVjNHQQ7IK89h4MpCLw==", + "requires": { + "convert-source-map": "^1.9.0", + "minimatch": "^3.0.2", + "terser": "^5.15.1", + "through2": "^4.0.2", + "xtend": "^4.0.1" + }, + "dependencies": { + "readable-stream": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "requires": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + } + }, + "through2": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/through2/-/through2-4.0.2.tgz", + "integrity": "sha512-iOqSav00cVxEEICeD7TjLB1sueEL+81Wpzp2bY17uZjZN0pWZPuo4suZ/61VujxmqSGFfgOcNuTZ85QJwNZQpw==", + "requires": { + "readable-stream": "3" + } + } + } + }, + "@colors/colors": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@colors/colors/-/colors-1.5.0.tgz", + "integrity": "sha512-ooWCrlZP11i8GImSjTHYHLkvFDP48nS4+204nGb1RiX/WXYHmJA2III9/e2DWVabCESdW7hBAEzHRqUn9OUVvQ==", + "optional": true + }, + "@cspotcode/source-map-support": { + "version": "0.8.1", + "resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz", + "integrity": "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==", + "dev": true, + "requires": { + "@jridgewell/trace-mapping": "0.3.9" + } + }, + "@cypress/request": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@cypress/request/-/request-3.0.1.tgz", + "integrity": "sha512-TWivJlJi8ZDx2wGOw1dbLuHJKUYX7bWySw377nlnGOW3hP9/MUKIsEdXT/YngWxVdgNCHRBmFlBipE+5/2ZZlQ==", + "optional": true, + "requires": { + "aws-sign2": "~0.7.0", + "aws4": "^1.8.0", + "caseless": "~0.12.0", + "combined-stream": "~1.0.6", + "extend": "~3.0.2", + "forever-agent": "~0.6.1", + "form-data": "~2.3.2", + "http-signature": "~1.3.6", + "is-typedarray": "~1.0.0", + "isstream": "~0.1.2", + "json-stringify-safe": "~5.0.1", + "mime-types": "~2.1.19", + "performance-now": "^2.1.0", + "qs": "6.10.4", + "safe-buffer": "^5.1.2", + "tough-cookie": "^4.1.3", + "tunnel-agent": "^0.6.0", + "uuid": "^8.3.2" + } + }, + "@cypress/schematic": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/@cypress/schematic/-/schematic-2.5.0.tgz", + "integrity": "sha512-Yt/fQxYIHl9lU8LSoJL92nIwTVyYG5uP4VqW4taTn3viVWvssjK7sRtTI/LRxOoeMYX2RRlXQyUbFEikByn0cQ==", + "optional": true, + "requires": { + "jsonc-parser": "^3.0.0", + "rxjs": "~6.6.0" + }, + "dependencies": { + "rxjs": { + "version": "6.6.7", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-6.6.7.tgz", + "integrity": "sha512-hTdwr+7yYNIT5n4AMYp85KA6yw2Va0FLa3Rguvbpa4W3I5xynaBZo41cM3XM+4Q6fRMj3sBYIR1VAmZMXYJvRQ==", + "optional": true, + "requires": { + "tslib": "^1.9.0" + } + }, + "tslib": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.14.1.tgz", + "integrity": "sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg==", + "optional": true + } + } + }, + "@cypress/xvfb": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/@cypress/xvfb/-/xvfb-1.2.4.tgz", + "integrity": "sha512-skbBzPggOVYCbnGgV+0dmBdW/s77ZkAOXIC1knS8NagwDjBrNC1LuXtQJeiN6l+m7lzmHtaoUw/ctJKdqkG57Q==", + "optional": true, + "requires": { + "debug": "^3.1.0", + "lodash.once": "^4.1.1" + }, + "dependencies": { + "debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "optional": true, + "requires": { + "ms": "^2.1.1" + } + } + } + }, + "@discoveryjs/json-ext": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/@discoveryjs/json-ext/-/json-ext-0.5.7.tgz", + "integrity": "sha512-dBVuXR082gk3jsFp7Rd/JI4kytwGHecnCoTtXFb7DB6CNHp4rg5k1bhg0nWdLGLnOV71lmDzGQaLMy8iPLY0pw==" + }, + "@esbuild/aix-ppc64": { + "version": "0.23.0", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.23.0.tgz", + "integrity": "sha512-3sG8Zwa5fMcA9bgqB8AfWPQ+HFke6uD3h1s3RIwUNK8EG7a4buxvuFTs3j1IMs2NXAk9F30C/FF4vxRgQCcmoQ==", + "optional": true + }, + "@esbuild/android-arm": { + "version": "0.23.0", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.23.0.tgz", + "integrity": "sha512-+KuOHTKKyIKgEEqKbGTK8W7mPp+hKinbMBeEnNzjJGyFcWsfrXjSTNluJHCY1RqhxFurdD8uNXQDei7qDlR6+g==", + "optional": true + }, + "@esbuild/android-arm64": { + "version": "0.23.0", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.23.0.tgz", + "integrity": "sha512-EuHFUYkAVfU4qBdyivULuu03FhJO4IJN9PGuABGrFy4vUuzk91P2d+npxHcFdpUnfYKy0PuV+n6bKIpHOB3prQ==", + "optional": true + }, + "@esbuild/android-x64": { + "version": "0.23.0", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.23.0.tgz", + "integrity": "sha512-WRrmKidLoKDl56LsbBMhzTTBxrsVwTKdNbKDalbEZr0tcsBgCLbEtoNthOW6PX942YiYq8HzEnb4yWQMLQuipQ==", + "optional": true + }, + "@esbuild/darwin-arm64": { + "version": "0.23.0", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.23.0.tgz", + "integrity": "sha512-YLntie/IdS31H54Ogdn+v50NuoWF5BDkEUFpiOChVa9UnKpftgwzZRrI4J132ETIi+D8n6xh9IviFV3eXdxfow==", + "optional": true + }, + "@esbuild/darwin-x64": { + "version": "0.23.0", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.23.0.tgz", + "integrity": "sha512-IMQ6eme4AfznElesHUPDZ+teuGwoRmVuuixu7sv92ZkdQcPbsNHzutd+rAfaBKo8YK3IrBEi9SLLKWJdEvJniQ==", + "optional": true + }, + "@esbuild/freebsd-arm64": { + "version": "0.23.0", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.23.0.tgz", + "integrity": "sha512-0muYWCng5vqaxobq6LB3YNtevDFSAZGlgtLoAc81PjUfiFz36n4KMpwhtAd4he8ToSI3TGyuhyx5xmiWNYZFyw==", + "optional": true + }, + "@esbuild/freebsd-x64": { + "version": "0.23.0", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.23.0.tgz", + "integrity": "sha512-XKDVu8IsD0/q3foBzsXGt/KjD/yTKBCIwOHE1XwiXmrRwrX6Hbnd5Eqn/WvDekddK21tfszBSrE/WMaZh+1buQ==", + "optional": true + }, + "@esbuild/linux-arm": { + "version": "0.23.0", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.23.0.tgz", + "integrity": "sha512-SEELSTEtOFu5LPykzA395Mc+54RMg1EUgXP+iw2SJ72+ooMwVsgfuwXo5Fn0wXNgWZsTVHwY2cg4Vi/bOD88qw==", + "optional": true + }, + "@esbuild/linux-arm64": { + "version": "0.23.0", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.23.0.tgz", + "integrity": "sha512-j1t5iG8jE7BhonbsEg5d9qOYcVZv/Rv6tghaXM/Ug9xahM0nX/H2gfu6X6z11QRTMT6+aywOMA8TDkhPo8aCGw==", + "optional": true + }, + "@esbuild/linux-ia32": { + "version": "0.23.0", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.23.0.tgz", + "integrity": "sha512-P7O5Tkh2NbgIm2R6x1zGJJsnacDzTFcRWZyTTMgFdVit6E98LTxO+v8LCCLWRvPrjdzXHx9FEOA8oAZPyApWUA==", + "optional": true + }, + "@esbuild/linux-loong64": { + "version": "0.23.0", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.23.0.tgz", + "integrity": "sha512-InQwepswq6urikQiIC/kkx412fqUZudBO4SYKu0N+tGhXRWUqAx+Q+341tFV6QdBifpjYgUndV1hhMq3WeJi7A==", + "optional": true + }, + "@esbuild/linux-mips64el": { + "version": "0.23.0", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.23.0.tgz", + "integrity": "sha512-J9rflLtqdYrxHv2FqXE2i1ELgNjT+JFURt/uDMoPQLcjWQA5wDKgQA4t/dTqGa88ZVECKaD0TctwsUfHbVoi4w==", + "optional": true + }, + "@esbuild/linux-ppc64": { + "version": "0.23.0", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.23.0.tgz", + "integrity": "sha512-cShCXtEOVc5GxU0fM+dsFD10qZ5UpcQ8AM22bYj0u/yaAykWnqXJDpd77ublcX6vdDsWLuweeuSNZk4yUxZwtw==", + "optional": true + }, + "@esbuild/linux-riscv64": { + "version": "0.23.0", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.23.0.tgz", + "integrity": "sha512-HEtaN7Y5UB4tZPeQmgz/UhzoEyYftbMXrBCUjINGjh3uil+rB/QzzpMshz3cNUxqXN7Vr93zzVtpIDL99t9aRw==", + "optional": true + }, + "@esbuild/linux-s390x": { + "version": "0.23.0", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.23.0.tgz", + "integrity": "sha512-WDi3+NVAuyjg/Wxi+o5KPqRbZY0QhI9TjrEEm+8dmpY9Xir8+HE/HNx2JoLckhKbFopW0RdO2D72w8trZOV+Wg==", + "optional": true + }, + "@esbuild/linux-x64": { + "version": "0.23.0", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.23.0.tgz", + "integrity": "sha512-a3pMQhUEJkITgAw6e0bWA+F+vFtCciMjW/LPtoj99MhVt+Mfb6bbL9hu2wmTZgNd994qTAEw+U/r6k3qHWWaOQ==", + "optional": true + }, + "@esbuild/netbsd-x64": { + "version": "0.23.0", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.23.0.tgz", + "integrity": "sha512-cRK+YDem7lFTs2Q5nEv/HHc4LnrfBCbH5+JHu6wm2eP+d8OZNoSMYgPZJq78vqQ9g+9+nMuIsAO7skzphRXHyw==", + "optional": true + }, + "@esbuild/openbsd-arm64": { + "version": "0.23.0", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-arm64/-/openbsd-arm64-0.23.0.tgz", + "integrity": "sha512-suXjq53gERueVWu0OKxzWqk7NxiUWSUlrxoZK7usiF50C6ipColGR5qie2496iKGYNLhDZkPxBI3erbnYkU0rQ==", + "optional": true + }, + "@esbuild/openbsd-x64": { + "version": "0.23.0", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.23.0.tgz", + "integrity": "sha512-6p3nHpby0DM/v15IFKMjAaayFhqnXV52aEmv1whZHX56pdkK+MEaLoQWj+H42ssFarP1PcomVhbsR4pkz09qBg==", + "optional": true + }, + "@esbuild/sunos-x64": { + "version": "0.23.0", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.23.0.tgz", + "integrity": "sha512-BFelBGfrBwk6LVrmFzCq1u1dZbG4zy/Kp93w2+y83Q5UGYF1d8sCzeLI9NXjKyujjBBniQa8R8PzLFAUrSM9OA==", + "optional": true + }, + "@esbuild/win32-arm64": { + "version": "0.23.0", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.23.0.tgz", + "integrity": "sha512-lY6AC8p4Cnb7xYHuIxQ6iYPe6MfO2CC43XXKo9nBXDb35krYt7KGhQnOkRGar5psxYkircpCqfbNDB4uJbS2jQ==", + "optional": true + }, + "@esbuild/win32-ia32": { + "version": "0.23.0", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.23.0.tgz", + "integrity": "sha512-7L1bHlOTcO4ByvI7OXVI5pNN6HSu6pUQq9yodga8izeuB1KcT2UkHaH6118QJwopExPn0rMHIseCTx1CRo/uNA==", + "optional": true + }, + "@esbuild/win32-x64": { + "version": "0.23.0", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.23.0.tgz", + "integrity": "sha512-Arm+WgUFLUATuoxCJcahGuk6Yj9Pzxd6l11Zb/2aAuv5kWWvvfhLFo2fni4uSK5vzlUdCGZ/BdV5tH8klj8p8g==", + "optional": true + }, + "@eslint-community/eslint-utils": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz", + "integrity": "sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA==", + "dev": true, + "requires": { + "eslint-visitor-keys": "^3.3.0" + } + }, + "@eslint-community/regexpp": { + "version": "4.10.0", + "resolved": "https://registry.npmjs.org/@eslint-community/regexpp/-/regexpp-4.10.0.tgz", + "integrity": "sha512-Cu96Sd2By9mCNTx2iyKOmq10v22jUVQv0lQnlGNy16oE9589yE+QADPbrMGCkA51cKZSg3Pu/aTJVTGfL/qjUA==", + "dev": true + }, + "@eslint/eslintrc": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/@eslint/eslintrc/-/eslintrc-2.1.4.tgz", + "integrity": "sha512-269Z39MS6wVJtsoUl10L60WdkhJVdPG24Q4eZTH3nnF6lpvSShEK3wQjDX9JRWAUPvPh7COouPpU9IrqaZFvtQ==", + "dev": true, + "requires": { + "ajv": "^6.12.4", + "debug": "^4.3.2", + "espree": "^9.6.0", + "globals": "^13.19.0", + "ignore": "^5.2.0", + "import-fresh": "^3.2.1", + "js-yaml": "^4.1.0", + "minimatch": "^3.1.2", + "strip-json-comments": "^3.1.1" + }, + "dependencies": { + "argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true + }, + "globals": { + "version": "13.24.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.24.0.tgz", + "integrity": "sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==", + "dev": true, + "requires": { + "type-fest": "^0.20.2" + } + }, + "js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "dev": true, + "requires": { + "argparse": "^2.0.1" + } + }, + "type-fest": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", + "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", + "dev": true + } + } + }, + "@eslint/js": { + "version": "8.57.0", + "resolved": "https://registry.npmjs.org/@eslint/js/-/js-8.57.0.tgz", + "integrity": "sha512-Ys+3g2TaW7gADOJzPt83SJtCDhMjndcDMFVQ/Tj9iA1BfJzFKD9mAUXT3OenpuPHbI6P/myECxRJrofUsDx/5g==", + "dev": true + }, + "@fortawesome/angular-fontawesome": { + "version": "0.14.1", + "resolved": "https://registry.npmjs.org/@fortawesome/angular-fontawesome/-/angular-fontawesome-0.14.1.tgz", + "integrity": "sha512-Yb5HLiEOAxjSLEcaOM51CKIrzdfvoDafXVJERm9vufxfZkVZPZJgrZRgqwLVpejgq4/Ez6TqHZ6SqmJwdtRF6g==", + "requires": { + "tslib": "^2.6.2" + } + }, + "@fortawesome/fontawesome-common-types": { + "version": "6.6.0", + "resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-common-types/-/fontawesome-common-types-6.6.0.tgz", + "integrity": "sha512-xyX0X9mc0kyz9plIyryrRbl7ngsA9jz77mCZJsUkLl+ZKs0KWObgaEBoSgQiYWAsSmjz/yjl0F++Got0Mdp4Rw==" + }, + "@fortawesome/fontawesome-svg-core": { + "version": "6.6.0", + "resolved": "https://registry.npmjs.org/@fortawesome/fontawesome-svg-core/-/fontawesome-svg-core-6.6.0.tgz", + "integrity": "sha512-KHwPkCk6oRT4HADE7smhfsKudt9N/9lm6EJ5BVg0tD1yPA5hht837fB87F8pn15D8JfTqQOjhKTktwmLMiD7Kg==", + "requires": { + "@fortawesome/fontawesome-common-types": "6.6.0" + } + }, + "@fortawesome/free-solid-svg-icons": { + "version": "6.6.0", + "resolved": "https://registry.npmjs.org/@fortawesome/free-solid-svg-icons/-/free-solid-svg-icons-6.6.0.tgz", + "integrity": "sha512-IYv/2skhEDFc2WGUcqvFJkeK39Q+HyPf5GHUrT/l2pKbtgEIv1al1TKd6qStR5OIwQdN1GZP54ci3y4mroJWjA==", + "requires": { + "@fortawesome/fontawesome-common-types": "6.6.0" + } + }, + "@goto-bus-stop/common-shake": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/@goto-bus-stop/common-shake/-/common-shake-2.4.0.tgz", + "integrity": "sha512-LO+7v+UbxE3IyAS4Suf/KYB7Zq9DEIHibwDe6Wph4apNEfDyyxP7BSxzRS/Qa9lUH5gsm9eL9nF8EE1E0/nQkQ==", + "requires": { + "acorn-walk": "^7.0.0", + "debug": "^3.2.6", + "escope": "^3.6.0" + }, + "dependencies": { + "debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "requires": { + "ms": "^2.1.1" + } + } + } + }, + "@hapi/hoek": { + "version": "9.3.0", + "resolved": "https://registry.npmjs.org/@hapi/hoek/-/hoek-9.3.0.tgz", + "integrity": "sha512-/c6rf4UJlmHlC9b5BaNvzAcFv7HZ2QHaV0D4/HNlBdvFnvQq8RI4kYdhyPCl7Xj+oWvTWQ8ujhqS53LIgAe6KQ==", + "optional": true + }, + "@hapi/topo": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/@hapi/topo/-/topo-5.1.0.tgz", + "integrity": "sha512-foQZKJig7Ob0BMAYBfcJk8d77QtOe7Wo4ox7ff1lQYoNNAb6jwcY1ncdoy2e9wQZzvNy7ODZCYJkK8kzmcAnAg==", + "optional": true, + "requires": { + "@hapi/hoek": "^9.0.0" + } + }, + "@humanwhocodes/config-array": { + "version": "0.11.14", + "resolved": "https://registry.npmjs.org/@humanwhocodes/config-array/-/config-array-0.11.14.tgz", + "integrity": "sha512-3T8LkOmg45BV5FICb15QQMsyUSWrQ8AygVfC7ZG32zOalnqrilm018ZVCw0eapXux8FtA33q8PSRSstjee3jSg==", + "dev": true, + "requires": { + "@humanwhocodes/object-schema": "^2.0.2", + "debug": "^4.3.1", + "minimatch": "^3.0.5" + } + }, + "@humanwhocodes/module-importer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/@humanwhocodes/module-importer/-/module-importer-1.0.1.tgz", + "integrity": "sha512-bxveV4V8v5Yb4ncFTT3rPSgZBOpCkjfK0y4oVVVJwIuDVBRMDXrPyXRL988i5ap9m9bnyEEjWfm5WkBmtffLfA==", + "dev": true + }, + "@humanwhocodes/object-schema": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/@humanwhocodes/object-schema/-/object-schema-2.0.2.tgz", + "integrity": "sha512-6EwiSjwWYP7pTckG6I5eyFANjPhmPjUX9JRLUSfNPC7FX7zK9gyZAfUEaECL6ALTpGX5AjnBq3C9XmVWPitNpw==", + "dev": true + }, + "@isaacs/cliui": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/@isaacs/cliui/-/cliui-8.0.2.tgz", + "integrity": "sha512-O8jcjabXaleOG9DQ0+ARXWZBTfnP4WNAqzuiJK7ll44AmxGKv/J2M4TPjxjY3znBCfvBXFzucm1twdyFybFqEA==", + "requires": { + "string-width": "^5.1.2", + "string-width-cjs": "npm:string-width@^4.2.0", + "strip-ansi": "^7.0.1", + "strip-ansi-cjs": "npm:strip-ansi@^6.0.1", + "wrap-ansi": "^8.1.0", + "wrap-ansi-cjs": "npm:wrap-ansi@^7.0.0" + }, + "dependencies": { + "ansi-regex": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-6.0.1.tgz", + "integrity": "sha512-n5M855fKb2SsfMIiFFoVrABHJC8QtHwVx+mHWP3QcEqBHYienj5dHSgjbxtC0WEZXYt4wcD6zrQElDPhFuZgfA==" + }, + "ansi-styles": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-6.2.1.tgz", + "integrity": "sha512-bN798gFfQX+viw3R7yrGWRqnrN2oRkEkUjjl4JNn4E8GxxbjtG3FbrEIIY3l8/hrwUwIeCZvi4QuOTP4MErVug==" + }, + "emoji-regex": { + "version": "9.2.2", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-9.2.2.tgz", + "integrity": "sha512-L18DaJsXSUk2+42pv8mLs5jJT2hqFkFE4j21wOmgbUqsZ2hL72NsUU785g9RXgo3s0ZNgVl42TiHp3ZtOv/Vyg==" + }, + "string-width": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-5.1.2.tgz", + "integrity": "sha512-HnLOCR3vjcY8beoNLtcjZ5/nxn2afmME6lhrDrebokqMap+XbeW8n9TXpPDOqdGK5qcI3oT0GKTW6wC7EMiVqA==", + "requires": { + "eastasianwidth": "^0.2.0", + "emoji-regex": "^9.2.2", + "strip-ansi": "^7.0.1" + } + }, + "strip-ansi": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-7.1.0.tgz", + "integrity": "sha512-iq6eVVI64nQQTRYq2KtEg2d2uU7LElhTJwsH4YzIHZshxlgZms/wIc4VoDQTlG/IvVIrBKG06CrZnp0qv7hkcQ==", + "requires": { + "ansi-regex": "^6.0.1" + } + }, + "wrap-ansi": { + "version": "8.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-8.1.0.tgz", + "integrity": "sha512-si7QWI6zUMq56bESFvagtmzMdGOtoxfR+Sez11Mobfc7tm+VkUckk9bW2UeffTGVUbOksxmSw0AA2gs8g71NCQ==", + "requires": { + "ansi-styles": "^6.1.0", + "string-width": "^5.0.1", + "strip-ansi": "^7.0.1" + } + } + } + }, + "@istanbuljs/load-nyc-config": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@istanbuljs/load-nyc-config/-/load-nyc-config-1.1.0.tgz", + "integrity": "sha512-VjeHSlIzpv/NyD3N0YuHfXOPDIixcA1q2ZV98wsMqcYlPmv2n3Yb2lYP9XMElnaFVXg5A7YLTeLu6V84uQDjmQ==", + "requires": { + "camelcase": "^5.3.1", + "find-up": "^4.1.0", + "get-package-type": "^0.1.0", + "js-yaml": "^3.13.1", + "resolve-from": "^5.0.0" + } + }, + "@istanbuljs/schema": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/@istanbuljs/schema/-/schema-0.1.2.tgz", + "integrity": "sha512-tsAQNx32a8CoFhjhijUIhI4kccIAgmGhy8LZMZgGfmXcpMbPRUqn5LWmgRttILi6yeGmBJd2xsPkFMs0PzgPCw==" + }, + "@jridgewell/gen-mapping": { + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/@jridgewell/gen-mapping/-/gen-mapping-0.3.5.tgz", + "integrity": "sha512-IzL8ZoEDIBRWEzlCcRhOaCupYyN5gdIK+Q6fbFdPDg6HqX6jpkItn7DFIpW9LQzXG6Df9sA7+OKnq0qlz/GaQg==", + "requires": { + "@jridgewell/set-array": "^1.2.1", + "@jridgewell/sourcemap-codec": "^1.4.10", + "@jridgewell/trace-mapping": "^0.3.24" + }, + "dependencies": { + "@jridgewell/trace-mapping": { + "version": "0.3.25", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz", + "integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==", + "requires": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + } + } + }, + "@jridgewell/resolve-uri": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.0.tgz", + "integrity": "sha512-F2msla3tad+Mfht5cJq7LSXcdudKTWCVYUgw6pLFOOHSTtZlj6SWNYAp+AhuqLmWdBO2X5hPrLcu8cVP8fy28w==" + }, + "@jridgewell/set-array": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/@jridgewell/set-array/-/set-array-1.2.1.tgz", + "integrity": "sha512-R8gLRTZeyp03ymzP/6Lil/28tGeGEzhx1q2k703KGWRAI1VdvPIXdG70VJc2pAMw3NA6JKL5hhFu1sJX0Mnn/A==" + }, + "@jridgewell/source-map": { + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/@jridgewell/source-map/-/source-map-0.3.5.tgz", + "integrity": "sha512-UTYAUj/wviwdsMfzoSJspJxbkH5o1snzwX0//0ENX1u/55kkZZkcTZP6u9bwKGkv+dkk9at4m1Cpt0uY80kcpQ==", + "requires": { + "@jridgewell/gen-mapping": "^0.3.0", + "@jridgewell/trace-mapping": "^0.3.9" + } + }, + "@jridgewell/sourcemap-codec": { + "version": "1.4.15", + "resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.4.15.tgz", + "integrity": "sha512-eF2rxCRulEKXHTRiDrDy6erMYWqNw4LPdQ8UQA4huuxaQsVeRPFl2oM8oDGxMFhJUWZf9McpLtJasDDZb/Bpeg==" + }, + "@jridgewell/trace-mapping": { + "version": "0.3.9", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz", + "integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==", + "requires": { + "@jridgewell/resolve-uri": "^3.0.3", + "@jridgewell/sourcemap-codec": "^1.4.10" + } + }, + "@leichtgewicht/ip-codec": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/@leichtgewicht/ip-codec/-/ip-codec-2.0.4.tgz", + "integrity": "sha512-Hcv+nVC0kZnQ3tD9GVu5xSMR4VVYOteQIr/hwFPVEvPdlXqgGEuRjiheChHgdM+JyqdgNcmzZOX/tnl0JOiI7A==" + }, + "@ljharb/through": { + "version": "2.3.13", + "resolved": "https://registry.npmjs.org/@ljharb/through/-/through-2.3.13.tgz", + "integrity": "sha512-/gKJun8NNiWGZJkGzI/Ragc53cOdcLNdzjLaIa+GEjguQs0ulsurx8WN0jijdK9yPqDvziX995sMRLyLt1uZMQ==", + "requires": { + "call-bind": "^1.0.7" + } + }, + "@mempool/mempool.js": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/@mempool/mempool.js/-/mempool.js-2.3.0.tgz", + "integrity": "sha512-FrN9WjZCEyyLodrTPQxmlWDh8B/UGK0jlKfVNzJxqzQ1IMPo/Hpdws8xwYEcsks5JqsaxbjLwaC3GAtJ6Brd0A==", + "requires": { + "axios": "0.24.0", + "ws": "8.3.0" + }, + "dependencies": { + "ws": { + "version": "8.3.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.3.0.tgz", + "integrity": "sha512-Gs5EZtpqZzLvmIM59w4igITU57lrtYVFneaa434VROv4thzJyV6UjIL3D42lslWlI+D4KzLYnxSwtfuiO79sNw==", + "requires": {} + } + } + }, + "@ng-bootstrap/ng-bootstrap": { + "version": "16.0.0", + "resolved": "https://registry.npmjs.org/@ng-bootstrap/ng-bootstrap/-/ng-bootstrap-16.0.0.tgz", + "integrity": "sha512-+FJ3e6cX9DW2t7021Ji3oz433rk3+4jLfqzU+Jyx6/vJz1dIOaML3EAY6lYuW4TLiXgMPOMvs6KzPFALGh4Lag==", + "requires": { + "tslib": "^2.3.0" + } + }, + "@ngtools/webpack": { + "version": "17.3.1", + "resolved": "https://registry.npmjs.org/@ngtools/webpack/-/webpack-17.3.1.tgz", + "integrity": "sha512-6qRYFN6DqogZK0ZFrSlhg1OsIWm3lL3m+/Ixoj6/MLLjDBrTtHqmI93vg6P1EKYTH4fWChL7jtv7iS/LSZubgw==", + "requires": {} + }, + "@nodelib/fs.scandir": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", + "requires": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" + } + }, + "@nodelib/fs.stat": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==" + }, + "@nodelib/fs.walk": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", + "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", + "requires": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + } + }, + "@npmcli/agent": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/@npmcli/agent/-/agent-2.2.1.tgz", + "integrity": "sha512-H4FrOVtNyWC8MUwL3UfjOsAihHvT1Pe8POj3JvjXhSTJipsZMtgUALCT4mGyYZNxymkUfOw3PUj6dE4QPp6osQ==", + "requires": { + "agent-base": "^7.1.0", + "http-proxy-agent": "^7.0.0", + "https-proxy-agent": "^7.0.1", + "lru-cache": "^10.0.1", + "socks-proxy-agent": "^8.0.1" + }, + "dependencies": { + "lru-cache": { + "version": "10.2.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.2.0.tgz", + "integrity": "sha512-2bIM8x+VAf6JT4bKAljS1qUWgMsqZRPGJS6FSahIMPVvctcNhyVp7AJu7quxOW9jwkryBReKZY5tY5JYv2n/7Q==" + } + } + }, + "@npmcli/fs": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@npmcli/fs/-/fs-3.1.0.tgz", + "integrity": "sha512-7kZUAaLscfgbwBQRbvdMYaZOWyMEcPTH/tJjnyAWJ/dvvs9Ef+CERx/qJb9GExJpl1qipaDGn7KqHnFGGixd0w==", + "requires": { + "semver": "^7.3.5" + } + }, + "@npmcli/git": { + "version": "5.0.4", + "resolved": "https://registry.npmjs.org/@npmcli/git/-/git-5.0.4.tgz", + "integrity": "sha512-nr6/WezNzuYUppzXRaYu/W4aT5rLxdXqEFupbh6e/ovlYFQ8hpu1UUPV3Ir/YTl+74iXl2ZOMlGzudh9ZPUchQ==", + "requires": { + "@npmcli/promise-spawn": "^7.0.0", + "lru-cache": "^10.0.1", + "npm-pick-manifest": "^9.0.0", + "proc-log": "^3.0.0", + "promise-inflight": "^1.0.1", + "promise-retry": "^2.0.1", + "semver": "^7.3.5", + "which": "^4.0.0" + }, + "dependencies": { + "isexe": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-3.1.1.tgz", + "integrity": "sha512-LpB/54B+/2J5hqQ7imZHfdU31OlgQqx7ZicVlkm9kzg9/w8GKLEcFfJl/t7DCEDueOyBAD6zCCwTO6Fzs0NoEQ==" + }, + "lru-cache": { + "version": "10.2.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.2.0.tgz", + "integrity": "sha512-2bIM8x+VAf6JT4bKAljS1qUWgMsqZRPGJS6FSahIMPVvctcNhyVp7AJu7quxOW9jwkryBReKZY5tY5JYv2n/7Q==" + }, + "which": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/which/-/which-4.0.0.tgz", + "integrity": "sha512-GlaYyEb07DPxYCKhKzplCWBJtvxZcZMrL+4UkrTSJHHPyZU4mYYTv3qaOe77H7EODLSSopAUFAc6W8U4yqvscg==", + "requires": { + "isexe": "^3.1.1" + } + } + } + }, + "@npmcli/installed-package-contents": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/@npmcli/installed-package-contents/-/installed-package-contents-2.0.2.tgz", + "integrity": "sha512-xACzLPhnfD51GKvTOOuNX2/V4G4mz9/1I2MfDoye9kBM3RYe5g2YbscsaGoTlaWqkxeiapBWyseULVKpSVHtKQ==", + "requires": { + "npm-bundled": "^3.0.0", + "npm-normalize-package-bin": "^3.0.0" + } + }, + "@npmcli/node-gyp": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@npmcli/node-gyp/-/node-gyp-3.0.0.tgz", + "integrity": "sha512-gp8pRXC2oOxu0DUE1/M3bYtb1b3/DbJ5aM113+XJBgfXdussRAsX0YOrOhdd8WvnAR6auDBvJomGAkLKA5ydxA==" + }, + "@npmcli/package-json": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/@npmcli/package-json/-/package-json-5.0.0.tgz", + "integrity": "sha512-OI2zdYBLhQ7kpNPaJxiflofYIpkNLi+lnGdzqUOfRmCF3r2l1nadcjtCYMJKv/Utm/ZtlffaUuTiAktPHbc17g==", + "requires": { + "@npmcli/git": "^5.0.0", + "glob": "^10.2.2", + "hosted-git-info": "^7.0.0", + "json-parse-even-better-errors": "^3.0.0", + "normalize-package-data": "^6.0.0", + "proc-log": "^3.0.0", + "semver": "^7.5.3" + }, + "dependencies": { + "brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "requires": { + "balanced-match": "^1.0.0" + } + }, + "glob": { + "version": "10.3.10", + "resolved": "https://registry.npmjs.org/glob/-/glob-10.3.10.tgz", + "integrity": "sha512-fa46+tv1Ak0UPK1TOy/pZrIybNNt4HCv7SDzwyfiOZkvZLEbjsZkJBPtDHVshZjbecAoAGSC20MjLDG/qr679g==", + "requires": { + "foreground-child": "^3.1.0", + "jackspeak": "^2.3.5", + "minimatch": "^9.0.1", + "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0", + "path-scurry": "^1.10.1" + } + }, + "json-parse-even-better-errors": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-3.0.1.tgz", + "integrity": "sha512-aatBvbL26wVUCLmbWdCpeu9iF5wOyWpagiKkInA+kfws3sWdBrTnsvN2CKcyCYyUrc7rebNBlK6+kteg7ksecg==" + }, + "minimatch": { + "version": "9.0.3", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.3.tgz", + "integrity": "sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==", + "requires": { + "brace-expansion": "^2.0.1" + } + } + } + }, + "@npmcli/promise-spawn": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/@npmcli/promise-spawn/-/promise-spawn-7.0.1.tgz", + "integrity": "sha512-P4KkF9jX3y+7yFUxgcUdDtLy+t4OlDGuEBLNs57AZsfSfg+uV6MLndqGpnl4831ggaEdXwR50XFoZP4VFtHolg==", + "requires": { + "which": "^4.0.0" + }, + "dependencies": { + "isexe": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-3.1.1.tgz", + "integrity": "sha512-LpB/54B+/2J5hqQ7imZHfdU31OlgQqx7ZicVlkm9kzg9/w8GKLEcFfJl/t7DCEDueOyBAD6zCCwTO6Fzs0NoEQ==" + }, + "which": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/which/-/which-4.0.0.tgz", + "integrity": "sha512-GlaYyEb07DPxYCKhKzplCWBJtvxZcZMrL+4UkrTSJHHPyZU4mYYTv3qaOe77H7EODLSSopAUFAc6W8U4yqvscg==", + "requires": { + "isexe": "^3.1.1" + } + } + } + }, + "@npmcli/run-script": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/@npmcli/run-script/-/run-script-7.0.4.tgz", + "integrity": "sha512-9ApYM/3+rBt9V80aYg6tZfzj3UWdiYyCt7gJUD1VJKvWF5nwKDSICXbYIQbspFTq6TOpbsEtIC0LArB8d9PFmg==", + "requires": { + "@npmcli/node-gyp": "^3.0.0", + "@npmcli/package-json": "^5.0.0", + "@npmcli/promise-spawn": "^7.0.0", + "node-gyp": "^10.0.0", + "which": "^4.0.0" + }, + "dependencies": { + "isexe": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-3.1.1.tgz", + "integrity": "sha512-LpB/54B+/2J5hqQ7imZHfdU31OlgQqx7ZicVlkm9kzg9/w8GKLEcFfJl/t7DCEDueOyBAD6zCCwTO6Fzs0NoEQ==" + }, + "which": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/which/-/which-4.0.0.tgz", + "integrity": "sha512-GlaYyEb07DPxYCKhKzplCWBJtvxZcZMrL+4UkrTSJHHPyZU4mYYTv3qaOe77H7EODLSSopAUFAc6W8U4yqvscg==", + "requires": { + "isexe": "^3.1.1" + } + } + } + }, + "@pkgjs/parseargs": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/@pkgjs/parseargs/-/parseargs-0.11.0.tgz", + "integrity": "sha512-+1VkjdD0QBLPodGrJUeqarH8VAIvQODIbwh9XpP5Syisf7YoQgsJKPNFoqqLQlu+VQ/tVSshMR6loPMn8U+dPg==", + "optional": true + }, + "@popperjs/core": { + "version": "2.11.8", + "resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.11.8.tgz", + "integrity": "sha512-P1st0aksCrn9sGZhp8GMYwBnQsbvAWsZAX44oXNNvLHGqAOcoVxmjZiohstwQ7SqKnbR47akdNi+uleWD8+g6A==", + "peer": true + }, + "@rollup/rollup-android-arm-eabi": { + "version": "4.13.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.13.0.tgz", + "integrity": "sha512-5ZYPOuaAqEH/W3gYsRkxQATBW3Ii1MfaT4EQstTnLKViLi2gLSQmlmtTpGucNP3sXEpOiI5tdGhjdE111ekyEg==", + "optional": true + }, + "@rollup/rollup-android-arm64": { + "version": "4.13.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.13.0.tgz", + "integrity": "sha512-BSbaCmn8ZadK3UAQdlauSvtaJjhlDEjS5hEVVIN3A4bbl3X+otyf/kOJV08bYiRxfejP3DXFzO2jz3G20107+Q==", + "optional": true + }, + "@rollup/rollup-darwin-arm64": { + "version": "4.13.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.13.0.tgz", + "integrity": "sha512-Ovf2evVaP6sW5Ut0GHyUSOqA6tVKfrTHddtmxGQc1CTQa1Cw3/KMCDEEICZBbyppcwnhMwcDce9ZRxdWRpVd6g==", + "optional": true + }, + "@rollup/rollup-darwin-x64": { + "version": "4.13.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.13.0.tgz", + "integrity": "sha512-U+Jcxm89UTK592vZ2J9st9ajRv/hrwHdnvyuJpa5A2ngGSVHypigidkQJP+YiGL6JODiUeMzkqQzbCG3At81Gg==", + "optional": true + }, + "@rollup/rollup-linux-arm-gnueabihf": { + "version": "4.13.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.13.0.tgz", + "integrity": "sha512-8wZidaUJUTIR5T4vRS22VkSMOVooG0F4N+JSwQXWSRiC6yfEsFMLTYRFHvby5mFFuExHa/yAp9juSphQQJAijQ==", + "optional": true + }, + "@rollup/rollup-linux-arm64-gnu": { + "version": "4.13.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.13.0.tgz", + "integrity": "sha512-Iu0Kno1vrD7zHQDxOmvweqLkAzjxEVqNhUIXBsZ8hu8Oak7/5VTPrxOEZXYC1nmrBVJp0ZcL2E7lSuuOVaE3+w==", + "optional": true + }, + "@rollup/rollup-linux-arm64-musl": { + "version": "4.13.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.13.0.tgz", + "integrity": "sha512-C31QrW47llgVyrRjIwiOwsHFcaIwmkKi3PCroQY5aVq4H0A5v/vVVAtFsI1nfBngtoRpeREvZOkIhmRwUKkAdw==", + "optional": true + }, + "@rollup/rollup-linux-riscv64-gnu": { + "version": "4.13.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.13.0.tgz", + "integrity": "sha512-Oq90dtMHvthFOPMl7pt7KmxzX7E71AfyIhh+cPhLY9oko97Zf2C9tt/XJD4RgxhaGeAraAXDtqxvKE1y/j35lA==", + "optional": true + }, + "@rollup/rollup-linux-x64-gnu": { + "version": "4.13.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.13.0.tgz", + "integrity": "sha512-yUD/8wMffnTKuiIsl6xU+4IA8UNhQ/f1sAnQebmE/lyQ8abjsVyDkyRkWop0kdMhKMprpNIhPmYlCxgHrPoXoA==", + "optional": true + }, + "@rollup/rollup-linux-x64-musl": { + "version": "4.13.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.13.0.tgz", + "integrity": "sha512-9RyNqoFNdF0vu/qqX63fKotBh43fJQeYC98hCaf89DYQpv+xu0D8QFSOS0biA7cGuqJFOc1bJ+m2rhhsKcw1hw==", + "optional": true + }, + "@rollup/rollup-win32-arm64-msvc": { + "version": "4.13.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.13.0.tgz", + "integrity": "sha512-46ue8ymtm/5PUU6pCvjlic0z82qWkxv54GTJZgHrQUuZnVH+tvvSP0LsozIDsCBFO4VjJ13N68wqrKSeScUKdA==", + "optional": true + }, + "@rollup/rollup-win32-ia32-msvc": { + "version": "4.13.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.13.0.tgz", + "integrity": "sha512-P5/MqLdLSlqxbeuJ3YDeX37srC8mCflSyTrUsgbU1c/U9j6l2g2GiIdYaGD9QjdMQPMSgYm7hgg0551wHyIluw==", + "optional": true + }, + "@rollup/rollup-win32-x64-msvc": { + "version": "4.13.0", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.13.0.tgz", + "integrity": "sha512-UKXUQNbO3DOhzLRwHSpa0HnhhCgNODvfoPWv2FCXme8N/ANFfhIPMGuOT+QuKd16+B5yxZ0HdpNlqPvTMS1qfw==", + "optional": true + }, + "@schematics/angular": { + "version": "17.3.1", + "resolved": "https://registry.npmjs.org/@schematics/angular/-/angular-17.3.1.tgz", + "integrity": "sha512-B3TkpjDjZhxX+tUc2ySEHU33x82Da0sssq/EMqQ1PQBHeRMa0ecyCeExjFEs2y57ZuC+QeVTaUt+TW45lLSjQw==", + "requires": { + "@angular-devkit/core": "17.3.1", + "@angular-devkit/schematics": "17.3.1", + "jsonc-parser": "3.2.1" + } + }, + "@sideway/address": { + "version": "4.1.4", + "resolved": "https://registry.npmjs.org/@sideway/address/-/address-4.1.4.tgz", + "integrity": "sha512-7vwq+rOHVWjyXxVlR76Agnvhy8I9rpzjosTESvmhNeXOXdZZB15Fl+TI9x1SiHZH5Jv2wTGduSxFDIaq0m3DUw==", + "optional": true, + "requires": { + "@hapi/hoek": "^9.0.0" + } + }, + "@sideway/formula": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/@sideway/formula/-/formula-3.0.1.tgz", + "integrity": "sha512-/poHZJJVjx3L+zVD6g9KgHfYnb443oi7wLu/XKojDviHy6HOEOA6z1Trk5aR1dGcmPenJEgb2sK2I80LeS3MIg==", + "optional": true + }, + "@sideway/pinpoint": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@sideway/pinpoint/-/pinpoint-2.0.0.tgz", + "integrity": "sha512-RNiOoTPkptFtSVzQevY/yWtZwf/RxyVnPy/OcA9HBM3MlGDnBEYL5B41H0MTn0Uec8Hi+2qUtTfG2WWZBmMejQ==", + "optional": true + }, + "@sigstore/bundle": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/@sigstore/bundle/-/bundle-2.2.0.tgz", + "integrity": "sha512-5VI58qgNs76RDrwXNhpmyN/jKpq9evV/7f1XrcqcAfvxDl5SeVY/I5Rmfe96ULAV7/FK5dge9RBKGBJPhL1WsQ==", + "requires": { + "@sigstore/protobuf-specs": "^0.3.0" + } + }, + "@sigstore/core": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/@sigstore/core/-/core-1.0.0.tgz", + "integrity": "sha512-dW2qjbWLRKGu6MIDUTBuJwXCnR8zivcSpf5inUzk7y84zqy/dji0/uahppoIgMoKeR+6pUZucrwHfkQQtiG9Rw==" + }, + "@sigstore/protobuf-specs": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/@sigstore/protobuf-specs/-/protobuf-specs-0.3.0.tgz", + "integrity": "sha512-zxiQ66JFOjVvP9hbhGj/F/qNdsZfkGb/dVXSanNRNuAzMlr4MC95voPUBX8//ZNnmv3uSYzdfR/JSkrgvZTGxA==" + }, + "@sigstore/sign": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/@sigstore/sign/-/sign-2.2.3.tgz", + "integrity": "sha512-LqlA+ffyN02yC7RKszCdMTS6bldZnIodiox+IkT8B2f8oRYXCB3LQ9roXeiEL21m64CVH1wyveYAORfD65WoSw==", + "requires": { + "@sigstore/bundle": "^2.2.0", + "@sigstore/core": "^1.0.0", + "@sigstore/protobuf-specs": "^0.3.0", + "make-fetch-happen": "^13.0.0" + } + }, + "@sigstore/tuf": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/@sigstore/tuf/-/tuf-2.3.1.tgz", + "integrity": "sha512-9Iv40z652td/QbV0o5n/x25H9w6IYRt2pIGbTX55yFDYlApDQn/6YZomjz6+KBx69rXHLzHcbtTS586mDdFD+Q==", + "requires": { + "@sigstore/protobuf-specs": "^0.3.0", + "tuf-js": "^2.2.0" + } + }, + "@sigstore/verify": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@sigstore/verify/-/verify-1.1.0.tgz", + "integrity": "sha512-1fTqnqyTBWvV7cftUUFtDcHPdSox0N3Ub7C0lRyReYx4zZUlNTZjCV+HPy4Lre+r45dV7Qx5JLKvqqsgxuyYfg==", + "requires": { + "@sigstore/bundle": "^2.2.0", + "@sigstore/core": "^1.0.0", + "@sigstore/protobuf-specs": "^0.3.0" + } + }, + "@sinonjs/commons": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-3.0.0.tgz", + "integrity": "sha512-jXBtWAF4vmdNmZgD5FoKsVLv3rPgDnLgPbU84LIJ3otV44vJlDRokVng5v8NFJdCf/da9legHcKaRuZs4L7faA==", + "optional": true, + "requires": { + "type-detect": "4.0.8" + } + }, + "@sinonjs/fake-timers": { + "version": "11.2.2", + "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-11.2.2.tgz", + "integrity": "sha512-G2piCSxQ7oWOxwGSAyFHfPIsyeJGXYtc6mFbnFA+kRXkiEnTl8c/8jul2S329iFBnDI9HGoeWWAZvuvOkZccgw==", + "optional": true, + "requires": { + "@sinonjs/commons": "^3.0.0" + } + }, + "@sinonjs/samsam": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/@sinonjs/samsam/-/samsam-8.0.0.tgz", + "integrity": "sha512-Bp8KUVlLp8ibJZrnvq2foVhP0IVX2CIprMJPK0vqGqgrDa0OHVKeZyBykqskkrdxV6yKBPmGasO8LVjAKR3Gew==", + "optional": true, + "requires": { + "@sinonjs/commons": "^2.0.0", + "lodash.get": "^4.4.2", + "type-detect": "^4.0.8" + }, + "dependencies": { + "@sinonjs/commons": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-2.0.0.tgz", + "integrity": "sha512-uLa0j859mMrg2slwQYdO/AkrOfmH+X6LTVmNTS9CqexuE2IvVORIkSpJLqePAbEnKJ77aMmCwr1NUZ57120Xcg==", + "optional": true, + "requires": { + "type-detect": "4.0.8" + } + } + } + }, + "@sinonjs/text-encoding": { + "version": "0.7.2", + "resolved": "https://registry.npmjs.org/@sinonjs/text-encoding/-/text-encoding-0.7.2.tgz", + "integrity": "sha512-sXXKG+uL9IrKqViTtao2Ws6dy0znu9sOaP1di/jKGW1M6VssO8vlpXCQcpZ+jisQ1tTFAC5Jo/EOzFbggBagFQ==", + "optional": true + }, + "@socket.io/component-emitter": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/@socket.io/component-emitter/-/component-emitter-3.1.0.tgz", + "integrity": "sha512-+9jVqKhRSpsc591z5vX+X5Yyw+he/HCB4iQ/RYxw35CEPaY1gnsNE43nf9n9AaYjAQrTiI/mOwKUKdUs9vf7Xg==", + "devOptional": true + }, + "@tsconfig/node10": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.9.tgz", + "integrity": "sha512-jNsYVVxU8v5g43Erja32laIDHXeoNvFEpX33OK4d6hljo3jDhCBDhx5dhCCTMWUojscpAagGiRkBKxpdl9fxqA==", + "dev": true + }, + "@tsconfig/node12": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.11.tgz", + "integrity": "sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==", + "dev": true + }, + "@tsconfig/node14": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.3.tgz", + "integrity": "sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==", + "dev": true + }, + "@tsconfig/node16": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.3.tgz", + "integrity": "sha512-yOlFc+7UtL/89t2ZhjPvvB/DeAr3r+Dq58IgzsFkOAvVC6NMJXmCGjbptdXdR9qsX7pKcTL+s87FtYREi2dEEQ==", + "dev": true + }, + "@tufjs/canonical-json": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@tufjs/canonical-json/-/canonical-json-2.0.0.tgz", + "integrity": "sha512-yVtV8zsdo8qFHe+/3kw81dSLyF7D576A5cCFCi4X7B39tWT7SekaEFUnvnWJHz+9qO7qJTah1JbrDjWKqFtdWA==" + }, + "@tufjs/models": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@tufjs/models/-/models-2.0.0.tgz", + "integrity": "sha512-c8nj8BaOExmZKO2DXhDfegyhSGcG9E/mPN3U13L+/PsoWm1uaGiHHjxqSHQiasDBQwDA3aHuw9+9spYAP1qvvg==", + "requires": { + "@tufjs/canonical-json": "2.0.0", + "minimatch": "^9.0.3" + }, + "dependencies": { + "brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "requires": { + "balanced-match": "^1.0.0" + } + }, + "minimatch": { + "version": "9.0.3", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.3.tgz", + "integrity": "sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==", + "requires": { + "brace-expansion": "^2.0.1" + } + } + } + }, + "@types/babel__core": { + "version": "7.20.5", + "resolved": "https://registry.npmjs.org/@types/babel__core/-/babel__core-7.20.5.tgz", + "integrity": "sha512-qoQprZvz5wQFJwMDqeseRXWv3rqMvhgpbXFfVyWhbx9X47POIA6i/+dXefEmZKoAgOaTdaIgNSMqMIU61yRyzA==", + "requires": { + "@babel/parser": "^7.20.7", + "@babel/types": "^7.20.7", + "@types/babel__generator": "*", + "@types/babel__template": "*", + "@types/babel__traverse": "*" + } + }, + "@types/babel__generator": { + "version": "7.6.8", + "resolved": "https://registry.npmjs.org/@types/babel__generator/-/babel__generator-7.6.8.tgz", + "integrity": "sha512-ASsj+tpEDsEiFr1arWrlN6V3mdfjRMZt6LtK/Vp/kreFLnr5QH5+DhvD5nINYZXzwJvXeGq+05iUXcAzVrqWtw==", + "requires": { + "@babel/types": "^7.0.0" + } + }, + "@types/babel__template": { + "version": "7.4.4", + "resolved": "https://registry.npmjs.org/@types/babel__template/-/babel__template-7.4.4.tgz", + "integrity": "sha512-h/NUaSyG5EyxBIp8YRxo4RMe2/qQgvyowRwVMzhYhBCONbW8PUsg4lkFMrhgZhUe5z3L3MiLDuvyJ/CaPa2A8A==", + "requires": { + "@babel/parser": "^7.1.0", + "@babel/types": "^7.0.0" + } + }, + "@types/babel__traverse": { + "version": "7.20.5", + "resolved": "https://registry.npmjs.org/@types/babel__traverse/-/babel__traverse-7.20.5.tgz", + "integrity": "sha512-WXCyOcRtH37HAUkpXhUduaxdm82b4GSlyTqajXviN4EfiuPgNYR109xMCKvpl6zPIpua0DGlMEDCq+g8EdoheQ==", + "requires": { + "@babel/types": "^7.20.7" + } + }, + "@types/body-parser": { + "version": "1.19.0", + "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.0.tgz", + "integrity": "sha512-W98JrE0j2K78swW4ukqMleo8R7h/pFETjM2DQ90MF6XK2i4LO4W3gQ71Lt4w3bfm2EvVSyWHplECvB5sK22yFQ==", + "requires": { + "@types/connect": "*", + "@types/node": "*" + } + }, + "@types/bonjour": { + "version": "3.5.13", + "resolved": "https://registry.npmjs.org/@types/bonjour/-/bonjour-3.5.13.tgz", + "integrity": "sha512-z9fJ5Im06zvUL548KvYNecEVlA7cVDkGUi6kZusb04mpyEFKCIZJvloCcmpmLaIahDpOQGHaHmG6imtPMmPXGQ==", + "requires": { + "@types/node": "*" + } + }, + "@types/connect": { + "version": "3.4.33", + "resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.33.tgz", + "integrity": "sha512-2+FrkXY4zllzTNfJth7jOqEHC+enpLeGslEhpnTAkg21GkRrWV4SsAtqchtT4YS9/nODBU2/ZfsBY2X4J/dX7A==", + "requires": { + "@types/node": "*" + } + }, + "@types/connect-history-api-fallback": { + "version": "1.5.4", + "resolved": "https://registry.npmjs.org/@types/connect-history-api-fallback/-/connect-history-api-fallback-1.5.4.tgz", + "integrity": "sha512-n6Cr2xS1h4uAulPRdlw6Jl6s1oG8KrVilPN2yUITEs+K48EzMJJ3W1xy8K5eWuFvjp3R74AOIGSmp2UfBJ8HFw==", + "requires": { + "@types/express-serve-static-core": "*", + "@types/node": "*" + } + }, + "@types/cookie": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/@types/cookie/-/cookie-0.4.1.tgz", + "integrity": "sha512-XW/Aa8APYr6jSVVA1y/DEIZX0/GMKLEVekNG727R8cs56ahETkRAy/3DR7+fJyh7oUgGwNQaRfXCun0+KbWY7Q==", + "devOptional": true + }, + "@types/cors": { + "version": "2.8.13", + "resolved": "https://registry.npmjs.org/@types/cors/-/cors-2.8.13.tgz", + "integrity": "sha512-RG8AStHlUiV5ysZQKq97copd2UmVYw3/pRMLefISZ3S1hK104Cwm7iLQ3fTKx+lsUH2CE8FlLaYeEA2LSeqYUA==", + "devOptional": true, + "requires": { + "@types/node": "*" + } + }, + "@types/cypress": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/@types/cypress/-/cypress-1.1.3.tgz", + "integrity": "sha512-OXe0Gw8LeCflkG1oPgFpyrYWJmEKqYncBsD/J0r17r0ETx/TnIGDNLwXt/pFYSYuYTpzcq1q3g62M9DrfsBL4g==", + "optional": true, + "requires": { + "cypress": "*" + } + }, + "@types/eslint": { + "version": "8.4.1", + "resolved": "https://registry.npmjs.org/@types/eslint/-/eslint-8.4.1.tgz", + "integrity": "sha512-GE44+DNEyxxh2Kc6ro/VkIj+9ma0pO0bwv9+uHSyBrikYOHr8zYcdPvnBOp1aw8s+CjRvuSx7CyWqRrNFQ59mA==", + "requires": { + "@types/estree": "*", + "@types/json-schema": "*" + } + }, + "@types/eslint-scope": { + "version": "3.7.3", + "resolved": "https://registry.npmjs.org/@types/eslint-scope/-/eslint-scope-3.7.3.tgz", + "integrity": "sha512-PB3ldyrcnAicT35TWPs5IcwKD8S333HMaa2VVv4+wdvebJkjWuW/xESoB8IwRcog8HYVYamb1g/R31Qv5Bx03g==", + "requires": { + "@types/eslint": "*", + "@types/estree": "*" + } + }, + "@types/estree": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/@types/estree/-/estree-1.0.5.tgz", + "integrity": "sha512-/kYRxGDLWzHOB7q+wtSUQlFrtcdUccpfy+X+9iMBpHK8QLLhx2wIPYuS5DYtR9Wa/YlZAbIovy7qVdB1Aq6Lyw==" + }, + "@types/express": { + "version": "4.17.13", + "resolved": "https://registry.npmjs.org/@types/express/-/express-4.17.13.tgz", + "integrity": "sha512-6bSZTPaTIACxn48l50SR+axgrqm6qXFIxrdAKaG6PaJk3+zuUr35hBlgT7vOmJcum+OEaIBLtHV/qloEAFITeA==", + "requires": { + "@types/body-parser": "*", + "@types/express-serve-static-core": "^4.17.18", + "@types/qs": "*", + "@types/serve-static": "*" + } + }, + "@types/express-serve-static-core": { + "version": "4.17.28", + "resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-4.17.28.tgz", + "integrity": "sha512-P1BJAEAW3E2DJUlkgq4tOL3RyMunoWXqbSCygWo5ZIWTjUgN1YnaXWW4VWl/oc8vs/XoYibEGBKP0uZyF4AHig==", + "requires": { + "@types/node": "*", + "@types/qs": "*", + "@types/range-parser": "*" + } + }, + "@types/http-proxy": { + "version": "1.17.8", + "resolved": "https://registry.npmjs.org/@types/http-proxy/-/http-proxy-1.17.8.tgz", + "integrity": "sha512-5kPLG5BKpWYkw/LVOGWpiq3nEVqxiN32rTgI53Sk12/xHFQ2rG3ehI9IO+O3W2QoKeyB92dJkoka8SUm6BX1pA==", + "requires": { + "@types/node": "*" + } + }, + "@types/json-schema": { + "version": "7.0.15", + "resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.15.tgz", + "integrity": "sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA==" + }, + "@types/mime": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/@types/mime/-/mime-2.0.3.tgz", + "integrity": "sha512-Jus9s4CDbqwocc5pOAnh8ShfrnMcPHuJYzVcSUU7lrh8Ni5HuIqX3oilL86p3dlTrk0LzHRCgA/GQ7uNCw6l2Q==" + }, + "@types/node": { + "version": "18.17.18", + "resolved": "https://registry.npmjs.org/@types/node/-/node-18.17.18.tgz", + "integrity": "sha512-/4QOuy3ZpV7Ya1GTRz5CYSz3DgkKpyUptXuQ5PPce7uuyJAOR7r9FhkmxJfvcNUXyklbC63a+YvB3jxy7s9ngw==" + }, + "@types/node-forge": { + "version": "1.3.11", + "resolved": "https://registry.npmjs.org/@types/node-forge/-/node-forge-1.3.11.tgz", + "integrity": "sha512-FQx220y22OKNTqaByeBGqHWYz4cl94tpcxeFdvBo3wjG6XPBuZ0BNgNZRV5J5TFmmcsJ4IzsLkmGRiQbnYsBEQ==", + "requires": { + "@types/node": "*" + } + }, + "@types/qrcode": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/@types/qrcode/-/qrcode-1.5.0.tgz", + "integrity": "sha512-x5ilHXRxUPIMfjtM+1vf/GPTRWZ81nqscursm5gMznJeK9M0YnZ1c3bEvRLQ0zSSgedLx1J6MGL231ObQGGhaA==", + "requires": { + "@types/node": "*" + } + }, + "@types/qs": { + "version": "6.9.5", + "resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.9.5.tgz", + "integrity": "sha512-/JHkVHtx/REVG0VVToGRGH2+23hsYLHdyG+GrvoUGlGAd0ErauXDyvHtRI/7H7mzLm+tBCKA7pfcpkQ1lf58iQ==" + }, + "@types/range-parser": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.3.tgz", + "integrity": "sha512-ewFXqrQHlFsgc09MK5jP5iR7vumV/BYayNC6PgJO2LPe8vrnNFyjQjSppfEngITi0qvfKtzFvgKymGheFM9UOA==" + }, + "@types/retry": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/@types/retry/-/retry-0.12.0.tgz", + "integrity": "sha512-wWKOClTTiizcZhXnPY4wikVAwmdYHp8q6DmC+EJUzAMsycb7HB32Kh9RN4+0gExjmPmZSAQjgURXIGATPegAvA==" + }, + "@types/semver": { + "version": "7.5.8", + "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.5.8.tgz", + "integrity": "sha512-I8EUhyrgfLrcTkzV3TSsGyl1tSuPrEDzr0yd5m90UgNxQkyDXULk3b6MlQqTCpZpNtWe1K0hzclnZkTcLBe2UQ==", + "dev": true + }, + "@types/serve-index": { + "version": "1.9.4", + "resolved": "https://registry.npmjs.org/@types/serve-index/-/serve-index-1.9.4.tgz", + "integrity": "sha512-qLpGZ/c2fhSs5gnYsQxtDEq3Oy8SXPClIXkW5ghvAvsNuVSA8k+gCONcUCS/UjLEYvYps+e8uBtfgXgvhwfNug==", + "requires": { + "@types/express": "*" + } + }, + "@types/serve-static": { + "version": "1.15.0", + "resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.15.0.tgz", + "integrity": "sha512-z5xyF6uh8CbjAu9760KDKsH2FcDxZ2tFCsA4HIMWE6IkiYMXfVoa+4f9KX+FN0ZLsaMw1WNG2ETLA6N+/YA+cg==", + "requires": { + "@types/mime": "*", + "@types/node": "*" + } + }, + "@types/sinonjs__fake-timers": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/@types/sinonjs__fake-timers/-/sinonjs__fake-timers-8.1.1.tgz", + "integrity": "sha512-0kSuKjAS0TrGLJ0M/+8MaFkGsQhZpB6pxOmvS3K8FYI72K//YmdfoW9X2qPsAKh1mkwxGD5zib9s1FIFed6E8g==", + "optional": true + }, + "@types/sizzle": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/@types/sizzle/-/sizzle-2.3.2.tgz", + "integrity": "sha512-7EJYyKTL7tFR8+gDbB6Wwz/arpGa0Mywk1TJbNzKzHtzbwVmY4HR9WqS5VV7dsBUKQmPNr192jHr/VpBluj/hg==", + "optional": true + }, + "@types/sockjs": { + "version": "0.3.36", + "resolved": "https://registry.npmjs.org/@types/sockjs/-/sockjs-0.3.36.tgz", + "integrity": "sha512-MK9V6NzAS1+Ud7JV9lJLFqW85VbC9dq3LmwZCuBe4wBDgKC0Kj/jd8Xl+nSviU+Qc3+m7umHHyHg//2KSa0a0Q==", + "requires": { + "@types/node": "*" + } + }, + "@types/ws": { + "version": "8.5.10", + "resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.5.10.tgz", + "integrity": "sha512-vmQSUcfalpIq0R9q7uTo2lXs6eGIpt9wtnLdMv9LVpIjCA/+ufZRozlVoVelIYixx1ugCBKDhn89vnsEGOCx9A==", + "requires": { + "@types/node": "*" + } + }, + "@types/yauzl": { + "version": "2.10.0", + "resolved": "https://registry.npmjs.org/@types/yauzl/-/yauzl-2.10.0.tgz", + "integrity": "sha512-Cn6WYCm0tXv8p6k+A8PvbDG763EDpBoTzHdA+Q/MF6H3sapGjCm9NzoaJncJS9tUKSuCoDs9XHxYYsQDgxR6kw==", + "optional": true, + "requires": { + "@types/node": "*" + } + }, + "@typescript-eslint/eslint-plugin": { + "version": "7.4.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-7.4.0.tgz", + "integrity": "sha512-yHMQ/oFaM7HZdVrVm/M2WHaNPgyuJH4WelkSVEWSSsir34kxW2kDJCxlXRhhGWEsMN0WAW/vLpKfKVcm8k+MPw==", + "dev": true, + "requires": { + "@eslint-community/regexpp": "^4.5.1", + "@typescript-eslint/scope-manager": "7.4.0", + "@typescript-eslint/type-utils": "7.4.0", + "@typescript-eslint/utils": "7.4.0", + "@typescript-eslint/visitor-keys": "7.4.0", + "debug": "^4.3.4", + "graphemer": "^1.4.0", + "ignore": "^5.2.4", + "natural-compare": "^1.4.0", + "semver": "^7.5.4", + "ts-api-utils": "^1.0.1" + } + }, + "@typescript-eslint/parser": { + "version": "7.4.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-7.4.0.tgz", + "integrity": "sha512-ZvKHxHLusweEUVwrGRXXUVzFgnWhigo4JurEj0dGF1tbcGh6buL+ejDdjxOQxv6ytcY1uhun1p2sm8iWStlgLQ==", + "dev": true, + "requires": { + "@typescript-eslint/scope-manager": "7.4.0", + "@typescript-eslint/types": "7.4.0", + "@typescript-eslint/typescript-estree": "7.4.0", + "@typescript-eslint/visitor-keys": "7.4.0", + "debug": "^4.3.4" + } + }, + "@typescript-eslint/scope-manager": { + "version": "7.4.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-7.4.0.tgz", + "integrity": "sha512-68VqENG5HK27ypafqLVs8qO+RkNc7TezCduYrx8YJpXq2QGZ30vmNZGJJJC48+MVn4G2dCV8m5ZTVnzRexTVtw==", + "dev": true, + "requires": { + "@typescript-eslint/types": "7.4.0", + "@typescript-eslint/visitor-keys": "7.4.0" + } + }, + "@typescript-eslint/type-utils": { + "version": "7.4.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-7.4.0.tgz", + "integrity": "sha512-247ETeHgr9WTRMqHbbQdzwzhuyaJ8dPTuyuUEMANqzMRB1rj/9qFIuIXK7l0FX9i9FXbHeBQl/4uz6mYuCE7Aw==", + "dev": true, + "requires": { + "@typescript-eslint/typescript-estree": "7.4.0", + "@typescript-eslint/utils": "7.4.0", + "debug": "^4.3.4", + "ts-api-utils": "^1.0.1" + } + }, + "@typescript-eslint/types": { + "version": "7.4.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.4.0.tgz", + "integrity": "sha512-mjQopsbffzJskos5B4HmbsadSJQWaRK0UxqQ7GuNA9Ga4bEKeiO6b2DnB6cM6bpc8lemaPseh0H9B/wyg+J7rw==", + "dev": true + }, + "@typescript-eslint/typescript-estree": { + "version": "7.4.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-7.4.0.tgz", + "integrity": "sha512-A99j5AYoME/UBQ1ucEbbMEmGkN7SE0BvZFreSnTd1luq7yulcHdyGamZKizU7canpGDWGJ+Q6ZA9SyQobipePg==", + "dev": true, + "requires": { + "@typescript-eslint/types": "7.4.0", + "@typescript-eslint/visitor-keys": "7.4.0", + "debug": "^4.3.4", + "globby": "^11.1.0", + "is-glob": "^4.0.3", + "minimatch": "9.0.3", + "semver": "^7.5.4", + "ts-api-utils": "^1.0.1" + }, + "dependencies": { + "brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "dev": true, + "requires": { + "balanced-match": "^1.0.0" + } + }, + "globby": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", + "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", + "dev": true, + "requires": { + "array-union": "^2.1.0", + "dir-glob": "^3.0.1", + "fast-glob": "^3.2.9", + "ignore": "^5.2.0", + "merge2": "^1.4.1", + "slash": "^3.0.0" + } + }, + "minimatch": { + "version": "9.0.3", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.3.tgz", + "integrity": "sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==", + "dev": true, + "requires": { + "brace-expansion": "^2.0.1" + } + }, + "slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "dev": true + } + } + }, + "@typescript-eslint/utils": { + "version": "7.4.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-7.4.0.tgz", + "integrity": "sha512-NQt9QLM4Tt8qrlBVY9lkMYzfYtNz8/6qwZg8pI3cMGlPnj6mOpRxxAm7BMJN9K0AiY+1BwJ5lVC650YJqYOuNg==", + "dev": true, + "requires": { + "@eslint-community/eslint-utils": "^4.4.0", + "@types/json-schema": "^7.0.12", + "@types/semver": "^7.5.0", + "@typescript-eslint/scope-manager": "7.4.0", + "@typescript-eslint/types": "7.4.0", + "@typescript-eslint/typescript-estree": "7.4.0", + "semver": "^7.5.4" + } + }, + "@typescript-eslint/visitor-keys": { + "version": "7.4.0", + "resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-7.4.0.tgz", + "integrity": "sha512-0zkC7YM0iX5Y41homUUeW1CHtZR01K3ybjM1l6QczoMuay0XKtrb93kv95AxUGwdjGr64nNqnOCwmEl616N8CA==", + "dev": true, + "requires": { + "@typescript-eslint/types": "7.4.0", + "eslint-visitor-keys": "^3.4.1" + } + }, + "@ungap/structured-clone": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@ungap/structured-clone/-/structured-clone-1.2.0.tgz", + "integrity": "sha512-zuVdFrMJiuCDQUMCzQaD6KL28MjnqqN8XnAqiEq9PNm/hCPTSGfrXCOfwj1ow4LFb/tNymJPwsNbVePc1xFqrQ==", + "dev": true + }, + "@vitejs/plugin-basic-ssl": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@vitejs/plugin-basic-ssl/-/plugin-basic-ssl-1.1.0.tgz", + "integrity": "sha512-wO4Dk/rm8u7RNhOf95ZzcEmC9rYOncYgvq4z3duaJrCgjN8BxAnDVyndanfcJZ0O6XZzHz6Q0hTimxTg8Y9g/A==", + "requires": {} + }, + "@webassemblyjs/ast": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.11.6.tgz", + "integrity": "sha512-IN1xI7PwOvLPgjcf180gC1bqn3q/QaOCwYUahIOhbYUu8KA/3tw2RT/T0Gidi1l7Hhj5D/INhJxiICObqpMu4Q==", + "requires": { + "@webassemblyjs/helper-numbers": "1.11.6", + "@webassemblyjs/helper-wasm-bytecode": "1.11.6" + } + }, + "@webassemblyjs/floating-point-hex-parser": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.11.6.tgz", + "integrity": "sha512-ejAj9hfRJ2XMsNHk/v6Fu2dGS+i4UaXBXGemOfQ/JfQ6mdQg/WXtwleQRLLS4OvfDhv8rYnVwH27YJLMyYsxhw==" + }, + "@webassemblyjs/helper-api-error": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-api-error/-/helper-api-error-1.11.6.tgz", + "integrity": "sha512-o0YkoP4pVu4rN8aTJgAyj9hC2Sv5UlkzCHhxqWj8butaLvnpdc2jOwh4ewE6CX0txSfLn/UYaV/pheS2Txg//Q==" + }, + "@webassemblyjs/helper-buffer": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-buffer/-/helper-buffer-1.11.6.tgz", + "integrity": "sha512-z3nFzdcp1mb8nEOFFk8DrYLpHvhKC3grJD2ardfKOzmbmJvEf/tPIqCY+sNcwZIY8ZD7IkB2l7/pqhUhqm7hLA==" + }, + "@webassemblyjs/helper-numbers": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-numbers/-/helper-numbers-1.11.6.tgz", + "integrity": "sha512-vUIhZ8LZoIWHBohiEObxVm6hwP034jwmc9kuq5GdHZH0wiLVLIPcMCdpJzG4C11cHoQ25TFIQj9kaVADVX7N3g==", + "requires": { + "@webassemblyjs/floating-point-hex-parser": "1.11.6", + "@webassemblyjs/helper-api-error": "1.11.6", + "@xtuc/long": "4.2.2" + } + }, + "@webassemblyjs/helper-wasm-bytecode": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.11.6.tgz", + "integrity": "sha512-sFFHKwcmBprO9e7Icf0+gddyWYDViL8bpPjJJl0WHxCdETktXdmtWLGVzoHbqUcY4Be1LkNfwTmXOJUFZYSJdA==" + }, + "@webassemblyjs/helper-wasm-section": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.11.6.tgz", + "integrity": "sha512-LPpZbSOwTpEC2cgn4hTydySy1Ke+XEu+ETXuoyvuyezHO3Kjdu90KK95Sh9xTbmjrCsUwvWwCOQQNta37VrS9g==", + "requires": { + "@webassemblyjs/ast": "1.11.6", + "@webassemblyjs/helper-buffer": "1.11.6", + "@webassemblyjs/helper-wasm-bytecode": "1.11.6", + "@webassemblyjs/wasm-gen": "1.11.6" + } + }, + "@webassemblyjs/ieee754": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/ieee754/-/ieee754-1.11.6.tgz", + "integrity": "sha512-LM4p2csPNvbij6U1f19v6WR56QZ8JcHg3QIJTlSwzFcmx6WSORicYj6I63f9yU1kEUtrpG+kjkiIAkevHpDXrg==", + "requires": { + "@xtuc/ieee754": "^1.2.0" + } + }, + "@webassemblyjs/leb128": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/leb128/-/leb128-1.11.6.tgz", + "integrity": "sha512-m7a0FhE67DQXgouf1tbN5XQcdWoNgaAuoULHIfGFIEVKA6tu/edls6XnIlkmS6FrXAquJRPni3ZZKjw6FSPjPQ==", + "requires": { + "@xtuc/long": "4.2.2" + } + }, + "@webassemblyjs/utf8": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/utf8/-/utf8-1.11.6.tgz", + "integrity": "sha512-vtXf2wTQ3+up9Zsg8sa2yWiQpzSsMyXj0qViVP6xKGCUT8p8YJ6HqI7l5eCnWx1T/FYdsv07HQs2wTFbbof/RA==" + }, + "@webassemblyjs/wasm-edit": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-edit/-/wasm-edit-1.11.6.tgz", + "integrity": "sha512-Ybn2I6fnfIGuCR+Faaz7YcvtBKxvoLV3Lebn1tM4o/IAJzmi9AWYIPWpyBfU8cC+JxAO57bk4+zdsTjJR+VTOw==", + "requires": { + "@webassemblyjs/ast": "1.11.6", + "@webassemblyjs/helper-buffer": "1.11.6", + "@webassemblyjs/helper-wasm-bytecode": "1.11.6", + "@webassemblyjs/helper-wasm-section": "1.11.6", + "@webassemblyjs/wasm-gen": "1.11.6", + "@webassemblyjs/wasm-opt": "1.11.6", + "@webassemblyjs/wasm-parser": "1.11.6", + "@webassemblyjs/wast-printer": "1.11.6" + } + }, + "@webassemblyjs/wasm-gen": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-gen/-/wasm-gen-1.11.6.tgz", + "integrity": "sha512-3XOqkZP/y6B4F0PBAXvI1/bky7GryoogUtfwExeP/v7Nzwo1QLcq5oQmpKlftZLbT+ERUOAZVQjuNVak6UXjPA==", + "requires": { + "@webassemblyjs/ast": "1.11.6", + "@webassemblyjs/helper-wasm-bytecode": "1.11.6", + "@webassemblyjs/ieee754": "1.11.6", + "@webassemblyjs/leb128": "1.11.6", + "@webassemblyjs/utf8": "1.11.6" + } + }, + "@webassemblyjs/wasm-opt": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-opt/-/wasm-opt-1.11.6.tgz", + "integrity": "sha512-cOrKuLRE7PCe6AsOVl7WasYf3wbSo4CeOk6PkrjS7g57MFfVUF9u6ysQBBODX0LdgSvQqRiGz3CXvIDKcPNy4g==", + "requires": { + "@webassemblyjs/ast": "1.11.6", + "@webassemblyjs/helper-buffer": "1.11.6", + "@webassemblyjs/wasm-gen": "1.11.6", + "@webassemblyjs/wasm-parser": "1.11.6" + } + }, + "@webassemblyjs/wasm-parser": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-parser/-/wasm-parser-1.11.6.tgz", + "integrity": "sha512-6ZwPeGzMJM3Dqp3hCsLgESxBGtT/OeCvCZ4TA1JUPYgmhAx38tTPR9JaKy0S5H3evQpO/h2uWs2j6Yc/fjkpTQ==", + "requires": { + "@webassemblyjs/ast": "1.11.6", + "@webassemblyjs/helper-api-error": "1.11.6", + "@webassemblyjs/helper-wasm-bytecode": "1.11.6", + "@webassemblyjs/ieee754": "1.11.6", + "@webassemblyjs/leb128": "1.11.6", + "@webassemblyjs/utf8": "1.11.6" + } + }, + "@webassemblyjs/wast-printer": { + "version": "1.11.6", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-printer/-/wast-printer-1.11.6.tgz", + "integrity": "sha512-JM7AhRcE+yW2GWYaKeHL5vt4xqee5N2WcezptmgyhNS+ScggqcT1OtXykhAb13Sn5Yas0j2uv9tHgrjwvzAP4A==", + "requires": { + "@webassemblyjs/ast": "1.11.6", + "@xtuc/long": "4.2.2" + } + }, + "@xtuc/ieee754": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@xtuc/ieee754/-/ieee754-1.2.0.tgz", + "integrity": "sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA==" + }, + "@xtuc/long": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/@xtuc/long/-/long-4.2.2.tgz", + "integrity": "sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==" + }, + "@yarnpkg/lockfile": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/@yarnpkg/lockfile/-/lockfile-1.1.0.tgz", + "integrity": "sha512-GpSwvyXOcOOlV70vbnzjj4fW5xW/FdUF6nQEt1ENy7m4ZCczi1+/buVUPAqmGfqznsORNFzUMjctTIp8a9tuCQ==" + }, + "abbrev": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-2.0.0.tgz", + "integrity": "sha512-6/mh1E2u2YgEsCHdY0Yx5oW+61gZU+1vXaoiHHrpKeuRNNgFvS+/jrwHiQhB5apAf5oB7UB7E19ol2R2LKH8hQ==" + }, + "accepts": { + "version": "1.3.8", + "resolved": "https://registry.npmjs.org/accepts/-/accepts-1.3.8.tgz", + "integrity": "sha512-PYAthTa2m2VKxuvSD3DPC/Gy+U+sOA1LAuT8mkmRuvw+NACSaeXEQ+NHcVF7rONl6qcaxV3Uuemwawk+7+SJLw==", + "requires": { + "mime-types": "~2.1.34", + "negotiator": "0.6.3" + } + }, + "acorn": { + "version": "7.4.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-7.4.1.tgz", + "integrity": "sha512-nQyp0o1/mNdbTO1PO6kHkwSrmgZ0MT/jCCpNiwbUjGoRN4dlBhqJtoQuCnEOKzgTVwg0ZWiCoQy6SxMebQVh8A==" + }, + "acorn-jsx": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/acorn-jsx/-/acorn-jsx-5.3.2.tgz", + "integrity": "sha512-rq9s+JNhf0IChjtDXxllJ7g41oZk5SlXtp0LHwyA5cejwn7vKmKp4pPri6YEePv2PU65sAsegbXtIinmDFDXgQ==", + "dev": true, + "requires": {} + }, + "acorn-node": { + "version": "1.8.2", + "resolved": "https://registry.npmjs.org/acorn-node/-/acorn-node-1.8.2.tgz", + "integrity": "sha512-8mt+fslDufLYntIoPAaIMUe/lrbrehIiwmR3t2k9LljIzoigEPF27eLk2hy8zSGzmR/ogr7zbRKINMo1u0yh5A==", + "requires": { + "acorn": "^7.0.0", + "acorn-walk": "^7.0.0", + "xtend": "^4.0.2" + } + }, + "acorn-walk": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-7.2.0.tgz", + "integrity": "sha512-OPdCF6GsMIP+Az+aWfAAOEt2/+iVDKE7oy6lJ098aoe59oAmK76qV6Gw60SbZ8jHuG2wH058GF4pLFbYamYrVA==" + }, + "adjust-sourcemap-loader": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/adjust-sourcemap-loader/-/adjust-sourcemap-loader-4.0.0.tgz", + "integrity": "sha512-OXwN5b9pCUXNQHJpwwD2qP40byEmSgzj8B4ydSN0uMNYWiFmJ6x6KwUllMmfk8Rwu/HJDFR7U8ubsWBoN0Xp0A==", + "requires": { + "loader-utils": "^2.0.0", + "regex-parser": "^2.2.11" + } + }, + "agent-base": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/agent-base/-/agent-base-7.1.0.tgz", + "integrity": "sha512-o/zjMZRhJxny7OyEF+Op8X+efiELC7k7yOjMzgfzVqOzXqkBkWI79YoTdOtsuWd5BWhAGAuOY/Xa6xpiaWXiNg==", + "requires": { + "debug": "^4.3.4" + } + }, + "aggregate-error": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/aggregate-error/-/aggregate-error-3.1.0.tgz", + "integrity": "sha512-4I7Td01quW/RpocfNayFdFVk1qSuoh0E7JrbRJ16nH01HhKFQ88INq9Sd+nd72zqRySlr9BmDA8xlEJ6vJMrYA==", + "requires": { + "clean-stack": "^2.0.0", + "indent-string": "^4.0.0" + } + }, + "ajv": { + "version": "6.12.6", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", + "integrity": "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g==", + "requires": { + "fast-deep-equal": "^3.1.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + } + }, + "ajv-formats": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ajv-formats/-/ajv-formats-2.1.1.tgz", + "integrity": "sha512-Wx0Kx52hxE7C18hkMEggYlEifqWZtYaRgouJor+WMdPnQyEK13vgEWyVNup7SoeeoLMsr4kf5h6dOW11I15MUA==", + "requires": { + "ajv": "^8.0.0" + }, + "dependencies": { + "ajv": { + "version": "8.11.2", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.11.2.tgz", + "integrity": "sha512-E4bfmKAhGiSTvMfL1Myyycaub+cUEU2/IvpylXkUu7CHBkBj1f/ikdzbD7YQ6FKUbixDxeYvB/xY4fvyroDlQg==", + "requires": { + "fast-deep-equal": "^3.1.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2", + "uri-js": "^4.2.2" + } + }, + "json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==" + } + } + }, + "ajv-keywords": { + "version": "3.5.2", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.5.2.tgz", + "integrity": "sha512-5p6WTN0DdTGVQk6VjcEju19IgaHudalcfabD7yhDGeA6bcQnmL+CpveLJq/3hvfwd1aof6L386Ougkx6RfyMIQ==", + "requires": {} + }, + "amdefine": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/amdefine/-/amdefine-1.0.1.tgz", + "integrity": "sha512-S2Hw0TtNkMJhIabBwIojKL9YHO5T0n5eNqWJ7Lrlel/zDbftQpxpapi8tZs3X1HWa+u+QeydGmzzNU0m09+Rcg==" + }, + "ansi-colors": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.3.tgz", + "integrity": "sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw==" + }, + "ansi-escapes": { + "version": "4.3.2", + "resolved": "https://registry.npmjs.org/ansi-escapes/-/ansi-escapes-4.3.2.tgz", + "integrity": "sha512-gKXj5ALrKWQLsYG9jlTRmR/xKluxHV+Z9QEwNIgCfM1/uwPMCuzVVnh5mwTd+OuBZcwSIMbqssNWRm1lE51QaQ==", + "requires": { + "type-fest": "^0.21.3" + } + }, + "ansi-html-community": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/ansi-html-community/-/ansi-html-community-0.0.8.tgz", + "integrity": "sha512-1APHAyr3+PCamwNw3bXCPp4HFLONZt/yIH0sZp0/469KWNTEy+qN5jQ3GVX6DMZ1UXAi34yVwtTeaG/HpBuuzw==" + }, + "ansi-regex": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz", + "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==" + }, + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "requires": { + "color-convert": "^1.9.0" + } + }, + "anymatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.2.tgz", + "integrity": "sha512-P43ePfOAIupkguHUycrc4qJ9kz8ZiuOUijaETwX7THt0Y/GNK7v0aa8rY816xWjZ7rJdA5XdMcpVFTKMq+RvWg==", + "requires": { + "normalize-path": "^3.0.0", + "picomatch": "^2.0.4" + } + }, + "arch": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/arch/-/arch-2.2.0.tgz", + "integrity": "sha512-Of/R0wqp83cgHozfIYLbBMnej79U/SVGOOyuB3VVFv1NRM/PSFMK12x9KVtiYzJqmnU5WR2qp0Z5rHb7sWGnFQ==", + "optional": true + }, + "arg": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz", + "integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==", + "dev": true + }, + "argparse": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-1.0.10.tgz", + "integrity": "sha512-o5Roy6tNG4SL/FOkCAN6RzjiakZS25RLYFrcMttJqbdd8BWrnA+fGz57iN5Pb06pvBGvl5gQ0B48dJlslXvoTg==", + "requires": { + "sprintf-js": "~1.0.2" + }, + "dependencies": { + "sprintf-js": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.0.3.tgz", + "integrity": "sha1-BOaSb2YolTVPPdAVIDYzuFcpfiw=" + } + } + }, + "array-filter": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/array-filter/-/array-filter-1.0.0.tgz", + "integrity": "sha1-uveeYubvTCpMC4MSMtr/7CUfnYM=" + }, + "array-flatten": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/array-flatten/-/array-flatten-1.1.1.tgz", + "integrity": "sha512-PCVAQswWemu6UdxsDFFX/+gVeYqKAod3D3UVm91jHwynguOwAvYPhx8nNlM++NqRcK6CxxpUafjmhIdKiHibqg==" + }, + "array-from": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/array-from/-/array-from-2.1.1.tgz", + "integrity": "sha1-z+nYwmYoudxa7MYqn12PHzUsEZU=" + }, + "array-union": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", + "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", + "dev": true + }, + "asn1": { + "version": "0.2.6", + "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.6.tgz", + "integrity": "sha512-ix/FxPn0MDjeyJ7i/yoHGFt/EX6LyNbxSEhPPXODPL+KB0VPk86UYfL0lMdy+KCnv+fmvIzySwaK5COwqVbWTQ==", + "optional": true, + "requires": { + "safer-buffer": "~2.1.0" + } + }, + "asn1.js": { + "version": "5.4.1", + "resolved": "https://registry.npmjs.org/asn1.js/-/asn1.js-5.4.1.tgz", + "integrity": "sha512-+I//4cYPccV8LdmBLiX8CYvf9Sp3vQsrqu2QNXRcrbiWvcx/UdlFiqUJJzxRQxgsZmvhXhn4cSKeSmoFjVdupA==", + "requires": { + "bn.js": "^4.0.0", + "inherits": "^2.0.1", + "minimalistic-assert": "^1.0.0", + "safer-buffer": "^2.1.0" + }, + "dependencies": { + "bn.js": { + "version": "4.12.0", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", + "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==" + } + } + }, + "assert": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/assert/-/assert-1.5.0.tgz", + "integrity": "sha512-EDsgawzwoun2CZkCgtxJbv392v4nbk9XDD06zI+kQYoBM/3RBWLlEyJARDOmhAAosBjWACEkKL6S+lIZtcAubA==", + "requires": { + "object-assign": "^4.1.1", + "util": "0.10.3" + }, + "dependencies": { + "inherits": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.1.tgz", + "integrity": "sha1-sX0I0ya0Qj5Wjv9xn5GwscvfafE=" + }, + "util": { + "version": "0.10.3", + "resolved": "https://registry.npmjs.org/util/-/util-0.10.3.tgz", + "integrity": "sha1-evsa/lCAUkZInj23/g7TeTNqwPk=", + "requires": { + "inherits": "2.0.1" + } + } + } + }, + "assert-plus": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", + "integrity": "sha512-NfJ4UzBCcQGLDlQq7nHxH+tv3kyZ0hHQqF5BO6J7tNJeP5do1llPr8dZ8zHonfhAu0PHAdMkSo+8o0wxg9lZWw==", + "optional": true + }, + "assertion-error": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/assertion-error/-/assertion-error-1.1.0.tgz", + "integrity": "sha512-jgsaNduz+ndvGyFt3uSuWqvy4lCnIJiovtouQN5JZHOKCS2QuhEdbcQHFhVksz2N2U9hXJo8odG7ETyWlEeuDw==", + "optional": true + }, + "astral-regex": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/astral-regex/-/astral-regex-2.0.0.tgz", + "integrity": "sha512-Z7tMw1ytTXt5jqMcOP+OQteU1VuNK9Y02uuJtKQ1Sv69jXQKKg5cibLwGJow8yzZP+eAc18EmLGPal0bp36rvQ==", + "optional": true + }, + "async": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/async/-/async-3.2.4.tgz", + "integrity": "sha512-iAB+JbDEGXhyIUavoDl9WP/Jj106Kz9DEn1DPgYw5ruDn0e3Wgi3sKFm55sASdGBNOQB8F59d9qQ7deqrHA8wQ==", + "optional": true + }, + "async-each-series": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/async-each-series/-/async-each-series-0.1.1.tgz", + "integrity": "sha512-p4jj6Fws4Iy2m0iCmI2am2ZNZCgbdgE+P8F/8csmn2vx7ixXrO2zGcuNsD46X5uZSVecmkEy/M06X2vG8KD6dQ==", + "devOptional": true + }, + "asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==", + "optional": true + }, + "at-least-node": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/at-least-node/-/at-least-node-1.0.0.tgz", + "integrity": "sha512-+q/t7Ekv1EDY2l6Gda6LLiX14rU9TV20Wa3ofeQmwPFZbOMo9DXrLbOjFaaclkXKWidIaopwAObQDqwWtGUjqg==", + "optional": true + }, + "autoprefixer": { + "version": "10.4.18", + "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.18.tgz", + "integrity": "sha512-1DKbDfsr6KUElM6wg+0zRNkB/Q7WcKYAaK+pzXn+Xqmszm/5Xa9coeNdtP88Vi+dPzZnMjhge8GIV49ZQkDa+g==", + "requires": { + "browserslist": "^4.23.0", + "caniuse-lite": "^1.0.30001591", + "fraction.js": "^4.3.7", + "normalize-range": "^0.1.2", + "picocolors": "^1.0.0", + "postcss-value-parser": "^4.2.0" + } + }, + "available-typed-arrays": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.2.tgz", + "integrity": "sha512-XWX3OX8Onv97LMk/ftVyBibpGwY5a8SmuxZPzeOxqmuEqUCOM9ZE+uIaD1VNJ5QnvU2UQusvmKbuM1FR8QWGfQ==", + "requires": { + "array-filter": "^1.0.0" + } + }, + "aws-sign2": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz", + "integrity": "sha512-08kcGqnYf/YmjoRhfxyu+CLxBjUtHLXLXX/vUfx9l2LYzG3c1m61nrpyFUZI6zeS+Li/wWMMidD9KgrqtGq3mA==", + "optional": true + }, + "aws4": { + "version": "1.12.0", + "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.12.0.tgz", + "integrity": "sha512-NmWvPnx0F1SfrQbYwOi7OeaNGokp9XhzNioJ/CSBs8Qa4vxug81mhJEAVZwxXuBmYB5KDRfMq/F3RR0BIU7sWg==", + "optional": true + }, + "axios": { + "version": "0.24.0", + "resolved": "https://registry.npmjs.org/axios/-/axios-0.24.0.tgz", + "integrity": "sha512-Q6cWsys88HoPgAaFAVUb0WpPk0O8iTeisR9IMqy9G8AbO4NlpVknrnQS03zzF9PGAWgO3cgletO3VjV/P7VztA==", + "requires": { + "follow-redirects": "^1.14.4" + } + }, + "babel-loader": { + "version": "9.1.3", + "resolved": "https://registry.npmjs.org/babel-loader/-/babel-loader-9.1.3.tgz", + "integrity": "sha512-xG3ST4DglodGf8qSwv0MdeWLhrDsw/32QMdTO5T1ZIp9gQur0HkCyFs7Awskr10JKXFXwpAhiCuYX5oGXnRGbw==", + "requires": { + "find-cache-dir": "^4.0.0", + "schema-utils": "^4.0.0" + } + }, + "babel-plugin-istanbul": { + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/babel-plugin-istanbul/-/babel-plugin-istanbul-6.1.1.tgz", + "integrity": "sha512-Y1IQok9821cC9onCx5otgFfRm7Lm+I+wwxOx738M/WLPZ9Q42m4IG5W0FNX8WLL2gYMZo3JkuXIH2DOpWM+qwA==", + "requires": { + "@babel/helper-plugin-utils": "^7.0.0", + "@istanbuljs/load-nyc-config": "^1.0.0", + "@istanbuljs/schema": "^0.1.2", + "istanbul-lib-instrument": "^5.0.4", + "test-exclude": "^6.0.0" + } + }, + "babel-plugin-polyfill-corejs2": { + "version": "0.4.10", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs2/-/babel-plugin-polyfill-corejs2-0.4.10.tgz", + "integrity": "sha512-rpIuu//y5OX6jVU+a5BCn1R5RSZYWAl2Nar76iwaOdycqb6JPxediskWFMMl7stfwNJR4b7eiQvh5fB5TEQJTQ==", + "requires": { + "@babel/compat-data": "^7.22.6", + "@babel/helper-define-polyfill-provider": "^0.6.1", + "semver": "^6.3.1" + }, + "dependencies": { + "semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==" + } + } + }, + "babel-plugin-polyfill-corejs3": { + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-corejs3/-/babel-plugin-polyfill-corejs3-0.9.0.tgz", + "integrity": "sha512-7nZPG1uzK2Ymhy/NbaOWTg3uibM2BmGASS4vHS4szRZAIR8R6GwA/xAujpdrXU5iyklrimWnLWU+BLF9suPTqg==", + "requires": { + "@babel/helper-define-polyfill-provider": "^0.5.0", + "core-js-compat": "^3.34.0" + }, + "dependencies": { + "@babel/helper-define-polyfill-provider": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.5.0.tgz", + "integrity": "sha512-NovQquuQLAQ5HuyjCz7WQP9MjRj7dx++yspwiyUiGl9ZyadHRSql1HZh5ogRd8W8w6YM6EQ/NTB8rgjLt5W65Q==", + "requires": { + "@babel/helper-compilation-targets": "^7.22.6", + "@babel/helper-plugin-utils": "^7.22.5", + "debug": "^4.1.1", + "lodash.debounce": "^4.0.8", + "resolve": "^1.14.2" + } + } + } + }, + "babel-plugin-polyfill-regenerator": { + "version": "0.5.5", + "resolved": "https://registry.npmjs.org/babel-plugin-polyfill-regenerator/-/babel-plugin-polyfill-regenerator-0.5.5.tgz", + "integrity": "sha512-OJGYZlhLqBh2DDHeqAxWB1XIvr49CxiJ2gIt61/PU55CQK4Z58OzMqjDe1zwQdQk+rBYsRc+1rJmdajM3gimHg==", + "requires": { + "@babel/helper-define-polyfill-provider": "^0.5.0" + }, + "dependencies": { + "@babel/helper-define-polyfill-provider": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/@babel/helper-define-polyfill-provider/-/helper-define-polyfill-provider-0.5.0.tgz", + "integrity": "sha512-NovQquuQLAQ5HuyjCz7WQP9MjRj7dx++yspwiyUiGl9ZyadHRSql1HZh5ogRd8W8w6YM6EQ/NTB8rgjLt5W65Q==", + "requires": { + "@babel/helper-compilation-targets": "^7.22.6", + "@babel/helper-plugin-utils": "^7.22.5", + "debug": "^4.1.1", + "lodash.debounce": "^4.0.8", + "resolve": "^1.14.2" + } + } + } + }, + "balanced-match": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", + "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=" + }, + "base64-js": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz", + "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==" + }, + "base64id": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/base64id/-/base64id-2.0.0.tgz", + "integrity": "sha512-lGe34o6EHj9y3Kts9R4ZYs/Gr+6N7MCaMlIFA3F1R2O5/m7K06AxfSeO5530PEERE6/WyEg3lsuyw4GHlPZHog==", + "devOptional": true + }, + "batch": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/batch/-/batch-0.6.1.tgz", + "integrity": "sha512-x+VAiMRL6UPkx+kudNvxTl6hB2XNNCG2r+7wixVfIYwu/2HKRXimwQyaumLjMveWvT2Hkd/cAJw+QBMfJ/EKVw==" + }, + "bcrypt-pbkdf": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz", + "integrity": "sha512-qeFIXtP4MSoi6NLqO12WfqARWWuCKi2Rn/9hJLEmtB5yTNr9DqFWkJRCf2qShWzPeAMRnOgCrq0sg/KLv5ES9w==", + "optional": true, + "requires": { + "tweetnacl": "^0.14.3" + } + }, + "big.js": { + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/big.js/-/big.js-5.2.2.tgz", + "integrity": "sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ==" + }, + "binary-extensions": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.1.0.tgz", + "integrity": "sha512-1Yj8h9Q+QDF5FzhMs/c9+6UntbD5MkRfRwac8DoEm9ZfUBZ7tZ55YcGVAzEe4bXsdQHEk+s9S5wsOKVdZrw0tQ==" + }, + "bl": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/bl/-/bl-4.1.0.tgz", + "integrity": "sha512-1W07cM9gS6DcLperZfFSj+bWLtaPGSOHWhPiGzXmvVJbRLdG82sH/Kn8EtW1VqWVA54AKf2h5k5BbnIbwF3h6w==", + "requires": { + "buffer": "^5.5.0", + "inherits": "^2.0.4", + "readable-stream": "^3.4.0" + }, + "dependencies": { + "readable-stream": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", + "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", + "requires": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + } + } + } + }, + "blob-util": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/blob-util/-/blob-util-2.0.2.tgz", + "integrity": "sha512-T7JQa+zsXXEa6/8ZhHcQEW1UFfVM49Ts65uBkFL6fz2QmrElqmbajIDJvuA0tEhRe5eIjpV9ZF+0RfZR9voJFQ==", + "optional": true + }, + "bluebird": { + "version": "3.7.2", + "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz", + "integrity": "sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==", + "optional": true + }, + "bn.js": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-5.2.1.tgz", + "integrity": "sha512-eXRvHzWyYPBuB4NBy0cmYQjGitUrtqwbvlzP3G6VFnNRbsZQIxQ10PbKKHt8gZ/HW/D/747aDl+QkDqg3KQLMQ==" + }, + "body-parser": { + "version": "1.20.2", + "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-1.20.2.tgz", + "integrity": "sha512-ml9pReCu3M61kGlqoTm2umSXTlRTuGTx0bfYj+uIUKKYycG5NtSbeetV3faSU6R7ajOPw0g/J1PvK4qNy7s5bA==", + "requires": { + "bytes": "3.1.2", + "content-type": "~1.0.5", + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "1.2.0", + "http-errors": "2.0.0", + "iconv-lite": "0.4.24", + "on-finished": "2.4.1", + "qs": "6.11.0", + "raw-body": "2.5.2", + "type-is": "~1.6.18", + "unpipe": "1.0.0" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "requires": { + "ms": "2.0.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=" + }, + "on-finished": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", + "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", + "requires": { + "ee-first": "1.1.1" + } + }, + "qs": { + "version": "6.11.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz", + "integrity": "sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==", + "requires": { + "side-channel": "^1.0.4" + } + } + } + }, + "bonjour-service": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/bonjour-service/-/bonjour-service-1.2.1.tgz", + "integrity": "sha512-oSzCS2zV14bh2kji6vNe7vrpJYCHGvcZnlffFQ1MEoX/WOeQ/teD8SYWKR942OI3INjq8OMNJlbPK5LLLUxFDw==", + "requires": { + "fast-deep-equal": "^3.1.3", + "multicast-dns": "^7.2.5" + } + }, + "boolbase": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/boolbase/-/boolbase-1.0.0.tgz", + "integrity": "sha512-JZOSA7Mo9sNGB8+UjSgzdLtokWAky1zbztM3WRLCbZ70/3cTANmQmOdR7y2g+J0e2WXywy1yS468tY+IruqEww==" + }, + "bootstrap": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/bootstrap/-/bootstrap-4.6.2.tgz", + "integrity": "sha512-51Bbp/Uxr9aTuy6ca/8FbFloBUJZLHwnhTcnjIeRn2suQWsWzcuJhGjKDB5eppVte/8oCdOL3VuwxvZDUggwGQ==", + "requires": {} + }, + "brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "braces": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", + "requires": { + "fill-range": "^7.1.1" + } + }, + "brorand": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/brorand/-/brorand-1.1.0.tgz", + "integrity": "sha1-EsJe/kCkXjwyPrhnWgoM5XsiNx8=" + }, + "browser-pack": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/browser-pack/-/browser-pack-6.1.0.tgz", + "integrity": "sha512-erYug8XoqzU3IfcU8fUgyHqyOXqIE4tUTTQ+7mqUjQlvnXkOO6OlT9c/ZoJVHYoAaqGxr09CN53G7XIsO4KtWA==", + "requires": { + "combine-source-map": "~0.8.0", + "defined": "^1.0.0", + "JSONStream": "^1.0.3", + "safe-buffer": "^5.1.1", + "through2": "^2.0.0", + "umd": "^3.0.0" + } + }, + "browser-pack-flat": { + "version": "3.4.2", + "resolved": "https://registry.npmjs.org/browser-pack-flat/-/browser-pack-flat-3.4.2.tgz", + "integrity": "sha512-TrUo6n2fGSOCYFAKkt/EkgenytAuuCI88fmXFA60aNFVHvz3CZEBTXYSvvXVpU6xpjM8lj/6vkC6Exn8KPjtPw==", + "requires": { + "combine-source-map": "^0.8.0", + "convert-source-map": "^1.5.1", + "count-lines": "^0.1.2", + "dedent": "^0.7.0", + "estree-is-member-expression": "^1.0.0", + "estree-is-require": "^1.0.0", + "esutils": "^2.0.2", + "JSONStream": "^1.3.2", + "path-parse": "^1.0.5", + "scope-analyzer": "^2.0.0", + "stream-combiner": "^0.2.2", + "through2": "^2.0.3", + "transform-ast": "^2.4.2", + "umd": "^3.0.3", + "wrap-comment": "^1.0.0" + } + }, + "browser-resolve": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/browser-resolve/-/browser-resolve-2.0.0.tgz", + "integrity": "sha512-7sWsQlYL2rGLy2IWm8WL8DCTJvYLc/qlOnsakDac87SOoCd16WLsaAMdCiAqsTNHIe+SXfaqyxyo6THoWqs8WQ==", + "requires": { + "resolve": "^1.17.0" + } + }, + "browser-sync": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/browser-sync/-/browser-sync-3.0.2.tgz", + "integrity": "sha512-PC9c7aWJFVR4IFySrJxOqLwB9ENn3/TaXCXtAa0SzLwocLN3qMjN+IatbjvtCX92BjNXsY6YWg9Eb7F3Wy255g==", + "devOptional": true, + "requires": { + "browser-sync-client": "^3.0.2", + "browser-sync-ui": "^3.0.2", + "bs-recipes": "1.3.4", + "chalk": "4.1.2", + "chokidar": "^3.5.1", + "connect": "3.6.6", + "connect-history-api-fallback": "^1", + "dev-ip": "^1.0.1", + "easy-extender": "^2.3.4", + "eazy-logger": "^4.0.1", + "etag": "^1.8.1", + "fresh": "^0.5.2", + "fs-extra": "3.0.1", + "http-proxy": "^1.18.1", + "immutable": "^3", + "micromatch": "^4.0.2", + "opn": "5.3.0", + "portscanner": "2.2.0", + "raw-body": "^2.3.2", + "resp-modifier": "6.0.2", + "rx": "4.1.0", + "send": "0.16.2", + "serve-index": "1.9.1", + "serve-static": "1.13.2", + "server-destroy": "1.0.1", + "socket.io": "^4.4.1", + "ua-parser-js": "^1.0.33", + "yargs": "^17.3.1" + }, + "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "devOptional": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "devOptional": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "cliui": { + "version": "8.0.1", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-8.0.1.tgz", + "integrity": "sha512-BSeNnyus75C4//NQ9gQt1/csTXyo/8Sb+afLAkzAptFuMsod9HFokGNudZpi/oQV73hnVK+sR+5PVRMd+Dr7YQ==", + "devOptional": true, + "requires": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.1", + "wrap-ansi": "^7.0.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "devOptional": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "devOptional": true + }, + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "devOptional": true, + "requires": { + "ms": "2.0.0" + } + }, + "depd": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", + "integrity": "sha512-7emPTl6Dpo6JRXOXjLRxck+FlLRX5847cLKEn00PLAgc3g2hTZZgr+e4c2v6QpSmLeFP3n5yUo7ft6avBK/5jQ==", + "devOptional": true + }, + "destroy": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.0.4.tgz", + "integrity": "sha512-3NdhDuEXnfun/z7x9GOElY49LoqVHoGScmOKwmxhsS8N5Y+Z8KyPPDnaSzqWgYt/ji4mqwfTS34Htrk0zPIXVg==", + "devOptional": true + }, + "fs-extra": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-3.0.1.tgz", + "integrity": "sha512-V3Z3WZWVUYd8hoCL5xfXJCaHWYzmtwW5XWYSlLgERi8PWd8bx1kUHUk8L1BT57e49oKnDDD180mjfrHc1yA9rg==", + "devOptional": true, + "requires": { + "graceful-fs": "^4.1.2", + "jsonfile": "^3.0.0", + "universalify": "^0.1.0" + } + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "devOptional": true + }, + "http-errors": { + "version": "1.6.3", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.6.3.tgz", + "integrity": "sha512-lks+lVC8dgGyh97jxvxeYTWQFvh4uw4yC12gVl63Cg30sjPX4wuGcdkICVXDAESr6OJGjqGA8Iz5mkeN6zlD7A==", + "devOptional": true, + "requires": { + "depd": "~1.1.2", + "inherits": "2.0.3", + "setprototypeof": "1.1.0", + "statuses": ">= 1.4.0 < 2" + } + }, + "inherits": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", + "integrity": "sha512-x00IRNXNy63jwGkJmzPigoySHbaqpNuzKbBOmzK+g2OdZpQ9w+sxCN+VSB3ja7IAge2OP2qpfxTjeNcyjmW1uw==", + "devOptional": true + }, + "jsonfile": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-3.0.1.tgz", + "integrity": "sha512-oBko6ZHlubVB5mRFkur5vgYR1UyqX+S6Y/oCfLhqNdcc2fYFlDpIoNc7AfKS1KOGcnNAkvsr0grLck9ANM815w==", + "devOptional": true, + "requires": { + "graceful-fs": "^4.1.6" + } + }, + "mime": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.4.1.tgz", + "integrity": "sha512-KI1+qOZu5DcW6wayYHSzR/tXKCDC5Om4s1z2QJjDULzLcmf3DvzS7oluY4HCTrc+9FiKmWUgeNLg7W3uIQvxtQ==", + "devOptional": true + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "devOptional": true + }, + "send": { + "version": "0.16.2", + "resolved": "https://registry.npmjs.org/send/-/send-0.16.2.tgz", + "integrity": "sha512-E64YFPUssFHEFBvpbbjr44NCLtI1AohxQ8ZSiJjQLskAdKuriYEP6VyGEsRDH8ScozGpkaX1BGvhanqCwkcEZw==", + "devOptional": true, + "requires": { + "debug": "2.6.9", + "depd": "~1.1.2", + "destroy": "~1.0.4", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "fresh": "0.5.2", + "http-errors": "~1.6.2", + "mime": "1.4.1", + "ms": "2.0.0", + "on-finished": "~2.3.0", + "range-parser": "~1.2.0", + "statuses": "~1.4.0" + } + }, + "serve-static": { + "version": "1.13.2", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.13.2.tgz", + "integrity": "sha512-p/tdJrO4U387R9oMjb1oj7qSMaMfmOyd4j9hOFoxZe2baQszgHcSWjuya/CiT5kgZZKRudHNOA0pYXOl8rQ5nw==", + "devOptional": true, + "requires": { + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "parseurl": "~1.3.2", + "send": "0.16.2" + } + }, + "setprototypeof": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.0.tgz", + "integrity": "sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ==", + "devOptional": true + }, + "statuses": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.4.0.tgz", + "integrity": "sha512-zhSCtt8v2NDrRlPQpCNtw/heZLtfUDqxBM1udqikb/Hbk52LK4nQSwr10u77iopCW5LsyHpuXS0GnEc48mLeew==", + "devOptional": true + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "devOptional": true, + "requires": { + "has-flag": "^4.0.0" + } + }, + "ua-parser-js": { + "version": "1.0.36", + "resolved": "https://registry.npmjs.org/ua-parser-js/-/ua-parser-js-1.0.36.tgz", + "integrity": "sha512-znuyCIXzl8ciS3+y3fHJI/2OhQIXbXw9MWC/o3qwyR+RGppjZHrM27CGFSKCJXi2Kctiz537iOu2KnXs1lMQhw==", + "devOptional": true + }, + "universalify": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.1.2.tgz", + "integrity": "sha512-rBJeI5CXAlmy1pV+617WB9J63U6XcazHHF2f2dbJix4XzpUF0RS3Zbj0FGIOCAva5P/d/GBOYaACQ1w+0azUkg==", + "devOptional": true + }, + "wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "devOptional": true, + "requires": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + } + }, + "y18n": { + "version": "5.0.8", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.8.tgz", + "integrity": "sha512-0pfFzegeDWJHJIAmTLRP2DwHjdF5s7jo9tuztdQxAhINCdvS+3nGINqPd00AphqJR/0LhANUS6/+7SCb98YOfA==", + "devOptional": true + }, + "yargs": { + "version": "17.7.2", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-17.7.2.tgz", + "integrity": "sha512-7dSzzRQ++CKnNI/krKnYRV7JKKPUXMEh61soaHKg9mrWEhzFWhFnxPxGl+69cD1Ou63C13NUPCnmIcrvqCuM6w==", + "devOptional": true, + "requires": { + "cliui": "^8.0.1", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.3", + "y18n": "^5.0.5", + "yargs-parser": "^21.1.1" + } + }, + "yargs-parser": { + "version": "21.1.1", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-21.1.1.tgz", + "integrity": "sha512-tVpsJW7DdjecAiFpbIB1e3qxIQsE6NoPc5/eTdrbbIC4h0LVsWhnoa3g+m2HclBIujHzsxZ4VJVA+GUuc2/LBw==", + "devOptional": true + } + } + }, + "browser-sync-client": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/browser-sync-client/-/browser-sync-client-3.0.2.tgz", + "integrity": "sha512-tBWdfn9L0wd2Pjuz/NWHtNEKthVb1Y67vg8/qyGNtCqetNz5lkDkFnrsx5UhPNPYUO8vci50IWC/BhYaQskDiQ==", + "devOptional": true, + "requires": { + "etag": "1.8.1", + "fresh": "0.5.2", + "mitt": "^1.1.3" + } + }, + "browser-sync-ui": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/browser-sync-ui/-/browser-sync-ui-3.0.2.tgz", + "integrity": "sha512-V3FwWAI+abVbFLTyJjXJlCMBwjc3GXf/BPGfwO2fMFACWbIGW9/4SrBOFYEOOtqzCjQE0Di+U3VIb7eES4omNA==", + "devOptional": true, + "requires": { + "async-each-series": "0.1.1", + "chalk": "4.1.2", + "connect-history-api-fallback": "^1", + "immutable": "^3", + "server-destroy": "1.0.1", + "socket.io-client": "^4.4.1", + "stream-throttle": "^0.1.3" + }, + "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "devOptional": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "devOptional": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "devOptional": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "devOptional": true + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "devOptional": true + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "devOptional": true, + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, + "browser-unpack": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/browser-unpack/-/browser-unpack-1.4.2.tgz", + "integrity": "sha512-uHkiY4bmXjjBBWoKH1aRnEGTQxUUCCcVtoJfH9w1lmGGjETY4u93Zk+GRYkCE/SRMrdoMTINQ/1/manr/3aMVA==", + "requires": { + "acorn-node": "^1.5.2", + "concat-stream": "^1.5.0", + "minimist": "^1.1.1" + } + }, + "browserify": { + "version": "17.0.0", + "resolved": "https://registry.npmjs.org/browserify/-/browserify-17.0.0.tgz", + "integrity": "sha512-SaHqzhku9v/j6XsQMRxPyBrSP3gnwmE27gLJYZgMT2GeK3J0+0toN+MnuNYDfHwVGQfLiMZ7KSNSIXHemy905w==", + "requires": { + "assert": "^1.4.0", + "browser-pack": "^6.0.1", + "browser-resolve": "^2.0.0", + "browserify-zlib": "~0.2.0", + "buffer": "~5.2.1", + "cached-path-relative": "^1.0.0", + "concat-stream": "^1.6.0", + "console-browserify": "^1.1.0", + "constants-browserify": "~1.0.0", + "crypto-browserify": "^3.0.0", + "defined": "^1.0.0", + "deps-sort": "^2.0.1", + "domain-browser": "^1.2.0", + "duplexer2": "~0.1.2", + "events": "^3.0.0", + "glob": "^7.1.0", + "has": "^1.0.0", + "htmlescape": "^1.1.0", + "https-browserify": "^1.0.0", + "inherits": "~2.0.1", + "insert-module-globals": "^7.2.1", + "JSONStream": "^1.0.3", + "labeled-stream-splicer": "^2.0.0", + "mkdirp-classic": "^0.5.2", + "module-deps": "^6.2.3", + "os-browserify": "~0.3.0", + "parents": "^1.0.1", + "path-browserify": "^1.0.0", + "process": "~0.11.0", + "punycode": "^1.3.2", + "querystring-es3": "~0.2.0", + "read-only-stream": "^2.0.0", + "readable-stream": "^2.0.2", + "resolve": "^1.1.4", + "shasum-object": "^1.0.0", + "shell-quote": "^1.6.1", + "stream-browserify": "^3.0.0", + "stream-http": "^3.0.0", + "string_decoder": "^1.1.1", + "subarg": "^1.0.0", + "syntax-error": "^1.1.1", + "through2": "^2.0.0", + "timers-browserify": "^1.0.1", + "tty-browserify": "0.0.1", + "url": "~0.11.0", + "util": "~0.12.0", + "vm-browserify": "^1.0.0", + "xtend": "^4.0.0" + }, + "dependencies": { + "buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.2.1.tgz", + "integrity": "sha512-c+Ko0loDaFfuPWiL02ls9Xd3GO3cPVmUobQ6t3rXNUk304u6hGq+8N/kFi+QEIKhzK3uwolVhLzszmfLmMLnqg==", + "requires": { + "base64-js": "^1.0.2", + "ieee754": "^1.1.4" + } + }, + "path-browserify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-browserify/-/path-browserify-1.0.1.tgz", + "integrity": "sha512-b7uo2UCUOYZcnF/3ID0lulOJi/bafxa1xPe7ZPsammBSpjSWQkjNxlt635YGS2MiR9GjvuXCtz2emr3jbsz98g==" + }, + "punycode": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz", + "integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4=" + }, + "stream-browserify": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/stream-browserify/-/stream-browserify-3.0.0.tgz", + "integrity": "sha512-H73RAHsVBapbim0tU2JwwOiXUj+fikfiaoYAKHF3VJfA0pe2BCzkhAHBlLG6REzE+2WNZcxOXjK7lkso+9euLA==", + "requires": { + "inherits": "~2.0.4", + "readable-stream": "^3.5.0" + }, + "dependencies": { + "readable-stream": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", + "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", + "requires": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + } + } + } + }, + "stream-http": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/stream-http/-/stream-http-3.1.1.tgz", + "integrity": "sha512-S7OqaYu0EkFpgeGFb/NPOoPLxFko7TPqtEeFg5DXPB4v/KETHG0Ln6fRFrNezoelpaDKmycEmmZ81cC9DAwgYg==", + "requires": { + "builtin-status-codes": "^3.0.0", + "inherits": "^2.0.4", + "readable-stream": "^3.6.0", + "xtend": "^4.0.2" + }, + "dependencies": { + "readable-stream": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", + "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", + "requires": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + } + } + } + }, + "timers-browserify": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/timers-browserify/-/timers-browserify-1.4.2.tgz", + "integrity": "sha1-ycWLV1voQHN1y14kYtrO50NZ9B0=", + "requires": { + "process": "~0.11.0" + } + }, + "tty-browserify": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/tty-browserify/-/tty-browserify-0.0.1.tgz", + "integrity": "sha512-C3TaO7K81YvjCgQH9Q1S3R3P3BtN3RIM8n+OvX4il1K1zgE8ZhI0op7kClgkxtutIE8hQrcrHBXvIheqKUUCxw==" + }, + "util": { + "version": "0.12.3", + "resolved": "https://registry.npmjs.org/util/-/util-0.12.3.tgz", + "integrity": "sha512-I8XkoQwE+fPQEhy9v012V+TSdH2kp9ts29i20TaaDUXsg7x/onePbhFJUExBfv/2ay1ZOp/Vsm3nDlmnFGSAog==", + "requires": { + "inherits": "^2.0.3", + "is-arguments": "^1.0.4", + "is-generator-function": "^1.0.7", + "is-typed-array": "^1.1.3", + "safe-buffer": "^5.1.2", + "which-typed-array": "^1.1.2" + } + } + } + }, + "browserify-aes": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/browserify-aes/-/browserify-aes-1.2.0.tgz", + "integrity": "sha512-+7CHXqGuspUn/Sl5aO7Ea0xWGAtETPXNSAjHo48JfLdPWcMng33Xe4znFvQweqc/uzk5zSOI3H52CYnjCfb5hA==", + "requires": { + "buffer-xor": "^1.0.3", + "cipher-base": "^1.0.0", + "create-hash": "^1.1.0", + "evp_bytestokey": "^1.0.3", + "inherits": "^2.0.1", + "safe-buffer": "^5.0.1" + } + }, + "browserify-cipher": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/browserify-cipher/-/browserify-cipher-1.0.1.tgz", + "integrity": "sha512-sPhkz0ARKbf4rRQt2hTpAHqn47X3llLkUGn+xEJzLjwY8LRs2p0v7ljvI5EyoRO/mexrNunNECisZs+gw2zz1w==", + "requires": { + "browserify-aes": "^1.0.4", + "browserify-des": "^1.0.0", + "evp_bytestokey": "^1.0.0" + } + }, + "browserify-des": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/browserify-des/-/browserify-des-1.0.2.tgz", + "integrity": "sha512-BioO1xf3hFwz4kc6iBhI3ieDFompMhrMlnDFC4/0/vd5MokpuAc3R+LYbwTA9A5Yc9pq9UYPqffKpW2ObuwX5A==", + "requires": { + "cipher-base": "^1.0.1", + "des.js": "^1.0.0", + "inherits": "^2.0.1", + "safe-buffer": "^5.1.2" + } + }, + "browserify-rsa": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/browserify-rsa/-/browserify-rsa-4.1.0.tgz", + "integrity": "sha512-AdEER0Hkspgno2aR97SAf6vi0y0k8NuOpGnVH3O99rcA5Q6sh8QxcngtHuJ6uXwnfAXNM4Gn1Gb7/MV1+Ymbog==", + "requires": { + "bn.js": "^5.0.0", + "randombytes": "^2.0.1" + } + }, + "browserify-sign": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/browserify-sign/-/browserify-sign-4.2.2.tgz", + "integrity": "sha512-1rudGyeYY42Dk6texmv7c4VcQ0EsvVbLwZkA+AQB7SxvXxmcD93jcHie8bzecJ+ChDlmAm2Qyu0+Ccg5uhZXCg==", + "requires": { + "bn.js": "^5.2.1", + "browserify-rsa": "^4.1.0", + "create-hash": "^1.2.0", + "create-hmac": "^1.1.7", + "elliptic": "^6.5.4", + "inherits": "^2.0.4", + "parse-asn1": "^5.1.6", + "readable-stream": "^3.6.2", + "safe-buffer": "^5.2.1" + }, + "dependencies": { + "readable-stream": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "requires": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + } + }, + "safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==" + } + } + }, + "browserify-zlib": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/browserify-zlib/-/browserify-zlib-0.2.0.tgz", + "integrity": "sha512-Z942RysHXmJrhqk88FmKBVq/v5tqmSkDz7p54G/MGyjMnCFFnC79XWNbg+Vta8W6Wb2qtSZTSxIGkJrRpCFEiA==", + "requires": { + "pako": "~1.0.5" + } + }, + "browserslist": { + "version": "4.23.0", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.23.0.tgz", + "integrity": "sha512-QW8HiM1shhT2GuzkvklfjcKDiWFXHOeFCIA/huJPwHsslwcydgk7X+z2zXpEijP98UCY7HbubZt5J2Zgvf0CaQ==", + "requires": { + "caniuse-lite": "^1.0.30001587", + "electron-to-chromium": "^1.4.668", + "node-releases": "^2.0.14", + "update-browserslist-db": "^1.0.13" + } + }, + "bs-recipes": { + "version": "1.3.4", + "resolved": "https://registry.npmjs.org/bs-recipes/-/bs-recipes-1.3.4.tgz", + "integrity": "sha512-BXvDkqhDNxXEjeGM8LFkSbR+jzmP/CYpCiVKYn+soB1dDldeU15EBNDkwVXndKuX35wnNUaPd0qSoQEAkmQtMw==", + "devOptional": true + }, + "buffer": { + "version": "5.7.1", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-5.7.1.tgz", + "integrity": "sha512-EHcyIPBQ4BSGlvjB16k5KgAJ27CIsHY/2JBmCRReo48y9rQ3MaUzWX3KVlBa4U7MyX02HdVj0K7C3WaB3ju7FQ==", + "requires": { + "base64-js": "^1.3.1", + "ieee754": "^1.1.13" + } + }, + "buffer-crc32": { + "version": "0.2.13", + "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz", + "integrity": "sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ==", + "optional": true + }, + "buffer-from": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz", + "integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==" + }, + "buffer-xor": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/buffer-xor/-/buffer-xor-1.0.3.tgz", + "integrity": "sha1-JuYe0UIvtw3ULm42cp7VHYVf6Nk=" + }, + "builtin-status-codes": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/builtin-status-codes/-/builtin-status-codes-3.0.0.tgz", + "integrity": "sha1-hZgoeOIbmOHGZCXgPQF0eI9Wnug=" + }, + "builtins": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/builtins/-/builtins-5.0.1.tgz", + "integrity": "sha512-qwVpFEHNfhYJIzNRBvd2C1kyo6jz3ZSMPyyuR47OPdiKWlbYnZNyDWuyR175qDnAJLiCo5fBBqPb3RiXgWlkOQ==", + "requires": { + "semver": "^7.0.0" + } + }, + "bundle-collapser": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/bundle-collapser/-/bundle-collapser-1.4.0.tgz", + "integrity": "sha512-Gd3K3+3KI1Utuk+gwAvuOVOjT/2XLGL8tU6FwDKk04LlOZkYfT0pwQllsG1Dv8RRhgcjNxZSDmmSXb0AOkwSwg==", + "requires": { + "browser-pack": "^6.0.2", + "browser-unpack": "^1.1.0", + "concat-stream": "^1.5.0", + "falafel": "^2.1.0", + "minimist": "^1.1.1", + "through2": "^2.0.0" + } + }, + "bytes": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", + "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==" + }, + "cacache": { + "version": "18.0.2", + "resolved": "https://registry.npmjs.org/cacache/-/cacache-18.0.2.tgz", + "integrity": "sha512-r3NU8h/P+4lVUHfeRw1dtgQYar3DZMm4/cm2bZgOvrFC/su7budSOeqh52VJIC4U4iG1WWwV6vRW0znqBvxNuw==", + "requires": { + "@npmcli/fs": "^3.1.0", + "fs-minipass": "^3.0.0", + "glob": "^10.2.2", + "lru-cache": "^10.0.1", + "minipass": "^7.0.3", + "minipass-collect": "^2.0.1", + "minipass-flush": "^1.0.5", + "minipass-pipeline": "^1.2.4", + "p-map": "^4.0.0", + "ssri": "^10.0.0", + "tar": "^6.1.11", + "unique-filename": "^3.0.0" + }, + "dependencies": { + "brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "requires": { + "balanced-match": "^1.0.0" + } + }, + "glob": { + "version": "10.3.10", + "resolved": "https://registry.npmjs.org/glob/-/glob-10.3.10.tgz", + "integrity": "sha512-fa46+tv1Ak0UPK1TOy/pZrIybNNt4HCv7SDzwyfiOZkvZLEbjsZkJBPtDHVshZjbecAoAGSC20MjLDG/qr679g==", + "requires": { + "foreground-child": "^3.1.0", + "jackspeak": "^2.3.5", + "minimatch": "^9.0.1", + "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0", + "path-scurry": "^1.10.1" + } + }, + "lru-cache": { + "version": "10.2.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.2.0.tgz", + "integrity": "sha512-2bIM8x+VAf6JT4bKAljS1qUWgMsqZRPGJS6FSahIMPVvctcNhyVp7AJu7quxOW9jwkryBReKZY5tY5JYv2n/7Q==" + }, + "minimatch": { + "version": "9.0.3", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.3.tgz", + "integrity": "sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==", + "requires": { + "brace-expansion": "^2.0.1" + } + } + } + }, + "cached-path-relative": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/cached-path-relative/-/cached-path-relative-1.1.0.tgz", + "integrity": "sha512-WF0LihfemtesFcJgO7xfOoOcnWzY/QHR4qeDqV44jPU3HTI54+LnfXK3SA27AVVGCdZFgjjFFaqUA9Jx7dMJZA==" + }, + "cachedir": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/cachedir/-/cachedir-2.3.0.tgz", + "integrity": "sha512-A+Fezp4zxnit6FanDmv9EqXNAi3vt9DWp51/71UEhXukb7QUuvtv9344h91dyAxuTLoSYJFU299qzR3tzwPAhw==", + "optional": true + }, + "call-bind": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.7.tgz", + "integrity": "sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w==", + "requires": { + "es-define-property": "^1.0.0", + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.4", + "set-function-length": "^1.2.1" + } + }, + "callsites": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/callsites/-/callsites-3.1.0.tgz", + "integrity": "sha512-P8BjAsXvZS+VIDUI11hHCQEv74YT67YUi5JJFNWIqL235sBmjX4+qx9Muvls5ivyNENctx46xQLQ3aTuE7ssaQ==" + }, + "camelcase": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-5.3.1.tgz", + "integrity": "sha512-L28STB170nwWS63UjtlEOE3dldQApaJXZkOI1uMFfzf3rRuPegHaHesyee+YxQ+W6SvRDQV6UrdOdRiR153wJg==" + }, + "caniuse-lite": { + "version": "1.0.30001600", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001600.tgz", + "integrity": "sha512-+2S9/2JFhYmYaDpZvo0lKkfvuKIglrx68MwOBqMGHhQsNkLjB5xtc/TGoEPs+MxjSyN/72qer2g97nzR641mOQ==" + }, + "caseless": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", + "integrity": "sha512-4tYFyifaFfGacoiObjJegolkwSU4xQNGbVgUiNYVUxbQ2x2lUsFvY4hVgVzGiIe6WLOPqycWXA40l+PWsxthUw==", + "optional": true + }, + "chai": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/chai/-/chai-4.4.0.tgz", + "integrity": "sha512-x9cHNq1uvkCdU+5xTkNh5WtgD4e4yDFCsp9jVc7N7qVeKeftv3gO/ZrviX5d+3ZfxdYnZXZYujjRInu1RogU6A==", + "optional": true, + "requires": { + "assertion-error": "^1.1.0", + "check-error": "^1.0.3", + "deep-eql": "^4.1.3", + "get-func-name": "^2.0.2", + "loupe": "^2.3.6", + "pathval": "^1.1.1", + "type-detect": "^4.0.8" + } + }, + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + } + }, + "chardet": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/chardet/-/chardet-0.7.0.tgz", + "integrity": "sha512-mT8iDcrh03qDGRRmoA2hmBJnxpllMR+0/0qlzjqZES6NdiWDcZkCNAk4rPFZ9Q85r27unkiNNg8ZOiwZXBHwcA==" + }, + "check-error": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/check-error/-/check-error-1.0.3.tgz", + "integrity": "sha512-iKEoDYaRmd1mxM90a2OEfWhjsjPpYPuQ+lMYsoxB126+t8fw7ySEO48nmDg5COTjxDI65/Y2OWpeEHk3ZOe8zg==", + "optional": true, + "requires": { + "get-func-name": "^2.0.2" + } + }, + "check-more-types": { + "version": "2.24.0", + "resolved": "https://registry.npmjs.org/check-more-types/-/check-more-types-2.24.0.tgz", + "integrity": "sha1-FCD/sQ/URNz8ebQ4kbv//TKoRgA=", + "optional": true + }, + "chokidar": { + "version": "3.5.3", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.5.3.tgz", + "integrity": "sha512-Dr3sfKRP6oTcjf2JmUmFJfeVMvXBdegxB0iVQ5eb2V10uFJUCAS8OByZdVAyVb8xXNz3GjjTgj9kLWsZTqE6kw==", + "requires": { + "anymatch": "~3.1.2", + "braces": "~3.0.2", + "fsevents": "~2.3.2", + "glob-parent": "~5.1.2", + "is-binary-path": "~2.1.0", + "is-glob": "~4.0.1", + "normalize-path": "~3.0.0", + "readdirp": "~3.6.0" + } + }, + "chownr": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/chownr/-/chownr-2.0.0.tgz", + "integrity": "sha512-bIomtDF5KGpdogkLd9VspvFzk9KfpyyGlS8YFVZl7TGPBHL5snIOnxeshwVgPteQ9b4Eydl+pVbIyE1DcvCWgQ==" + }, + "chrome-trace-event": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/chrome-trace-event/-/chrome-trace-event-1.0.3.tgz", + "integrity": "sha512-p3KULyQg4S7NIHixdwbGX+nFHkoBiA4YQmyWtjb8XngSKV124nJmRysgAeujbUVb15vh+RvFUfCPqU7rXk+hZg==" + }, + "ci-info": { + "version": "3.8.0", + "resolved": "https://registry.npmjs.org/ci-info/-/ci-info-3.8.0.tgz", + "integrity": "sha512-eXTggHWSooYhq49F2opQhuHWgzucfF2YgODK4e1566GQs5BIfP30B0oenwBJHfWxAs2fyPB1s7Mg949zLf61Yw==", + "optional": true + }, + "cipher-base": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/cipher-base/-/cipher-base-1.0.4.tgz", + "integrity": "sha512-Kkht5ye6ZGmwv40uUDZztayT2ThLQGfnj/T71N/XzeZeo3nf8foyW7zGTsPYkEya3m5f3cAypH+qe7YOrM1U2Q==", + "requires": { + "inherits": "^2.0.1", + "safe-buffer": "^5.0.1" + } + }, + "clean-stack": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/clean-stack/-/clean-stack-2.2.0.tgz", + "integrity": "sha512-4diC9HaTE+KRAMWhDhrGOECgWZxoevMc5TlkObMqNSsVU62PYzXZ/SMTjzyGAFF1YusgxGcSWTEXBhp0CPwQ1A==" + }, + "cli-cursor": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/cli-cursor/-/cli-cursor-3.1.0.tgz", + "integrity": "sha512-I/zHAwsKf9FqGoXM4WWRACob9+SNukZTd94DWF57E4toouRulbCxcUh6RKUEOQlYTHJnzkPMySvPNaaSLNfLZw==", + "requires": { + "restore-cursor": "^3.1.0" + } + }, + "cli-spinners": { + "version": "2.6.0", + "resolved": "https://registry.npmjs.org/cli-spinners/-/cli-spinners-2.6.0.tgz", + "integrity": "sha512-t+4/y50K/+4xcCRosKkA7W4gTr1MySvLV0q+PxmG7FJ5g+66ChKurYjxBCjHggHH3HA5Hh9cy+lcUGWDqVH+4Q==" + }, + "cli-table3": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/cli-table3/-/cli-table3-0.6.3.tgz", + "integrity": "sha512-w5Jac5SykAeZJKntOxJCrm63Eg5/4dhMWIcuTbo9rpE+brgaSZo0RuNJZeOyMgsUdhDeojvgyQLmjI+K50ZGyg==", + "optional": true, + "requires": { + "@colors/colors": "1.5.0", + "string-width": "^4.2.0" + } + }, + "cli-truncate": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/cli-truncate/-/cli-truncate-2.1.0.tgz", + "integrity": "sha512-n8fOixwDD6b/ObinzTrp1ZKFzbgvKZvuz/TvejnLn1aQfC6r52XEx85FmuC+3HI+JM7coBRXUvNqEU2PHVrHpg==", + "optional": true, + "requires": { + "slice-ansi": "^3.0.0", + "string-width": "^4.2.0" + } + }, + "cli-width": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/cli-width/-/cli-width-4.1.0.tgz", + "integrity": "sha512-ouuZd4/dm2Sw5Gmqy6bGyNNNe1qt9RpmxveLSO7KcgsTnU7RXfsw+/bukWGo1abgBiMAic068rclZsO4IWmmxQ==" + }, + "clipboard": { + "version": "2.0.11", + "resolved": "https://registry.npmjs.org/clipboard/-/clipboard-2.0.11.tgz", + "integrity": "sha512-C+0bbOqkezLIsmWSvlsXS0Q0bmkugu7jcfMIACB+RDEntIzQIkdr148we28AfSloQLRdZlYL/QYyrq05j/3Faw==", + "requires": { + "good-listener": "^1.2.2", + "select": "^1.1.2", + "tiny-emitter": "^2.0.0" + } + }, + "cliui": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-6.0.0.tgz", + "integrity": "sha512-t6wbgtoCXvAzst7QgXxJYqPt0usEfbgQdftEPbLL/cvv6HPE5VgvqCuAIDR0NgU52ds6rFwqrgakNLrHEjCbrQ==", + "requires": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^6.2.0" + } + }, + "clone": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/clone/-/clone-1.0.4.tgz", + "integrity": "sha1-2jCcwmPfFZlMaIypAheco8fNfH4=" + }, + "clone-deep": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/clone-deep/-/clone-deep-4.0.1.tgz", + "integrity": "sha512-neHB9xuzh/wk0dIHweyAXv2aPGZIVk3pLMe+/RNzINf17fe0OG96QroktYAUm7SM1PBnzTabaLboqqxDyMU+SQ==", + "requires": { + "is-plain-object": "^2.0.4", + "kind-of": "^6.0.2", + "shallow-clone": "^3.0.0" + } + }, + "color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "requires": { + "color-name": "1.1.3" + } + }, + "color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha512-72fSenhMw2HZMTVHeCA9KCmpEIbzWiQsjN+BHcBbS9vr1mtt+vJjPdksIBNUmKAW8TFUDPJK5SUU3QhE9NEXDw==" + }, + "colorette": { + "version": "2.0.20", + "resolved": "https://registry.npmjs.org/colorette/-/colorette-2.0.20.tgz", + "integrity": "sha512-IfEDxwoWIjkeXL1eXcDiow4UbKjhLdq6/EuSVR9GMN7KVH3r9gQ83e73hsz1Nd1T3ijd5xv1wcWRYO+D6kCI2w==" + }, + "combine-source-map": { + "version": "0.8.0", + "resolved": "https://registry.npmjs.org/combine-source-map/-/combine-source-map-0.8.0.tgz", + "integrity": "sha1-pY0N8ELBhvz4IqjoAV9UUNLXmos=", + "requires": { + "convert-source-map": "~1.1.0", + "inline-source-map": "~0.6.0", + "lodash.memoize": "~3.0.3", + "source-map": "~0.5.3" + }, + "dependencies": { + "convert-source-map": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.1.3.tgz", + "integrity": "sha1-SCnId+n+SbMWHzvzZziI4gRpmGA=" + }, + "lodash.memoize": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/lodash.memoize/-/lodash.memoize-3.0.4.tgz", + "integrity": "sha1-LcvSwofLwKVcxCMovQxzYVDVPj8=" + }, + "source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=" + } + } + }, + "combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "optional": true, + "requires": { + "delayed-stream": "~1.0.0" + } + }, + "commander": { + "version": "2.20.3", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", + "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==" + }, + "common-path-prefix": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/common-path-prefix/-/common-path-prefix-3.0.0.tgz", + "integrity": "sha512-QE33hToZseCH3jS0qN96O/bSh3kaw/h+Tq7ngyY9eWDUnTlTNUyqfqvCXioLe5Na5jFsL78ra/wuBU4iuEgd4w==" + }, + "common-shakeify": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/common-shakeify/-/common-shakeify-1.1.1.tgz", + "integrity": "sha512-M9hTU14RkpKvNggSU4zJIzgm89inwjnhipxvKxCNms/gM77R7keRqOqGYIM/Jr4BBhtbZB8ZF//raYqAbHk/DA==", + "requires": { + "@goto-bus-stop/common-shake": "^2.3.0", + "convert-source-map": "^1.5.1", + "through2": "^2.0.3", + "transform-ast": "^2.4.3", + "wrap-comment": "^1.0.1" + } + }, + "common-tags": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/common-tags/-/common-tags-1.8.0.tgz", + "integrity": "sha512-6P6g0uetGpW/sdyUy/iQQCbFF0kWVMSIVSyYz7Zgjcgh8mgw8PQzDNZeyZ5DQ2gM7LBoZPHmnjz8rUthkBG5tw==", + "optional": true + }, + "compressible": { + "version": "2.0.18", + "resolved": "https://registry.npmjs.org/compressible/-/compressible-2.0.18.tgz", + "integrity": "sha512-AF3r7P5dWxL8MxyITRMlORQNaOA2IkAFaTr4k7BUumjPtRpGDTZpl0Pb1XCO6JeDCBdp126Cgs9sMxqSjgYyRg==", + "requires": { + "mime-db": ">= 1.43.0 < 2" + } + }, + "compression": { + "version": "1.7.4", + "resolved": "https://registry.npmjs.org/compression/-/compression-1.7.4.tgz", + "integrity": "sha512-jaSIDzP9pZVS4ZfQ+TzvtiWhdpFhE2RDHz8QJkpX9SIpLq88VueF5jJw6t+6CUQcAoA6t+x89MLrWAqpfDE8iQ==", + "requires": { + "accepts": "~1.3.5", + "bytes": "3.0.0", + "compressible": "~2.0.16", + "debug": "2.6.9", + "on-headers": "~1.0.2", + "safe-buffer": "5.1.2", + "vary": "~1.1.2" + }, + "dependencies": { + "bytes": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.0.0.tgz", + "integrity": "sha512-pMhOfFDPiv9t5jjIXkHosWmkSyQbvsgEVNkz0ERHbuLh2T/7j4Mqqpz523Fe8MVY89KC6Sh/QfS2sM+SjgFDcw==" + }, + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "requires": { + "ms": "2.0.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" + } + } + }, + "concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=" + }, + "concat-stream": { + "version": "1.6.2", + "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.2.tgz", + "integrity": "sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==", + "requires": { + "buffer-from": "^1.0.0", + "inherits": "^2.0.3", + "readable-stream": "^2.2.2", + "typedarray": "^0.0.6" + } + }, + "connect": { + "version": "3.6.6", + "resolved": "https://registry.npmjs.org/connect/-/connect-3.6.6.tgz", + "integrity": "sha512-OO7axMmPpu/2XuX1+2Yrg0ddju31B6xLZMWkJ5rYBu4YRmRVlOjvlY6kw2FJKiAzyxGwnrDUAG4s1Pf0sbBMCQ==", + "devOptional": true, + "requires": { + "debug": "2.6.9", + "finalhandler": "1.1.0", + "parseurl": "~1.3.2", + "utils-merge": "1.0.1" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "devOptional": true, + "requires": { + "ms": "2.0.0" + } + }, + "finalhandler": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.0.tgz", + "integrity": "sha512-ejnvM9ZXYzp6PUPUyQBMBf0Co5VX2gr5H2VQe2Ui2jWXNlxv+PYZo8wpAymJNJdLsG1R4p+M4aynF8KuoUEwRw==", + "devOptional": true, + "requires": { + "debug": "2.6.9", + "encodeurl": "~1.0.1", + "escape-html": "~1.0.3", + "on-finished": "~2.3.0", + "parseurl": "~1.3.2", + "statuses": "~1.3.1", + "unpipe": "~1.0.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "devOptional": true + }, + "statuses": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.3.1.tgz", + "integrity": "sha512-wuTCPGlJONk/a1kqZ4fQM2+908lC7fa7nPYpTC1EhnvqLX/IICbeP1OZGDtA374trpSq68YubKUMo8oRhN46yg==", + "devOptional": true + } + } + }, + "connect-history-api-fallback": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/connect-history-api-fallback/-/connect-history-api-fallback-1.6.0.tgz", + "integrity": "sha512-e54B99q/OUoH64zYYRf3HBP5z24G38h5D3qXu23JGRoigpX5Ss4r9ZnDk3g0Z8uQC2x2lPaJ+UlWBc1ZWBWdLg==", + "devOptional": true + }, + "console-browserify": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/console-browserify/-/console-browserify-1.2.0.tgz", + "integrity": "sha512-ZMkYO/LkF17QvCPqM0gxw8yUzigAOZOSWSHg91FH6orS7vcEj5dVZTidN2fQ14yBSdg97RqhSNwLUXInd52OTA==" + }, + "constants-browserify": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/constants-browserify/-/constants-browserify-1.0.0.tgz", + "integrity": "sha1-wguW2MYXdIqvHBYCF2DNJ/y4y3U=" + }, + "content-disposition": { + "version": "0.5.4", + "resolved": "https://registry.npmjs.org/content-disposition/-/content-disposition-0.5.4.tgz", + "integrity": "sha512-FveZTNuGw04cxlAiWbzi6zTAL/lhehaWbTtgluJh4/E95DqMwTmha3KZN1aAWA8cFIhHzMZUvLevkw5Rqk+tSQ==", + "requires": { + "safe-buffer": "5.2.1" + }, + "dependencies": { + "safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==" + } + } + }, + "content-type": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/content-type/-/content-type-1.0.5.tgz", + "integrity": "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA==" + }, + "convert-source-map": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.9.0.tgz", + "integrity": "sha512-ASFBup0Mz1uyiIjANan1jzLQami9z1PoYSZCiiYW2FczPbenXc45FZdBZLzOT+r6+iciuEModtmCti+hjaAk0A==" + }, + "cookie": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.6.0.tgz", + "integrity": "sha512-U71cyTamuh1CRNCfpGY6to28lxvNwPG4Guz/EVjgf3Jmzv0vlDp1atT9eS5dDjMYHucpHbWns6Lwf3BKz6svdw==" + }, + "cookie-signature": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/cookie-signature/-/cookie-signature-1.0.6.tgz", + "integrity": "sha512-QADzlaHc8icV8I7vbaJXJwod9HWYp8uCqf1xa4OfNu1T7JVxQIrUgOWtHdNDtPiywmFbiS12VjotIXLrKM3orQ==" + }, + "copy-anything": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/copy-anything/-/copy-anything-2.0.6.tgz", + "integrity": "sha512-1j20GZTsvKNkc4BY3NpMOM8tt///wY3FpIzozTOFO2ffuZcV61nojHXVKIy3WM+7ADCy5FVhdZYHYDdgTU0yJw==", + "requires": { + "is-what": "^3.14.1" + } + }, + "copy-webpack-plugin": { + "version": "11.0.0", + "resolved": "https://registry.npmjs.org/copy-webpack-plugin/-/copy-webpack-plugin-11.0.0.tgz", + "integrity": "sha512-fX2MWpamkW0hZxMEg0+mYnA40LTosOSa5TqZ9GYIBzyJa9C3QUaMPSE2xAi/buNr8u89SfD9wHSQVBzrRa/SOQ==", + "requires": { + "fast-glob": "^3.2.11", + "glob-parent": "^6.0.1", + "globby": "^13.1.1", + "normalize-path": "^3.0.0", + "schema-utils": "^4.0.0", + "serialize-javascript": "^6.0.0" + }, + "dependencies": { + "glob-parent": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "requires": { + "is-glob": "^4.0.3" + } + } + } + }, + "core-js-compat": { + "version": "3.36.1", + "resolved": "https://registry.npmjs.org/core-js-compat/-/core-js-compat-3.36.1.tgz", + "integrity": "sha512-Dk997v9ZCt3X/npqzyGdTlq6t7lDBhZwGvV94PKzDArjp7BTRm7WlDAXYd/OWdeFHO8OChQYRJNJvUCqCbrtKA==", + "requires": { + "browserslist": "^4.23.0" + } + }, + "core-util-is": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", + "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=" + }, + "cors": { + "version": "2.8.5", + "resolved": "https://registry.npmjs.org/cors/-/cors-2.8.5.tgz", + "integrity": "sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g==", + "devOptional": true, + "requires": { + "object-assign": "^4", + "vary": "^1" + } + }, + "cosmiconfig": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-9.0.0.tgz", + "integrity": "sha512-itvL5h8RETACmOTFc4UfIyB2RfEHi71Ax6E/PivVxq9NseKbOWpeyHEOIbmAw1rs8Ak0VursQNww7lf7YtUwzg==", + "requires": { + "env-paths": "^2.2.1", + "import-fresh": "^3.3.0", + "js-yaml": "^4.1.0", + "parse-json": "^5.2.0" + }, + "dependencies": { + "argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==" + }, + "js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "requires": { + "argparse": "^2.0.1" + } + } + } + }, + "count-lines": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/count-lines/-/count-lines-0.1.2.tgz", + "integrity": "sha1-4zST+2hgqC9xWdgjeEP7+u/uWWI=" + }, + "create-ecdh": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/create-ecdh/-/create-ecdh-4.0.4.tgz", + "integrity": "sha512-mf+TCx8wWc9VpuxfP2ht0iSISLZnt0JgWlrOKZiNqyUZWnjIaCIVNQArMHnCZKfEYRg6IM7A+NeJoN8gf/Ws0A==", + "requires": { + "bn.js": "^4.1.0", + "elliptic": "^6.5.3" + }, + "dependencies": { + "bn.js": { + "version": "4.12.0", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", + "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==" + } + } + }, + "create-hash": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/create-hash/-/create-hash-1.2.0.tgz", + "integrity": "sha512-z00bCGNHDG8mHAkP7CtT1qVu+bFQUPjYq/4Iv3C3kWjTFV10zIjfSoeqXo9Asws8gwSHDGj/hl2u4OGIjapeCg==", + "requires": { + "cipher-base": "^1.0.1", + "inherits": "^2.0.1", + "md5.js": "^1.3.4", + "ripemd160": "^2.0.1", + "sha.js": "^2.4.0" + } + }, + "create-hmac": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/create-hmac/-/create-hmac-1.1.7.tgz", + "integrity": "sha512-MJG9liiZ+ogc4TzUwuvbER1JRdgvUFSB5+VR/g5h82fGaIRWMWddtKBHi7/sVhfjQZ6SehlyhvQYrcYkaUIpLg==", + "requires": { + "cipher-base": "^1.0.3", + "create-hash": "^1.1.0", + "inherits": "^2.0.1", + "ripemd160": "^2.0.0", + "safe-buffer": "^5.0.1", + "sha.js": "^2.4.8" + } + }, + "create-require": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz", + "integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==", + "dev": true + }, + "critters": { + "version": "0.0.22", + "resolved": "https://registry.npmjs.org/critters/-/critters-0.0.22.tgz", + "integrity": "sha512-NU7DEcQZM2Dy8XTKFHxtdnIM/drE312j2T4PCVaSUcS0oBeyT/NImpRw/Ap0zOr/1SE7SgPK9tGPg1WK/sVakw==", + "requires": { + "chalk": "^4.1.0", + "css-select": "^5.1.0", + "dom-serializer": "^2.0.0", + "domhandler": "^5.0.2", + "htmlparser2": "^8.0.2", + "postcss": "^8.4.23", + "postcss-media-query-parser": "^0.2.3" + }, + "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "requires": { + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==" + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, + "cross-spawn": { + "version": "7.0.3", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.3.tgz", + "integrity": "sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==", + "requires": { + "path-key": "^3.1.0", + "shebang-command": "^2.0.0", + "which": "^2.0.1" + } + }, + "crypto-browserify": { + "version": "3.12.0", + "resolved": "https://registry.npmjs.org/crypto-browserify/-/crypto-browserify-3.12.0.tgz", + "integrity": "sha512-fz4spIh+znjO2VjL+IdhEpRJ3YN6sMzITSBijk6FK2UvTqruSQW+/cCZTSNsMiZNvUeq0CqurF+dAbyiGOY6Wg==", + "requires": { + "browserify-cipher": "^1.0.0", + "browserify-sign": "^4.0.0", + "create-ecdh": "^4.0.0", + "create-hash": "^1.1.0", + "create-hmac": "^1.1.0", + "diffie-hellman": "^5.0.0", + "inherits": "^2.0.1", + "pbkdf2": "^3.0.3", + "public-encrypt": "^4.0.0", + "randombytes": "^2.0.0", + "randomfill": "^1.0.3" + } + }, + "css-loader": { + "version": "6.10.0", + "resolved": "https://registry.npmjs.org/css-loader/-/css-loader-6.10.0.tgz", + "integrity": "sha512-LTSA/jWbwdMlk+rhmElbDR2vbtQoTBPr7fkJE+mxrHj+7ru0hUmHafDRzWIjIHTwpitWVaqY2/UWGRca3yUgRw==", + "requires": { + "icss-utils": "^5.1.0", + "postcss": "^8.4.33", + "postcss-modules-extract-imports": "^3.0.0", + "postcss-modules-local-by-default": "^4.0.4", + "postcss-modules-scope": "^3.1.1", + "postcss-modules-values": "^4.0.0", + "postcss-value-parser": "^4.2.0", + "semver": "^7.5.4" + } + }, + "css-select": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/css-select/-/css-select-5.1.0.tgz", + "integrity": "sha512-nwoRF1rvRRnnCqqY7updORDsuqKzqYJ28+oSMaJMMgOauh3fvwHqMS7EZpIPqK8GL+g9mKxF1vP/ZjSeNjEVHg==", + "requires": { + "boolbase": "^1.0.0", + "css-what": "^6.1.0", + "domhandler": "^5.0.2", + "domutils": "^3.0.1", + "nth-check": "^2.0.1" + } + }, + "css-what": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/css-what/-/css-what-6.1.0.tgz", + "integrity": "sha512-HTUrgRJ7r4dsZKU6GjmpfRK1O76h97Z8MfS1G0FozR+oF2kG6Vfe8JE6zwrkbxigziPHinCJ+gCPjA9EaBDtRw==" + }, + "cssesc": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz", + "integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==" + }, + "custom-event": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/custom-event/-/custom-event-1.0.1.tgz", + "integrity": "sha1-XQKkaFCt8bSjF5RqOSj8y1v9BCU=", + "optional": true, + "peer": true + }, + "cypress": { + "version": "13.13.0", + "resolved": "https://registry.npmjs.org/cypress/-/cypress-13.13.0.tgz", + "integrity": "sha512-ou/MQUDq4tcDJI2FsPaod2FZpex4kpIK43JJlcBgWrX8WX7R/05ZxGTuxedOuZBfxjZxja+fbijZGyxiLP6CFA==", + "optional": true, + "requires": { + "@cypress/request": "^3.0.0", + "@cypress/xvfb": "^1.2.4", + "@types/sinonjs__fake-timers": "8.1.1", + "@types/sizzle": "^2.3.2", + "arch": "^2.2.0", + "blob-util": "^2.0.2", + "bluebird": "^3.7.2", + "buffer": "^5.7.1", + "cachedir": "^2.3.0", + "chalk": "^4.1.0", + "check-more-types": "^2.24.0", + "cli-cursor": "^3.1.0", + "cli-table3": "~0.6.1", + "commander": "^6.2.1", + "common-tags": "^1.8.0", + "dayjs": "^1.10.4", + "debug": "^4.3.4", + "enquirer": "^2.3.6", + "eventemitter2": "6.4.7", + "execa": "4.1.0", + "executable": "^4.1.1", + "extract-zip": "2.0.1", + "figures": "^3.2.0", + "fs-extra": "^9.1.0", + "getos": "^3.2.1", + "is-ci": "^3.0.1", + "is-installed-globally": "~0.4.0", + "lazy-ass": "^1.6.0", + "listr2": "^3.8.3", + "lodash": "^4.17.21", + "log-symbols": "^4.0.0", + "minimist": "^1.2.8", + "ospath": "^1.2.2", + "pretty-bytes": "^5.6.0", + "process": "^0.11.10", + "proxy-from-env": "1.0.0", + "request-progress": "^3.0.0", + "semver": "^7.5.3", + "supports-color": "^8.1.1", + "tmp": "~0.2.3", + "untildify": "^4.0.0", + "yauzl": "^2.10.0" + }, + "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "optional": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "optional": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + }, + "dependencies": { + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "optional": true, + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "optional": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "optional": true + }, + "commander": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-6.2.1.tgz", + "integrity": "sha512-U7VdrJFnJgo4xjrHpTzu0yrHPGImdsmD95ZlgYSEajAn2JKzDhDTPG9kBTefmObL2w/ngeZnilk+OV9CG3d7UA==", + "optional": true + }, + "execa": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/execa/-/execa-4.1.0.tgz", + "integrity": "sha512-j5W0//W7f8UxAn8hXVnwG8tLwdiUy4FJLcSupCg6maBYZDpyBvTApK7KyuI4bKj8KOh1r2YH+6ucuYtJv1bTZA==", + "optional": true, + "requires": { + "cross-spawn": "^7.0.0", + "get-stream": "^5.0.0", + "human-signals": "^1.1.1", + "is-stream": "^2.0.0", + "merge-stream": "^2.0.0", + "npm-run-path": "^4.0.0", + "onetime": "^5.1.0", + "signal-exit": "^3.0.2", + "strip-final-newline": "^2.0.0" + } + }, + "fs-extra": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-9.1.0.tgz", + "integrity": "sha512-hcg3ZmepS30/7BSFqRvoo3DOMQu7IjqxO5nCDt+zM9XWjb33Wg7ziNT+Qvqbuc3+gWpzO02JubVyk2G4Zvo1OQ==", + "optional": true, + "requires": { + "at-least-node": "^1.0.0", + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + } + }, + "get-stream": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz", + "integrity": "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==", + "optional": true, + "requires": { + "pump": "^3.0.0" + } + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "optional": true + }, + "supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "optional": true, + "requires": { + "has-flag": "^4.0.0" + } + }, + "tmp": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.2.3.tgz", + "integrity": "sha512-nZD7m9iCPC5g0pYmcaxogYKggSfLsdxl8of3Q/oIbqCqLLIO9IAF0GWjX1z9NZRHPiXv8Wex4yDCaZsgEw0Y8w==", + "optional": true + } + } + }, + "cypress-fail-on-console-error": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/cypress-fail-on-console-error/-/cypress-fail-on-console-error-5.1.0.tgz", + "integrity": "sha512-u/AXLE9obLd9KcGHkGJluJVZeOj1EEOFOs0URxxca4FrftUDJQ3u+IoNfjRUjsrBKmJxgM4vKd0G10D+ZT1uIA==", + "optional": true, + "requires": { + "chai": "^4.3.10", + "sinon": "^17.0.0", + "sinon-chai": "^3.7.0", + "type-detect": "^4.0.8" + } + }, + "cypress-wait-until": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/cypress-wait-until/-/cypress-wait-until-2.0.1.tgz", + "integrity": "sha512-+IyVnYNiaX1+C+V/LazrJWAi/CqiwfNoRSrFviECQEyolW1gDRy765PZosL2alSSGK8V10Y7BGfOQyZUDgmnjQ==", + "optional": true + }, + "d": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/d/-/d-1.0.1.tgz", + "integrity": "sha512-m62ShEObQ39CfralilEQRjH6oAMtNCV1xJyEx5LpRYUVN+EviphDgUc/F3hnYbADmkiNs67Y+3ylmlG7Lnu+FA==", + "requires": { + "es5-ext": "^0.10.50", + "type": "^1.0.1" + } + }, + "dash-ast": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/dash-ast/-/dash-ast-1.0.0.tgz", + "integrity": "sha512-Vy4dx7gquTeMcQR/hDkYLGUnwVil6vk4FOOct+djUnHOUWt+zJPJAaRIXaAFkPXtJjvlY7o3rfRu0/3hpnwoUA==" + }, + "dashdash": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", + "integrity": "sha512-jRFi8UDGo6j+odZiEpjazZaWqEal3w/basFjQHQEwVtZJGDpxbH1MeYluwCS8Xq5wmLJooDlMgvVarmWfGM44g==", + "optional": true, + "requires": { + "assert-plus": "^1.0.0" + } + }, + "date-format": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/date-format/-/date-format-4.0.3.tgz", + "integrity": "sha512-7P3FyqDcfeznLZp2b+OMitV9Sz2lUnsT87WaTat9nVwqsBkTzPG3lPLNwW3en6F4pHUiWzr6vb8CLhjdK9bcxQ==", + "optional": true, + "peer": true + }, + "dayjs": { + "version": "1.11.9", + "resolved": "https://registry.npmjs.org/dayjs/-/dayjs-1.11.9.tgz", + "integrity": "sha512-QvzAURSbQ0pKdIye2txOzNaHmxtUBXerpY0FJsFXUMKbIZeFm5ht1LS/jFsrncjnmtv8HsG0W2g6c0zUjZWmpA==", + "optional": true + }, + "debug": { + "version": "4.3.4", + "resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz", + "integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==", + "requires": { + "ms": "2.1.2" + } + }, + "decamelize": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", + "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=" + }, + "dedent": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/dedent/-/dedent-0.7.0.tgz", + "integrity": "sha1-JJXduvbrh0q7Dhvp3yLS5aVEMmw=" + }, + "deep-eql": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/deep-eql/-/deep-eql-4.1.3.tgz", + "integrity": "sha512-WaEtAOpRA1MQ0eohqZjpGD8zdI0Ovsm8mmFhaDN8dvDZzyoUMcYDnf5Y6iu7HTXxf8JDS23qWa4a+hKCDyOPzw==", + "optional": true, + "requires": { + "type-detect": "^4.0.0" + } + }, + "deep-is": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/deep-is/-/deep-is-0.1.4.tgz", + "integrity": "sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ==", + "dev": true + }, + "default-gateway": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/default-gateway/-/default-gateway-6.0.3.tgz", + "integrity": "sha512-fwSOJsbbNzZ/CUFpqFBqYfYNLj1NbMPm8MMCIzHjC83iSJRBEGmDUxU+WP661BaBQImeC2yHwXtz+P/O9o+XEg==", + "requires": { + "execa": "^5.0.0" + } + }, + "defaults": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/defaults/-/defaults-1.0.3.tgz", + "integrity": "sha1-xlYFHpgX2f8I7YgUd/P+QBnz730=", + "requires": { + "clone": "^1.0.2" + } + }, + "define-data-property": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz", + "integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==", + "requires": { + "es-define-property": "^1.0.0", + "es-errors": "^1.3.0", + "gopd": "^1.0.1" + } + }, + "define-lazy-prop": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/define-lazy-prop/-/define-lazy-prop-2.0.0.tgz", + "integrity": "sha512-Ds09qNh8yw3khSjiJjiUInaGX9xlqZDY7JVryGxdxV7NPeuqQfplOpQ66yJFZut3jLa5zOwkXw1g9EI2uKh4Og==" + }, + "define-properties": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.2.1.tgz", + "integrity": "sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==", + "requires": { + "define-data-property": "^1.0.1", + "has-property-descriptors": "^1.0.0", + "object-keys": "^1.1.1" + } + }, + "defined": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/defined/-/defined-1.0.0.tgz", + "integrity": "sha1-yY2bzvdWdBiOEQlpFRGZ45sfppM=" + }, + "delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", + "optional": true + }, + "delegate": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/delegate/-/delegate-3.2.0.tgz", + "integrity": "sha512-IofjkYBZaZivn0V8nnsMJGBr4jVLxHDheKSW88PyxS5QC4Vo9ZbZVvhzlSxY87fVq3STR6r+4cGepyHkcWOQSw==" + }, + "depd": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/depd/-/depd-2.0.0.tgz", + "integrity": "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw==" + }, + "deps-sort": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/deps-sort/-/deps-sort-2.0.1.tgz", + "integrity": "sha512-1orqXQr5po+3KI6kQb9A4jnXT1PBwggGl2d7Sq2xsnOeI9GPcE/tGcF9UiSZtZBM7MukY4cAh7MemS6tZYipfw==", + "requires": { + "JSONStream": "^1.0.3", + "shasum-object": "^1.0.0", + "subarg": "^1.0.0", + "through2": "^2.0.0" + } + }, + "des.js": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/des.js/-/des.js-1.0.1.tgz", + "integrity": "sha512-Q0I4pfFrv2VPd34/vfLrFOoRmlYj3OV50i7fskps1jZWK1kApMWWT9G6RRUeYedLcBDIhnSDaUvJMb3AhUlaEA==", + "requires": { + "inherits": "^2.0.1", + "minimalistic-assert": "^1.0.0" + } + }, + "destroy": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/destroy/-/destroy-1.2.0.tgz", + "integrity": "sha512-2sJGJTaXIIaR1w4iJSNoN0hnMY7Gpc/n8D4qSCJw8QqFWXf7cuAgnEHxBpweaVcPevC2l3KpjYCx3NypQQgaJg==" + }, + "detect-node": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/detect-node/-/detect-node-2.1.0.tgz", + "integrity": "sha512-T0NIuQpnTvFDATNuHN5roPwSBG83rFsuO+MXXH9/3N1eFbn4wcPjttvjMLEPWJ0RGUYgQE7cGgS3tNxbqCGM7g==" + }, + "detective": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/detective/-/detective-5.2.0.tgz", + "integrity": "sha512-6SsIx+nUUbuK0EthKjv0zrdnajCCXVYGmbYYiYjFVpzcjwEs/JMDZ8tPRG29J/HhN56t3GJp2cGSWDRjjot8Pg==", + "requires": { + "acorn-node": "^1.6.1", + "defined": "^1.0.0", + "minimist": "^1.1.1" + } + }, + "dev-ip": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/dev-ip/-/dev-ip-1.0.1.tgz", + "integrity": "sha512-LmVkry/oDShEgSZPNgqCIp2/TlqtExeGmymru3uCELnfyjY11IzpAproLYs+1X88fXO6DBoYP3ul2Xo2yz2j6A==", + "devOptional": true + }, + "di": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/di/-/di-0.0.1.tgz", + "integrity": "sha1-gGZJMmzqp8qjMG112YXqJ0i6kTw=", + "optional": true, + "peer": true + }, + "diff": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz", + "integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==", + "dev": true + }, + "diffie-hellman": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/diffie-hellman/-/diffie-hellman-5.0.3.tgz", + "integrity": "sha512-kqag/Nl+f3GwyK25fhUMYj81BUOrZ9IuJsjIcDE5icNM9FJHAVm3VcUDxdLPoQtTuUylWm6ZIknYJwwaPxsUzg==", + "requires": { + "bn.js": "^4.1.0", + "miller-rabin": "^4.0.0", + "randombytes": "^2.0.0" + }, + "dependencies": { + "bn.js": { + "version": "4.12.0", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", + "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==" + } + } + }, + "dijkstrajs": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/dijkstrajs/-/dijkstrajs-1.0.1.tgz", + "integrity": "sha1-082BIh4+pAdCz83lVtTpnpjdxxs=" + }, + "dir-glob": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", + "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", + "requires": { + "path-type": "^4.0.0" + } + }, + "dns-packet": { + "version": "5.6.1", + "resolved": "https://registry.npmjs.org/dns-packet/-/dns-packet-5.6.1.tgz", + "integrity": "sha512-l4gcSouhcgIKRvyy99RNVOgxXiicE+2jZoNmaNmZ6JXiGajBOJAesk1OBlJuM5k2c+eudGdLxDqXuPCKIj6kpw==", + "requires": { + "@leichtgewicht/ip-codec": "^2.0.1" + } + }, + "doctrine": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", + "integrity": "sha512-yS+Q5i3hBf7GBkd4KG8a7eBNNWNGLTaEwwYWUijIYM7zrlYDM0BFXHjjPWlWZ1Rg7UaddZeIDmi9jF3HmqiQ2w==", + "dev": true, + "requires": { + "esutils": "^2.0.2" + } + }, + "dom-serialize": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/dom-serialize/-/dom-serialize-2.2.1.tgz", + "integrity": "sha1-ViromZ9Evl6jB29UGdzVnrQ6yVs=", + "optional": true, + "peer": true, + "requires": { + "custom-event": "~1.0.0", + "ent": "~2.2.0", + "extend": "^3.0.0", + "void-elements": "^2.0.0" + } + }, + "dom-serializer": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/dom-serializer/-/dom-serializer-2.0.0.tgz", + "integrity": "sha512-wIkAryiqt/nV5EQKqQpo3SToSOV9J0DnbJqwK7Wv/Trc92zIAYZ4FlMu+JPFW1DfGFt81ZTCGgDEabffXeLyJg==", + "requires": { + "domelementtype": "^2.3.0", + "domhandler": "^5.0.2", + "entities": "^4.2.0" + } + }, + "domain-browser": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/domain-browser/-/domain-browser-1.2.0.tgz", + "integrity": "sha512-jnjyiM6eRyZl2H+W8Q/zLMA481hzi0eszAaBUzIVnmYVDBbnLxVNnfu1HgEBvCbL+71FrxMl3E6lpKH7Ge3OXA==" + }, + "domelementtype": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/domelementtype/-/domelementtype-2.3.0.tgz", + "integrity": "sha512-OLETBj6w0OsagBwdXnPdN0cnMfF9opN69co+7ZrbfPGrdpPVNBUj02spi6B1N7wChLQiPn4CSH/zJvXw56gmHw==" + }, + "domhandler": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/domhandler/-/domhandler-5.0.3.tgz", + "integrity": "sha512-cgwlv/1iFQiFnU96XXgROh8xTeetsnJiDsTc7TYCLFd9+/WNkIqPTxiM/8pSd8VIrhXGTf1Ny1q1hquVqDJB5w==", + "requires": { + "domelementtype": "^2.3.0" + } + }, + "domino": { + "version": "2.1.6", + "resolved": "https://registry.npmjs.org/domino/-/domino-2.1.6.tgz", + "integrity": "sha512-3VdM/SXBZX2omc9JF9nOPCtDaYQ67BGp5CoLpIQlO2KCAPETs8TcDHacF26jXadGbvUteZzRTeos2fhID5+ucQ==" + }, + "domutils": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/domutils/-/domutils-3.1.0.tgz", + "integrity": "sha512-H78uMmQtI2AhgDJjWeQmHwJJ2bLPD3GMmO7Zja/ZZh84wkm+4ut+IUnUdRa8uCGX88DiVx1j6FRe1XfxEgjEZA==", + "requires": { + "dom-serializer": "^2.0.0", + "domelementtype": "^2.3.0", + "domhandler": "^5.0.3" + } + }, + "duplexer": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/duplexer/-/duplexer-0.1.2.tgz", + "integrity": "sha512-jtD6YG370ZCIi/9GTaJKQxWTZD045+4R4hTk/x1UyoqadyJ9x9CgSi1RlVDQF8U2sxLLSnFkCaMihqljHIWgMg==" + }, + "duplexer2": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/duplexer2/-/duplexer2-0.1.4.tgz", + "integrity": "sha1-ixLauHjA1p4+eJEFFmKjL8a93ME=", + "requires": { + "readable-stream": "^2.0.2" + } + }, + "eastasianwidth": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", + "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==" + }, + "easy-extender": { + "version": "2.3.4", + "resolved": "https://registry.npmjs.org/easy-extender/-/easy-extender-2.3.4.tgz", + "integrity": "sha512-8cAwm6md1YTiPpOvDULYJL4ZS6WfM5/cTeVVh4JsvyYZAoqlRVUpHL9Gr5Fy7HA6xcSZicUia3DeAgO3Us8E+Q==", + "devOptional": true, + "requires": { + "lodash": "^4.17.10" + } + }, + "eazy-logger": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/eazy-logger/-/eazy-logger-4.0.1.tgz", + "integrity": "sha512-2GSFtnnC6U4IEKhEI7+PvdxrmjJ04mdsj3wHZTFiw0tUtG4HCWzTr13ZYTk8XOGnA1xQMaDljoBOYlk3D/MMSw==", + "devOptional": true, + "requires": { + "chalk": "4.1.2" + }, + "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "devOptional": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "devOptional": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "devOptional": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "devOptional": true + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "devOptional": true + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "devOptional": true, + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, + "ecc-jsbn": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz", + "integrity": "sha512-eh9O+hwRHNbG4BLTjEl3nw044CkGm5X6LoaCf7LPp7UU8Qrt47JYNi6nPX8xjW97TKGKm1ouctg0QSpZe9qrnw==", + "optional": true, + "requires": { + "jsbn": "~0.1.0", + "safer-buffer": "^2.1.0" + } + }, + "echarts": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/echarts/-/echarts-5.5.0.tgz", + "integrity": "sha512-rNYnNCzqDAPCr4m/fqyUFv7fD9qIsd50S6GDFgO1DxZhncCsNsG7IfUlAlvZe5oSEQxtsjnHiUuppzccry93Xw==", + "requires": { + "tslib": "2.3.0", + "zrender": "5.5.0" + }, + "dependencies": { + "tslib": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.3.0.tgz", + "integrity": "sha512-N82ooyxVNm6h1riLCoyS9e3fuJ3AMG2zIZs2Gd1ATcSFjSA23Q0fzjjZeh0jbJvWVDZ0cJT8yaNNaaXHzueNjg==" + } + } + }, + "ee-first": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", + "integrity": "sha1-WQxhFWsK4vTwJVcyoViyZrxWsh0=" + }, + "electron-to-chromium": { + "version": "1.4.715", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.715.tgz", + "integrity": "sha512-XzWNH4ZSa9BwVUQSDorPWAUQ5WGuYz7zJUNpNif40zFCiCl20t8zgylmreNmn26h5kiyw2lg7RfTmeMBsDklqg==" + }, + "elliptic": { + "version": "6.5.4", + "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.5.4.tgz", + "integrity": "sha512-iLhC6ULemrljPZb+QutR5TQGB+pdW6KGD5RSegS+8sorOZT+rdQFbsQFJgvN3eRqNALqJer4oQ16YvJHlU8hzQ==", + "requires": { + "bn.js": "^4.11.9", + "brorand": "^1.1.0", + "hash.js": "^1.0.0", + "hmac-drbg": "^1.0.1", + "inherits": "^2.0.4", + "minimalistic-assert": "^1.0.1", + "minimalistic-crypto-utils": "^1.0.1" + }, + "dependencies": { + "bn.js": { + "version": "4.12.0", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", + "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==" + } + } + }, + "emoji-regex": { + "version": "8.0.0", + "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", + "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==" + }, + "emojis-list": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/emojis-list/-/emojis-list-3.0.0.tgz", + "integrity": "sha512-/kyM18EfinwXZbno9FyUGeFh87KC8HRQBQGildHZbEuRyWFOmv1U10o9BBp8XVZDVNNuQKyIGIu5ZYAAXJ0V2Q==" + }, + "encode-utf8": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/encode-utf8/-/encode-utf8-1.0.3.tgz", + "integrity": "sha512-ucAnuBEhUK4boH2HjVYG5Q2mQyPorvv0u/ocS+zhdw0S8AlHYY+GOFhP1Gio5z4icpP2ivFSvhtFjQi8+T9ppw==" + }, + "encodeurl": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/encodeurl/-/encodeurl-1.0.2.tgz", + "integrity": "sha1-rT/0yG7C0CkyL1oCw6mmBslbP1k=" + }, + "encoding": { + "version": "0.1.13", + "resolved": "https://registry.npmjs.org/encoding/-/encoding-0.1.13.tgz", + "integrity": "sha512-ETBauow1T35Y/WZMkio9jiM0Z5xjHHmJ4XmjZOq1l/dXz3lr2sRn87nJy20RupqSh1F2m3HHPSp8ShIPQJrJ3A==", + "optional": true, + "requires": { + "iconv-lite": "^0.6.2" + }, + "dependencies": { + "iconv-lite": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", + "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", + "optional": true, + "requires": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + } + } + } + }, + "end-of-stream": { + "version": "1.4.4", + "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz", + "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==", + "requires": { + "once": "^1.4.0" + } + }, + "engine.io": { + "version": "6.5.1", + "resolved": "https://registry.npmjs.org/engine.io/-/engine.io-6.5.1.tgz", + "integrity": "sha512-mGqhI+D7YxS9KJMppR6Iuo37Ed3abhU8NdfgSvJSDUafQutrN+sPTncJYTyM9+tkhSmWodKtVYGPPHyXJEwEQA==", + "devOptional": true, + "requires": { + "@types/cookie": "^0.4.1", + "@types/cors": "^2.8.12", + "@types/node": ">=10.0.0", + "accepts": "~1.3.4", + "base64id": "2.0.0", + "cookie": "~0.4.1", + "cors": "~2.8.5", + "debug": "~4.3.1", + "engine.io-parser": "~5.1.0", + "ws": "~8.11.0" + }, + "dependencies": { + "cookie": { + "version": "0.4.2", + "resolved": "https://registry.npmjs.org/cookie/-/cookie-0.4.2.tgz", + "integrity": "sha512-aSWTXFzaKWkvHO1Ny/s+ePFpvKsPnjc551iI41v3ny/ow6tBG5Vd+FuqGNhh1LxOmVzOlGUriIlOaokOvhaStA==", + "devOptional": true + }, + "ws": { + "version": "8.11.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.11.0.tgz", + "integrity": "sha512-HPG3wQd9sNQoT9xHyNCXoDUa+Xw/VevmY9FoHyQ+g+rrMn4j6FB4np7Z0OhdTgjx6MgQLK7jwSy1YecU1+4Asg==", + "devOptional": true, + "requires": {} + } + } + }, + "engine.io-client": { + "version": "6.5.3", + "resolved": "https://registry.npmjs.org/engine.io-client/-/engine.io-client-6.5.3.tgz", + "integrity": "sha512-9Z0qLB0NIisTRt1DZ/8U2k12RJn8yls/nXMZLn+/N8hANT3TcYjKFKcwbw5zFQiN4NTde3TSY9zb79e1ij6j9Q==", + "devOptional": true, + "requires": { + "@socket.io/component-emitter": "~3.1.0", + "debug": "~4.3.1", + "engine.io-parser": "~5.2.1", + "ws": "~8.11.0", + "xmlhttprequest-ssl": "~2.0.0" + }, + "dependencies": { + "engine.io-parser": { + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-5.2.2.tgz", + "integrity": "sha512-RcyUFKA93/CXH20l4SoVvzZfrSDMOTUS3bWVpTt2FuFP+XYrL8i8oonHP7WInRyVHXh0n/ORtoeiE1os+8qkSw==", + "devOptional": true + }, + "ws": { + "version": "8.11.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.11.0.tgz", + "integrity": "sha512-HPG3wQd9sNQoT9xHyNCXoDUa+Xw/VevmY9FoHyQ+g+rrMn4j6FB4np7Z0OhdTgjx6MgQLK7jwSy1YecU1+4Asg==", + "devOptional": true, + "requires": {} + } + } + }, + "engine.io-parser": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/engine.io-parser/-/engine.io-parser-5.1.0.tgz", + "integrity": "sha512-enySgNiK5tyZFynt3z7iqBR+Bto9EVVVvDFuTT0ioHCGbzirZVGDGiQjZzEp8hWl6hd5FSVytJGuScX1C1C35w==", + "devOptional": true + }, + "enhanced-resolve": { + "version": "5.15.0", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-5.15.0.tgz", + "integrity": "sha512-LXYT42KJ7lpIKECr2mAXIaMldcNCh/7E0KBKOu4KSfkHmP+mZmSs+8V5gBAqisWBy0OO4W5Oyys0GO1Y8KtdKg==", + "requires": { + "graceful-fs": "^4.2.4", + "tapable": "^2.2.0" + } + }, + "enquirer": { + "version": "2.3.6", + "resolved": "https://registry.npmjs.org/enquirer/-/enquirer-2.3.6.tgz", + "integrity": "sha512-yjNnPr315/FjS4zIsUxYguYUPP2e1NK4d7E7ZOLiyYCcbFBiTMyID+2wvm2w6+pZ/odMA7cRkjhsPbltwBOrLg==", + "optional": true, + "requires": { + "ansi-colors": "^4.1.1" + } + }, + "ent": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/ent/-/ent-2.2.0.tgz", + "integrity": "sha1-6WQhkyWiHQX0RGai9obtbOX13R0=", + "optional": true, + "peer": true + }, + "entities": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", + "integrity": "sha512-V0hjH4dGPh9Ao5p0MoRY6BVqtwCjhz6vI5LT8AJ55H+4g9/4vbHx1I54fS0XuclLhDHArPQCiMjDxjaL8fPxhw==" + }, + "env-paths": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/env-paths/-/env-paths-2.2.1.tgz", + "integrity": "sha512-+h1lkLKhZMTYjog1VEpJNG7NZJWcuc2DDk/qsqSTRRCOXiLjeQ1d1/udrUGhqMxUgAlwKNZ0cf2uqan5GLuS2A==" + }, + "err-code": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/err-code/-/err-code-2.0.3.tgz", + "integrity": "sha512-2bmlRpNKBxT/CRmPOlyISQpNj+qSeYvcym/uT0Jx2bMOlKLtSy1ZmLuVxSEKKyor/N5yhvp/ZiG1oE3DEYMSFA==" + }, + "errno": { + "version": "0.1.8", + "resolved": "https://registry.npmjs.org/errno/-/errno-0.1.8.tgz", + "integrity": "sha512-dJ6oBr5SQ1VSd9qkk7ByRgb/1SH4JZjCHSW/mr63/QcXO9zLVxvJ6Oy13nio03rxpSnVDDjFor75SjVeZWPW/A==", + "optional": true, + "requires": { + "prr": "~1.0.1" + } + }, + "error-ex": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", + "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", + "requires": { + "is-arrayish": "^0.2.1" + } + }, + "es-abstract": { + "version": "1.18.0", + "resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.18.0.tgz", + "integrity": "sha512-LJzK7MrQa8TS0ja2w3YNLzUgJCGPdPOV1yVvezjNnS89D+VR08+Szt2mz3YB2Dck/+w5tfIq/RoUAFqJJGM2yw==", + "requires": { + "call-bind": "^1.0.2", + "es-to-primitive": "^1.2.1", + "function-bind": "^1.1.1", + "get-intrinsic": "^1.1.1", + "has": "^1.0.3", + "has-symbols": "^1.0.2", + "is-callable": "^1.2.3", + "is-negative-zero": "^2.0.1", + "is-regex": "^1.1.2", + "is-string": "^1.0.5", + "object-inspect": "^1.9.0", + "object-keys": "^1.1.1", + "object.assign": "^4.1.2", + "string.prototype.trimend": "^1.0.4", + "string.prototype.trimstart": "^1.0.4", + "unbox-primitive": "^1.0.0" + } + }, + "es-define-property": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.0.tgz", + "integrity": "sha512-jxayLKShrEqqzJ0eumQbVhTYQM27CfT1T35+gCgDFoL82JLsXqTJ76zv6A0YLOgEnLUMvLzsDsGIrl8NFpT2gQ==", + "requires": { + "get-intrinsic": "^1.2.4" + } + }, + "es-errors": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz", + "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==" + }, + "es-module-lexer": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/es-module-lexer/-/es-module-lexer-1.3.0.tgz", + "integrity": "sha512-vZK7T0N2CBmBOixhmjdqx2gWVbFZ4DXZ/NyRMZVlJXPa7CyFS+/a4QQsDGDQy9ZfEzxFuNEsMLeQJnKP2p5/JA==" + }, + "es-to-primitive": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/es-to-primitive/-/es-to-primitive-1.2.1.tgz", + "integrity": "sha512-QCOllgZJtaUo9miYBcLChTUaHNjJF3PYs1VidD7AwiEj1kYxKeQTctLAezAOH5ZKRH0g2IgPn6KwB4IT8iRpvA==", + "requires": { + "is-callable": "^1.1.4", + "is-date-object": "^1.0.1", + "is-symbol": "^1.0.2" + } + }, + "es5-ext": { + "version": "0.10.64", + "resolved": "https://registry.npmjs.org/es5-ext/-/es5-ext-0.10.64.tgz", + "integrity": "sha512-p2snDhiLaXe6dahss1LddxqEm+SkuDvV8dnIQG0MWjyHpcMNfXKPE+/Cc0y+PhxJX3A4xGNeFCj5oc0BUh6deg==", + "requires": { + "es6-iterator": "^2.0.3", + "es6-symbol": "^3.1.3", + "esniff": "^2.0.1", + "next-tick": "^1.1.0" + } + }, + "es6-iterator": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/es6-iterator/-/es6-iterator-2.0.3.tgz", + "integrity": "sha1-p96IkUGgWpSwhUQDstCg+/qY87c=", + "requires": { + "d": "1", + "es5-ext": "^0.10.35", + "es6-symbol": "^3.1.1" + } + }, + "es6-map": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/es6-map/-/es6-map-0.1.5.tgz", + "integrity": "sha1-kTbgUD3MBqMBaQ8LsU/042TpSfA=", + "requires": { + "d": "1", + "es5-ext": "~0.10.14", + "es6-iterator": "~2.0.1", + "es6-set": "~0.1.5", + "es6-symbol": "~3.1.1", + "event-emitter": "~0.3.5" + } + }, + "es6-set": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/es6-set/-/es6-set-0.1.5.tgz", + "integrity": "sha1-0rPsXU2ADO2BjbU40ol02wpzzLE=", + "requires": { + "d": "1", + "es5-ext": "~0.10.14", + "es6-iterator": "~2.0.1", + "es6-symbol": "3.1.1", + "event-emitter": "~0.3.5" + }, + "dependencies": { + "es6-symbol": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/es6-symbol/-/es6-symbol-3.1.1.tgz", + "integrity": "sha1-vwDvT9q2uhtG7Le2KbTH7VcVzHc=", + "requires": { + "d": "1", + "es5-ext": "~0.10.14" + } + } + } + }, + "es6-symbol": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/es6-symbol/-/es6-symbol-3.1.3.tgz", + "integrity": "sha512-NJ6Yn3FuDinBaBRWl/q5X/s4koRHBrgKAu+yGI6JCBeiu3qrcbJhwT2GeR/EXVfylRk8dpQVJoLEFhK+Mu31NA==", + "requires": { + "d": "^1.0.1", + "ext": "^1.1.2" + } + }, + "es6-weak-map": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/es6-weak-map/-/es6-weak-map-2.0.3.tgz", + "integrity": "sha512-p5um32HOTO1kP+w7PRnB+5lQ43Z6muuMuIMffvDN8ZB4GcnjLBV6zGStpbASIMk4DCAvEaamhe2zhyCb/QXXsA==", + "requires": { + "d": "1", + "es5-ext": "^0.10.46", + "es6-iterator": "^2.0.3", + "es6-symbol": "^3.1.1" + } + }, + "esbuild": { + "version": "0.23.0", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.23.0.tgz", + "integrity": "sha512-1lvV17H2bMYda/WaFb2jLPeHU3zml2k4/yagNMG8Q/YtfMjCwEUZa2eXXMgZTVSL5q1n4H7sQ0X6CdJDqqeCFA==", + "requires": { + "@esbuild/aix-ppc64": "0.23.0", + "@esbuild/android-arm": "0.23.0", + "@esbuild/android-arm64": "0.23.0", + "@esbuild/android-x64": "0.23.0", + "@esbuild/darwin-arm64": "0.23.0", + "@esbuild/darwin-x64": "0.23.0", + "@esbuild/freebsd-arm64": "0.23.0", + "@esbuild/freebsd-x64": "0.23.0", + "@esbuild/linux-arm": "0.23.0", + "@esbuild/linux-arm64": "0.23.0", + "@esbuild/linux-ia32": "0.23.0", + "@esbuild/linux-loong64": "0.23.0", + "@esbuild/linux-mips64el": "0.23.0", + "@esbuild/linux-ppc64": "0.23.0", + "@esbuild/linux-riscv64": "0.23.0", + "@esbuild/linux-s390x": "0.23.0", + "@esbuild/linux-x64": "0.23.0", + "@esbuild/netbsd-x64": "0.23.0", + "@esbuild/openbsd-arm64": "0.23.0", + "@esbuild/openbsd-x64": "0.23.0", + "@esbuild/sunos-x64": "0.23.0", + "@esbuild/win32-arm64": "0.23.0", + "@esbuild/win32-ia32": "0.23.0", + "@esbuild/win32-x64": "0.23.0" + } + }, + "esbuild-wasm": { + "version": "0.20.1", + "resolved": "https://registry.npmjs.org/esbuild-wasm/-/esbuild-wasm-0.20.1.tgz", + "integrity": "sha512-6v/WJubRsjxBbQdz6izgvx7LsVFvVaGmSdwrFHmEzoVgfXL89hkKPoQHsnVI2ngOkcBUQT9kmAM1hVL1k/Av4A==" + }, + "escalade": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.1.tgz", + "integrity": "sha512-k0er2gUkLf8O0zKJiAhmkTnJlTvINGv7ygDNPbeIsX/TJjGJZHuh9B2UxbsaEkmlEo9MfhrSzmhIlhRlI2GXnw==" + }, + "escape-html": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz", + "integrity": "sha1-Aljq5NPQwJdN4cFpGI7wBR0dGYg=" + }, + "escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=" + }, + "escodegen": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/escodegen/-/escodegen-2.1.0.tgz", + "integrity": "sha512-2NlIDTwUWJN0mRPQOdtQBzbUHvdGY2P1VXSyU83Q3xKxM7WHX2Ql8dKq782Q9TgQUNOLEzEYu9bzLNj1q88I5w==", + "requires": { + "esprima": "^4.0.1", + "estraverse": "^5.2.0", + "esutils": "^2.0.2", + "source-map": "~0.6.1" + }, + "dependencies": { + "estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==" + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "optional": true + } + } + }, + "escope": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/escope/-/escope-3.6.0.tgz", + "integrity": "sha512-75IUQsusDdalQEW/G/2esa87J7raqdJF+Ca0/Xm5C3Q58Nr4yVYjZGp/P1+2xiEVgXRrA39dpRb8LcshajbqDQ==", + "requires": { + "es6-map": "^0.1.3", + "es6-weak-map": "^2.0.1", + "esrecurse": "^4.1.0", + "estraverse": "^4.1.1" + } + }, + "eslint": { + "version": "8.57.0", + "resolved": "https://registry.npmjs.org/eslint/-/eslint-8.57.0.tgz", + "integrity": "sha512-dZ6+mexnaTIbSBZWgou51U6OmzIhYM2VcNdtiTtI7qPNZm35Akpr0f6vtw3w1Kmn5PYo+tZVfh13WrhpS6oLqQ==", + "dev": true, + "requires": { + "@eslint-community/eslint-utils": "^4.2.0", + "@eslint-community/regexpp": "^4.6.1", + "@eslint/eslintrc": "^2.1.4", + "@eslint/js": "8.57.0", + "@humanwhocodes/config-array": "^0.11.14", + "@humanwhocodes/module-importer": "^1.0.1", + "@nodelib/fs.walk": "^1.2.8", + "@ungap/structured-clone": "^1.2.0", + "ajv": "^6.12.4", + "chalk": "^4.0.0", + "cross-spawn": "^7.0.2", + "debug": "^4.3.2", + "doctrine": "^3.0.0", + "escape-string-regexp": "^4.0.0", + "eslint-scope": "^7.2.2", + "eslint-visitor-keys": "^3.4.3", + "espree": "^9.6.1", + "esquery": "^1.4.2", + "esutils": "^2.0.2", + "fast-deep-equal": "^3.1.3", + "file-entry-cache": "^6.0.1", + "find-up": "^5.0.0", + "glob-parent": "^6.0.2", + "globals": "^13.19.0", + "graphemer": "^1.4.0", + "ignore": "^5.2.0", + "imurmurhash": "^0.1.4", + "is-glob": "^4.0.0", + "is-path-inside": "^3.0.3", + "js-yaml": "^4.1.0", + "json-stable-stringify-without-jsonify": "^1.0.1", + "levn": "^0.4.1", + "lodash.merge": "^4.6.2", + "minimatch": "^3.1.2", + "natural-compare": "^1.4.0", + "optionator": "^0.9.3", + "strip-ansi": "^6.0.1", + "text-table": "^0.2.0" + }, + "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "dev": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "argparse": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", + "integrity": "sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q==", + "dev": true + }, + "chalk": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz", + "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==", + "dev": true, + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "dev": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "dev": true + }, + "escape-string-regexp": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz", + "integrity": "sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA==", + "dev": true + }, + "eslint-scope": { + "version": "7.2.2", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-7.2.2.tgz", + "integrity": "sha512-dOt21O7lTMhDM+X9mB4GX+DZrZtCUJPL/wlcTqxyrx5IvO0IYtILdtrQGQp+8n5S0gwSVmOf9NQrjMOgfQZlIg==", + "dev": true, + "requires": { + "esrecurse": "^4.3.0", + "estraverse": "^5.2.0" + } + }, + "estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true + }, + "find-up": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", + "integrity": "sha512-78/PXT1wlLLDgTzDs7sjq9hzz0vXD+zn+7wypEe4fXQxCmdmqfGsEPQxmiCSQI3ajFV91bVSsvNtrJRiW6nGng==", + "dev": true, + "requires": { + "locate-path": "^6.0.0", + "path-exists": "^4.0.0" + } + }, + "glob-parent": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", + "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==", + "dev": true, + "requires": { + "is-glob": "^4.0.3" + } + }, + "globals": { + "version": "13.24.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-13.24.0.tgz", + "integrity": "sha512-AhO5QUcj8llrbG09iWhPU2B204J1xnPeL8kQmVorSsy+Sjj1sk8gIyh6cUocGmH4L0UuhAJy+hJMRA4mgA4mFQ==", + "dev": true, + "requires": { + "type-fest": "^0.20.2" + } + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "dev": true + }, + "js-yaml": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-4.1.0.tgz", + "integrity": "sha512-wpxZs9NoxZaJESJGIZTyDEaYpl0FKSA+FB9aJiyemKhMwkxQg63h4T1KJgUGHpTqPDNRcmmYLugrRjJlBtWvRA==", + "dev": true, + "requires": { + "argparse": "^2.0.1" + } + }, + "locate-path": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-6.0.0.tgz", + "integrity": "sha512-iPZK6eYjbxRu3uB4/WZ3EsEIMJFMqAoopl3R+zuq0UjcAm/MO6KCweDgPfP3elTztoKP3KtnVHxTn2NHBSDVUw==", + "dev": true, + "requires": { + "p-locate": "^5.0.0" + } + }, + "p-locate": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-5.0.0.tgz", + "integrity": "sha512-LaNjtRWUBY++zB5nE/NwcaoMylSPk+S+ZHNB1TzdbMJMny6dynpAGt7X/tl/QYq3TIeE6nxHppbo2LGymrG5Pw==", + "dev": true, + "requires": { + "p-limit": "^3.0.2" + } + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "dev": true, + "requires": { + "has-flag": "^4.0.0" + } + }, + "type-fest": { + "version": "0.20.2", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.20.2.tgz", + "integrity": "sha512-Ne+eE4r0/iWnpAxD852z3A+N0Bt5RN//NjJwRd2VFHEmrywxf5vsZlh4R6lixl6B+wz/8d+maTSAkN1FIkI3LQ==", + "dev": true + } + } + }, + "eslint-scope": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-5.1.1.tgz", + "integrity": "sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw==", + "requires": { + "esrecurse": "^4.3.0", + "estraverse": "^4.1.1" + } + }, + "eslint-visitor-keys": { + "version": "3.4.3", + "resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz", + "integrity": "sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag==", + "dev": true + }, + "esniff": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/esniff/-/esniff-2.0.1.tgz", + "integrity": "sha512-kTUIGKQ/mDPFoJ0oVfcmyJn4iBDRptjNVIzwIFR7tqWXdVI9xfA2RMwY/gbSpJG3lkdWNEjLap/NqVHZiJsdfg==", + "requires": { + "d": "^1.0.1", + "es5-ext": "^0.10.62", + "event-emitter": "^0.3.5", + "type": "^2.7.2" + }, + "dependencies": { + "type": { + "version": "2.7.2", + "resolved": "https://registry.npmjs.org/type/-/type-2.7.2.tgz", + "integrity": "sha512-dzlvlNlt6AXU7EBSfpAscydQ7gXB+pPGsPnfJnZpiNJBDj7IaJzQlBZYGdEi4R9HmPdBv2XmWJ6YUtoTa7lmCw==" + } + } + }, + "espree": { + "version": "9.6.1", + "resolved": "https://registry.npmjs.org/espree/-/espree-9.6.1.tgz", + "integrity": "sha512-oruZaFkjorTpF32kDSI5/75ViwGeZginGGy2NoOSg3Q9bnwlnmDm4HLnkl0RE3n+njDXR037aY1+x58Z/zFdwQ==", + "dev": true, + "requires": { + "acorn": "^8.9.0", + "acorn-jsx": "^5.3.2", + "eslint-visitor-keys": "^3.4.1" + }, + "dependencies": { + "acorn": { + "version": "8.11.3", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.11.3.tgz", + "integrity": "sha512-Y9rRfJG5jcKOE0CLisYbojUjIrIEE7AGMzA/Sm4BslANhbS+cDMpgBdcPT91oJ7OuJ9hYJBx59RjbhxVnrF8Xg==", + "dev": true + } + } + }, + "esprima": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/esprima/-/esprima-4.0.1.tgz", + "integrity": "sha512-eGuFFw7Upda+g4p+QHvnW0RyTX/SVeJBDM/gCtMARO0cLuT2HcEKnTPvhjV6aGeqrCB/sbNop0Kszm0jsaWU4A==" + }, + "esquery": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/esquery/-/esquery-1.5.0.tgz", + "integrity": "sha512-YQLXUplAwJgCydQ78IMJywZCceoqk1oH01OERdSAJc/7U2AylwjhSCLDEtqwg811idIS/9fIU5GjG73IgjKMVg==", + "dev": true, + "requires": { + "estraverse": "^5.1.0" + }, + "dependencies": { + "estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==", + "dev": true + } + } + }, + "esrecurse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.3.0.tgz", + "integrity": "sha512-KmfKL3b6G+RXvP8N1vr3Tq1kL/oCFgn2NYXEtqP8/L3pKapUA4G8cFVaoF3SU323CD4XypR/ffioHmkti6/Tag==", + "requires": { + "estraverse": "^5.2.0" + }, + "dependencies": { + "estraverse": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.2.0.tgz", + "integrity": "sha512-BxbNGGNm0RyRYvUdHpIwv9IWzeM9XClbOxwoATuFdOE7ZE6wHL+HQ5T8hoPM+zHvmKzzsEqhgy0GrQ5X13afiQ==" + } + } + }, + "estraverse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", + "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==" + }, + "estree-is-function": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/estree-is-function/-/estree-is-function-1.0.0.tgz", + "integrity": "sha512-nSCWn1jkSq2QAtkaVLJZY2ezwcFO161HVc174zL1KPW3RJ+O6C3eJb8Nx7OXzvhoEv+nLgSR1g71oWUHUDTrJA==" + }, + "estree-is-identifier": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/estree-is-identifier/-/estree-is-identifier-1.0.0.tgz", + "integrity": "sha512-2BDRGrkQJV/NhCAmmE33A35WAaxq3WQaGHgQuD//7orGWfpFqj8Srkwvx0TH+20yIdOF1yMQwi8anv5ISec2AQ==" + }, + "estree-is-member-expression": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/estree-is-member-expression/-/estree-is-member-expression-1.0.0.tgz", + "integrity": "sha512-Ec+X44CapIGExvSZN+pGkmr5p7HwUVQoPQSd458Lqwvaf4/61k/invHSh4BYK8OXnCkfEhWuIoG5hayKLQStIg==" + }, + "estree-is-require": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/estree-is-require/-/estree-is-require-1.0.0.tgz", + "integrity": "sha512-oWxQdSEmnUwNZsDQYiBNpVxKEhMmsJQSSxnDrwsr1MWtooCLfhgzsNGzmokdmfK0EzEIS5V4LPvqxv1Kmb1vvA==", + "requires": { + "estree-is-identifier": "^1.0.0" + } + }, + "esutils": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/esutils/-/esutils-2.0.3.tgz", + "integrity": "sha512-kVscqXk4OCp68SZ0dkgEKVi6/8ij300KBWTJq32P/dYeWTSwK41WyTxalN1eRmA5Z9UU/LX9D7FWSmV9SAYx6g==" + }, + "etag": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/etag/-/etag-1.8.1.tgz", + "integrity": "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg==" + }, + "event-emitter": { + "version": "0.3.5", + "resolved": "https://registry.npmjs.org/event-emitter/-/event-emitter-0.3.5.tgz", + "integrity": "sha1-34xp7vFkeSPHFXuc6DhAYQsCzDk=", + "requires": { + "d": "1", + "es5-ext": "~0.10.14" + } + }, + "event-stream": { + "version": "3.3.4", + "resolved": "https://registry.npmjs.org/event-stream/-/event-stream-3.3.4.tgz", + "integrity": "sha1-SrTJoPWlTbkzi0w02Gv86PSzVXE=", + "optional": true, + "requires": { + "duplexer": "~0.1.1", + "from": "~0", + "map-stream": "~0.1.0", + "pause-stream": "0.0.11", + "split": "0.3", + "stream-combiner": "~0.0.4", + "through": "~2.3.1" + }, + "dependencies": { + "stream-combiner": { + "version": "0.0.4", + "resolved": "https://registry.npmjs.org/stream-combiner/-/stream-combiner-0.0.4.tgz", + "integrity": "sha1-TV5DPBhSYd3mI8o/RMWGvPXErRQ=", + "optional": true, + "requires": { + "duplexer": "~0.1.1" + } + } + } + }, + "eventemitter2": { + "version": "6.4.7", + "resolved": "https://registry.npmjs.org/eventemitter2/-/eventemitter2-6.4.7.tgz", + "integrity": "sha512-tYUSVOGeQPKt/eC1ABfhHy5Xd96N3oIijJvN3O9+TsC28T5V9yX9oEfEK5faP0EFSNVOG97qtAS68GBrQB2hDg==", + "optional": true + }, + "eventemitter3": { + "version": "4.0.7", + "resolved": "https://registry.npmjs.org/eventemitter3/-/eventemitter3-4.0.7.tgz", + "integrity": "sha512-8guHBZCwKnFhYdHr2ysuRWErTwhoN2X8XELRlrRwpmfeY2jjuUN4taQMsULKUVo1K4DvZl+0pgfyoysHxvmvEw==" + }, + "events": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz", + "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==" + }, + "evp_bytestokey": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/evp_bytestokey/-/evp_bytestokey-1.0.3.tgz", + "integrity": "sha512-/f2Go4TognH/KvCISP7OUsHn85hT9nUkxxA9BEWxFn+Oj9o8ZNLm/40hdlgSLyuOimsrTKLUMEorQexp/aPQeA==", + "requires": { + "md5.js": "^1.3.4", + "safe-buffer": "^5.1.1" + } + }, + "execa": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/execa/-/execa-5.1.1.tgz", + "integrity": "sha512-8uSpZZocAZRBAPIEINJj3Lo9HyGitllczc27Eh5YYojjMFMn8yHMDMaUHE2Jqfq05D/wucwI4JGURyXt1vchyg==", + "requires": { + "cross-spawn": "^7.0.3", + "get-stream": "^6.0.0", + "human-signals": "^2.1.0", + "is-stream": "^2.0.0", + "merge-stream": "^2.0.0", + "npm-run-path": "^4.0.1", + "onetime": "^5.1.2", + "signal-exit": "^3.0.3", + "strip-final-newline": "^2.0.0" + }, + "dependencies": { + "human-signals": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-2.1.0.tgz", + "integrity": "sha512-B4FFZ6q/T2jhhksgkbEW3HBvWIfDW85snkQgawt07S7J5QXTk6BkNV+0yAeZrM5QpMAdYlocGoljn0sJ/WQkFw==" + } + } + }, + "executable": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/executable/-/executable-4.1.1.tgz", + "integrity": "sha512-8iA79xD3uAch729dUG8xaaBBFGaEa0wdD2VkYLFHwlqosEj/jT66AzcreRDSgV7ehnNLBW2WR5jIXwGKjVdTLg==", + "optional": true, + "requires": { + "pify": "^2.2.0" + } + }, + "exponential-backoff": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/exponential-backoff/-/exponential-backoff-3.1.1.tgz", + "integrity": "sha512-dX7e/LHVJ6W3DE1MHWi9S1EYzDESENfLrYohG2G++ovZrYOkm4Knwa0mc1cn84xJOR4KEU0WSchhLbd0UklbHw==" + }, + "express": { + "version": "4.19.2", + "resolved": "https://registry.npmjs.org/express/-/express-4.19.2.tgz", + "integrity": "sha512-5T6nhjsT+EOMzuck8JjBHARTHfMht0POzlA60WV2pMD3gyXw2LZnZ+ueGdNxG+0calOJcWKbpFcuzLZ91YWq9Q==", + "requires": { + "accepts": "~1.3.8", + "array-flatten": "1.1.1", + "body-parser": "1.20.2", + "content-disposition": "0.5.4", + "content-type": "~1.0.4", + "cookie": "0.6.0", + "cookie-signature": "1.0.6", + "debug": "2.6.9", + "depd": "2.0.0", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "finalhandler": "1.2.0", + "fresh": "0.5.2", + "http-errors": "2.0.0", + "merge-descriptors": "1.0.1", + "methods": "~1.1.2", + "on-finished": "2.4.1", + "parseurl": "~1.3.3", + "path-to-regexp": "0.1.7", + "proxy-addr": "~2.0.7", + "qs": "6.11.0", + "range-parser": "~1.2.1", + "safe-buffer": "5.2.1", + "send": "0.18.0", + "serve-static": "1.15.0", + "setprototypeof": "1.2.0", + "statuses": "2.0.1", + "type-is": "~1.6.18", + "utils-merge": "1.0.1", + "vary": "~1.1.2" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "requires": { + "ms": "2.0.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" + }, + "on-finished": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", + "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", + "requires": { + "ee-first": "1.1.1" + } + }, + "qs": { + "version": "6.11.0", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.11.0.tgz", + "integrity": "sha512-MvjoMCJwEarSbUYk5O+nmoSzSutSsTwF85zcHPQ9OrlFoZOYIjaqBAJIqIXjptyD5vThxGq52Xu/MaJzRkIk4Q==", + "requires": { + "side-channel": "^1.0.4" + } + }, + "safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==" + }, + "statuses": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", + "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==" + } + } + }, + "ext": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/ext/-/ext-1.4.0.tgz", + "integrity": "sha512-Key5NIsUxdqKg3vIsdw9dSuXpPCQ297y6wBjL30edxwPgt2E44WcWBZey/ZvUc6sERLTxKdyCu4gZFmUbk1Q7A==", + "requires": { + "type": "^2.0.0" + }, + "dependencies": { + "type": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/type/-/type-2.1.0.tgz", + "integrity": "sha512-G9absDWvhAWCV2gmF1zKud3OyC61nZDwWvBL2DApaVFogI07CprggiQAOOjvp2NRjYWFzPyu7vwtDrQFq8jeSA==" + } + } + }, + "extend": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", + "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==", + "optional": true + }, + "external-editor": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/external-editor/-/external-editor-3.1.0.tgz", + "integrity": "sha512-hMQ4CX1p1izmuLYyZqLMO/qGNw10wSv9QDCPfzXfyFrOaCSSoRfqE1Kf1s5an66J5JZC62NewG+mK49jOCtQew==", + "requires": { + "chardet": "^0.7.0", + "iconv-lite": "^0.4.24", + "tmp": "^0.0.33" + } + }, + "extract-zip": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extract-zip/-/extract-zip-2.0.1.tgz", + "integrity": "sha512-GDhU9ntwuKyGXdZBUgTIe+vXnWj0fppUEtMDL0+idd5Sta8TGpHssn/eusA9mrPr9qNDym6SxAYZjNvCn/9RBg==", + "optional": true, + "requires": { + "@types/yauzl": "^2.9.1", + "debug": "^4.1.1", + "get-stream": "^5.1.0", + "yauzl": "^2.10.0" + }, + "dependencies": { + "get-stream": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-5.2.0.tgz", + "integrity": "sha512-nBF+F1rAZVCu/p7rjzgA+Yb4lfYXrpl7a6VmJrU8wF9I1CKvP/QwPNZHnOlwbTkY6dvtFIzFMSyQXbLoTQPRpA==", + "optional": true, + "requires": { + "pump": "^3.0.0" + } + } + } + }, + "extsprintf": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz", + "integrity": "sha512-11Ndz7Nv+mvAC1j0ktTa7fAb0vLyGGX+rMHNBYQviQDGU0Hw7lhctJANqbPhu9nV9/izT/IntTgZ7Im/9LJs9g==", + "optional": true + }, + "falafel": { + "version": "2.2.4", + "resolved": "https://registry.npmjs.org/falafel/-/falafel-2.2.4.tgz", + "integrity": "sha512-0HXjo8XASWRmsS0X1EkhwEMZaD3Qvp7FfURwjLKjG1ghfRm/MGZl2r4cWUTv41KdNghTw4OUMmVtdGQp3+H+uQ==", + "requires": { + "acorn": "^7.1.1", + "foreach": "^2.0.5", + "isarray": "^2.0.1", + "object-keys": "^1.0.6" + } + }, + "fancy-canvas": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/fancy-canvas/-/fancy-canvas-0.2.2.tgz", + "integrity": "sha512-50qi8xA0QkHbjmb8h7XQ6k2fvD7y/yMfiUw9YTarJ7rWrq6o5/3CCXPouYk+XSLASvvxtjyiQLRBFt3qkE3oyA==" + }, + "fast-deep-equal": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz", + "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==" + }, + "fast-glob": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.2.tgz", + "integrity": "sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==", + "requires": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.2", + "merge2": "^1.3.0", + "micromatch": "^4.0.4" + } + }, + "fast-json-stable-stringify": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", + "integrity": "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw==" + }, + "fast-levenshtein": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-2.0.6.tgz", + "integrity": "sha512-DCXu6Ifhqcks7TZKY3Hxp3y6qphY5SJZmrWMDrKcERSOXWQdMhU9Ig/PYrzyw/ul9jOIyh0N4M0tbC5hodg8dw==", + "dev": true + }, + "fast-safe-stringify": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/fast-safe-stringify/-/fast-safe-stringify-2.0.7.tgz", + "integrity": "sha512-Utm6CdzT+6xsDk2m8S6uL8VHxNwI6Jub+e9NYTcAms28T84pTa25GJQV9j0CY0N1rM8hK4x6grpF2BQf+2qwVA==" + }, + "fastq": { + "version": "1.13.0", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.13.0.tgz", + "integrity": "sha512-YpkpUnK8od0o1hmeSc7UUs/eB/vIPWJYjKck2QKIzAf71Vm1AAQ3EbuZB3g2JIy+pg+ERD0vqI79KyZiB2e2Nw==", + "requires": { + "reusify": "^1.0.4" + } + }, + "faye-websocket": { + "version": "0.11.4", + "resolved": "https://registry.npmjs.org/faye-websocket/-/faye-websocket-0.11.4.tgz", + "integrity": "sha512-CzbClwlXAuiRQAlUyfqPgvPoNKTckTPGfwZV4ZdAhVcP2lh9KUxJg2b5GkE7XbjKQ3YJnQ9z6D9ntLAlB+tP8g==", + "requires": { + "websocket-driver": ">=0.5.1" + } + }, + "fd-slicer": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/fd-slicer/-/fd-slicer-1.1.0.tgz", + "integrity": "sha512-cE1qsB/VwyQozZ+q1dGxR8LBYNZeofhEdUNGSMbQD3Gw2lAzX9Zb3uIU6Ebc/Fmyjo9AWWfnn0AUCHqtevs/8g==", + "optional": true, + "requires": { + "pend": "~1.2.0" + } + }, + "figures": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/figures/-/figures-3.2.0.tgz", + "integrity": "sha512-yaduQFRKLXYOGgEn6AZau90j3ggSOyiqXU0F9JZfeXYhNa+Jk4X+s45A2zg5jns87GAFa34BBm2kXw4XpNcbdg==", + "requires": { + "escape-string-regexp": "^1.0.5" + } + }, + "file-entry-cache": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz", + "integrity": "sha512-7Gps/XWymbLk2QLYK4NzpMOrYjMhdIxXuIvy2QBsLE6ljuodKvdkWs/cpyJJ3CVIVpH0Oi1Hvg1ovbMzLdFBBg==", + "dev": true, + "requires": { + "flat-cache": "^3.0.4" + } + }, + "fill-range": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", + "requires": { + "to-regex-range": "^5.0.1" + } + }, + "finalhandler": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.2.0.tgz", + "integrity": "sha512-5uXcUVftlQMFnWC9qu/svkWv3GTd2PfUhK/3PLkYNAe7FbqJMt3515HaxE6eRL74GdsriiwujiawdaB1BpEISg==", + "requires": { + "debug": "2.6.9", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "on-finished": "2.4.1", + "parseurl": "~1.3.3", + "statuses": "2.0.1", + "unpipe": "~1.0.0" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "requires": { + "ms": "2.0.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" + }, + "on-finished": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", + "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", + "requires": { + "ee-first": "1.1.1" + } + }, + "statuses": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", + "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==" + } + } + }, + "find-cache-dir": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-4.0.0.tgz", + "integrity": "sha512-9ZonPT4ZAK4a+1pUPVPZJapbi7O5qbbJPdYw/NOQWZZbVLdDTYM3A4R9z/DpAM08IDaFGsvPgiGZ82WEwUDWjg==", + "requires": { + "common-path-prefix": "^3.0.0", + "pkg-dir": "^7.0.0" + } + }, + "find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "requires": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + } + }, + "flat": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/flat/-/flat-5.0.2.tgz", + "integrity": "sha512-b6suED+5/3rTpUBdG1gupIl8MPFCAMA0QXwmljLhvCUKcUvdE4gWky9zpuGCcXHOsz4J9wPGNWq6OKpmIzz3hQ==" + }, + "flat-cache": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/flat-cache/-/flat-cache-3.2.0.tgz", + "integrity": "sha512-CYcENa+FtcUKLmhhqyctpclsq7QF38pKjZHsGNiSQF5r4FtoKDWabFDl3hzaEQMvT1LHEysw5twgLvpYYb4vbw==", + "dev": true, + "requires": { + "flatted": "^3.2.9", + "keyv": "^4.5.3", + "rimraf": "^3.0.2" + } + }, + "flatted": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/flatted/-/flatted-3.3.1.tgz", + "integrity": "sha512-X8cqMLLie7KsNUDSdzeN8FYK9rEt4Dt67OsG/DNGnYTSDBG4uFAJFBnUeiV+zCVAvwFy56IjM9sH51jVaEhNxw==", + "devOptional": true + }, + "follow-redirects": { + "version": "1.15.6", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.6.tgz", + "integrity": "sha512-wWN62YITEaOpSK584EZXJafH1AGpO8RVgElfkuXbTOrPX4fIfOyEpW/CsiNd8JdYrAoOvafRTOEnvsO++qCqFA==" + }, + "foreach": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/foreach/-/foreach-2.0.5.tgz", + "integrity": "sha1-C+4AUBiusmDQo6865ljdATbsG5k=" + }, + "foreground-child": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/foreground-child/-/foreground-child-3.1.1.tgz", + "integrity": "sha512-TMKDUnIte6bfb5nWv7V/caI169OHgvwjb7V4WkeUvbQQdjr5rWKqHFiKWb/fcOwB+CzBT+qbWjvj+DVwRskpIg==", + "requires": { + "cross-spawn": "^7.0.0", + "signal-exit": "^4.0.1" + }, + "dependencies": { + "signal-exit": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-4.1.0.tgz", + "integrity": "sha512-bzyZ1e88w9O1iNJbKnOlvYTrWPDl46O1bG0D3XInv+9tkPrxrN8jUUTiFlDkkmKWgn1M6CfIA13SuGqOa9Korw==" + } + } + }, + "forever-agent": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", + "integrity": "sha512-j0KLYPhm6zeac4lz3oJ3o65qvgQCcPubiyotZrXqEaG4hNagNYO8qdlUrX5vwqv9ohqeT/Z3j6+yW067yWWdUw==", + "optional": true + }, + "form-data": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.3.tgz", + "integrity": "sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==", + "optional": true, + "requires": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.6", + "mime-types": "^2.1.12" + } + }, + "forwarded": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/forwarded/-/forwarded-0.2.0.tgz", + "integrity": "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow==" + }, + "fraction.js": { + "version": "4.3.7", + "resolved": "https://registry.npmjs.org/fraction.js/-/fraction.js-4.3.7.tgz", + "integrity": "sha512-ZsDfxO51wGAXREY55a7la9LScWpwv9RxIrYABrlvOFBlH/ShPnrtsXeuUIfXKKOVicNxQ+o8JTbJvjS4M89yew==" + }, + "fresh": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/fresh/-/fresh-0.5.2.tgz", + "integrity": "sha512-zJ2mQYM18rEFOudeV4GShTGIQ7RbzA7ozbU9I/XBpm7kqgMywgmylMwXHxZJmkVoYkna9d2pVXVXPdYTP9ej8Q==" + }, + "from": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/from/-/from-0.1.7.tgz", + "integrity": "sha1-g8YK/Fi5xWmXAH7Rp2izqzA6RP4=", + "optional": true + }, + "from2": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/from2/-/from2-2.3.0.tgz", + "integrity": "sha1-i/tVAr3kpNNs/e6gB/zKIdfjgq8=", + "requires": { + "inherits": "^2.0.1", + "readable-stream": "^2.0.0" + } + }, + "from2-string": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/from2-string/-/from2-string-1.1.0.tgz", + "integrity": "sha1-GCgrJ9CKJnyzAwzSuLSw8hKvdSo=", + "requires": { + "from2": "^2.0.3" + } + }, + "fs-extra": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-10.0.1.tgz", + "integrity": "sha512-NbdoVMZso2Lsrn/QwLXOy6rm0ufY2zEOKCDzJR/0kBsb0E6qed0P3iYK+Ath3BfvXEeu4JhEtXLgILx5psUfag==", + "optional": true, + "peer": true, + "requires": { + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + } + }, + "fs-minipass": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-3.0.3.tgz", + "integrity": "sha512-XUBA9XClHbnJWSfBzjkm6RvPsyg3sryZt06BEQoXcF7EK/xpGaQYJgQKDJSUH5SGZ76Y7pFx1QBnXz09rU5Fbw==", + "requires": { + "minipass": "^7.0.3" + } + }, + "fs-monkey": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/fs-monkey/-/fs-monkey-1.0.5.tgz", + "integrity": "sha512-8uMbBjrhzW76TYgEV27Y5E//W2f/lTFmx78P2w19FZSxarhI/798APGQyuGCwmkNxgwGRhrLfvWyLBvNtuOmew==" + }, + "fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=" + }, + "fsevents": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", + "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==", + "optional": true + }, + "function-bind": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", + "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==" + }, + "gensync": { + "version": "1.0.0-beta.2", + "resolved": "https://registry.npmjs.org/gensync/-/gensync-1.0.0-beta.2.tgz", + "integrity": "sha512-3hN7NaskYvMDLQY55gnW3NQ+mesEAepTqlg+VEbj7zzqEMBVNhzcGYYeqFo/TlYz6eQiFcp1HcsCZO+nGgS8zg==" + }, + "get-assigned-identifiers": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/get-assigned-identifiers/-/get-assigned-identifiers-1.2.0.tgz", + "integrity": "sha512-mBBwmeGTrxEMO4pMaaf/uUEFHnYtwr8FTe8Y/mer4rcV/bye0qGm6pw1bGZFGStxC5O76c5ZAVBGnqHmOaJpdQ==" + }, + "get-caller-file": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz", + "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==" + }, + "get-func-name": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/get-func-name/-/get-func-name-2.0.2.tgz", + "integrity": "sha512-8vXOvuE167CtIc3OyItco7N/dpRtBbYOsPsXCz7X/PMnlGjYjSGuZJgM1Y7mmew7BKf9BqvLX2tnOVy1BBUsxQ==", + "optional": true + }, + "get-intrinsic": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.4.tgz", + "integrity": "sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ==", + "requires": { + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "has-proto": "^1.0.1", + "has-symbols": "^1.0.3", + "hasown": "^2.0.0" + } + }, + "get-package-type": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/get-package-type/-/get-package-type-0.1.0.tgz", + "integrity": "sha512-pjzuKtY64GYfWizNAJ0fr9VqttZkNiK2iS430LtIHzjBEr6bX8Am2zm4sW4Ro5wjWW5cAlRL1qAMTcXbjNAO2Q==" + }, + "get-stream": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-6.0.1.tgz", + "integrity": "sha512-ts6Wi+2j3jQjqi70w5AlN8DFnkSwC+MqmxEzdEALB2qXZYV3X/b1CTfgPLGJNMeAWxdPfU8FO1ms3NUfaHCPYg==" + }, + "getos": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/getos/-/getos-3.2.1.tgz", + "integrity": "sha512-U56CfOK17OKgTVqozZjUKNdkfEv6jk5WISBJ8SHoagjE6L69zOwl3Z+O8myjY9MEW3i2HPWQBt/LTbCgcC973Q==", + "optional": true, + "requires": { + "async": "^3.2.0" + } + }, + "getpass": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz", + "integrity": "sha512-0fzj9JxOLfJ+XGLhR8ze3unN0KZCgZwiSSDz168VERjK8Wl8kVSdcu2kspd4s4wtAa1y/qrVRiAA0WclVsu0ng==", + "optional": true, + "requires": { + "assert-plus": "^1.0.0" + } + }, + "glob": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.0.tgz", + "integrity": "sha512-lmLf6gtyrPq8tTjSmrO94wBeQbFR3HbLHbuyD69wuyQkImp2hWqMGB47OX65FBkPffO641IP9jWa1z4ivqG26Q==", + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + }, + "glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "requires": { + "is-glob": "^4.0.1" + } + }, + "glob-to-regexp": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/glob-to-regexp/-/glob-to-regexp-0.4.1.tgz", + "integrity": "sha512-lkX1HJXwyMcprw/5YUZc2s7DrpAiHB21/V+E1rHUrVNokkvB6bqMzT0VfV6/86ZNabt1k14YOIaT7nDvOX3Iiw==" + }, + "global-dirs": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/global-dirs/-/global-dirs-3.0.1.tgz", + "integrity": "sha512-NBcGGFbBA9s1VzD41QXDG+3++t9Mn5t1FpLdhESY6oKY4gYTFpX4wO3sqGUa0Srjtbfj3szX0RnemmrVRUdULA==", + "optional": true, + "requires": { + "ini": "2.0.0" + }, + "dependencies": { + "ini": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ini/-/ini-2.0.0.tgz", + "integrity": "sha512-7PnF4oN3CvZF23ADhA5wRaYEQpJ8qygSkbtTXWBeXWXmEVRXK+1ITciHWwHhsjv1TmW0MgacIv6hEi5pX5NQdA==", + "optional": true + } + } + }, + "globals": { + "version": "11.12.0", + "resolved": "https://registry.npmjs.org/globals/-/globals-11.12.0.tgz", + "integrity": "sha512-WOBp/EEGUiIsJSp7wcv/y6MO+lV9UoncWqxuFfm8eBwzWNgyfBd6Gz+IeKQ9jCmyhoH99g15M3T+QaVHFjizVA==" + }, + "globby": { + "version": "13.1.2", + "resolved": "https://registry.npmjs.org/globby/-/globby-13.1.2.tgz", + "integrity": "sha512-LKSDZXToac40u8Q1PQtZihbNdTYSNMuWe+K5l+oa6KgDzSvVrHXlJy40hUP522RjAIoNLJYBJi7ow+rbFpIhHQ==", + "requires": { + "dir-glob": "^3.0.1", + "fast-glob": "^3.2.11", + "ignore": "^5.2.0", + "merge2": "^1.4.1", + "slash": "^4.0.0" + } + }, + "good-listener": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/good-listener/-/good-listener-1.2.2.tgz", + "integrity": "sha1-1TswzfkxPf+33JoNR3CWqm0UXFA=", + "requires": { + "delegate": "^3.1.2" + } + }, + "gopd": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz", + "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==", + "requires": { + "get-intrinsic": "^1.1.3" + } + }, + "graceful-fs": { + "version": "4.2.9", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.9.tgz", + "integrity": "sha512-NtNxqUcXgpW2iMrfqSfR73Glt39K+BLwWsPs94yR63v45T0Wbej7eRmL5cWfwEgqXnmjQp3zaJTshdRW/qC2ZQ==" + }, + "graphemer": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/graphemer/-/graphemer-1.4.0.tgz", + "integrity": "sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag==", + "dev": true + }, + "handle-thing": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/handle-thing/-/handle-thing-2.0.1.tgz", + "integrity": "sha512-9Qn4yBxelxoh2Ow62nP+Ka/kMnOXRi8BXnRaUwezLNhqelnN49xKz4F/dPP8OYLxLxq6JDtZb2i9XznUQbNPTg==" + }, + "has": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has/-/has-1.0.3.tgz", + "integrity": "sha512-f2dvO0VU6Oej7RkWJGrehjbzMAjFp5/VKPp5tTpWIV4JHHZK1/BxbFRtf/siA2SWTe09caDmVtYYzWEIbBS4zw==", + "requires": { + "function-bind": "^1.1.1" + } + }, + "has-ansi": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz", + "integrity": "sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE=", + "requires": { + "ansi-regex": "^2.0.0" + }, + "dependencies": { + "ansi-regex": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", + "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=" + } + } + }, + "has-bigints": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.1.tgz", + "integrity": "sha512-LSBS2LjbNBTf6287JEbEzvJgftkF5qFkmCo9hDRpAzKhUOlJ+hx8dd4USs00SgsUNwc4617J9ki5YtEClM2ffA==" + }, + "has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha512-sKJf1+ceQBr4SMkvQnBDNDtf4TXpVhVGateu0t918bl30FnbE2m4vNLX+VWe/dpjlb+HugGYzW7uQXH98HPEYw==" + }, + "has-property-descriptors": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz", + "integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==", + "requires": { + "es-define-property": "^1.0.0" + } + }, + "has-proto": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.1.tgz", + "integrity": "sha512-7qE+iP+O+bgF9clE5+UoBFzE65mlBiVj3tKCrlNQ0Ogwm0BjpT/gK4SlLYDMybDh5I3TCTKnPPa0oMG7JDYrhg==" + }, + "has-symbols": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz", + "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==" + }, + "has-tostringtag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.0.tgz", + "integrity": "sha512-kFjcSNhnlGV1kyoGk7OXKSawH5JOb/LzUc5w9B02hOTO0dfFRjbHQKvg1d6cf3HbeUmtU9VbbV3qzZ2Teh97WQ==", + "requires": { + "has-symbols": "^1.0.2" + } + }, + "hash-base": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/hash-base/-/hash-base-3.1.0.tgz", + "integrity": "sha512-1nmYp/rhMDiE7AYkDw+lLwlAzz0AntGIe51F3RfFfEqyQ3feY2eI/NcwC6umIQVOASPMsWJLJScWKSSvzL9IVA==", + "requires": { + "inherits": "^2.0.4", + "readable-stream": "^3.6.0", + "safe-buffer": "^5.2.0" + }, + "dependencies": { + "readable-stream": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", + "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", + "requires": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + } + }, + "safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==" + } + } + }, + "hash.js": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/hash.js/-/hash.js-1.1.7.tgz", + "integrity": "sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA==", + "requires": { + "inherits": "^2.0.3", + "minimalistic-assert": "^1.0.1" + } + }, + "hasown": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.0.tgz", + "integrity": "sha512-vUptKVTpIJhcczKBbgnS+RtcuYMB8+oNzPK2/Hp3hanz8JmpATdmmgLgSaadVREkDm+e2giHwY3ZRkyjSIDDFA==", + "requires": { + "function-bind": "^1.1.2" + } + }, + "hmac-drbg": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/hmac-drbg/-/hmac-drbg-1.0.1.tgz", + "integrity": "sha1-0nRXAQJabHdabFRXk+1QL8DGSaE=", + "requires": { + "hash.js": "^1.0.3", + "minimalistic-assert": "^1.0.0", + "minimalistic-crypto-utils": "^1.0.1" + } + }, + "hosted-git-info": { + "version": "7.0.1", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-7.0.1.tgz", + "integrity": "sha512-+K84LB1DYwMHoHSgaOY/Jfhw3ucPmSET5v98Ke/HdNSw4a0UktWzyW1mjhjpuxxTqOOsfWT/7iVshHmVZ4IpOA==", + "requires": { + "lru-cache": "^10.0.1" + }, + "dependencies": { + "lru-cache": { + "version": "10.2.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.2.0.tgz", + "integrity": "sha512-2bIM8x+VAf6JT4bKAljS1qUWgMsqZRPGJS6FSahIMPVvctcNhyVp7AJu7quxOW9jwkryBReKZY5tY5JYv2n/7Q==" + } + } + }, + "hpack.js": { + "version": "2.1.6", + "resolved": "https://registry.npmjs.org/hpack.js/-/hpack.js-2.1.6.tgz", + "integrity": "sha512-zJxVehUdMGIKsRaNt7apO2Gqp0BdqW5yaiGHXXmbpvxgBYVZnAql+BJb4RO5ad2MgpbZKn5G6nMnegrH1FcNYQ==", + "requires": { + "inherits": "^2.0.1", + "obuf": "^1.0.0", + "readable-stream": "^2.0.1", + "wbuf": "^1.1.0" + } + }, + "html-entities": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/html-entities/-/html-entities-2.5.2.tgz", + "integrity": "sha512-K//PSRMQk4FZ78Kyau+mZurHn3FH0Vwr+H36eE0rPbeYkRRi9YxceYPhuN60UwWorxyKHhqoAJl2OFKa4BVtaA==" + }, + "htmlescape": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/htmlescape/-/htmlescape-1.1.1.tgz", + "integrity": "sha1-OgPtwiFLyjtmQko+eVk0lQnLA1E=" + }, + "htmlparser2": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/htmlparser2/-/htmlparser2-8.0.2.tgz", + "integrity": "sha512-GYdjWKDkbRLkZ5geuHs5NY1puJ+PXwP7+fHPRz06Eirsb9ugf6d8kkXav6ADhcODhFFPMIXyxkxSuMf3D6NCFA==", + "requires": { + "domelementtype": "^2.3.0", + "domhandler": "^5.0.3", + "domutils": "^3.0.1", + "entities": "^4.4.0" + } + }, + "http-cache-semantics": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/http-cache-semantics/-/http-cache-semantics-4.1.1.tgz", + "integrity": "sha512-er295DKPVsV82j5kw1Gjt+ADA/XYHsajl82cGNQG2eyoPkvgUhX+nDIyelzhIWbbsXP39EHcI6l5tYs2FYqYXQ==" + }, + "http-deceiver": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/http-deceiver/-/http-deceiver-1.2.7.tgz", + "integrity": "sha512-LmpOGxTfbpgtGVxJrj5k7asXHCgNZp5nLfp+hWc8QQRqtb7fUy6kRY3BO1h9ddF6yIPYUARgxGOwB42DnxIaNw==" + }, + "http-errors": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-2.0.0.tgz", + "integrity": "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ==", + "requires": { + "depd": "2.0.0", + "inherits": "2.0.4", + "setprototypeof": "1.2.0", + "statuses": "2.0.1", + "toidentifier": "1.0.1" + }, + "dependencies": { + "statuses": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", + "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==" + } + } + }, + "http-parser-js": { + "version": "0.5.8", + "resolved": "https://registry.npmjs.org/http-parser-js/-/http-parser-js-0.5.8.tgz", + "integrity": "sha512-SGeBX54F94Wgu5RH3X5jsDtf4eHyRogWX1XGT3b4HuW3tQPM4AaBzoUji/4AAJNXCEOWZ5O0DgZmJw1947gD5Q==" + }, + "http-proxy": { + "version": "1.18.1", + "resolved": "https://registry.npmjs.org/http-proxy/-/http-proxy-1.18.1.tgz", + "integrity": "sha512-7mz/721AbnJwIVbnaSv1Cz3Am0ZLT/UBwkC92VlxhXv/k/BBQfM2fXElQNC27BVGr0uwUpplYPQM9LnaBMR5NQ==", + "requires": { + "eventemitter3": "^4.0.0", + "follow-redirects": "^1.0.0", + "requires-port": "^1.0.0" + } + }, + "http-proxy-agent": { + "version": "7.0.2", + "resolved": "https://registry.npmjs.org/http-proxy-agent/-/http-proxy-agent-7.0.2.tgz", + "integrity": "sha512-T1gkAiYYDWYx3V5Bmyu7HcfcvL7mUrTWiM6yOfa3PIphViJ/gFPbvidQ+veqSOHci/PxBcDabeUNCzpOODJZig==", + "requires": { + "agent-base": "^7.1.0", + "debug": "^4.3.4" + } + }, + "http-proxy-middleware": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/http-proxy-middleware/-/http-proxy-middleware-2.0.6.tgz", + "integrity": "sha512-ya/UeJ6HVBYxrgYotAZo1KvPWlgB48kUJLDePFeneHsVujFaW5WNj2NgWCAE//B1Dl02BIfYlpNgBy8Kf8Rjmw==", + "requires": { + "@types/http-proxy": "^1.17.8", + "http-proxy": "^1.18.1", + "is-glob": "^4.0.1", + "is-plain-obj": "^3.0.0", + "micromatch": "^4.0.2" + } + }, + "http-signature": { + "version": "1.3.6", + "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.3.6.tgz", + "integrity": "sha512-3adrsD6zqo4GsTqtO7FyrejHNv+NgiIfAfv68+jVlFmSr9OGy7zrxONceFRLKvnnZA5jbxQBX1u9PpB6Wi32Gw==", + "optional": true, + "requires": { + "assert-plus": "^1.0.0", + "jsprim": "^2.0.2", + "sshpk": "^1.14.1" + } + }, + "https-browserify": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/https-browserify/-/https-browserify-1.0.0.tgz", + "integrity": "sha1-7AbBDgo0wPL68Zn3/X/Hj//QPHM=" + }, + "https-proxy-agent": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/https-proxy-agent/-/https-proxy-agent-7.0.4.tgz", + "integrity": "sha512-wlwpilI7YdjSkWaQ/7omYBMTliDcmCN8OLihO6I9B86g06lMyAoqgoDpV0XqoaPOKj+0DIdAvnsWfyAAhmimcg==", + "requires": { + "agent-base": "^7.0.2", + "debug": "4" + } + }, + "human-signals": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/human-signals/-/human-signals-1.1.1.tgz", + "integrity": "sha512-SEQu7vl8KjNL2eoGBLF3+wAjpsNfA9XMlXAYj/3EdaNfAlxKthD1xjEQfGOUhllCGGJVNY34bRr6lPINhNjyZw==", + "optional": true + }, + "iconv-lite": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "requires": { + "safer-buffer": ">= 2.1.2 < 3" + } + }, + "icss-utils": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/icss-utils/-/icss-utils-5.1.0.tgz", + "integrity": "sha512-soFhflCVWLfRNOPU3iv5Z9VUdT44xFRbzjLsEzSr5AQmgqPMTHdU3PMT1Cf1ssx8fLNJDA1juftYl+PUcv3MqA==", + "requires": {} + }, + "ieee754": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz", + "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==" + }, + "ignore": { + "version": "5.3.1", + "resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.1.tgz", + "integrity": "sha512-5Fytz/IraMjqpwfd34ke28PTVMjZjJG2MPn5t7OE4eUCUNf8BAa7b5WUS9/Qvr6mwOQS7Mk6vdsMno5he+T8Xw==" + }, + "ignore-walk": { + "version": "6.0.4", + "resolved": "https://registry.npmjs.org/ignore-walk/-/ignore-walk-6.0.4.tgz", + "integrity": "sha512-t7sv42WkwFkyKbivUCglsQW5YWMskWtbEf4MNKX5u/CCWHKSPzN4FtBQGsQZgCLbxOzpVlcbWVK5KB3auIOjSw==", + "requires": { + "minimatch": "^9.0.0" + }, + "dependencies": { + "brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "requires": { + "balanced-match": "^1.0.0" + } + }, + "minimatch": { + "version": "9.0.3", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.3.tgz", + "integrity": "sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==", + "requires": { + "brace-expansion": "^2.0.1" + } + } + } + }, + "image-size": { + "version": "0.5.5", + "resolved": "https://registry.npmjs.org/image-size/-/image-size-0.5.5.tgz", + "integrity": "sha512-6TDAlDPZxUFCv+fuOkIoXT/V/f3Qbq8e37p+YOiYrUv3v9cc3/6x78VdfPgFVaB9dZYeLUfKgHRebpkm/oP2VQ==", + "optional": true + }, + "immutable": { + "version": "3.8.2", + "resolved": "https://registry.npmjs.org/immutable/-/immutable-3.8.2.tgz", + "integrity": "sha512-15gZoQ38eYjEjxkorfbcgBKBL6R7T459OuK+CpcWt7O3KF4uPCx2tD0uFETlUDIyo+1789crbMhTvQBSR5yBMg==", + "devOptional": true + }, + "import-fresh": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/import-fresh/-/import-fresh-3.3.0.tgz", + "integrity": "sha512-veYYhQa+D1QBKznvhUHxb8faxlrwUnxseDAbAp457E0wLNio2bOSKnjYDhMj+YiAq61xrMGhQk9iXVk5FzgQMw==", + "requires": { + "parent-module": "^1.0.0", + "resolve-from": "^4.0.0" + }, + "dependencies": { + "resolve-from": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-4.0.0.tgz", + "integrity": "sha512-pb/MYmXstAkysRFx8piNI1tGFNQIFA3vkE3Gq4EuA1dF6gHp/+vgZqsCGJapvy8N3Q+4o7FwvquPJcnZ7RYy4g==" + } + } + }, + "imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=" + }, + "indent-string": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-4.0.0.tgz", + "integrity": "sha512-EdDDZu4A2OyIK7Lr/2zG+w5jmbuk1DVBnEwREQvBzspBJkCEbRa8GxU1lghYcaGJCnRWibjDXlq779X1/y5xwg==" + }, + "inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", + "requires": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "inherits": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz", + "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==" + }, + "ini": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/ini/-/ini-4.1.2.tgz", + "integrity": "sha512-AMB1mvwR1pyBFY/nSevUX6y8nJWS63/SzUKD3JyQn97s4xgIdgQPT75IRouIiBAN4yLQBUShNYVW0+UG25daCw==" + }, + "inline-source-map": { + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/inline-source-map/-/inline-source-map-0.6.2.tgz", + "integrity": "sha1-+Tk0ccGKedFyT4Y/o4tYY3Ct4qU=", + "requires": { + "source-map": "~0.5.3" + }, + "dependencies": { + "source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=" + } + } + }, + "inquirer": { + "version": "9.2.15", + "resolved": "https://registry.npmjs.org/inquirer/-/inquirer-9.2.15.tgz", + "integrity": "sha512-vI2w4zl/mDluHt9YEQ/543VTCwPKWiHzKtm9dM2V0NdFcqEexDAjUHzO1oA60HRNaVifGXXM1tRRNluLVHa0Kg==", + "requires": { + "@ljharb/through": "^2.3.12", + "ansi-escapes": "^4.3.2", + "chalk": "^5.3.0", + "cli-cursor": "^3.1.0", + "cli-width": "^4.1.0", + "external-editor": "^3.1.0", + "figures": "^3.2.0", + "lodash": "^4.17.21", + "mute-stream": "1.0.0", + "ora": "^5.4.1", + "run-async": "^3.0.0", + "rxjs": "^7.8.1", + "string-width": "^4.2.3", + "strip-ansi": "^6.0.1", + "wrap-ansi": "^6.2.0" + }, + "dependencies": { + "chalk": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.3.0.tgz", + "integrity": "sha512-dLitG79d+GV1Nb/VYcCDFivJeK1hiukt9QjRNVOsUtTy1rR1YJsmpGGTZ3qJos+uw7WmWF4wUwBd9jxjocFC2w==" + } + } + }, + "insert-module-globals": { + "version": "7.2.1", + "resolved": "https://registry.npmjs.org/insert-module-globals/-/insert-module-globals-7.2.1.tgz", + "integrity": "sha512-ufS5Qq9RZN+Bu899eA9QCAYThY+gGW7oRkmb0vC93Vlyu/CFGcH0OYPEjVkDXA5FEbTt1+VWzdoOD3Ny9N+8tg==", + "requires": { + "acorn-node": "^1.5.2", + "combine-source-map": "^0.8.0", + "concat-stream": "^1.6.1", + "is-buffer": "^1.1.0", + "JSONStream": "^1.0.3", + "path-is-absolute": "^1.0.1", + "process": "~0.11.0", + "through2": "^2.0.0", + "undeclared-identifiers": "^1.1.2", + "xtend": "^4.0.0" + } + }, + "ip-address": { + "version": "9.0.5", + "resolved": "https://registry.npmjs.org/ip-address/-/ip-address-9.0.5.tgz", + "integrity": "sha512-zHtQzGojZXTwZTHQqra+ETKd4Sn3vgi7uBmlPoXVWZqYvuKmtI0l/VZTjqGmJY9x88GGOaZ9+G9ES8hC4T4X8g==", + "requires": { + "jsbn": "1.1.0", + "sprintf-js": "^1.1.3" + }, + "dependencies": { + "jsbn": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-1.1.0.tgz", + "integrity": "sha512-4bYVV3aAMtDTTu4+xsDYa6sy9GyJ69/amsu9sYF2zqjiEoZA5xJi3BrfX3uY+/IekIu7MwdObdbDWpoZdBv3/A==" + } + } + }, + "ipaddr.js": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-2.1.0.tgz", + "integrity": "sha512-LlbxQ7xKzfBusov6UMi4MFpEg0m+mAm9xyNGEduwXMEDuf4WfzB/RZwMVYEd7IKGvh4IUkEXYxtAVu9T3OelJQ==" + }, + "is-arguments": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/is-arguments/-/is-arguments-1.1.1.tgz", + "integrity": "sha512-8Q7EARjzEnKpt/PCD7e1cgUS0a6X8u5tdSiMqXhojOdoV9TsMsiO+9VLC5vAmO8N7/GmXn7yjR8qnA6bVAEzfA==", + "requires": { + "call-bind": "^1.0.2", + "has-tostringtag": "^1.0.0" + } + }, + "is-arrayish": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", + "integrity": "sha512-zz06S8t0ozoDXMG+ube26zeCTNXcKIPJZJi8hBrF4idCLms4CG9QtK7qBl1boi5ODzFpjswb5JPmHCbMpjaYzg==" + }, + "is-bigint": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.0.1.tgz", + "integrity": "sha512-J0ELF4yHFxHy0cmSxZuheDOz2luOdVvqjwmEcj8H/L1JHeuEDSDbeRP+Dk9kFVk5RTFzbucJ2Kb9F7ixY2QaCg==" + }, + "is-binary-path": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz", + "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==", + "requires": { + "binary-extensions": "^2.0.0" + } + }, + "is-boolean-object": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.1.0.tgz", + "integrity": "sha512-a7Uprx8UtD+HWdyYwnD1+ExtTgqQtD2k/1yJgtXP6wnMm8byhkoTZRl+95LLThpzNZJ5aEvi46cdH+ayMFRwmA==", + "requires": { + "call-bind": "^1.0.0" + } + }, + "is-buffer": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", + "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==" + }, + "is-callable": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.3.tgz", + "integrity": "sha512-J1DcMe8UYTBSrKezuIUTUwjXsho29693unXM2YhJUTR2txK/eG47bvNa/wipPFmZFgr/N6f1GA66dv0mEyTIyQ==" + }, + "is-ci": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/is-ci/-/is-ci-3.0.1.tgz", + "integrity": "sha512-ZYvCgrefwqoQ6yTyYUbQu64HsITZ3NfKX1lzaEYdkTDcfKzzCI/wthRRYKkdjHKFVgNiXKAKm65Zo1pk2as/QQ==", + "optional": true, + "requires": { + "ci-info": "^3.2.0" + } + }, + "is-core-module": { + "version": "2.13.1", + "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.13.1.tgz", + "integrity": "sha512-hHrIjvZsftOsvKSn2TRYl63zvxsgE0K+0mYMoH6gD4omR5IWB2KynivBQczo3+wF1cCkjzvptnI9Q0sPU66ilw==", + "requires": { + "hasown": "^2.0.0" + } + }, + "is-date-object": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.5.tgz", + "integrity": "sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==", + "requires": { + "has-tostringtag": "^1.0.0" + } + }, + "is-docker": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/is-docker/-/is-docker-2.2.1.tgz", + "integrity": "sha512-F+i2BKsFrH66iaUFc0woD8sLy8getkwTwtOBjvs56Cx4CgJDeKQeqfz8wAYiSb8JOprWhHH5p77PbmYCvvUuXQ==" + }, + "is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=" + }, + "is-fullwidth-code-point": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz", + "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==" + }, + "is-generator-function": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/is-generator-function/-/is-generator-function-1.0.8.tgz", + "integrity": "sha512-2Omr/twNtufVZFr1GhxjOMFPAj2sjc/dKaIqBhvo4qciXfJmITGH6ZGd8eZYNHza8t1y0e01AuqRhJwfWp26WQ==" + }, + "is-glob": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz", + "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==", + "requires": { + "is-extglob": "^2.1.1" + } + }, + "is-installed-globally": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/is-installed-globally/-/is-installed-globally-0.4.0.tgz", + "integrity": "sha512-iwGqO3J21aaSkC7jWnHP/difazwS7SFeIqxv6wEtLU8Y5KlzFTjyqcSIT0d8s4+dDhKytsk9PJZ2BkS5eZwQRQ==", + "optional": true, + "requires": { + "global-dirs": "^3.0.0", + "is-path-inside": "^3.0.2" + } + }, + "is-interactive": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-interactive/-/is-interactive-1.0.0.tgz", + "integrity": "sha512-2HvIEKRoqS62guEC+qBjpvRubdX910WCMuJTZ+I9yvqKU2/12eSL549HMwtabb4oupdj2sMP50k+XJfB/8JE6w==" + }, + "is-lambda": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-lambda/-/is-lambda-1.0.1.tgz", + "integrity": "sha512-z7CMFGNrENq5iFB9Bqo64Xk6Y9sg+epq1myIcdHaGnbMTYOxvzsEtdYqQUylB7LxfkvgrrjP32T6Ywciio9UIQ==" + }, + "is-negative-zero": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-negative-zero/-/is-negative-zero-2.0.1.tgz", + "integrity": "sha512-2z6JzQvZRa9A2Y7xC6dQQm4FSTSTNWjKIYYTt4246eMTJmIo0Q+ZyOsU66X8lxK1AbB92dFeglPLrhwpeRKO6w==" + }, + "is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==" + }, + "is-number-like": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/is-number-like/-/is-number-like-1.0.8.tgz", + "integrity": "sha512-6rZi3ezCyFcn5L71ywzz2bS5b2Igl1En3eTlZlvKjpz1n3IZLAYMbKYAIQgFmEu0GENg92ziU/faEOA/aixjbA==", + "devOptional": true, + "requires": { + "lodash.isfinite": "^3.3.2" + } + }, + "is-number-object": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.4.tgz", + "integrity": "sha512-zohwelOAur+5uXtk8O3GPQ1eAcu4ZX3UwxQhUlfFFMNpUd83gXgjbhJh6HmB6LUNV/ieOLQuDwJO3dWJosUeMw==" + }, + "is-path-inside": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/is-path-inside/-/is-path-inside-3.0.3.tgz", + "integrity": "sha512-Fd4gABb+ycGAmKou8eMftCupSir5lRxqf4aD/vd0cD2qc4HL07OjCeuHMr8Ro4CoMaeCKDB0/ECBOVWjTwUvPQ==", + "devOptional": true + }, + "is-plain-obj": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-3.0.0.tgz", + "integrity": "sha512-gwsOE28k+23GP1B6vFl1oVh/WOzmawBrKwo5Ev6wMKzPkaXaCDIQKzLnvsA42DRlbVTWorkgTKIviAKCWkfUwA==" + }, + "is-plain-object": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", + "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", + "requires": { + "isobject": "^3.0.1" + } + }, + "is-regex": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz", + "integrity": "sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==", + "requires": { + "call-bind": "^1.0.2", + "has-tostringtag": "^1.0.0" + } + }, + "is-stream": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-2.0.1.tgz", + "integrity": "sha512-hFoiJiTl63nn+kstHGBtewWSKnQLpyb155KHheA1l39uvtO9nWIop1p3udqPcUd/xbF1VLMO4n7OI6p7RbngDg==" + }, + "is-string": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.5.tgz", + "integrity": "sha512-buY6VNRjhQMiF1qWDouloZlQbRhDPCebwxSjxMjxgemYT46YMd2NR0/H+fBhEfWX4A/w9TBJ+ol+okqJKFE6vQ==" + }, + "is-symbol": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.3.tgz", + "integrity": "sha512-OwijhaRSgqvhm/0ZdAcXNZt9lYdKFpcRDT5ULUuYXPoT794UNOdU+gpT6Rzo7b4V2HUl/op6GqY894AZwv9faQ==", + "requires": { + "has-symbols": "^1.0.1" + } + }, + "is-typed-array": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/is-typed-array/-/is-typed-array-1.1.5.tgz", + "integrity": "sha512-S+GRDgJlR3PyEbsX/Fobd9cqpZBuvUS+8asRqYDMLCb2qMzt1oz5m5oxQCxOgUDxiWsOVNi4yaF+/uvdlHlYug==", + "requires": { + "available-typed-arrays": "^1.0.2", + "call-bind": "^1.0.2", + "es-abstract": "^1.18.0-next.2", + "foreach": "^2.0.5", + "has-symbols": "^1.0.1" + } + }, + "is-typedarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", + "integrity": "sha512-cyA56iCMHAh5CdzjJIa4aohJyeO1YbwLi3Jc35MmRU6poroFjIGZzUzupGiRPOjgHg9TLu43xbpwXk523fMxKA==", + "optional": true + }, + "is-unicode-supported": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/is-unicode-supported/-/is-unicode-supported-0.1.0.tgz", + "integrity": "sha512-knxG2q4UC3u8stRGyAVJCOdxFmv5DZiRcdlIaAQXAbSfJya+OhopNotLQrstBhququ4ZpuKbDc/8S6mgXgPFPw==" + }, + "is-what": { + "version": "3.14.1", + "resolved": "https://registry.npmjs.org/is-what/-/is-what-3.14.1.tgz", + "integrity": "sha512-sNxgpk9793nzSs7bA6JQJGeIuRBQhAaNGG77kzYQgMkrID+lS6SlK07K5LaptscDlSaIgH+GPFzf+d75FVxozA==" + }, + "is-wsl": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-2.2.0.tgz", + "integrity": "sha512-fKzAra0rGJUUBwGBgNkHZuToZcn+TtXHpeCgmkMJMMYx1sQDYaCSyjJBSCa2nH1DGm7s3n1oBnohoVTBaN7Lww==", + "requires": { + "is-docker": "^2.0.0" + } + }, + "isarray": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz", + "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw==" + }, + "isbinaryfile": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/isbinaryfile/-/isbinaryfile-4.0.8.tgz", + "integrity": "sha512-53h6XFniq77YdW+spoRrebh0mnmTxRPTlcuIArO57lmMdq4uBKFKaeTjnb92oYWrSn/LVL+LT+Hap2tFQj8V+w==", + "optional": true, + "peer": true + }, + "isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=" + }, + "isobject": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", + "integrity": "sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg==" + }, + "isstream": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", + "integrity": "sha512-Yljz7ffyPbrLpLngrMtZ7NduUgVvi6wG9RJ9IUcyCd59YQ911PBJphODUcbOVbqYfxe1wuYf/LJ8PauMRwsM/g==", + "optional": true + }, + "istanbul-lib-coverage": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/istanbul-lib-coverage/-/istanbul-lib-coverage-3.2.0.tgz", + "integrity": "sha512-eOeJ5BHCmHYvQK7xt9GkdHuzuCGS1Y6g9Gvnx3Ym33fz/HpLRYxiS0wHNr+m/MBC8B647Xt608vCDEvhl9c6Mw==" + }, + "istanbul-lib-instrument": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/istanbul-lib-instrument/-/istanbul-lib-instrument-5.2.0.tgz", + "integrity": "sha512-6Lthe1hqXHBNsqvgDzGO6l03XNeu3CrG4RqQ1KM9+l5+jNGpEJfIELx1NS3SEHmJQA8np/u+E4EPRKRiu6m19A==", + "requires": { + "@babel/core": "^7.12.3", + "@babel/parser": "^7.14.7", + "@istanbuljs/schema": "^0.1.2", + "istanbul-lib-coverage": "^3.2.0", + "semver": "^6.3.0" + }, + "dependencies": { + "semver": { + "version": "6.3.1", + "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz", + "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==" + } + } + }, + "jackspeak": { + "version": "2.3.6", + "resolved": "https://registry.npmjs.org/jackspeak/-/jackspeak-2.3.6.tgz", + "integrity": "sha512-N3yCS/NegsOBokc8GAdM8UcmfsKiSS8cipheD/nivzr700H+nsMOxJjQnvwOcRYVuFkdH0wGUvW2WbXGmrZGbQ==", + "requires": { + "@isaacs/cliui": "^8.0.2", + "@pkgjs/parseargs": "^0.11.0" + } + }, + "jest-worker": { + "version": "27.5.1", + "resolved": "https://registry.npmjs.org/jest-worker/-/jest-worker-27.5.1.tgz", + "integrity": "sha512-7vuh85V5cdDofPyxn58nrPjBktZo0u9x1g8WtjQol+jZDaE+fhN+cIvTj11GndBnMnyfrUOG1sZQxCdjKh+DKg==", + "requires": { + "@types/node": "*", + "merge-stream": "^2.0.0", + "supports-color": "^8.0.0" + }, + "dependencies": { + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==" + }, + "supports-color": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-8.1.1.tgz", + "integrity": "sha512-MpUEN2OodtUzxvKQl72cUF7RQ5EiHsGvSsVG0ia9c5RbWGL2CI4C7EpPS8UTBIplnlzZiNuV56w+FuNxy3ty2Q==", + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, + "jiti": { + "version": "1.21.0", + "resolved": "https://registry.npmjs.org/jiti/-/jiti-1.21.0.tgz", + "integrity": "sha512-gFqAIbuKyyso/3G2qhiO2OM6shY6EPP/R0+mkDbyspxKazh8BXDC5FiFsUjlczgdNz/vfra0da2y+aHrusLG/Q==" + }, + "joi": { + "version": "17.11.0", + "resolved": "https://registry.npmjs.org/joi/-/joi-17.11.0.tgz", + "integrity": "sha512-NgB+lZLNoqISVy1rZocE9PZI36bL/77ie924Ri43yEvi9GUUMPeyVIr8KdFTMUlby1p0PBYMk9spIxEUQYqrJQ==", + "optional": true, + "requires": { + "@hapi/hoek": "^9.0.0", + "@hapi/topo": "^5.0.0", + "@sideway/address": "^4.1.3", + "@sideway/formula": "^3.0.1", + "@sideway/pinpoint": "^2.0.0" + } + }, + "jquery": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/jquery/-/jquery-3.6.0.tgz", + "integrity": "sha512-JVzAR/AjBvVt2BmYhxRCSYysDsPcssdmTFnzyLEts9qNwmjmu4JTAMYubEfwVOSwpQ1I1sKKFcxhZCI2buerfw==", + "peer": true + }, + "js-tokens": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz", + "integrity": "sha512-RdJUflcE3cUzKiMqQgsCu06FPu9UdIJO0beYbPhHN4k6apgJtifcoCtT9bcxOpYBtpD2kCM6Sbzg4CausW/PKQ==" + }, + "js-yaml": { + "version": "3.14.0", + "resolved": "https://registry.npmjs.org/js-yaml/-/js-yaml-3.14.0.tgz", + "integrity": "sha512-/4IbIeHcD9VMHFqDR/gQ7EdZdLimOvW2DdcxFjdyyZ9NsbS+ccrXqVWDtab/lRl5AlUqmpBx8EhPaWR+OtY17A==", + "requires": { + "argparse": "^1.0.7", + "esprima": "^4.0.0" + } + }, + "jsbn": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", + "integrity": "sha512-UVU9dibq2JcFWxQPA6KCqj5O42VOmAY3zQUfEKxU0KpTGXwNoCjkX1e13eHNvw/xPynt6pU0rZ1htjWTNTSXsg==", + "optional": true + }, + "jsesc": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-2.5.2.tgz", + "integrity": "sha512-OYu7XEzjkCQ3C5Ps3QIZsQfNpqoJyZZA99wd9aWd05NCtC5pWOkShK2mkL6HXQR6/Cy2lbNdPlZBpuQHXE63gA==" + }, + "json-buffer": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/json-buffer/-/json-buffer-3.0.1.tgz", + "integrity": "sha512-4bV5BfR2mqfQTJm+V5tPPdf+ZpuhiIvTuAB5g8kcrXOZpTT/QwwVRWBywX1ozr6lEuPdbHxwaJlm9G6mI2sfSQ==", + "dev": true + }, + "json-parse-even-better-errors": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-2.3.1.tgz", + "integrity": "sha512-xyFwyhro/JEof6Ghe2iz2NcXoj2sloNsWr/XsERDK/oiPCfaNhl5ONfp+jQdAZRQQ0IJWNzH9zIZF7li91kh2w==" + }, + "json-schema": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.4.0.tgz", + "integrity": "sha512-es94M3nTIfsEPisRafak+HDLfHXnKBhV3vU5eqPcS3flIWqcxJWgXHXiey3YrpaNsanY5ei1VoYEbOzijuq9BA==", + "optional": true + }, + "json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==" + }, + "json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", + "integrity": "sha512-Bdboy+l7tA3OGW6FjyFHWkP5LuByj1Tk33Ljyq0axyzdk9//JSi2u3fP1QSmd1KNwq6VOKYGlAu87CisVir6Pw==", + "dev": true + }, + "json-stringify-safe": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", + "integrity": "sha512-ZClg6AaYvamvYEE82d3Iyd3vSSIjQ+odgjaTzRuO3s7toCdFKczob2i0zCh7JE8kWn17yvAWhUVxvqGwUalsRA==", + "optional": true + }, + "json5": { + "version": "2.2.3", + "resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz", + "integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==" + }, + "jsonc-parser": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/jsonc-parser/-/jsonc-parser-3.2.1.tgz", + "integrity": "sha512-AilxAyFOAcK5wA1+LeaySVBrHsGQvUFCDWXKpZjzaL0PqW+xfBOttn8GNtWKFWqneyMZj41MWF9Kl6iPWLwgOA==" + }, + "jsonfile": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", + "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", + "optional": true, + "requires": { + "graceful-fs": "^4.1.6", + "universalify": "^2.0.0" + } + }, + "jsonparse": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/jsonparse/-/jsonparse-1.3.1.tgz", + "integrity": "sha1-P02uSpH6wxX3EGL4UhzCOfE2YoA=" + }, + "JSONStream": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/JSONStream/-/JSONStream-1.3.5.tgz", + "integrity": "sha512-E+iruNOY8VV9s4JEbe1aNEm6MiszPRr/UfcHMz0TQh1BXSxHK+ASV1R6W4HpjBhSeS+54PIsAMCBmwD06LLsqQ==", + "requires": { + "jsonparse": "^1.2.0", + "through": ">=2.2.7 <3" + } + }, + "jsprim": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-2.0.2.tgz", + "integrity": "sha512-gqXddjPqQ6G40VdnI6T6yObEC+pDNvyP95wdQhkWkg7crHH3km5qP1FsOXEkzEQwnz6gz5qGTn1c2Y52wP3OyQ==", + "optional": true, + "requires": { + "assert-plus": "1.0.0", + "extsprintf": "1.3.0", + "json-schema": "0.4.0", + "verror": "1.10.0" + } + }, + "just-extend": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/just-extend/-/just-extend-4.2.1.tgz", + "integrity": "sha512-g3UB796vUFIY90VIv/WX3L2c8CS2MdWUww3CNrYmqza1Fg0DURc2K/O4YrnklBdQarSJ/y8JnJYDGc+1iumQjg==", + "optional": true + }, + "karma": { + "version": "6.3.19", + "resolved": "https://registry.npmjs.org/karma/-/karma-6.3.19.tgz", + "integrity": "sha512-NDhWckzES/Y9xMiddyU1RzaKL76/scCsu8Mp0vR0Z3lQRvC3p72+Ab4ppoxs36S9tyPNX5V48yvaV++RNEBPZw==", + "optional": true, + "peer": true, + "requires": { + "@colors/colors": "1.5.0", + "body-parser": "^1.19.0", + "braces": "^3.0.2", + "chokidar": "^3.5.1", + "connect": "^3.7.0", + "di": "^0.0.1", + "dom-serialize": "^2.2.1", + "glob": "^7.1.7", + "graceful-fs": "^4.2.6", + "http-proxy": "^1.18.1", + "isbinaryfile": "^4.0.8", + "lodash": "^4.17.21", + "log4js": "^6.4.1", + "mime": "^2.5.2", + "minimatch": "^3.0.4", + "mkdirp": "^0.5.5", + "qjobs": "^1.2.0", + "range-parser": "^1.2.1", + "rimraf": "^3.0.2", + "socket.io": "^4.4.1", + "source-map": "^0.6.1", + "tmp": "^0.2.1", + "ua-parser-js": "^0.7.30", + "yargs": "^16.1.1" + }, + "dependencies": { + "connect": { + "version": "3.7.0", + "resolved": "https://registry.npmjs.org/connect/-/connect-3.7.0.tgz", + "integrity": "sha512-ZqRXc+tZukToSNmh5C2iWMSoV3X1YUcPbqEM4DkEG5tNQXrQUZCNVGGv3IuicnkMtPfGf3Xtp8WCXs295iQ1pQ==", + "optional": true, + "peer": true, + "requires": { + "debug": "2.6.9", + "finalhandler": "1.1.2", + "parseurl": "~1.3.3", + "utils-merge": "1.0.1" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "optional": true, + "peer": true, + "requires": { + "ms": "2.0.0" + } + } + } + }, + "finalhandler": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/finalhandler/-/finalhandler-1.1.2.tgz", + "integrity": "sha512-aAWcW57uxVNrQZqFXjITpW3sIUQmHGG3qSb9mUah9MgMC4NeWhNOlNjXEYq3HjRAvL6arUviZGGJsBg6z0zsWA==", + "optional": true, + "peer": true, + "requires": { + "debug": "2.6.9", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "on-finished": "~2.3.0", + "parseurl": "~1.3.3", + "statuses": "~1.5.0", + "unpipe": "~1.0.0" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "optional": true, + "peer": true, + "requires": { + "ms": "2.0.0" + } + } + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "optional": true, + "peer": true + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "optional": true, + "peer": true + }, + "tmp": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.2.1.tgz", + "integrity": "sha512-76SUhtfqR2Ijn+xllcI5P1oyannHNHByD80W1q447gU3mp9G9PSpGdWmjUOHRDPiHYacIk66W7ubDTuPF3BEtQ==", + "optional": true, + "peer": true, + "requires": { + "rimraf": "^3.0.0" + } + } + } + }, + "karma-source-map-support": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/karma-source-map-support/-/karma-source-map-support-1.4.0.tgz", + "integrity": "sha512-RsBECncGO17KAoJCYXjv+ckIz+Ii9NCi+9enk+rq6XC81ezYkb4/RHE6CTXdA7IOJqoF3wcaLfVG0CPmE5ca6A==", + "requires": { + "source-map-support": "^0.5.5" + } + }, + "keyv": { + "version": "4.5.4", + "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", + "integrity": "sha512-oxVHkHR/EJf2CNXnWxRLW6mg7JyCCUcG0DtEGmL2ctUo1PNTin1PUil+r/+4r5MpVgC/fn1kjsx7mjSujKqIpw==", + "dev": true, + "requires": { + "json-buffer": "3.0.1" + } + }, + "kind-of": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", + "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==" + }, + "klona": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/klona/-/klona-2.0.6.tgz", + "integrity": "sha512-dhG34DXATL5hSxJbIexCft8FChFXtmskoZYnoPWjXQuebWYCNkVeV3KkGegCK9CP1oswI/vQibS2GY7Em/sJJA==" + }, + "labeled-stream-splicer": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/labeled-stream-splicer/-/labeled-stream-splicer-2.0.2.tgz", + "integrity": "sha512-Ca4LSXFFZUjPScRaqOcFxneA0VpKZr4MMYCljyQr4LIewTLb3Y0IUTIsnBBsVubIeEfxeSZpSjSsRM8APEQaAw==", + "requires": { + "inherits": "^2.0.1", + "stream-splicer": "^2.0.0" + } + }, + "launch-editor": { + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/launch-editor/-/launch-editor-2.6.1.tgz", + "integrity": "sha512-eB/uXmFVpY4zezmGp5XtU21kwo7GBbKB+EQ+UZeWtGb9yAM5xt/Evk+lYH3eRNAtId+ej4u7TYPFZ07w4s7rRw==", + "requires": { + "picocolors": "^1.0.0", + "shell-quote": "^1.8.1" + } + }, + "lazy-ass": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/lazy-ass/-/lazy-ass-1.6.0.tgz", + "integrity": "sha1-eZllXoZGwX8In90YfRUNMyTVRRM=", + "optional": true + }, + "less": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/less/-/less-4.2.0.tgz", + "integrity": "sha512-P3b3HJDBtSzsXUl0im2L7gTO5Ubg8mEN6G8qoTS77iXxXX4Hvu4Qj540PZDvQ8V6DmX6iXo98k7Md0Cm1PrLaA==", + "requires": { + "copy-anything": "^2.0.1", + "errno": "^0.1.1", + "graceful-fs": "^4.1.2", + "image-size": "~0.5.0", + "make-dir": "^2.1.0", + "mime": "^1.4.1", + "needle": "^3.1.0", + "parse-node-version": "^1.0.1", + "source-map": "~0.6.0", + "tslib": "^2.3.0" + }, + "dependencies": { + "make-dir": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-2.1.0.tgz", + "integrity": "sha512-LS9X+dc8KLxXCb8dni79fLIIUA5VyZoyjSMCwTluaXA0o27cCK0bhXkpgw+sTXVpPy/lSO57ilRixqk0vDmtRA==", + "optional": true, + "requires": { + "pify": "^4.0.1", + "semver": "^5.6.0" + } + }, + "mime": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", + "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==", + "optional": true + }, + "pify": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz", + "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==", + "optional": true + }, + "semver": { + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.7.2.tgz", + "integrity": "sha512-cBznnQ9KjJqU67B52RMC65CMarK2600WFnbkcaiwWq3xy/5haFJlshgnpjovMVJ+Hff49d8GEn0b87C5pDQ10g==", + "optional": true + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "optional": true + } + } + }, + "less-loader": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/less-loader/-/less-loader-11.1.0.tgz", + "integrity": "sha512-C+uDBV7kS7W5fJlUjq5mPBeBVhYpTIm5gB09APT9o3n/ILeaXVsiSFTbZpTJCJwQ/Crczfn3DmfQFwxYusWFug==", + "requires": { + "klona": "^2.0.4" + } + }, + "levn": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/levn/-/levn-0.4.1.tgz", + "integrity": "sha512-+bT2uH4E5LGE7h/n3evcS/sQlJXCpIp6ym8OWJ5eV6+67Dsql/LaaT7qJBAt2rzfoa/5QBGBhxDix1dMt2kQKQ==", + "dev": true, + "requires": { + "prelude-ls": "^1.2.1", + "type-check": "~0.4.0" + } + }, + "license-webpack-plugin": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/license-webpack-plugin/-/license-webpack-plugin-4.0.2.tgz", + "integrity": "sha512-771TFWFD70G1wLTC4oU2Cw4qvtmNrIw+wRvBtn+okgHl7slJVi7zfNcdmqDL72BojM30VNJ2UHylr1o77U37Jw==", + "requires": { + "webpack-sources": "^3.0.0" + } + }, + "lightweight-charts": { + "version": "3.8.0", + "resolved": "https://registry.npmjs.org/lightweight-charts/-/lightweight-charts-3.8.0.tgz", + "integrity": "sha512-7yFGnYuE1RjRJG9RwUTBz5wvF1QtjBOSW4FFlikr8Dh+/TDNt4ci+HsWSYmStgQUpawpvkCJ3j5/W25GppGj9Q==", + "requires": { + "fancy-canvas": "0.2.2" + } + }, + "limiter": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/limiter/-/limiter-1.1.5.tgz", + "integrity": "sha512-FWWMIEOxz3GwUI4Ts/IvgVy6LPvoMPgjMdQ185nN6psJyBJ4yOpzqm695/h5umdLJg2vW3GR5iG11MAkR2AzJA==", + "devOptional": true + }, + "lines-and-columns": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz", + "integrity": "sha512-7ylylesZQ/PV29jhEDl3Ufjo6ZX7gCqJr5F7PKrqc93v7fzSymt1BpwEU8nAUXs8qzzvqhbjhK5QZg6Mt/HkBg==" + }, + "listr2": { + "version": "3.14.0", + "resolved": "https://registry.npmjs.org/listr2/-/listr2-3.14.0.tgz", + "integrity": "sha512-TyWI8G99GX9GjE54cJ+RrNMcIFBfwMPxc3XTFiAYGN4s10hWROGtOg7+O6u6LE3mNkyld7RSLE6nrKBvTfcs3g==", + "optional": true, + "requires": { + "cli-truncate": "^2.1.0", + "colorette": "^2.0.16", + "log-update": "^4.0.0", + "p-map": "^4.0.0", + "rfdc": "^1.3.0", + "rxjs": "^7.5.1", + "through": "^2.3.8", + "wrap-ansi": "^7.0.0" + }, + "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "optional": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "optional": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "optional": true + }, + "wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "optional": true, + "requires": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + } + } + } + }, + "loader-runner": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-4.2.0.tgz", + "integrity": "sha512-92+huvxMvYlMzMt0iIOukcwYBFpkYJdpl2xsZ7LrlayO7E8SOv+JJUEK17B/dJIHAOLMfh2dZZ/Y18WgmGtYNw==" + }, + "loader-utils": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-2.0.4.tgz", + "integrity": "sha512-xXqpXoINfFhgua9xiqD8fPFHgkoq1mmmpE92WlDbm9rNRd/EbRb+Gqf908T2DMfuHjjJlksiK2RbHVOdD/MqSw==", + "requires": { + "big.js": "^5.2.2", + "emojis-list": "^3.0.0", + "json5": "^2.1.2" + } + }, + "locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "requires": { + "p-locate": "^4.1.0" + } + }, + "lodash": { + "version": "4.17.21", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz", + "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==" + }, + "lodash.debounce": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz", + "integrity": "sha512-FT1yDzDYEoYWhnSGnpE/4Kj1fLZkDFyqRb7fNt6FdYOSxlUWAtp42Eh6Wb0rGIv/m9Bgo7x4GhQbm5Ys4SG5ow==" + }, + "lodash.get": { + "version": "4.4.2", + "resolved": "https://registry.npmjs.org/lodash.get/-/lodash.get-4.4.2.tgz", + "integrity": "sha512-z+Uw/vLuy6gQe8cfaFWD7p0wVv8fJl3mbzXh33RS+0oW2wvUqiRXiQ69gLWSLpgB5/6sU+r6BlQR0MBILadqTQ==", + "optional": true + }, + "lodash.isfinite": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/lodash.isfinite/-/lodash.isfinite-3.3.2.tgz", + "integrity": "sha512-7FGG40uhC8Mm633uKW1r58aElFlBlxCrg9JfSi3P6aYiWmfiWF0PgMd86ZUsxE5GwWPdHoS2+48bwTh2VPkIQA==", + "devOptional": true + }, + "lodash.merge": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", + "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", + "dev": true + }, + "lodash.once": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/lodash.once/-/lodash.once-4.1.1.tgz", + "integrity": "sha1-DdOXEhPHxW34gJd9UEyI+0cal6w=", + "optional": true + }, + "log-symbols": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/log-symbols/-/log-symbols-4.1.0.tgz", + "integrity": "sha512-8XPvpAA8uyhfteu8pIvQxpJZ7SYYdpUivZpGy6sFsBuKRY/7rQGavedeB8aK+Zkyq6upMFVL/9AW6vOYzfRyLg==", + "requires": { + "chalk": "^4.1.0", + "is-unicode-supported": "^0.1.0" + }, + "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "requires": { + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz", + "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==", + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==" + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, + "log-update": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/log-update/-/log-update-4.0.0.tgz", + "integrity": "sha512-9fkkDevMefjg0mmzWFBW8YkFP91OrizzkW3diF7CpG+S2EYdy4+TVfGwz1zeF8x7hCx1ovSPTOE9Ngib74qqUg==", + "optional": true, + "requires": { + "ansi-escapes": "^4.3.0", + "cli-cursor": "^3.1.0", + "slice-ansi": "^4.0.0", + "wrap-ansi": "^6.2.0" + }, + "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "optional": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "optional": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "optional": true + }, + "slice-ansi": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-4.0.0.tgz", + "integrity": "sha512-qMCMfhY040cVHT43K9BFygqYbUPFZKHOg7K73mtTWJRb8pyP3fzf4Ixd5SzdEJQ6MRUg/WBnOLxghZtKKurENQ==", + "optional": true, + "requires": { + "ansi-styles": "^4.0.0", + "astral-regex": "^2.0.0", + "is-fullwidth-code-point": "^3.0.0" + } + } + } + }, + "log4js": { + "version": "6.4.1", + "resolved": "https://registry.npmjs.org/log4js/-/log4js-6.4.1.tgz", + "integrity": "sha512-iUiYnXqAmNKiIZ1XSAitQ4TmNs8CdZYTAWINARF3LjnsLN8tY5m0vRwd6uuWj/yNY0YHxeZodnbmxKFUOM2rMg==", + "optional": true, + "peer": true, + "requires": { + "date-format": "^4.0.3", + "debug": "^4.3.3", + "flatted": "^3.2.4", + "rfdc": "^1.3.0", + "streamroller": "^3.0.2" + } + }, + "loupe": { + "version": "2.3.7", + "resolved": "https://registry.npmjs.org/loupe/-/loupe-2.3.7.tgz", + "integrity": "sha512-zSMINGVYkdpYSOBmLi0D1Uo7JU9nVdQKrHxC8eYlV+9YKK9WePqAlL7lSlorG/U2Fw1w0hTBmaa/jrQ3UbPHtA==", + "optional": true, + "requires": { + "get-func-name": "^2.0.1" + } + }, + "lru-cache": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", + "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", + "requires": { + "yallist": "^4.0.0" + } + }, + "magic-string": { + "version": "0.30.8", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.30.8.tgz", + "integrity": "sha512-ISQTe55T2ao7XtlAStud6qwYPZjE4GK1S/BeVPus4jrq6JuOnQ00YKQC581RWhR122W7msZV263KzVeLoqidyQ==", + "requires": { + "@jridgewell/sourcemap-codec": "^1.4.15" + } + }, + "make-error": { + "version": "1.3.6", + "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz", + "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==", + "dev": true + }, + "make-fetch-happen": { + "version": "13.0.0", + "resolved": "https://registry.npmjs.org/make-fetch-happen/-/make-fetch-happen-13.0.0.tgz", + "integrity": "sha512-7ThobcL8brtGo9CavByQrQi+23aIfgYU++wg4B87AIS8Rb2ZBt/MEaDqzA00Xwv/jUjAjYkLHjVolYuTLKda2A==", + "requires": { + "@npmcli/agent": "^2.0.0", + "cacache": "^18.0.0", + "http-cache-semantics": "^4.1.1", + "is-lambda": "^1.0.1", + "minipass": "^7.0.2", + "minipass-fetch": "^3.0.0", + "minipass-flush": "^1.0.5", + "minipass-pipeline": "^1.2.4", + "negotiator": "^0.6.3", + "promise-retry": "^2.0.1", + "ssri": "^10.0.0" + } + }, + "map-stream": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/map-stream/-/map-stream-0.1.0.tgz", + "integrity": "sha1-5WqpTEyAVaFkBKBnS3jyFffI4ZQ=", + "optional": true + }, + "md5.js": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/md5.js/-/md5.js-1.3.5.tgz", + "integrity": "sha512-xitP+WxNPcTTOgnTJcrhM0xvdPepipPSf3I8EIpGKeFLjt3PlJLIDG3u8EX53ZIubkb+5U2+3rELYpEhHhzdkg==", + "requires": { + "hash-base": "^3.0.0", + "inherits": "^2.0.1", + "safe-buffer": "^5.1.2" + } + }, + "media-typer": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/media-typer/-/media-typer-0.3.0.tgz", + "integrity": "sha1-hxDXrwqmJvj/+hzgAWhUUmMlV0g=" + }, + "memfs": { + "version": "3.5.3", + "resolved": "https://registry.npmjs.org/memfs/-/memfs-3.5.3.tgz", + "integrity": "sha512-UERzLsxzllchadvbPs5aolHh65ISpKpM+ccLbOJ8/vvpBKmAWf+la7dXFy7Mr0ySHbdHrFv5kGFCUHHe6GFEmw==", + "requires": { + "fs-monkey": "^1.0.4" + } + }, + "merge-descriptors": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/merge-descriptors/-/merge-descriptors-1.0.1.tgz", + "integrity": "sha512-cCi6g3/Zr1iqQi6ySbseM1Xvooa98N0w31jzUYrXPX2xqObmFGHJ0tQ5u74H3mVh7wLouTseZyYIq39g8cNp1w==" + }, + "merge-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/merge-stream/-/merge-stream-2.0.0.tgz", + "integrity": "sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w==" + }, + "merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==" + }, + "methods": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/methods/-/methods-1.1.2.tgz", + "integrity": "sha512-iclAHeNqNm68zFtnZ0e+1L2yUIdvzNoauKU4WBA3VvH/vPFieF7qfRlwUZU+DA9P9bPXIS90ulxoUoCH23sV2w==" + }, + "micromatch": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.4.tgz", + "integrity": "sha512-pRmzw/XUcwXGpD9aI9q/0XOwLNygjETJ8y0ao0wdqprrzDa4YnxLcz7fQRZr8voh8V10kGhABbNcHVk5wHgWwg==", + "requires": { + "braces": "^3.0.1", + "picomatch": "^2.2.3" + } + }, + "miller-rabin": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/miller-rabin/-/miller-rabin-4.0.1.tgz", + "integrity": "sha512-115fLhvZVqWwHPbClyntxEVfVDfl9DLLTuJvq3g2O/Oxi8AiNouAHvDSzHS0viUJc+V5vm3eq91Xwqn9dp4jRA==", + "requires": { + "bn.js": "^4.0.0", + "brorand": "^1.0.1" + }, + "dependencies": { + "bn.js": { + "version": "4.12.0", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", + "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==" + } + } + }, + "mime": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/mime/-/mime-2.5.2.tgz", + "integrity": "sha512-tqkh47FzKeCPD2PUiPB6pkbMzsCasjxAfC62/Wap5qrUWcb+sFasXUC5I3gYM5iBM8v/Qpn4UK0x+j0iHyFPDg==", + "optional": true, + "peer": true + }, + "mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==" + }, + "mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "requires": { + "mime-db": "1.52.0" + } + }, + "mimic-fn": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/mimic-fn/-/mimic-fn-2.1.0.tgz", + "integrity": "sha512-OqbOk5oEQeAZ8WXWydlu9HJjz9WVdEIvamMCcXmuqUYjTknH/sqsWvhQ3vgwKFRR1HpjvNBKQ37nbJgYzGqGcg==" + }, + "mini-css-extract-plugin": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/mini-css-extract-plugin/-/mini-css-extract-plugin-2.8.1.tgz", + "integrity": "sha512-/1HDlyFRxWIZPI1ZpgqlZ8jMw/1Dp/dl3P0L1jtZ+zVcHqwPhGwaJwKL00WVgfnBy6PWCde9W65or7IIETImuA==", + "requires": { + "schema-utils": "^4.0.0", + "tapable": "^2.2.1" + } + }, + "minify-stream": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/minify-stream/-/minify-stream-2.1.0.tgz", + "integrity": "sha512-P5xE4EQRkn7Td54VGcgfDMFx1jmKPPIXCdcMfrbXS6cNHK4dO1LXwtYFb48hHrSmZfT+jlGImvHgSZEkbpNtCw==", + "requires": { + "concat-stream": "^2.0.0", + "convert-source-map": "^1.5.0", + "duplexify": "^4.1.1", + "from2-string": "^1.1.0", + "terser": "^4.7.0", + "xtend": "^4.0.1" + }, + "dependencies": { + "concat-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-2.0.0.tgz", + "integrity": "sha512-MWufYdFw53ccGjCA+Ol7XJYpAlW6/prSMzuPOTRnJGcGzuhLn4Scrz7qf6o8bROZ514ltazcIFJZevcfbo0x7A==", + "requires": { + "buffer-from": "^1.0.0", + "inherits": "^2.0.3", + "readable-stream": "^3.0.2", + "typedarray": "^0.0.6" + } + }, + "duplexify": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/duplexify/-/duplexify-4.1.1.tgz", + "integrity": "sha512-DY3xVEmVHTv1wSzKNbwoU6nVjzI369Y6sPoqfYr0/xlx3IdX2n94xIszTcjPO8W8ZIv0Wb0PXNcjuZyT4wiICA==", + "requires": { + "end-of-stream": "^1.4.1", + "inherits": "^2.0.3", + "readable-stream": "^3.1.1", + "stream-shift": "^1.0.0" + } + }, + "readable-stream": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.0.tgz", + "integrity": "sha512-BViHy7LKeTz4oNnkcLJ+lVSL6vpiFeX6/d3oSH8zCW7UxP2onchk+vTGB143xuFjHS3deTgkKoXXymXqymiIdA==", + "requires": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + } + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" + }, + "terser": { + "version": "4.8.1", + "resolved": "https://registry.npmjs.org/terser/-/terser-4.8.1.tgz", + "integrity": "sha512-4GnLC0x667eJG0ewJTa6z/yXrbLGv80D9Ru6HIpCQmO+Q4PfEtBFi0ObSckqwL6VyQv/7ENJieXHo2ANmdQwgw==", + "requires": { + "commander": "^2.20.0", + "source-map": "~0.6.1", + "source-map-support": "~0.5.12" + } + } + } + }, + "minimalistic-assert": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz", + "integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==" + }, + "minimalistic-crypto-utils": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz", + "integrity": "sha1-9sAMHAsIIkblxNmd+4x8CDsrWCo=" + }, + "minimatch": { + "version": "3.1.2", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", + "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==", + "requires": { + "brace-expansion": "^1.1.7" + } + }, + "minimist": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz", + "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==" + }, + "minipass": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-7.0.4.tgz", + "integrity": "sha512-jYofLM5Dam9279rdkWzqHozUo4ybjdZmCsDHePy5V/PbBcVMiSZR97gmAy45aqi8CK1lG2ECd356FU86avfwUQ==" + }, + "minipass-collect": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/minipass-collect/-/minipass-collect-2.0.1.tgz", + "integrity": "sha512-D7V8PO9oaz7PWGLbCACuI1qEOsq7UKfLotx/C0Aet43fCUB/wfQ7DYeq2oR/svFJGYDHPr38SHATeaj/ZoKHKw==", + "requires": { + "minipass": "^7.0.3" + } + }, + "minipass-fetch": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/minipass-fetch/-/minipass-fetch-3.0.4.tgz", + "integrity": "sha512-jHAqnA728uUpIaFm7NWsCnqKT6UqZz7GcI/bDpPATuwYyKwJwW0remxSCxUlKiEty+eopHGa3oc8WxgQ1FFJqg==", + "requires": { + "encoding": "^0.1.13", + "minipass": "^7.0.3", + "minipass-sized": "^1.0.3", + "minizlib": "^2.1.2" + } + }, + "minipass-flush": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/minipass-flush/-/minipass-flush-1.0.5.tgz", + "integrity": "sha512-JmQSYYpPUqX5Jyn1mXaRwOda1uQ8HP5KAT/oDSLCzt1BYRhQU0/hDtsB1ufZfEEzMZ9aAVmsBw8+FWsIXlClWw==", + "requires": { + "minipass": "^3.0.0" + }, + "dependencies": { + "minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "requires": { + "yallist": "^4.0.0" + } + } + } + }, + "minipass-json-stream": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/minipass-json-stream/-/minipass-json-stream-1.0.1.tgz", + "integrity": "sha512-ODqY18UZt/I8k+b7rl2AENgbWE8IDYam+undIJONvigAz8KR5GWblsFTEfQs0WODsjbSXWlm+JHEv8Gr6Tfdbg==", + "requires": { + "jsonparse": "^1.3.1", + "minipass": "^3.0.0" + }, + "dependencies": { + "minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "requires": { + "yallist": "^4.0.0" + } + } + } + }, + "minipass-pipeline": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/minipass-pipeline/-/minipass-pipeline-1.2.4.tgz", + "integrity": "sha512-xuIq7cIOt09RPRJ19gdi4b+RiNvDFYe5JH+ggNvBqGqpQXcru3PcRmOZuHBKWK1Txf9+cQ+HMVN4d6z46LZP7A==", + "requires": { + "minipass": "^3.0.0" + }, + "dependencies": { + "minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "requires": { + "yallist": "^4.0.0" + } + } + } + }, + "minipass-sized": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/minipass-sized/-/minipass-sized-1.0.3.tgz", + "integrity": "sha512-MbkQQ2CTiBMlA2Dm/5cY+9SWFEN8pzzOXi6rlM5Xxq0Yqbda5ZQy9sU75a673FE9ZK0Zsbr6Y5iP6u9nktfg2g==", + "requires": { + "minipass": "^3.0.0" + }, + "dependencies": { + "minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "requires": { + "yallist": "^4.0.0" + } + } + } + }, + "minizlib": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-2.1.2.tgz", + "integrity": "sha512-bAxsR8BVfj60DWXHE3u30oHzfl4G7khkSuPW+qvpd7jFRHm7dLxOjUk1EHACJ/hxLY8phGJ0YhYHZo7jil7Qdg==", + "requires": { + "minipass": "^3.0.0", + "yallist": "^4.0.0" + }, + "dependencies": { + "minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "requires": { + "yallist": "^4.0.0" + } + } + } + }, + "mitt": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/mitt/-/mitt-1.2.0.tgz", + "integrity": "sha512-r6lj77KlwqLhIUku9UWYes7KJtsczvolZkzp8hbaDPPaE24OmWl5s539Mytlj22siEQKosZ26qCBgda2PKwoJw==", + "devOptional": true + }, + "mkdirp": { + "version": "0.5.5", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.5.tgz", + "integrity": "sha512-NKmAlESf6jMGym1++R0Ra7wvhV+wFW63FaSOFPwRahvea0gMUcGUhVeAg/0BC0wiv9ih5NYPB1Wn1UEI1/L+xQ==", + "optional": true, + "peer": true, + "requires": { + "minimist": "^1.2.5" + } + }, + "mkdirp-classic": { + "version": "0.5.3", + "resolved": "https://registry.npmjs.org/mkdirp-classic/-/mkdirp-classic-0.5.3.tgz", + "integrity": "sha512-gKLcREMhtuZRwRAfqP3RFW+TK4JqApVBtOIftVgjuABpAtpxhPGaDcfvbhNvD0B8iD1oUr/txX35NjcaY6Ns/A==" + }, + "mock-socket": { + "version": "9.3.1", + "resolved": "https://registry.npmjs.org/mock-socket/-/mock-socket-9.3.1.tgz", + "integrity": "sha512-qxBgB7Qa2sEQgHFjj0dSigq7fX4k6Saisd5Nelwp2q8mlbAFh5dHV9JTTlF8viYJLSSWgMCZFUom8PJcMNBoJw==", + "optional": true + }, + "module-deps": { + "version": "6.2.3", + "resolved": "https://registry.npmjs.org/module-deps/-/module-deps-6.2.3.tgz", + "integrity": "sha512-fg7OZaQBcL4/L+AK5f4iVqf9OMbCclXfy/znXRxTVhJSeW5AIlS9AwheYwDaXM3lVW7OBeaeUEY3gbaC6cLlSA==", + "requires": { + "browser-resolve": "^2.0.0", + "cached-path-relative": "^1.0.2", + "concat-stream": "~1.6.0", + "defined": "^1.0.0", + "detective": "^5.2.0", + "duplexer2": "^0.1.2", + "inherits": "^2.0.1", + "JSONStream": "^1.0.3", + "parents": "^1.0.0", + "readable-stream": "^2.0.2", + "resolve": "^1.4.0", + "stream-combiner2": "^1.1.1", + "subarg": "^1.0.0", + "through2": "^2.0.0", + "xtend": "^4.0.0" + } + }, + "mrmime": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/mrmime/-/mrmime-2.0.0.tgz", + "integrity": "sha512-eu38+hdgojoyq63s+yTpN4XMBdt5l8HhMhc4VKLO9KM5caLIBvUm4thi7fFaxyTmCKeNnXZ5pAlBwCUnhA09uw==" + }, + "ms": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" + }, + "multi-stage-sourcemap": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/multi-stage-sourcemap/-/multi-stage-sourcemap-0.3.1.tgz", + "integrity": "sha512-UiTLYjqeIoVnJHyWGskwMKIhtZKK9uXUjSTWuwatarrc0d2H/6MAVFdwvEA/aKOHamIn7z4tfvxjz+FYucFpNQ==", + "requires": { + "source-map": "^0.1.34" + }, + "dependencies": { + "source-map": { + "version": "0.1.43", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.1.43.tgz", + "integrity": "sha512-VtCvB9SIQhk3aF6h+N85EaqIaBFIAfZ9Cu+NJHHVvc8BbEcnvDcFw6sqQ2dQrT6SlOrZq3tIvyD9+EGq/lJryQ==", + "requires": { + "amdefine": ">=0.0.4" + } + } + } + }, + "multicast-dns": { + "version": "7.2.5", + "resolved": "https://registry.npmjs.org/multicast-dns/-/multicast-dns-7.2.5.tgz", + "integrity": "sha512-2eznPJP8z2BFLX50tf0LuODrpINqP1RVIm/CObbTcBRITQgmC/TjcREF1NeTBzIcR5XO/ukWo+YHOjBbFwIupg==", + "requires": { + "dns-packet": "^5.2.2", + "thunky": "^1.0.2" + } + }, + "multisplice": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/multisplice/-/multisplice-1.0.0.tgz", + "integrity": "sha512-KU5tVjIdTGsMb92JlWwEZCGrvtI1ku9G9GuNbWdQT/Ici1ztFXX0L8lWpbbC3pISVMfBNL56wdqplHvva2XSlA==" + }, + "mute-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/mute-stream/-/mute-stream-1.0.0.tgz", + "integrity": "sha512-avsJQhyd+680gKXyG/sQc0nXaC6rBkPOfyHYcFb9+hdkqQkR9bdnkJ0AMZhke0oesPqIO+mFFJ+IdBc7mst4IA==" + }, + "mutexify": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/mutexify/-/mutexify-1.3.1.tgz", + "integrity": "sha512-nU7mOEuaXiQIB/EgTIjYZJ7g8KqMm2D8l4qp+DqA4jxWOb/tnb1KEoqp+tlbdQIDIAiC1i7j7X/3yHDFXLxr9g==" + }, + "nanobench": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/nanobench/-/nanobench-2.1.1.tgz", + "integrity": "sha512-z+Vv7zElcjN+OpzAxAquUayFLGK3JI/ubCl0Oh64YQqsTGG09CGqieJVQw4ui8huDnnAgrvTv93qi5UaOoNj8A==", + "requires": { + "browser-process-hrtime": "^0.1.2", + "chalk": "^1.1.3", + "mutexify": "^1.1.0", + "pretty-hrtime": "^1.0.2" + }, + "dependencies": { + "ansi-regex": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", + "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=" + }, + "ansi-styles": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", + "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=" + }, + "browser-process-hrtime": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/browser-process-hrtime/-/browser-process-hrtime-0.1.3.tgz", + "integrity": "sha512-bRFnI4NnjO6cnyLmOV/7PVoDEMJChlcfN0z4s1YMBY989/SvlfMI1lgCnkFUs53e9gQF+w7qu7XdllSTiSl8Aw==" + }, + "chalk": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", + "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", + "requires": { + "ansi-styles": "^2.2.1", + "escape-string-regexp": "^1.0.2", + "has-ansi": "^2.0.0", + "strip-ansi": "^3.0.0", + "supports-color": "^2.0.0" + } + }, + "strip-ansi": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", + "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", + "requires": { + "ansi-regex": "^2.0.0" + } + }, + "supports-color": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", + "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=" + } + } + }, + "nanoid": { + "version": "3.3.7", + "resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.7.tgz", + "integrity": "sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==" + }, + "natural-compare": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/natural-compare/-/natural-compare-1.4.0.tgz", + "integrity": "sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==", + "dev": true + }, + "needle": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/needle/-/needle-3.2.0.tgz", + "integrity": "sha512-oUvzXnyLiVyVGoianLijF9O/RecZUf7TkBfimjGrLM4eQhXyeJwM6GeAWccwfQ9aa4gMCZKqhAOuLaMIcQxajQ==", + "optional": true, + "requires": { + "debug": "^3.2.6", + "iconv-lite": "^0.6.3", + "sax": "^1.2.4" + }, + "dependencies": { + "debug": { + "version": "3.2.7", + "resolved": "https://registry.npmjs.org/debug/-/debug-3.2.7.tgz", + "integrity": "sha512-CFjzYYAi4ThfiQvizrFQevTTXHtnCqWfe7x1AhgEscTz6ZbLbfoLRLPugTQyBth6f8ZERVUSyWHFD/7Wu4t1XQ==", + "optional": true, + "requires": { + "ms": "^2.1.1" + } + }, + "iconv-lite": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", + "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", + "optional": true, + "requires": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + } + } + } + }, + "negotiator": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/negotiator/-/negotiator-0.6.3.tgz", + "integrity": "sha512-+EUsqGPLsM+j/zdChZjsnX51g4XrHFOIXwfnCVPGlQk/k5giakcKsuxCObBRu6DSm9opw/O6slWbJdghQM4bBg==" + }, + "neo-async": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.2.tgz", + "integrity": "sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw==" + }, + "next-tick": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/next-tick/-/next-tick-1.1.0.tgz", + "integrity": "sha512-CXdUiJembsNjuToQvxayPZF9Vqht7hewsvy2sOWafLvi2awflj9mOC6bHIg50orX8IJvWKY9wYQ/zB2kogPslQ==" + }, + "ngx-echarts": { + "version": "17.2.0", + "resolved": "https://registry.npmjs.org/ngx-echarts/-/ngx-echarts-17.2.0.tgz", + "integrity": "sha512-i3XDE9d53zmJH4bp8RQ/271oPlhBkczO1M3VtWk8nCXdxQq9qx8UckjWEQ7oV1AbSDLGK5sRiFu5EaY5hvdWPA==", + "requires": { + "tslib": "^2.3.0" + } + }, + "ngx-infinite-scroll": { + "version": "17.0.0", + "resolved": "https://registry.npmjs.org/ngx-infinite-scroll/-/ngx-infinite-scroll-17.0.0.tgz", + "integrity": "sha512-pQXLuRiuhRuDKD3nmgyW1V08JVNBepmk6nb8qjHc5hgsWNts01+R/p33rYcRDzcut6/PWqGyrZ9o9i8swzMYMA==", + "requires": { + "tslib": "^2.3.0" + } + }, + "nice-napi": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/nice-napi/-/nice-napi-1.0.2.tgz", + "integrity": "sha512-px/KnJAJZf5RuBGcfD+Sp2pAKq0ytz8j+1NehvgIGFkvtvFrDM3T8E4x/JJODXK9WZow8RRGrbA9QQ3hs+pDhA==", + "optional": true, + "requires": { + "node-addon-api": "^3.0.0", + "node-gyp-build": "^4.2.2" + } + }, + "nise": { + "version": "5.1.5", + "resolved": "https://registry.npmjs.org/nise/-/nise-5.1.5.tgz", + "integrity": "sha512-VJuPIfUFaXNRzETTQEEItTOP8Y171ijr+JLq42wHes3DiryR8vT+1TXQW/Rx8JNUhyYYWyIvjXTU6dOhJcs9Nw==", + "optional": true, + "requires": { + "@sinonjs/commons": "^2.0.0", + "@sinonjs/fake-timers": "^10.0.2", + "@sinonjs/text-encoding": "^0.7.1", + "just-extend": "^4.0.2", + "path-to-regexp": "^1.7.0" + }, + "dependencies": { + "@sinonjs/commons": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-2.0.0.tgz", + "integrity": "sha512-uLa0j859mMrg2slwQYdO/AkrOfmH+X6LTVmNTS9CqexuE2IvVORIkSpJLqePAbEnKJ77aMmCwr1NUZ57120Xcg==", + "optional": true, + "requires": { + "type-detect": "4.0.8" + } + }, + "@sinonjs/fake-timers": { + "version": "10.3.0", + "resolved": "https://registry.npmjs.org/@sinonjs/fake-timers/-/fake-timers-10.3.0.tgz", + "integrity": "sha512-V4BG07kuYSUkTCSBHG8G8TNhM+F19jXFWnQtzj+we8DrkpSBCee9Z3Ms8yiGer/dlmhe35/Xdgyo3/0rQKg7YA==", + "optional": true, + "requires": { + "@sinonjs/commons": "^3.0.0" + }, + "dependencies": { + "@sinonjs/commons": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/@sinonjs/commons/-/commons-3.0.0.tgz", + "integrity": "sha512-jXBtWAF4vmdNmZgD5FoKsVLv3rPgDnLgPbU84LIJ3otV44vJlDRokVng5v8NFJdCf/da9legHcKaRuZs4L7faA==", + "optional": true, + "requires": { + "type-detect": "4.0.8" + } + } + } + }, + "isarray": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz", + "integrity": "sha512-D2S+3GLxWH+uhrNEcoh/fnmYeP8E8/zHl644d/jdA0g2uyXvy3sb0qxotE+ne0LtccHknQzWwZEzhak7oJ0COQ==", + "optional": true + }, + "path-to-regexp": { + "version": "1.8.0", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-1.8.0.tgz", + "integrity": "sha512-n43JRhlUKUAlibEJhPeir1ncUID16QnEjNpwzNdO3Lm4ywrBpBZ5oLD0I6br9evr1Y9JTqwRtAh7JLoOzAQdVA==", + "optional": true, + "requires": { + "isarray": "0.0.1" + } + } + } + }, + "node-addon-api": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/node-addon-api/-/node-addon-api-3.2.1.tgz", + "integrity": "sha512-mmcei9JghVNDYydghQmeDX8KoAm0FAiYyIcUt/N4nhyAipB17pllZQDOJD2fotxABnt4Mdz+dKTO7eftLg4d0A==", + "optional": true + }, + "node-forge": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/node-forge/-/node-forge-1.3.1.tgz", + "integrity": "sha512-dPEtOeMvF9VMcYV/1Wb8CPoVAXtp6MKMlcbAt4ddqmGqUJ6fQZFXkNZNkNlfevtNkGtaSoXf/vNNNSvgrdXwtA==" + }, + "node-gyp": { + "version": "10.0.1", + "resolved": "https://registry.npmjs.org/node-gyp/-/node-gyp-10.0.1.tgz", + "integrity": "sha512-gg3/bHehQfZivQVfqIyy8wTdSymF9yTyP4CJifK73imyNMU8AIGQE2pUa7dNWfmMeG9cDVF2eehiRMv0LC1iAg==", + "requires": { + "env-paths": "^2.2.0", + "exponential-backoff": "^3.1.1", + "glob": "^10.3.10", + "graceful-fs": "^4.2.6", + "make-fetch-happen": "^13.0.0", + "nopt": "^7.0.0", + "proc-log": "^3.0.0", + "semver": "^7.3.5", + "tar": "^6.1.2", + "which": "^4.0.0" + }, + "dependencies": { + "brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "requires": { + "balanced-match": "^1.0.0" + } + }, + "glob": { + "version": "10.3.10", + "resolved": "https://registry.npmjs.org/glob/-/glob-10.3.10.tgz", + "integrity": "sha512-fa46+tv1Ak0UPK1TOy/pZrIybNNt4HCv7SDzwyfiOZkvZLEbjsZkJBPtDHVshZjbecAoAGSC20MjLDG/qr679g==", + "requires": { + "foreground-child": "^3.1.0", + "jackspeak": "^2.3.5", + "minimatch": "^9.0.1", + "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0", + "path-scurry": "^1.10.1" + } + }, + "isexe": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-3.1.1.tgz", + "integrity": "sha512-LpB/54B+/2J5hqQ7imZHfdU31OlgQqx7ZicVlkm9kzg9/w8GKLEcFfJl/t7DCEDueOyBAD6zCCwTO6Fzs0NoEQ==" + }, + "minimatch": { + "version": "9.0.3", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.3.tgz", + "integrity": "sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==", + "requires": { + "brace-expansion": "^2.0.1" + } + }, + "which": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/which/-/which-4.0.0.tgz", + "integrity": "sha512-GlaYyEb07DPxYCKhKzplCWBJtvxZcZMrL+4UkrTSJHHPyZU4mYYTv3qaOe77H7EODLSSopAUFAc6W8U4yqvscg==", + "requires": { + "isexe": "^3.1.1" + } + } + } + }, + "node-gyp-build": { + "version": "4.8.0", + "resolved": "https://registry.npmjs.org/node-gyp-build/-/node-gyp-build-4.8.0.tgz", + "integrity": "sha512-u6fs2AEUljNho3EYTJNBfImO5QTo/J/1Etd+NVdCj7qWKUSN/bSLkZwhDv7I+w/MSC6qJ4cknepkAYykDdK8og==", + "optional": true + }, + "node-releases": { + "version": "2.0.14", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-2.0.14.tgz", + "integrity": "sha512-y10wOWt8yZpqXmOgRo77WaHEmhYQYGNA6y421PKsKYWEK8aW+cqAphborZDhqfyKrbZEN92CN1X2KbafY2s7Yw==" + }, + "nopt": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/nopt/-/nopt-7.2.0.tgz", + "integrity": "sha512-CVDtwCdhYIvnAzFoJ6NJ6dX3oga9/HyciQDnG1vQDjSLMeKLJ4A93ZqYKDrgYSr1FBY5/hMYC+2VCi24pgpkGA==", + "requires": { + "abbrev": "^2.0.0" + } + }, + "normalize-package-data": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-6.0.0.tgz", + "integrity": "sha512-UL7ELRVxYBHBgYEtZCXjxuD5vPxnmvMGq0jp/dGPKKrN7tfsBh2IY7TlJ15WWwdjRWD3RJbnsygUurTK3xkPkg==", + "requires": { + "hosted-git-info": "^7.0.0", + "is-core-module": "^2.8.1", + "semver": "^7.3.5", + "validate-npm-package-license": "^3.0.4" + } + }, + "normalize-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz", + "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==" + }, + "normalize-range": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/normalize-range/-/normalize-range-0.1.2.tgz", + "integrity": "sha512-bdok/XvKII3nUpklnV6P2hxtMNrCboOjAcyBuQnWEhO665FwrSNRxU+AqpsyvO6LgGYPspN+lu5CLtw4jPRKNA==" + }, + "npm-bundled": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/npm-bundled/-/npm-bundled-3.0.0.tgz", + "integrity": "sha512-Vq0eyEQy+elFpzsKjMss9kxqb9tG3YHg4dsyWuUENuzvSUWe1TCnW/vV9FkhvBk/brEDoDiVd+M1Btosa6ImdQ==", + "requires": { + "npm-normalize-package-bin": "^3.0.0" + } + }, + "npm-install-checks": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/npm-install-checks/-/npm-install-checks-6.3.0.tgz", + "integrity": "sha512-W29RiK/xtpCGqn6f3ixfRYGk+zRyr+Ew9F2E20BfXxT5/euLdA/Nm7fO7OeTGuAmTs30cpgInyJ0cYe708YTZw==", + "requires": { + "semver": "^7.1.1" + } + }, + "npm-normalize-package-bin": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/npm-normalize-package-bin/-/npm-normalize-package-bin-3.0.1.tgz", + "integrity": "sha512-dMxCf+zZ+3zeQZXKxmyuCKlIDPGuv8EF940xbkC4kQVDTtqoh6rJFO+JTKSA6/Rwi0getWmtuy4Itup0AMcaDQ==" + }, + "npm-package-arg": { + "version": "11.0.1", + "resolved": "https://registry.npmjs.org/npm-package-arg/-/npm-package-arg-11.0.1.tgz", + "integrity": "sha512-M7s1BD4NxdAvBKUPqqRW957Xwcl/4Zvo8Aj+ANrzvIPzGJZElrH7Z//rSaec2ORcND6FHHLnZeY8qgTpXDMFQQ==", + "requires": { + "hosted-git-info": "^7.0.0", + "proc-log": "^3.0.0", + "semver": "^7.3.5", + "validate-npm-package-name": "^5.0.0" + } + }, + "npm-packlist": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/npm-packlist/-/npm-packlist-8.0.2.tgz", + "integrity": "sha512-shYrPFIS/JLP4oQmAwDyk5HcyysKW8/JLTEA32S0Z5TzvpaeeX2yMFfoK1fjEBnCBvVyIB/Jj/GBFdm0wsgzbA==", + "requires": { + "ignore-walk": "^6.0.4" + } + }, + "npm-pick-manifest": { + "version": "9.0.0", + "resolved": "https://registry.npmjs.org/npm-pick-manifest/-/npm-pick-manifest-9.0.0.tgz", + "integrity": "sha512-VfvRSs/b6n9ol4Qb+bDwNGUXutpy76x6MARw/XssevE0TnctIKcmklJZM5Z7nqs5z5aW+0S63pgCNbpkUNNXBg==", + "requires": { + "npm-install-checks": "^6.0.0", + "npm-normalize-package-bin": "^3.0.0", + "npm-package-arg": "^11.0.0", + "semver": "^7.3.5" + } + }, + "npm-registry-fetch": { + "version": "16.1.0", + "resolved": "https://registry.npmjs.org/npm-registry-fetch/-/npm-registry-fetch-16.1.0.tgz", + "integrity": "sha512-PQCELXKt8Azvxnt5Y85GseQDJJlglTFM9L9U9gkv2y4e9s0k3GVDdOx3YoB6gm2Do0hlkzC39iCGXby+Wve1Bw==", + "requires": { + "make-fetch-happen": "^13.0.0", + "minipass": "^7.0.2", + "minipass-fetch": "^3.0.0", + "minipass-json-stream": "^1.0.1", + "minizlib": "^2.1.2", + "npm-package-arg": "^11.0.0", + "proc-log": "^3.0.0" + } + }, + "npm-run-path": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/npm-run-path/-/npm-run-path-4.0.1.tgz", + "integrity": "sha512-S48WzZW777zhNIrn7gxOlISNAqi9ZC/uQFnRdbeIHhZhCA6UqpkOT8T1G7BvfdgP4Er8gF4sUbaS0i7QvIfCWw==", + "requires": { + "path-key": "^3.0.0" + } + }, + "nth-check": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.1.1.tgz", + "integrity": "sha512-lqjrjmaOoAnWfMmBPL+XNnynZh2+swxiX3WUE0s4yEHI6m+AwrK2UZOimIRl3X/4QctVqS8AiZjFqyOGrMXb/w==", + "requires": { + "boolbase": "^1.0.0" + } + }, + "object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=" + }, + "object-inspect": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.9.0.tgz", + "integrity": "sha512-i3Bp9iTqwhaLZBxGkRfo5ZbE07BQRT7MGu8+nNgwW9ItGp1TzCTw2DLEoWwjClxBjOFI/hWljTAmYGCEwmtnOw==" + }, + "object-keys": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", + "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==" + }, + "object.assign": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.2.tgz", + "integrity": "sha512-ixT2L5THXsApyiUPYKmW+2EHpXXe5Ii3M+f4e+aJFAHao5amFRW6J0OO6c/LU8Be47utCx2GL89hxGB6XSmKuQ==", + "requires": { + "call-bind": "^1.0.0", + "define-properties": "^1.1.3", + "has-symbols": "^1.0.1", + "object-keys": "^1.1.1" + } + }, + "obuf": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/obuf/-/obuf-1.1.2.tgz", + "integrity": "sha512-PX1wu0AmAdPqOL1mWhqmlOd8kOIZQwGZw6rh7uby9fTc5lhaOWFLX3I6R1hrF9k3zUY40e6igsLGkDXK92LJNg==" + }, + "on-finished": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.3.0.tgz", + "integrity": "sha1-IPEzZIGwg811M3mSoWlxqi2QaUc=", + "devOptional": true, + "requires": { + "ee-first": "1.1.1" + } + }, + "on-headers": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/on-headers/-/on-headers-1.0.2.tgz", + "integrity": "sha512-pZAE+FJLoyITytdqK0U5s+FIpjN0JP3OzFi/u8Rx+EV5/W+JTWGXG8xFzevE7AjBfDqHv/8vL8qQsIhHnqRkrA==" + }, + "once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", + "requires": { + "wrappy": "1" + } + }, + "onetime": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/onetime/-/onetime-5.1.2.tgz", + "integrity": "sha512-kbpaSSGJTWdAY5KPVeMOKXSrPtr8C8C7wodJbcsd51jRnmD+GZu8Y0VoU6Dm5Z4vWr0Ig/1NKuWRKf7j5aaYSg==", + "requires": { + "mimic-fn": "^2.1.0" + } + }, + "open": { + "version": "8.4.2", + "resolved": "https://registry.npmjs.org/open/-/open-8.4.2.tgz", + "integrity": "sha512-7x81NCL719oNbsq/3mh+hVrAWmFuEYUqrq/Iw3kUzH8ReypT9QQ0BLoJS7/G9k6N81XjW4qHWtjWwe/9eLy1EQ==", + "requires": { + "define-lazy-prop": "^2.0.0", + "is-docker": "^2.1.1", + "is-wsl": "^2.2.0" + } + }, + "opn": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/opn/-/opn-5.3.0.tgz", + "integrity": "sha512-bYJHo/LOmoTd+pfiYhfZDnf9zekVJrY+cnS2a5F2x+w5ppvTqObojTP7WiFG+kVZs9Inw+qQ/lw7TroWwhdd2g==", + "devOptional": true, + "requires": { + "is-wsl": "^1.1.0" + }, + "dependencies": { + "is-wsl": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-1.1.0.tgz", + "integrity": "sha512-gfygJYZ2gLTDlmbWMI0CE2MwnFzSN/2SZfkMlItC4K/JBlsWVDB0bO6XhqcY13YXE7iMcAJnzTCJjPiTeJJ0Mw==", + "devOptional": true + } + } + }, + "optionator": { + "version": "0.9.3", + "resolved": "https://registry.npmjs.org/optionator/-/optionator-0.9.3.tgz", + "integrity": "sha512-JjCoypp+jKn1ttEFExxhetCKeJt9zhAgAve5FXHixTvFDW/5aEktX9bufBKLRRMdU7bNtpLfcGu94B3cdEJgjg==", + "dev": true, + "requires": { + "@aashutoshrathi/word-wrap": "^1.2.3", + "deep-is": "^0.1.3", + "fast-levenshtein": "^2.0.6", + "levn": "^0.4.1", + "prelude-ls": "^1.2.1", + "type-check": "^0.4.0" + } + }, + "ora": { + "version": "5.4.1", + "resolved": "https://registry.npmjs.org/ora/-/ora-5.4.1.tgz", + "integrity": "sha512-5b6Y85tPxZZ7QytO+BQzysW31HJku27cRIlkbAXaNx+BdcVi+LlRFmVXzeF6a7JCwJpyw5c4b+YSVImQIrBpuQ==", + "requires": { + "bl": "^4.1.0", + "chalk": "^4.1.0", + "cli-cursor": "^3.1.0", + "cli-spinners": "^2.5.0", + "is-interactive": "^1.0.0", + "is-unicode-supported": "^0.1.0", + "log-symbols": "^4.1.0", + "strip-ansi": "^6.0.0", + "wcwidth": "^1.0.1" + }, + "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "requires": { + "color-convert": "^2.0.1" + } + }, + "chalk": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.0.tgz", + "integrity": "sha512-qwx12AxXe2Q5xQ43Ac//I6v5aXTipYrSESdOgzrN+9XjgEpyjpKuvSGaN4qE93f7TQTlerQQ8S+EQ0EyDoVL1A==", + "requires": { + "ansi-styles": "^4.1.0", + "supports-color": "^7.1.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==" + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, + "os-browserify": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/os-browserify/-/os-browserify-0.3.0.tgz", + "integrity": "sha1-hUNzx/XCMVkU/Jv8a9gjj92h7Cc=" + }, + "os-tmpdir": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", + "integrity": "sha512-D2FR03Vir7FIu45XBY20mTb+/ZSWB00sjU9jdQXt83gDrI4Ztz5Fs7/yy74g2N5SVQY4xY1qDr4rNddwYRVX0g==" + }, + "ospath": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/ospath/-/ospath-1.2.2.tgz", + "integrity": "sha1-EnZjl3Sj+O8lcvf+QoDg6kVQwHs=", + "optional": true + }, + "p-limit": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-3.1.0.tgz", + "integrity": "sha512-TYOanM3wGwNGsZN2cVTYPArw454xnXj5qmWF1bEoAc4+cU/ol7GVh7odevjp1FNHduHc3KZMcFduxU5Xc6uJRQ==", + "dev": true, + "requires": { + "yocto-queue": "^0.1.0" + } + }, + "p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "requires": { + "p-limit": "^2.2.0" + }, + "dependencies": { + "p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "requires": { + "p-try": "^2.0.0" + } + } + } + }, + "p-map": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/p-map/-/p-map-4.0.0.tgz", + "integrity": "sha512-/bjOqmgETBYB5BoEeGVea8dmvHb2m9GLy1E9W43yeyfP6QQCZGFNa+XRceJEuDB6zqr+gKpIAmlLebMpykw/MQ==", + "requires": { + "aggregate-error": "^3.0.0" + } + }, + "p-retry": { + "version": "4.6.2", + "resolved": "https://registry.npmjs.org/p-retry/-/p-retry-4.6.2.tgz", + "integrity": "sha512-312Id396EbJdvRONlngUx0NydfrIQ5lsYu0znKVUzVvArzEIt08V1qhtyESbGVd1FGX7UKtiFp5uwKZdM8wIuQ==", + "requires": { + "@types/retry": "0.12.0", + "retry": "^0.13.1" + }, + "dependencies": { + "retry": { + "version": "0.13.1", + "resolved": "https://registry.npmjs.org/retry/-/retry-0.13.1.tgz", + "integrity": "sha512-XQBQ3I8W1Cge0Seh+6gjj03LbmRFWuoszgK9ooCpwYIrhhoO80pfq4cUkU5DkknwfOfFteRwlZ56PYOGYyFWdg==" + } + } + }, + "p-try": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", + "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==" + }, + "pacote": { + "version": "17.0.6", + "resolved": "https://registry.npmjs.org/pacote/-/pacote-17.0.6.tgz", + "integrity": "sha512-cJKrW21VRE8vVTRskJo78c/RCvwJCn1f4qgfxL4w77SOWrTCRcmfkYHlHtS0gqpgjv3zhXflRtgsrUCX5xwNnQ==", + "requires": { + "@npmcli/git": "^5.0.0", + "@npmcli/installed-package-contents": "^2.0.1", + "@npmcli/promise-spawn": "^7.0.0", + "@npmcli/run-script": "^7.0.0", + "cacache": "^18.0.0", + "fs-minipass": "^3.0.0", + "minipass": "^7.0.2", + "npm-package-arg": "^11.0.0", + "npm-packlist": "^8.0.0", + "npm-pick-manifest": "^9.0.0", + "npm-registry-fetch": "^16.0.0", + "proc-log": "^3.0.0", + "promise-retry": "^2.0.1", + "read-package-json": "^7.0.0", + "read-package-json-fast": "^3.0.0", + "sigstore": "^2.2.0", + "ssri": "^10.0.0", + "tar": "^6.1.11" + } + }, + "pako": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/pako/-/pako-1.0.11.tgz", + "integrity": "sha512-4hLB8Py4zZce5s4yd9XzopqwVv/yGNhV1Bl8NTmCq1763HeK2+EwVTv+leGeL13Dnh2wfbqowVPXCIO0z4taYw==" + }, + "parent-module": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", + "integrity": "sha512-GQ2EWRpQV8/o+Aw8YqtfZZPfNRWZYkbidE9k5rpl/hC3vtHHBfGm2Ifi6qWV+coDGkrUKZAxE3Lot5kcsRlh+g==", + "requires": { + "callsites": "^3.0.0" + } + }, + "parents": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parents/-/parents-1.0.1.tgz", + "integrity": "sha1-/t1NK/GTp3dF/nHjcdc8MwfZx1E=", + "requires": { + "path-platform": "~0.11.15" + } + }, + "parse-asn1": { + "version": "5.1.6", + "resolved": "https://registry.npmjs.org/parse-asn1/-/parse-asn1-5.1.6.tgz", + "integrity": "sha512-RnZRo1EPU6JBnra2vGHj0yhp6ebyjBZpmUCLHWiFhxlzvBCCpAuZ7elsBp1PVAbQN0/04VD/19rfzlBSwLstMw==", + "requires": { + "asn1.js": "^5.2.0", + "browserify-aes": "^1.0.0", + "evp_bytestokey": "^1.0.0", + "pbkdf2": "^3.0.3", + "safe-buffer": "^5.1.1" + } + }, + "parse-json": { + "version": "5.2.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-5.2.0.tgz", + "integrity": "sha512-ayCKvm/phCGxOkYRSCM82iDwct8/EonSEgCSxWxD7ve6jHggsFl4fZVQBPRNgQoKiuV/odhFrGzQXZwbifC8Rg==", + "requires": { + "@babel/code-frame": "^7.0.0", + "error-ex": "^1.3.1", + "json-parse-even-better-errors": "^2.3.0", + "lines-and-columns": "^1.1.6" + } + }, + "parse-node-version": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parse-node-version/-/parse-node-version-1.0.1.tgz", + "integrity": "sha512-3YHlOa/JgH6Mnpr05jP9eDG254US9ek25LyIxZlDItp2iJtwyaXQb57lBYLdT3MowkUFYEV2XXNAYIPlESvJlA==" + }, + "parse5": { + "version": "7.1.2", + "resolved": "https://registry.npmjs.org/parse5/-/parse5-7.1.2.tgz", + "integrity": "sha512-Czj1WaSVpaoj0wbhMzLmWD69anp2WH7FXMB9n1Sy8/ZFF9jolSQVMu1Ij5WIyGmcBmhk7EOndpO4mIpihVqAXw==", + "requires": { + "entities": "^4.4.0" + } + }, + "parse5-html-rewriting-stream": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/parse5-html-rewriting-stream/-/parse5-html-rewriting-stream-7.0.0.tgz", + "integrity": "sha512-mazCyGWkmCRWDI15Zp+UiCqMp/0dgEmkZRvhlsqqKYr4SsVm/TvnSpD9fCvqCA2zoWJcfRym846ejWBBHRiYEg==", + "requires": { + "entities": "^4.3.0", + "parse5": "^7.0.0", + "parse5-sax-parser": "^7.0.0" + } + }, + "parse5-sax-parser": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/parse5-sax-parser/-/parse5-sax-parser-7.0.0.tgz", + "integrity": "sha512-5A+v2SNsq8T6/mG3ahcz8ZtQ0OUFTatxPbeidoMB7tkJSGDY3tdfl4MHovtLQHkEn5CGxijNWRQHhRQ6IRpXKg==", + "requires": { + "parse5": "^7.0.0" + } + }, + "parseurl": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/parseurl/-/parseurl-1.3.3.tgz", + "integrity": "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ==" + }, + "path-exists": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz", + "integrity": "sha512-ak9Qy5Q7jYb2Wwcey5Fpvg2KoAc/ZIhLSLOSBmRmygPsGwkVVt0fZa0qrtMz+m6tJTAHfZQ8FnmB4MG4LWy7/w==" + }, + "path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=" + }, + "path-key": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/path-key/-/path-key-3.1.1.tgz", + "integrity": "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q==" + }, + "path-parse": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz", + "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==" + }, + "path-platform": { + "version": "0.11.15", + "resolved": "https://registry.npmjs.org/path-platform/-/path-platform-0.11.15.tgz", + "integrity": "sha1-6GQhf3TDaFDwhSt43Hv31KVyG/I=" + }, + "path-scurry": { + "version": "1.10.1", + "resolved": "https://registry.npmjs.org/path-scurry/-/path-scurry-1.10.1.tgz", + "integrity": "sha512-MkhCqzzBEpPvxxQ71Md0b1Kk51W01lrYvlMzSUaIzNsODdd7mqhiimSZlr+VegAz5Z6Vzt9Xg2ttE//XBhH3EQ==", + "requires": { + "lru-cache": "^9.1.1 || ^10.0.0", + "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0" + }, + "dependencies": { + "lru-cache": { + "version": "10.2.0", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-10.2.0.tgz", + "integrity": "sha512-2bIM8x+VAf6JT4bKAljS1qUWgMsqZRPGJS6FSahIMPVvctcNhyVp7AJu7quxOW9jwkryBReKZY5tY5JYv2n/7Q==" + } + } + }, + "path-to-regexp": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-0.1.7.tgz", + "integrity": "sha512-5DFkuoqlv1uYQKxy8omFBeJPQcdoE07Kv2sferDCrAq1ohOU+MSDswDIbnx3YAM60qIOnYa53wBhXW0EbMonrQ==" + }, + "path-type": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", + "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==" + }, + "pathval": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/pathval/-/pathval-1.1.1.tgz", + "integrity": "sha512-Dp6zGqpTdETdR63lehJYPeIOqpiNBNtc7BpWSLrOje7UaIsE5aY92r/AunQA7rsXvet3lrJ3JnZX29UPTKXyKQ==", + "optional": true + }, + "pause-stream": { + "version": "0.0.11", + "resolved": "https://registry.npmjs.org/pause-stream/-/pause-stream-0.0.11.tgz", + "integrity": "sha1-/lo0sMvOErWqaitAPuLnO2AvFEU=", + "optional": true, + "requires": { + "through": "~2.3" + } + }, + "pbkdf2": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/pbkdf2/-/pbkdf2-3.1.1.tgz", + "integrity": "sha512-4Ejy1OPxi9f2tt1rRV7Go7zmfDQ+ZectEQz3VGUQhgq62HtIRPDyG/JtnwIxs6x3uNMwo2V7q1fMvKjb+Tnpqg==", + "requires": { + "create-hash": "^1.1.2", + "create-hmac": "^1.1.4", + "ripemd160": "^2.0.1", + "safe-buffer": "^5.0.1", + "sha.js": "^2.4.8" + } + }, + "pend": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/pend/-/pend-1.2.0.tgz", + "integrity": "sha512-F3asv42UuXchdzt+xXqfW1OGlVBe+mxa2mqI0pg5yAHZPvFmY3Y6drSf/GQ1A86WgWEN9Kzh/WrgKa6iGcHXLg==", + "optional": true + }, + "performance-now": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", + "integrity": "sha512-7EAHlyLHI56VEIdK57uwHdHKIaAGbnXPiw0yWbarQZOKaKpvUIgW0jWRVLiatnM+XXlSwsanIBH/hzGMJulMow==", + "optional": true + }, + "picocolors": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.0.0.tgz", + "integrity": "sha512-1fygroTLlHu66zi26VoTDv8yRgm0Fccecssto+MhsZ0D/DGW2sm8E8AjW7NU5VVTRt5GxbeZ5qBuJr+HyLYkjQ==" + }, + "picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==" + }, + "pify": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "integrity": "sha512-udgsAY+fTnvv7kI7aaxbqwWNb0AHiB0qBO89PZKPkoTmGOgdbrHDKD+0B2X4uTfJ/FT1R09r9gTsjUjNJotuog==", + "optional": true + }, + "piscina": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/piscina/-/piscina-4.4.0.tgz", + "integrity": "sha512-+AQduEJefrOApE4bV7KRmp3N2JnnyErlVqq4P/jmko4FPz9Z877BCccl/iB3FdrWSUkvbGV9Kan/KllJgat3Vg==", + "requires": { + "nice-napi": "^1.0.2" + } + }, + "pkg-dir": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-7.0.0.tgz", + "integrity": "sha512-Ie9z/WINcxxLp27BKOCHGde4ITq9UklYKDzVo1nhk5sqGEXU3FpkwP5GM2voTGJkGd9B3Otl+Q4uwSOeSUtOBA==", + "requires": { + "find-up": "^6.3.0" + }, + "dependencies": { + "find-up": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-6.3.0.tgz", + "integrity": "sha512-v2ZsoEuVHYy8ZIlYqwPe/39Cy+cFDzp4dXPaxNvkEuouymu+2Jbz0PxpKarJHYJTmv2HWT3O382qY8l4jMWthw==", + "requires": { + "locate-path": "^7.1.0", + "path-exists": "^5.0.0" + } + }, + "locate-path": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-7.2.0.tgz", + "integrity": "sha512-gvVijfZvn7R+2qyPX8mAuKcFGDf6Nc61GdvGafQsHL0sBIxfKzA+usWn4GFC/bk+QdwPUD4kWFJLhElipq+0VA==", + "requires": { + "p-locate": "^6.0.0" + } + }, + "p-limit": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-4.0.0.tgz", + "integrity": "sha512-5b0R4txpzjPWVw/cXXUResoD4hb6U/x9BH08L7nw+GN1sezDzPdxeRvpc9c433fZhBan/wusjbCsqwqm4EIBIQ==", + "requires": { + "yocto-queue": "^1.0.0" + } + }, + "p-locate": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-6.0.0.tgz", + "integrity": "sha512-wPrq66Llhl7/4AGC6I+cqxT07LhXvWL08LNXz1fENOw0Ap4sRZZ/gZpTTJ5jpurzzzfS2W/Ge9BY3LgLjCShcw==", + "requires": { + "p-limit": "^4.0.0" + } + }, + "path-exists": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-5.0.0.tgz", + "integrity": "sha512-RjhtfwJOxzcFmNOi6ltcbcu4Iu+FL3zEj83dk4kAS+fVpTxXLO1b38RvJgT/0QwvV/L3aY9TAnyv0EOqW4GoMQ==" + }, + "yocto-queue": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-1.0.0.tgz", + "integrity": "sha512-9bnSc/HEW2uRy67wc+T8UwauLuPJVn28jb+GtJY16iiKWyvmYJRXVT4UamsAEGQfPohgr2q4Tq0sQbQlxTfi1g==" + } + } + }, + "pngjs": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/pngjs/-/pngjs-5.0.0.tgz", + "integrity": "sha512-40QW5YalBNfQo5yRYmiw7Yz6TKKVr3h6970B2YE+3fQpsWcrbj1PzJgxeJ19DRQjhMbKPIuMY8rFaXc8moolVw==" + }, + "popper.js": { + "version": "1.16.1", + "resolved": "https://registry.npmjs.org/popper.js/-/popper.js-1.16.1.tgz", + "integrity": "sha512-Wb4p1J4zyFTbM+u6WuO4XstYx4Ky9Cewe4DWrel7B0w6VVICvPwdOpotjzcf6eD8TsckVnIMNONQyPIUFOUbCQ==", + "peer": true + }, + "portscanner": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/portscanner/-/portscanner-2.2.0.tgz", + "integrity": "sha512-IFroCz/59Lqa2uBvzK3bKDbDDIEaAY8XJ1jFxcLWTqosrsc32//P4VuSB2vZXoHiHqOmx8B5L5hnKOxL/7FlPw==", + "devOptional": true, + "requires": { + "async": "^2.6.0", + "is-number-like": "^1.0.3" + }, + "dependencies": { + "async": { + "version": "2.6.4", + "resolved": "https://registry.npmjs.org/async/-/async-2.6.4.tgz", + "integrity": "sha512-mzo5dfJYwAn29PeiJ0zvwTo04zj8HDJj0Mn8TD7sno7q12prdbnasKJHhkm2c1LgrhlJ0teaea8860oxi51mGA==", + "devOptional": true, + "requires": { + "lodash": "^4.17.14" + } + } + } + }, + "postcss": { + "version": "8.4.35", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.35.tgz", + "integrity": "sha512-u5U8qYpBCpN13BsiEB0CbR1Hhh4Gc0zLFuedrHJKMctHCHAGrMdG0PRM/KErzAL3CU6/eckEtmHNB3x6e3c0vA==", + "requires": { + "nanoid": "^3.3.7", + "picocolors": "^1.0.0", + "source-map-js": "^1.0.2" + } + }, + "postcss-loader": { + "version": "8.1.1", + "resolved": "https://registry.npmjs.org/postcss-loader/-/postcss-loader-8.1.1.tgz", + "integrity": "sha512-0IeqyAsG6tYiDRCYKQJLAmgQr47DX6N7sFSWvQxt6AcupX8DIdmykuk/o/tx0Lze3ErGHJEp5OSRxrelC6+NdQ==", + "requires": { + "cosmiconfig": "^9.0.0", + "jiti": "^1.20.0", + "semver": "^7.5.4" + } + }, + "postcss-media-query-parser": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/postcss-media-query-parser/-/postcss-media-query-parser-0.2.3.tgz", + "integrity": "sha512-3sOlxmbKcSHMjlUXQZKQ06jOswE7oVkXPxmZdoB1r5l0q6gTFTQSHxNxOrCccElbW7dxNytifNEo8qidX2Vsig==" + }, + "postcss-modules-extract-imports": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/postcss-modules-extract-imports/-/postcss-modules-extract-imports-3.0.0.tgz", + "integrity": "sha512-bdHleFnP3kZ4NYDhuGlVK+CMrQ/pqUm8bx/oGL93K6gVwiclvX5x0n76fYMKuIGKzlABOy13zsvqjb0f92TEXw==", + "requires": {} + }, + "postcss-modules-local-by-default": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/postcss-modules-local-by-default/-/postcss-modules-local-by-default-4.0.4.tgz", + "integrity": "sha512-L4QzMnOdVwRm1Qb8m4x8jsZzKAaPAgrUF1r/hjDR2Xj7R+8Zsf97jAlSQzWtKx5YNiNGN8QxmPFIc/sh+RQl+Q==", + "requires": { + "icss-utils": "^5.0.0", + "postcss-selector-parser": "^6.0.2", + "postcss-value-parser": "^4.1.0" + } + }, + "postcss-modules-scope": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/postcss-modules-scope/-/postcss-modules-scope-3.1.1.tgz", + "integrity": "sha512-uZgqzdTleelWjzJY+Fhti6F3C9iF1JR/dODLs/JDefozYcKTBCdD8BIl6nNPbTbcLnGrk56hzwZC2DaGNvYjzA==", + "requires": { + "postcss-selector-parser": "^6.0.4" + } + }, + "postcss-modules-values": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/postcss-modules-values/-/postcss-modules-values-4.0.0.tgz", + "integrity": "sha512-RDxHkAiEGI78gS2ofyvCsu7iycRv7oqw5xMWn9iMoR0N/7mf9D50ecQqUo5BZ9Zh2vH4bCUR/ktCqbB9m8vJjQ==", + "requires": { + "icss-utils": "^5.0.0" + } + }, + "postcss-selector-parser": { + "version": "6.0.16", + "resolved": "https://registry.npmjs.org/postcss-selector-parser/-/postcss-selector-parser-6.0.16.tgz", + "integrity": "sha512-A0RVJrX+IUkVZbW3ClroRWurercFhieevHB38sr2+l9eUClMqome3LmEmnhlNy+5Mr2EYN6B2Kaw9wYdd+VHiw==", + "requires": { + "cssesc": "^3.0.0", + "util-deprecate": "^1.0.2" + } + }, + "postcss-value-parser": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz", + "integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ==" + }, + "prelude-ls": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz", + "integrity": "sha512-vkcDPrRZo1QZLbn5RLGPpg/WmIQ65qoWWhcGKf/b5eplkkarX0m9z8ppCat4mlOqUsWpyNuYgO3VRyrYHSzX5g==", + "dev": true + }, + "prettier": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.0.0.tgz", + "integrity": "sha512-zBf5eHpwHOGPC47h0zrPyNn+eAEIdEzfywMoYn2XPi0P44Zp0tSq64rq0xAREh4auw2cJZHo9QUob+NqCQky4g==", + "dev": true + }, + "pretty-bytes": { + "version": "5.6.0", + "resolved": "https://registry.npmjs.org/pretty-bytes/-/pretty-bytes-5.6.0.tgz", + "integrity": "sha512-FFw039TmrBqFK8ma/7OL3sDz/VytdtJr044/QUJtH0wK9lb9jLq9tJyIxUwtQJHwar2BqtiA4iCWSwo9JLkzFg==", + "optional": true + }, + "pretty-hrtime": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/pretty-hrtime/-/pretty-hrtime-1.0.3.tgz", + "integrity": "sha1-t+PqQkNaTJsnWdmeDyAesZWALuE=" + }, + "proc-log": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/proc-log/-/proc-log-3.0.0.tgz", + "integrity": "sha512-++Vn7NS4Xf9NacaU9Xq3URUuqZETPsf8L4j5/ckhaRYsfPeRyzGw+iDjFhV/Jr3uNmTvvddEJFWh5R1gRgUH8A==" + }, + "process": { + "version": "0.11.10", + "resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz", + "integrity": "sha1-czIwDoQBYb2j5podHZGn1LwW8YI=" + }, + "process-nextick-args": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", + "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==" + }, + "promise-inflight": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/promise-inflight/-/promise-inflight-1.0.1.tgz", + "integrity": "sha512-6zWPyEOFaQBJYcGMHBKTKJ3u6TBsnMFOIZSa6ce1e/ZrrsOlnHRHbabMjLiBYKp+n44X9eUI6VUPaukCXHuG4g==" + }, + "promise-retry": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/promise-retry/-/promise-retry-2.0.1.tgz", + "integrity": "sha512-y+WKFlBR8BGXnsNlIHFGPZmyDf3DFMoLhaflAnyZgV6rG6xu+JwesTo2Q9R6XwYmtmwAFCkAk3e35jEdoeh/3g==", + "requires": { + "err-code": "^2.0.2", + "retry": "^0.12.0" + } + }, + "proxy-addr": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/proxy-addr/-/proxy-addr-2.0.7.tgz", + "integrity": "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg==", + "requires": { + "forwarded": "0.2.0", + "ipaddr.js": "1.9.1" + }, + "dependencies": { + "ipaddr.js": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/ipaddr.js/-/ipaddr.js-1.9.1.tgz", + "integrity": "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g==" + } + } + }, + "proxy-from-env": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.0.0.tgz", + "integrity": "sha512-F2JHgJQ1iqwnHDcQjVBsq3n/uoaFL+iPW/eAeL7kVxy/2RrWaN4WroKjjvbsoRtv0ftelNyC01bjRhn/bhcf4A==", + "optional": true + }, + "prr": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/prr/-/prr-1.0.1.tgz", + "integrity": "sha512-yPw4Sng1gWghHQWj0B3ZggWUm4qVbPwPFcRG8KyxiU7J2OHFSoEHKS+EZ3fv5l1t9CyCiop6l/ZYeWbrgoQejw==", + "optional": true + }, + "ps-tree": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/ps-tree/-/ps-tree-1.2.0.tgz", + "integrity": "sha512-0VnamPPYHl4uaU/nSFeZZpR21QAWRz+sRv4iW9+v/GS/J5U5iZB5BNN6J0RMoOvdx2gWM2+ZFMIm58q24e4UYA==", + "optional": true, + "requires": { + "event-stream": "=3.3.4" + } + }, + "psl": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/psl/-/psl-1.9.0.tgz", + "integrity": "sha512-E/ZsdU4HLs/68gYzgGTkMicWTLPdAftJLfJFlLUAAKZGkStNU72sZjT66SnMDVOfOWY/YAoiD7Jxa9iHvngcag==", + "optional": true + }, + "public-encrypt": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/public-encrypt/-/public-encrypt-4.0.3.tgz", + "integrity": "sha512-zVpa8oKZSz5bTMTFClc1fQOnyyEzpl5ozpi1B5YcvBrdohMjH2rfsBtyXcuNuwjsDIXmBYlF2N5FlJYhR29t8Q==", + "requires": { + "bn.js": "^4.1.0", + "browserify-rsa": "^4.0.0", + "create-hash": "^1.1.0", + "parse-asn1": "^5.0.0", + "randombytes": "^2.0.1", + "safe-buffer": "^5.1.2" + }, + "dependencies": { + "bn.js": { + "version": "4.12.0", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.12.0.tgz", + "integrity": "sha512-c98Bf3tPniI+scsdk237ku1Dc3ujXQTSgyiPUDEOe7tRkhrqridvh8klBv0HCEso1OLOYcHuCv/cS6DNxKH+ZA==" + } + } + }, + "pump": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", + "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", + "optional": true, + "requires": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + }, + "punycode": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.0.tgz", + "integrity": "sha512-rRV+zQD8tVFys26lAGR9WUuS4iUAngJScM+ZRSKtvl5tKeZ2t5bvdNFdNHBW9FWR4guGHlgmsZ1G7BSm2wTbuA==" + }, + "qjobs": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/qjobs/-/qjobs-1.2.0.tgz", + "integrity": "sha512-8YOJEHtxpySA3fFDyCRxA+UUV+fA+rTWnuWvylOK/NCjhY+b4ocCtmu8TtsWb+mYeU+GCHf/S66KZF/AsteKHg==", + "optional": true, + "peer": true + }, + "qrcode": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/qrcode/-/qrcode-1.5.1.tgz", + "integrity": "sha512-nS8NJ1Z3md8uTjKtP+SGGhfqmTCs5flU/xR623oI0JX+Wepz9R8UrRVCTBTJm3qGw3rH6jJ6MUHjkDx15cxSSg==", + "requires": { + "dijkstrajs": "^1.0.1", + "encode-utf8": "^1.0.3", + "pngjs": "^5.0.0", + "yargs": "^15.3.1" + }, + "dependencies": { + "yargs": { + "version": "15.4.1", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-15.4.1.tgz", + "integrity": "sha512-aePbxDmcYW++PaqBsJ+HYUFwCdv4LVvdnhBy78E57PIor8/OVvhMrADFFEDh8DHDFRv/O9i3lPhsENjO7QX0+A==", + "requires": { + "cliui": "^6.0.0", + "decamelize": "^1.2.0", + "find-up": "^4.1.0", + "get-caller-file": "^2.0.1", + "require-directory": "^2.1.1", + "require-main-filename": "^2.0.0", + "set-blocking": "^2.0.0", + "string-width": "^4.2.0", + "which-module": "^2.0.0", + "y18n": "^4.0.0", + "yargs-parser": "^18.1.2" + } + } + } + }, + "qs": { + "version": "6.10.4", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.10.4.tgz", + "integrity": "sha512-OQiU+C+Ds5qiH91qh/mg0w+8nwQuLjM4F4M/PbmhDOoYehPh+Fb0bDjtR1sOvy7YKxvj28Y/M0PhP5uVX0kB+g==", + "optional": true, + "requires": { + "side-channel": "^1.0.4" + } + }, + "querystring": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/querystring/-/querystring-0.2.0.tgz", + "integrity": "sha1-sgmEkgO7Jd+CDadW50cAWHhSFiA=" + }, + "querystring-es3": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/querystring-es3/-/querystring-es3-0.2.1.tgz", + "integrity": "sha1-nsYfeQSYdXB9aUFFlv2Qek1xHnM=" + }, + "querystringify": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/querystringify/-/querystringify-2.2.0.tgz", + "integrity": "sha512-FIqgj2EUvTa7R50u0rGsyTftzjYmv/a3hO345bZNrqabNqjtgiDMgmo4mkUjd+nzU5oF3dClKqFIPUKybUyqoQ==", + "optional": true + }, + "queue-microtask": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==" + }, + "randombytes": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", + "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", + "requires": { + "safe-buffer": "^5.1.0" + } + }, + "randomfill": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/randomfill/-/randomfill-1.0.4.tgz", + "integrity": "sha512-87lcbR8+MhcWcUiQ+9e+Rwx8MyR2P7qnt15ynUlbm3TU/fjbgz4GsvfSUDTemtCCtVCqb4ZcEFlyPNTh9bBTLw==", + "requires": { + "randombytes": "^2.0.5", + "safe-buffer": "^5.1.0" + } + }, + "range-parser": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/range-parser/-/range-parser-1.2.1.tgz", + "integrity": "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg==" + }, + "raw-body": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/raw-body/-/raw-body-2.5.2.tgz", + "integrity": "sha512-8zGqypfENjCIqGhgXToC8aB2r7YrBX+AQAfIPs/Mlk+BtPTztOvTS01NRW/3Eh60J+a48lt8qsCzirQ6loCVfA==", + "requires": { + "bytes": "3.1.2", + "http-errors": "2.0.0", + "iconv-lite": "0.4.24", + "unpipe": "1.0.0" + } + }, + "read-only-stream": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/read-only-stream/-/read-only-stream-2.0.0.tgz", + "integrity": "sha1-JyT9aoET1zdkrCiNQ4YnDB2/F/A=", + "requires": { + "readable-stream": "^2.0.2" + } + }, + "read-package-json": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/read-package-json/-/read-package-json-7.0.0.tgz", + "integrity": "sha512-uL4Z10OKV4p6vbdvIXB+OzhInYtIozl/VxUBPgNkBuUi2DeRonnuspmaVAMcrkmfjKGNmRndyQAbE7/AmzGwFg==", + "requires": { + "glob": "^10.2.2", + "json-parse-even-better-errors": "^3.0.0", + "normalize-package-data": "^6.0.0", + "npm-normalize-package-bin": "^3.0.0" + }, + "dependencies": { + "brace-expansion": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", + "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", + "requires": { + "balanced-match": "^1.0.0" + } + }, + "glob": { + "version": "10.3.10", + "resolved": "https://registry.npmjs.org/glob/-/glob-10.3.10.tgz", + "integrity": "sha512-fa46+tv1Ak0UPK1TOy/pZrIybNNt4HCv7SDzwyfiOZkvZLEbjsZkJBPtDHVshZjbecAoAGSC20MjLDG/qr679g==", + "requires": { + "foreground-child": "^3.1.0", + "jackspeak": "^2.3.5", + "minimatch": "^9.0.1", + "minipass": "^5.0.0 || ^6.0.2 || ^7.0.0", + "path-scurry": "^1.10.1" + } + }, + "json-parse-even-better-errors": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-3.0.1.tgz", + "integrity": "sha512-aatBvbL26wVUCLmbWdCpeu9iF5wOyWpagiKkInA+kfws3sWdBrTnsvN2CKcyCYyUrc7rebNBlK6+kteg7ksecg==" + }, + "minimatch": { + "version": "9.0.3", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.3.tgz", + "integrity": "sha512-RHiac9mvaRw0x3AYRgDC1CxAP7HTcNrrECeA8YYJeWnpo+2Q5CegtZjaotWTWxDG3UeGA1coE05iH1mPjT/2mg==", + "requires": { + "brace-expansion": "^2.0.1" + } + } + } + }, + "read-package-json-fast": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/read-package-json-fast/-/read-package-json-fast-3.0.2.tgz", + "integrity": "sha512-0J+Msgym3vrLOUB3hzQCuZHII0xkNGCtz/HJH9xZshwv9DbDwkw1KaE3gx/e2J5rpEY5rtOy6cyhKOPrkP7FZw==", + "requires": { + "json-parse-even-better-errors": "^3.0.0", + "npm-normalize-package-bin": "^3.0.0" + }, + "dependencies": { + "json-parse-even-better-errors": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/json-parse-even-better-errors/-/json-parse-even-better-errors-3.0.1.tgz", + "integrity": "sha512-aatBvbL26wVUCLmbWdCpeu9iF5wOyWpagiKkInA+kfws3sWdBrTnsvN2CKcyCYyUrc7rebNBlK6+kteg7ksecg==" + } + } + }, + "readable-stream": { + "version": "2.3.7", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.7.tgz", + "integrity": "sha512-Ebho8K4jIbHAxnuxi7o42OrZgF/ZTNcsZj6nRKyUmkhLFq8CHItp/fy6hQZuZmP/n3yZ9VBUbp4zz/mX8hmYPw==", + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + }, + "dependencies": { + "isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=" + } + } + }, + "readdirp": { + "version": "3.6.0", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", + "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", + "requires": { + "picomatch": "^2.2.1" + } + }, + "reflect-metadata": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/reflect-metadata/-/reflect-metadata-0.2.1.tgz", + "integrity": "sha512-i5lLI6iw9AU3Uu4szRNPPEkomnkjRTaVt9hy/bn5g/oSzekBSMeLZblcjP74AW0vBabqERLLIrz+gR8QYR54Tw==" + }, + "regenerate": { + "version": "1.4.2", + "resolved": "https://registry.npmjs.org/regenerate/-/regenerate-1.4.2.tgz", + "integrity": "sha512-zrceR/XhGYU/d/opr2EKO7aRHUeiBI8qjtfHqADTwZd6Szfy16la6kqD0MIUs5z5hx6AaKa+PixpPrR289+I0A==" + }, + "regenerate-unicode-properties": { + "version": "10.1.1", + "resolved": "https://registry.npmjs.org/regenerate-unicode-properties/-/regenerate-unicode-properties-10.1.1.tgz", + "integrity": "sha512-X007RyZLsCJVVrjgEFVpLUTZwyOZk3oiL75ZcuYjlIWd6rNJtOjkBwQc5AsRrpbKVkxN6sklw/k/9m2jJYOf8Q==", + "requires": { + "regenerate": "^1.4.2" + } + }, + "regenerator-runtime": { + "version": "0.14.1", + "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz", + "integrity": "sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw==" + }, + "regenerator-transform": { + "version": "0.15.2", + "resolved": "https://registry.npmjs.org/regenerator-transform/-/regenerator-transform-0.15.2.tgz", + "integrity": "sha512-hfMp2BoF0qOk3uc5V20ALGDS2ddjQaLrdl7xrGXvAIow7qeWRM2VA2HuCHkUKk9slq3VwEwLNK3DFBqDfPGYtg==", + "requires": { + "@babel/runtime": "^7.8.4" + } + }, + "regex-parser": { + "version": "2.2.11", + "resolved": "https://registry.npmjs.org/regex-parser/-/regex-parser-2.2.11.tgz", + "integrity": "sha512-jbD/FT0+9MBU2XAZluI7w2OBs1RBi6p9M83nkoZayQXXU9e8Robt69FcZc7wU4eJD/YFTjn1JdCk3rbMJajz8Q==" + }, + "regexpu-core": { + "version": "5.3.2", + "resolved": "https://registry.npmjs.org/regexpu-core/-/regexpu-core-5.3.2.tgz", + "integrity": "sha512-RAM5FlZz+Lhmo7db9L298p2vHP5ZywrVXmVXpmAD9GuL5MPH6t9ROw1iA/wfHkQ76Qe7AaPF0nGuim96/IrQMQ==", + "requires": { + "@babel/regjsgen": "^0.8.0", + "regenerate": "^1.4.2", + "regenerate-unicode-properties": "^10.1.0", + "regjsparser": "^0.9.1", + "unicode-match-property-ecmascript": "^2.0.0", + "unicode-match-property-value-ecmascript": "^2.1.0" + } + }, + "regjsparser": { + "version": "0.9.1", + "resolved": "https://registry.npmjs.org/regjsparser/-/regjsparser-0.9.1.tgz", + "integrity": "sha512-dQUtn90WanSNl+7mQKcXAgZxvUe7Z0SqXlgzv0za4LwiUhyzBC58yQO3liFoUgu8GiJVInAhJjkj1N0EtQ5nkQ==", + "requires": { + "jsesc": "~0.5.0" + }, + "dependencies": { + "jsesc": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/jsesc/-/jsesc-0.5.0.tgz", + "integrity": "sha512-uZz5UnB7u4T9LvwmFqXii7pZSouaRPorGs5who1Ip7VO0wxanFvBL7GkM6dTHlgX+jhBApRetaWpnDabOeTcnA==" + } + } + }, + "request-progress": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/request-progress/-/request-progress-3.0.0.tgz", + "integrity": "sha1-TKdUCBx/7GP1BeT6qCWqBs1mnb4=", + "optional": true, + "requires": { + "throttleit": "^1.0.0" + } + }, + "require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=" + }, + "require-from-string": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/require-from-string/-/require-from-string-2.0.2.tgz", + "integrity": "sha512-Xf0nWe6RseziFMu+Ap9biiUbmplq6S9/p+7w7YXP/JBHhrUDDUhwa+vANyubuqfZWTveU//DYVGsDG7RKL/vEw==" + }, + "require-main-filename": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-2.0.0.tgz", + "integrity": "sha512-NKN5kMDylKuldxYLSUfrbo5Tuzh4hd+2E8NPPX02mZtn1VuREQToYe/ZdlJy+J3uCpfaiGF05e7B8W0iXbQHmg==" + }, + "requires-port": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/requires-port/-/requires-port-1.0.0.tgz", + "integrity": "sha1-kl0mAdOaxIXgkc8NpcbmlNw9yv8=" + }, + "resolve": { + "version": "1.22.8", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.8.tgz", + "integrity": "sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==", + "requires": { + "is-core-module": "^2.13.0", + "path-parse": "^1.0.7", + "supports-preserve-symlinks-flag": "^1.0.0" + } + }, + "resolve-from": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/resolve-from/-/resolve-from-5.0.0.tgz", + "integrity": "sha512-qYg9KP24dD5qka9J47d0aVky0N+b4fTU89LN9iDnjB5waksiC49rvMB0PrUJQGoTmH50XPiqOvAjDfaijGxYZw==" + }, + "resolve-url-loader": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/resolve-url-loader/-/resolve-url-loader-5.0.0.tgz", + "integrity": "sha512-uZtduh8/8srhBoMx//5bwqjQ+rfYOUq8zC9NrMUGtjBiGTtFJM42s58/36+hTqeqINcnYe08Nj3LkK9lW4N8Xg==", + "requires": { + "adjust-sourcemap-loader": "^4.0.0", + "convert-source-map": "^1.7.0", + "loader-utils": "^2.0.0", + "postcss": "^8.2.14", + "source-map": "0.6.1" + }, + "dependencies": { + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" + } + } + }, + "resp-modifier": { + "version": "6.0.2", + "resolved": "https://registry.npmjs.org/resp-modifier/-/resp-modifier-6.0.2.tgz", + "integrity": "sha512-U1+0kWC/+4ncRFYqQWTx/3qkfE6a4B/h3XXgmXypfa0SPZ3t7cbbaFk297PjQS/yov24R18h6OZe6iZwj3NSLw==", + "devOptional": true, + "requires": { + "debug": "^2.2.0", + "minimatch": "^3.0.2" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "devOptional": true, + "requires": { + "ms": "2.0.0" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==", + "devOptional": true + } + } + }, + "restore-cursor": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/restore-cursor/-/restore-cursor-3.1.0.tgz", + "integrity": "sha512-l+sSefzHpj5qimhFSE5a8nufZYAM3sBSVMAPtYkmC+4EH2anSGaEMXSD0izRQbu9nfyQ9y5JrVmp7E8oZrUjvA==", + "requires": { + "onetime": "^5.1.0", + "signal-exit": "^3.0.2" + } + }, + "retry": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/retry/-/retry-0.12.0.tgz", + "integrity": "sha512-9LkiTwjUh6rT555DtE9rTX+BKByPfrMzEAtnlEtdEwr3Nkffwiihqe2bWADg+OQRjt9gl6ICdmB/ZFDCGAtSow==" + }, + "reusify": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz", + "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==" + }, + "rfdc": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/rfdc/-/rfdc-1.3.0.tgz", + "integrity": "sha512-V2hovdzFbOi77/WajaSMXk2OLm+xNIeQdMMuB7icj7bk6zi2F8GGAxigcnDFpJHbNyNcgyJDiP+8nOrY5cZGrA==", + "optional": true + }, + "rimraf": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-3.0.2.tgz", + "integrity": "sha512-JZkJMZkAGFFPP2YqXZXPbMlMBgsxzE8ILs4lMIX/2o0L9UBw9O/Y3o6wFw/i9YLapcUJWwqbi3kdxIPdC62TIA==", + "requires": { + "glob": "^7.1.3" + } + }, + "ripemd160": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/ripemd160/-/ripemd160-2.0.2.tgz", + "integrity": "sha512-ii4iagi25WusVoiC4B4lq7pbXfAp3D9v5CwfkY33vffw2+pkDjY1D8GaN7spsxvCSx8dkPqOZCEZyfxcmJG2IA==", + "requires": { + "hash-base": "^3.0.0", + "inherits": "^2.0.1" + } + }, + "rollup": { + "version": "4.13.0", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.13.0.tgz", + "integrity": "sha512-3YegKemjoQnYKmsBlOHfMLVPPA5xLkQ8MHLLSw/fBrFaVkEayL51DilPpNNLq1exr98F2B1TzrV0FUlN3gWRPg==", + "requires": { + "@rollup/rollup-android-arm-eabi": "4.13.0", + "@rollup/rollup-android-arm64": "4.13.0", + "@rollup/rollup-darwin-arm64": "4.13.0", + "@rollup/rollup-darwin-x64": "4.13.0", + "@rollup/rollup-linux-arm-gnueabihf": "4.13.0", + "@rollup/rollup-linux-arm64-gnu": "4.13.0", + "@rollup/rollup-linux-arm64-musl": "4.13.0", + "@rollup/rollup-linux-riscv64-gnu": "4.13.0", + "@rollup/rollup-linux-x64-gnu": "4.13.0", + "@rollup/rollup-linux-x64-musl": "4.13.0", + "@rollup/rollup-win32-arm64-msvc": "4.13.0", + "@rollup/rollup-win32-ia32-msvc": "4.13.0", + "@rollup/rollup-win32-x64-msvc": "4.13.0", + "@types/estree": "1.0.5", + "fsevents": "~2.3.2" + } + }, + "run-async": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/run-async/-/run-async-3.0.0.tgz", + "integrity": "sha512-540WwVDOMxA6dN6We19EcT9sc3hkXPw5mzRNGM3FkdN/vtE9NFvj5lFAPNwUDmJjXidm3v7TC1cTE7t17Ulm1Q==" + }, + "run-parallel": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", + "requires": { + "queue-microtask": "^1.2.2" + } + }, + "rx": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/rx/-/rx-4.1.0.tgz", + "integrity": "sha512-CiaiuN6gapkdl+cZUr67W6I8jquN4lkak3vtIsIWCl4XIPP8ffsoyN6/+PuGXnQy8Cu8W2y9Xxh31Rq4M6wUug==", + "devOptional": true + }, + "rxjs": { + "version": "7.8.1", + "resolved": "https://registry.npmjs.org/rxjs/-/rxjs-7.8.1.tgz", + "integrity": "sha512-AA3TVj+0A2iuIoQkWEK/tqFjBq2j+6PO6Y0zJcvzLAFhEFIO3HL0vls9hWLncZbAAbK0mar7oZ4V079I/qPMxg==", + "requires": { + "tslib": "^2.1.0" + } + }, + "safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==" + }, + "safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==" + }, + "sass": { + "version": "1.71.1", + "resolved": "https://registry.npmjs.org/sass/-/sass-1.71.1.tgz", + "integrity": "sha512-wovtnV2PxzteLlfNzbgm1tFXPLoZILYAMJtvoXXkD7/+1uP41eKkIt1ypWq5/q2uT94qHjXehEYfmjKOvjL9sg==", + "requires": { + "chokidar": ">=3.0.0 <4.0.0", + "immutable": "^4.0.0", + "source-map-js": ">=0.6.2 <2.0.0" + }, + "dependencies": { + "immutable": { + "version": "4.3.5", + "resolved": "https://registry.npmjs.org/immutable/-/immutable-4.3.5.tgz", + "integrity": "sha512-8eabxkth9gZatlwl5TBuJnCsoTADlL6ftEr7A4qgdaTsPyreilDSnUk57SO+jfKcNtxPa22U5KK6DSeAYhpBJw==" + } + } + }, + "sass-loader": { + "version": "14.1.1", + "resolved": "https://registry.npmjs.org/sass-loader/-/sass-loader-14.1.1.tgz", + "integrity": "sha512-QX8AasDg75monlybel38BZ49JP5Z+uSKfKwF2rO7S74BywaRmGQMUBw9dtkS+ekyM/QnP+NOrRYq8ABMZ9G8jw==", + "requires": { + "neo-async": "^2.6.2" + } + }, + "sax": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz", + "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==", + "optional": true + }, + "schema-utils": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-4.2.0.tgz", + "integrity": "sha512-L0jRsrPpjdckP3oPug3/VxNKt2trR8TcabrM6FOAAlvC/9Phcmm+cuAgTlxBqdBR1WJx7Naj9WHw+aOmheSVbw==", + "requires": { + "@types/json-schema": "^7.0.9", + "ajv": "^8.9.0", + "ajv-formats": "^2.1.1", + "ajv-keywords": "^5.1.0" + }, + "dependencies": { + "ajv": { + "version": "8.12.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-8.12.0.tgz", + "integrity": "sha512-sRu1kpcO9yLtYxBKvqfTeh9KzZEwO3STyX1HT+4CaDzC6HpTGYhIhPIzj9XuKU7KYDwnaeh5hcOwjy1QuJzBPA==", + "requires": { + "fast-deep-equal": "^3.1.1", + "json-schema-traverse": "^1.0.0", + "require-from-string": "^2.0.2", + "uri-js": "^4.2.2" + } + }, + "ajv-keywords": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-5.1.0.tgz", + "integrity": "sha512-YCS/JNFAUyr5vAuhk1DWm1CBxRHW9LbJ2ozWeemrIqpbsqKjHVxYPyi5GC0rjZIT5JxJ3virVTS8wk4i/Z+krw==", + "requires": { + "fast-deep-equal": "^3.1.3" + } + }, + "json-schema-traverse": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-1.0.0.tgz", + "integrity": "sha512-NM8/P9n3XjXhIZn1lLhkFaACTOURQXjWhV4BA/RnOv8xvgqtqpAX9IO4mRQxSx1Rlo4tqzeqb0sOlruaOy3dug==" + } + } + }, + "scope-analyzer": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/scope-analyzer/-/scope-analyzer-2.1.1.tgz", + "integrity": "sha512-azEAihtQ9mEyZGhfgTJy3IbOWEzeOrYbg7NcYEshPKnKd+LZmC3TNd5dmDxbLBsTG/JVWmCp+vDJ03vJjeXMHg==", + "requires": { + "array-from": "^2.1.1", + "dash-ast": "^1.0.0", + "es6-map": "^0.1.5", + "es6-set": "^0.1.5", + "es6-symbol": "^3.1.1", + "estree-is-function": "^1.0.0", + "get-assigned-identifiers": "^1.1.0" + } + }, + "select": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/select/-/select-1.1.2.tgz", + "integrity": "sha1-DnNQrN7ICxEIUoeG7B1EGNEbOW0=" + }, + "select-hose": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/select-hose/-/select-hose-2.0.0.tgz", + "integrity": "sha512-mEugaLK+YfkijB4fx0e6kImuJdCIt2LxCRcbEYPqRGCs4F2ogyfZU5IAZRdjCP8JPq2AtdNoC/Dux63d9Kiryg==" + }, + "selfsigned": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/selfsigned/-/selfsigned-2.4.1.tgz", + "integrity": "sha512-th5B4L2U+eGLq1TVh7zNRGBapioSORUeymIydxgFpwww9d2qyKvtuPU2jJuHvYAwwqi2Y596QBL3eEqcPEYL8Q==", + "requires": { + "@types/node-forge": "^1.3.0", + "node-forge": "^1" + } + }, + "semver": { + "version": "7.5.4", + "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", + "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", + "requires": { + "lru-cache": "^6.0.0" + } + }, + "send": { + "version": "0.18.0", + "resolved": "https://registry.npmjs.org/send/-/send-0.18.0.tgz", + "integrity": "sha512-qqWzuOjSFOuqPjFe4NOsMLafToQQwBSOEpS+FwEt3A2V3vKubTquT3vmLTQpFgMXp8AlFWFuP1qKaJZOtPpVXg==", + "requires": { + "debug": "2.6.9", + "depd": "2.0.0", + "destroy": "1.2.0", + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "etag": "~1.8.1", + "fresh": "0.5.2", + "http-errors": "2.0.0", + "mime": "1.6.0", + "ms": "2.1.3", + "on-finished": "2.4.1", + "range-parser": "~1.2.1", + "statuses": "2.0.1" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "requires": { + "ms": "2.0.0" + }, + "dependencies": { + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" + } + } + }, + "mime": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/mime/-/mime-1.6.0.tgz", + "integrity": "sha512-x0Vn8spI+wuJ1O6S7gnbaQg8Pxh4NNHb7KSINmEWKiPE4RKOplvijn+NkmYmmRgP68mc70j2EbeTFRsrswaQeg==" + }, + "ms": { + "version": "2.1.3", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz", + "integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA==" + }, + "on-finished": { + "version": "2.4.1", + "resolved": "https://registry.npmjs.org/on-finished/-/on-finished-2.4.1.tgz", + "integrity": "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg==", + "requires": { + "ee-first": "1.1.1" + } + }, + "statuses": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-2.0.1.tgz", + "integrity": "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ==" + } + } + }, + "serialize-javascript": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-6.0.1.tgz", + "integrity": "sha512-owoXEFjWRllis8/M1Q+Cw5k8ZH40e3zhp/ovX+Xr/vi1qj6QesbyXXViFbpNvWvPNAD62SutwEXavefrLJWj7w==", + "requires": { + "randombytes": "^2.1.0" + } + }, + "serve-index": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/serve-index/-/serve-index-1.9.1.tgz", + "integrity": "sha512-pXHfKNP4qujrtteMrSBb0rc8HJ9Ms/GrXwcUtUtD5s4ewDJI8bT3Cz2zTVRMKtri49pLx2e0Ya8ziP5Ya2pZZw==", + "requires": { + "accepts": "~1.3.4", + "batch": "0.6.1", + "debug": "2.6.9", + "escape-html": "~1.0.3", + "http-errors": "~1.6.2", + "mime-types": "~2.1.17", + "parseurl": "~1.3.2" + }, + "dependencies": { + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "requires": { + "ms": "2.0.0" + } + }, + "depd": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/depd/-/depd-1.1.2.tgz", + "integrity": "sha512-7emPTl6Dpo6JRXOXjLRxck+FlLRX5847cLKEn00PLAgc3g2hTZZgr+e4c2v6QpSmLeFP3n5yUo7ft6avBK/5jQ==" + }, + "http-errors": { + "version": "1.6.3", + "resolved": "https://registry.npmjs.org/http-errors/-/http-errors-1.6.3.tgz", + "integrity": "sha512-lks+lVC8dgGyh97jxvxeYTWQFvh4uw4yC12gVl63Cg30sjPX4wuGcdkICVXDAESr6OJGjqGA8Iz5mkeN6zlD7A==", + "requires": { + "depd": "~1.1.2", + "inherits": "2.0.3", + "setprototypeof": "1.1.0", + "statuses": ">= 1.4.0 < 2" + } + }, + "inherits": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", + "integrity": "sha512-x00IRNXNy63jwGkJmzPigoySHbaqpNuzKbBOmzK+g2OdZpQ9w+sxCN+VSB3ja7IAge2OP2qpfxTjeNcyjmW1uw==" + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha512-Tpp60P6IUJDTuOq/5Z8cdskzJujfwqfOTkrwIwj7IRISpnkJnT6SyJ4PCPnGMoFjC9ddhal5KVIYtAt97ix05A==" + }, + "setprototypeof": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.1.0.tgz", + "integrity": "sha512-BvE/TwpZX4FXExxOxZyRGQQv651MSwmWKZGqvmPcRIjDqWub67kTKuIMx43cZZrS/cBBzwBcNDWoFxt2XEFIpQ==" + } + } + }, + "serve-static": { + "version": "1.15.0", + "resolved": "https://registry.npmjs.org/serve-static/-/serve-static-1.15.0.tgz", + "integrity": "sha512-XGuRDNjXUijsUL0vl6nSD7cwURuzEgglbOaFuZM9g3kwDXOWVTck0jLzjPzGD+TazWbboZYu52/9/XPdUgne9g==", + "requires": { + "encodeurl": "~1.0.2", + "escape-html": "~1.0.3", + "parseurl": "~1.3.3", + "send": "0.18.0" + } + }, + "server-destroy": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/server-destroy/-/server-destroy-1.0.1.tgz", + "integrity": "sha512-rb+9B5YBIEzYcD6x2VKidaa+cqYBJQKnU4oe4E3ANwRRN56yk/ua1YCJT1n21NTS8w6CcOclAKNP3PhdCXKYtQ==", + "devOptional": true + }, + "set-blocking": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", + "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=" + }, + "set-function-length": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz", + "integrity": "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==", + "requires": { + "define-data-property": "^1.1.4", + "es-errors": "^1.3.0", + "function-bind": "^1.1.2", + "get-intrinsic": "^1.2.4", + "gopd": "^1.0.1", + "has-property-descriptors": "^1.0.2" + } + }, + "setprototypeof": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/setprototypeof/-/setprototypeof-1.2.0.tgz", + "integrity": "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw==" + }, + "sha.js": { + "version": "2.4.11", + "resolved": "https://registry.npmjs.org/sha.js/-/sha.js-2.4.11.tgz", + "integrity": "sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ==", + "requires": { + "inherits": "^2.0.1", + "safe-buffer": "^5.0.1" + } + }, + "shallow-clone": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/shallow-clone/-/shallow-clone-3.0.1.tgz", + "integrity": "sha512-/6KqX+GVUdqPuPPd2LxDDxzX6CAbjJehAAOKlNpqqUpAqPM6HeL8f+o3a+JsyGjn2lv0WY8UsTgUJjU9Ok55NA==", + "requires": { + "kind-of": "^6.0.2" + } + }, + "shasum-object": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/shasum-object/-/shasum-object-1.0.0.tgz", + "integrity": "sha512-Iqo5rp/3xVi6M4YheapzZhhGPVs0yZwHj7wvwQ1B9z8H6zk+FEnI7y3Teq7qwnekfEhu8WmG2z0z4iWZaxLWVg==", + "requires": { + "fast-safe-stringify": "^2.0.7" + } + }, + "shebang-command": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/shebang-command/-/shebang-command-2.0.0.tgz", + "integrity": "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA==", + "requires": { + "shebang-regex": "^3.0.0" + } + }, + "shebang-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/shebang-regex/-/shebang-regex-3.0.0.tgz", + "integrity": "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A==" + }, + "shell-quote": { + "version": "1.8.1", + "resolved": "https://registry.npmjs.org/shell-quote/-/shell-quote-1.8.1.tgz", + "integrity": "sha512-6j1W9l1iAs/4xYBI1SYOVZyFcCis9b4KCLQ8fgAGG07QvzaRLVVRQvAy85yNmmZSjYjg4MWh4gNvlPujU/5LpA==" + }, + "side-channel": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.4.tgz", + "integrity": "sha512-q5XPytqFEIKHkGdiMIrY10mvLRvnQh42/+GoBlFW3b2LXLE2xxJpZFdm94we0BaoV3RwJyGqg5wS7epxTv0Zvw==", + "requires": { + "call-bind": "^1.0.0", + "get-intrinsic": "^1.0.2", + "object-inspect": "^1.9.0" + } + }, + "signal-exit": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.7.tgz", + "integrity": "sha512-wnD2ZE+l+SPC/uoS0vXeE9L1+0wuaMqKlfz9AMUo38JsyLSBWSFcHR1Rri62LZc12vLr1gb3jl7iwQhgwpAbGQ==" + }, + "sigstore": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/sigstore/-/sigstore-2.2.2.tgz", + "integrity": "sha512-2A3WvXkQurhuMgORgT60r6pOWiCOO5LlEqY2ADxGBDGVYLSo5HN0uLtb68YpVpuL/Vi8mLTe7+0Dx2Fq8lLqEg==", + "requires": { + "@sigstore/bundle": "^2.2.0", + "@sigstore/core": "^1.0.0", + "@sigstore/protobuf-specs": "^0.3.0", + "@sigstore/sign": "^2.2.3", + "@sigstore/tuf": "^2.3.1", + "@sigstore/verify": "^1.1.0" + } + }, + "simple-concat": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/simple-concat/-/simple-concat-1.0.1.tgz", + "integrity": "sha512-cSFtAPtRhljv69IK0hTVZQ+OfE9nePi/rtJmw5UjHeVyVroEqJXP1sFztKUy1qU+xvz3u/sfYJLa947b7nAN2Q==" + }, + "sinon": { + "version": "17.0.1", + "resolved": "https://registry.npmjs.org/sinon/-/sinon-17.0.1.tgz", + "integrity": "sha512-wmwE19Lie0MLT+ZYNpDymasPHUKTaZHUH/pKEubRXIzySv9Atnlw+BUMGCzWgV7b7wO+Hw6f1TEOr0IUnmU8/g==", + "optional": true, + "requires": { + "@sinonjs/commons": "^3.0.0", + "@sinonjs/fake-timers": "^11.2.2", + "@sinonjs/samsam": "^8.0.0", + "diff": "^5.1.0", + "nise": "^5.1.5", + "supports-color": "^7.2.0" + }, + "dependencies": { + "diff": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/diff/-/diff-5.1.0.tgz", + "integrity": "sha512-D+mk+qE8VC/PAUrlAU34N+VfXev0ghe5ywmpqrawphmVZc1bEfn56uo9qpyGp1p4xpzOHkSW4ztBd6L7Xx4ACw==", + "optional": true + }, + "has-flag": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz", + "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==", + "optional": true + }, + "supports-color": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", + "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==", + "optional": true, + "requires": { + "has-flag": "^4.0.0" + } + } + } + }, + "sinon-chai": { + "version": "3.7.0", + "resolved": "https://registry.npmjs.org/sinon-chai/-/sinon-chai-3.7.0.tgz", + "integrity": "sha512-mf5NURdUaSdnatJx3uhoBOrY9dtL19fiOtAdT1Azxg3+lNJFiuN0uzaU3xX1LeAfL17kHQhTAJgpsfhbMJMY2g==", + "optional": true, + "requires": {} + }, + "slash": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-4.0.0.tgz", + "integrity": "sha512-3dOsAHXXUkQTpOYcoAxLIorMTp4gIQr5IW3iVb7A7lFIp0VHhnynm9izx6TssdrIcVIESAlVjtnO2K8bg+Coew==" + }, + "slice-ansi": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slice-ansi/-/slice-ansi-3.0.0.tgz", + "integrity": "sha512-pSyv7bSTC7ig9Dcgbw9AuRNUb5k5V6oDudjZoMBSr13qpLBG7tB+zgCkARjq7xIUgdz5P1Qe8u+rSGdouOOIyQ==", + "optional": true, + "requires": { + "ansi-styles": "^4.0.0", + "astral-regex": "^2.0.0", + "is-fullwidth-code-point": "^3.0.0" + }, + "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "optional": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "optional": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "optional": true + } + } + }, + "smart-buffer": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/smart-buffer/-/smart-buffer-4.2.0.tgz", + "integrity": "sha512-94hK0Hh8rPqQl2xXc3HsaBoOXKV20MToPkcXvwbISWLEs+64sBq5kFgn2kJDHb1Pry9yrP0dxrCI9RRci7RXKg==" + }, + "socket.io": { + "version": "4.7.1", + "resolved": "https://registry.npmjs.org/socket.io/-/socket.io-4.7.1.tgz", + "integrity": "sha512-W+utHys2w//dhFjy7iQQu9sGd3eokCjGbl2r59tyLqNiJJBdIebn3GAKEXBr3osqHTObJi2die/25bCx2zsaaw==", + "devOptional": true, + "requires": { + "accepts": "~1.3.4", + "base64id": "~2.0.0", + "cors": "~2.8.5", + "debug": "~4.3.2", + "engine.io": "~6.5.0", + "socket.io-adapter": "~2.5.2", + "socket.io-parser": "~4.2.4" + } + }, + "socket.io-adapter": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/socket.io-adapter/-/socket.io-adapter-2.5.2.tgz", + "integrity": "sha512-87C3LO/NOMc+eMcpcxUBebGjkpMDkNBS9tf7KJqcDsmL936EChtVva71Dw2q4tQcuVC+hAUy4an2NO/sYXmwRA==", + "devOptional": true, + "requires": { + "ws": "~8.11.0" + }, + "dependencies": { + "ws": { + "version": "8.11.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.11.0.tgz", + "integrity": "sha512-HPG3wQd9sNQoT9xHyNCXoDUa+Xw/VevmY9FoHyQ+g+rrMn4j6FB4np7Z0OhdTgjx6MgQLK7jwSy1YecU1+4Asg==", + "devOptional": true, + "requires": {} + } + } + }, + "socket.io-client": { + "version": "4.7.5", + "resolved": "https://registry.npmjs.org/socket.io-client/-/socket.io-client-4.7.5.tgz", + "integrity": "sha512-sJ/tqHOCe7Z50JCBCXrsY3I2k03iOiUe+tj1OmKeD2lXPiGH/RUCdTZFoqVyN7l1MnpIzPrGtLcijffmeouNlQ==", + "devOptional": true, + "requires": { + "@socket.io/component-emitter": "~3.1.0", + "debug": "~4.3.2", + "engine.io-client": "~6.5.2", + "socket.io-parser": "~4.2.4" + } + }, + "socket.io-parser": { + "version": "4.2.4", + "resolved": "https://registry.npmjs.org/socket.io-parser/-/socket.io-parser-4.2.4.tgz", + "integrity": "sha512-/GbIKmo8ioc+NIWIhwdecY0ge+qVBSMdgxGygevmdHj24bsfgtCmcUUcQ5ZzcylGFHsN3k4HB4Cgkl96KVnuew==", + "devOptional": true, + "requires": { + "@socket.io/component-emitter": "~3.1.0", + "debug": "~4.3.1" + } + }, + "sockjs": { + "version": "0.3.24", + "resolved": "https://registry.npmjs.org/sockjs/-/sockjs-0.3.24.tgz", + "integrity": "sha512-GJgLTZ7vYb/JtPSSZ10hsOYIvEYsjbNU+zPdIHcUaWVNUEPivzxku31865sSSud0Da0W4lEeOPlmw93zLQchuQ==", + "requires": { + "faye-websocket": "^0.11.3", + "uuid": "^8.3.2", + "websocket-driver": "^0.7.4" + } + }, + "socks": { + "version": "2.8.1", + "resolved": "https://registry.npmjs.org/socks/-/socks-2.8.1.tgz", + "integrity": "sha512-B6w7tkwNid7ToxjZ08rQMT8M9BJAf8DKx8Ft4NivzH0zBUfd6jldGcisJn/RLgxcX3FPNDdNQCUEMMT79b+oCQ==", + "requires": { + "ip-address": "^9.0.5", + "smart-buffer": "^4.2.0" + } + }, + "socks-proxy-agent": { + "version": "8.0.2", + "resolved": "https://registry.npmjs.org/socks-proxy-agent/-/socks-proxy-agent-8.0.2.tgz", + "integrity": "sha512-8zuqoLv1aP/66PHF5TqwJ7Czm3Yv32urJQHrVyhD7mmA6d61Zv8cIXQYPTWwmg6qlupnPvs/QKDmfa4P/qct2g==", + "requires": { + "agent-base": "^7.0.2", + "debug": "^4.3.4", + "socks": "^2.7.1" + } + }, + "source-map": { + "version": "0.7.4", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.4.tgz", + "integrity": "sha512-l3BikUxvPOcn5E74dZiq5BGsTb5yEwhaTSzccU6t4sDOH8NWJCstKO5QT2CvtFoK6F0saL7p9xHAqHOlCPJygA==" + }, + "source-map-js": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.0.2.tgz", + "integrity": "sha512-R0XvVJ9WusLiqTCEiGCmICCMplcCkIwwR11mOSD9CR5u+IXYdiseeEuXCVAjS54zqwkLcPNnmU4OeJ6tUrWhDw==" + }, + "source-map-loader": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/source-map-loader/-/source-map-loader-5.0.0.tgz", + "integrity": "sha512-k2Dur7CbSLcAH73sBcIkV5xjPV4SzqO1NJ7+XaQl8if3VODDUj3FNchNGpqgJSKbvUfJuhVdv8K2Eu8/TNl2eA==", + "requires": { + "iconv-lite": "^0.6.3", + "source-map-js": "^1.0.2" + }, + "dependencies": { + "iconv-lite": { + "version": "0.6.3", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz", + "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==", + "requires": { + "safer-buffer": ">= 2.1.2 < 3.0.0" + } + } + } + }, + "source-map-support": { + "version": "0.5.21", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz", + "integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==", + "requires": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + }, + "dependencies": { + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" + } + } + }, + "sourcemap-codec": { + "version": "1.4.8", + "resolved": "https://registry.npmjs.org/sourcemap-codec/-/sourcemap-codec-1.4.8.tgz", + "integrity": "sha512-9NykojV5Uih4lgo5So5dtw+f0JgJX30KCNI8gwhz2J9A15wD0Ml6tjHKwf6fTSa6fAdVBdZeNOs9eJ71qCk8vA==" + }, + "spdx-correct": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.2.0.tgz", + "integrity": "sha512-kN9dJbvnySHULIluDHy32WHRUu3Og7B9sbY7tsFLctQkIqnMh3hErYgdMjTYuqmcXX+lK5T1lnUt3G7zNswmZA==", + "requires": { + "spdx-expression-parse": "^3.0.0", + "spdx-license-ids": "^3.0.0" + } + }, + "spdx-exceptions": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.5.0.tgz", + "integrity": "sha512-PiU42r+xO4UbUS1buo3LPJkjlO7430Xn5SVAhdpzzsPHsjbYVflnnFdATgabnLude+Cqu25p6N+g2lw/PFsa4w==" + }, + "spdx-expression-parse": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.1.tgz", + "integrity": "sha512-cbqHunsQWnJNE6KhVSMsMeH5H/L9EpymbzqTQ3uLwNCLZ1Q481oWaofqH7nO6V07xlXwY6PhQdQ2IedWx/ZK4Q==", + "requires": { + "spdx-exceptions": "^2.1.0", + "spdx-license-ids": "^3.0.0" + } + }, + "spdx-license-ids": { + "version": "3.0.17", + "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.17.tgz", + "integrity": "sha512-sh8PWc/ftMqAAdFiBu6Fy6JUOYjqDJBJvIhpfDMyHrr0Rbp5liZqd4TjtQ/RgfLjKFZb+LMx5hpml5qOWy0qvg==" + }, + "spdy": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/spdy/-/spdy-4.0.2.tgz", + "integrity": "sha512-r46gZQZQV+Kl9oItvl1JZZqJKGr+oEkB08A6BzkiR7593/7IbtuncXHd2YoYeTsG4157ZssMu9KYvUHLcjcDoA==", + "requires": { + "debug": "^4.1.0", + "handle-thing": "^2.0.0", + "http-deceiver": "^1.2.7", + "select-hose": "^2.0.0", + "spdy-transport": "^3.0.0" + } + }, + "spdy-transport": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/spdy-transport/-/spdy-transport-3.0.0.tgz", + "integrity": "sha512-hsLVFE5SjA6TCisWeJXFKniGGOpBgMLmerfO2aCyCU5s7nJ/rpAepqmFifv/GCbSbueEeAJJnmSQ2rKC/g8Fcw==", + "requires": { + "debug": "^4.1.0", + "detect-node": "^2.0.4", + "hpack.js": "^2.1.6", + "obuf": "^1.1.2", + "readable-stream": "^3.0.6", + "wbuf": "^1.7.3" + }, + "dependencies": { + "readable-stream": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "requires": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + } + } + } + }, + "split": { + "version": "0.3.3", + "resolved": "https://registry.npmjs.org/split/-/split-0.3.3.tgz", + "integrity": "sha1-zQ7qXmOiEd//frDwkcQTPi0N0o8=", + "optional": true, + "requires": { + "through": "2" + } + }, + "sprintf-js": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/sprintf-js/-/sprintf-js-1.1.3.tgz", + "integrity": "sha512-Oo+0REFV59/rz3gfJNKQiBlwfHaSESl1pcGyABQsnnIfWOFt6JNj5gCog2U6MLZ//IGYD+nA8nI+mTShREReaA==" + }, + "sshpk": { + "version": "1.17.0", + "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.17.0.tgz", + "integrity": "sha512-/9HIEs1ZXGhSPE8X6Ccm7Nam1z8KcoCqPdI7ecm1N33EzAetWahvQWVqLZtaZQ+IDKX4IyA2o0gBzqIMkAagHQ==", + "optional": true, + "requires": { + "asn1": "~0.2.3", + "assert-plus": "^1.0.0", + "bcrypt-pbkdf": "^1.0.0", + "dashdash": "^1.12.0", + "ecc-jsbn": "~0.1.1", + "getpass": "^0.1.1", + "jsbn": "~0.1.0", + "safer-buffer": "^2.0.2", + "tweetnacl": "~0.14.0" + } + }, + "ssri": { + "version": "10.0.5", + "resolved": "https://registry.npmjs.org/ssri/-/ssri-10.0.5.tgz", + "integrity": "sha512-bSf16tAFkGeRlUNDjXu8FzaMQt6g2HZJrun7mtMbIPOddxt3GLMSz5VWUWcqTJUPfLEaDIepGxv+bYQW49596A==", + "requires": { + "minipass": "^7.0.3" + } + }, + "start-server-and-test": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/start-server-and-test/-/start-server-and-test-2.0.3.tgz", + "integrity": "sha512-QsVObjfjFZKJE6CS6bSKNwWZCKBG6975/jKRPPGFfFh+yOQglSeGXiNWjzgQNXdphcBI9nXbyso9tPfX4YAUhg==", + "optional": true, + "requires": { + "arg": "^5.0.2", + "bluebird": "3.7.2", + "check-more-types": "2.24.0", + "debug": "4.3.4", + "execa": "5.1.1", + "lazy-ass": "1.6.0", + "ps-tree": "1.2.0", + "wait-on": "7.2.0" + }, + "dependencies": { + "arg": { + "version": "5.0.2", + "resolved": "https://registry.npmjs.org/arg/-/arg-5.0.2.tgz", + "integrity": "sha512-PYjyFOLKQ9y57JvQ6QLo8dAgNqswh8M1RMJYdQduT6xbWSgK36P/Z/v+p888pM69jMMfS8Xd8F6I1kQ/I9HUGg==", + "optional": true + } + } + }, + "statuses": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/statuses/-/statuses-1.5.0.tgz", + "integrity": "sha1-Fhx9rBd2Wf2YEfQ3cfqZOBR4Yow=" + }, + "stream-combiner": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/stream-combiner/-/stream-combiner-0.2.2.tgz", + "integrity": "sha1-rsjLrBd7Vrb0+kec7YwZEs7lKFg=", + "requires": { + "duplexer": "~0.1.1", + "through": "~2.3.4" + } + }, + "stream-combiner2": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/stream-combiner2/-/stream-combiner2-1.1.1.tgz", + "integrity": "sha1-+02KFCDqNidk4hrUeAOXvry0HL4=", + "requires": { + "duplexer2": "~0.1.0", + "readable-stream": "^2.0.2" + } + }, + "stream-shift": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/stream-shift/-/stream-shift-1.0.1.tgz", + "integrity": "sha512-AiisoFqQ0vbGcZgQPY1cdP2I76glaVA/RauYR4G4thNFgkTqr90yXTo4LYX60Jl+sIlPNHHdGSwo01AvbKUSVQ==" + }, + "stream-splicer": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/stream-splicer/-/stream-splicer-2.0.1.tgz", + "integrity": "sha512-Xizh4/NPuYSyAXyT7g8IvdJ9HJpxIGL9PjyhtywCZvvP0OPIdqyrr4dMikeuvY8xahpdKEBlBTySe583totajg==", + "requires": { + "inherits": "^2.0.1", + "readable-stream": "^2.0.2" + } + }, + "stream-throttle": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/stream-throttle/-/stream-throttle-0.1.3.tgz", + "integrity": "sha512-889+B9vN9dq7/vLbGyuHeZ6/ctf5sNuGWsDy89uNxkFTAgzy0eK7+w5fL3KLNRTkLle7EgZGvHUphZW0Q26MnQ==", + "devOptional": true, + "requires": { + "commander": "^2.2.0", + "limiter": "^1.0.5" + } + }, + "streamroller": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/streamroller/-/streamroller-3.0.2.tgz", + "integrity": "sha512-ur6y5S5dopOaRXBuRIZ1u6GC5bcEXHRZKgfBjfCglMhmIf+roVCECjvkEYzNQOXIN2/JPnkMPW/8B3CZoKaEPA==", + "optional": true, + "peer": true, + "requires": { + "date-format": "^4.0.3", + "debug": "^4.1.1", + "fs-extra": "^10.0.0" + } + }, + "string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "requires": { + "safe-buffer": "~5.1.0" + } + }, + "string-width": { + "version": "4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "requires": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + } + }, + "string-width-cjs": { + "version": "npm:string-width@4.2.3", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz", + "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==", + "requires": { + "emoji-regex": "^8.0.0", + "is-fullwidth-code-point": "^3.0.0", + "strip-ansi": "^6.0.1" + } + }, + "string.prototype.trimend": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/string.prototype.trimend/-/string.prototype.trimend-1.0.4.tgz", + "integrity": "sha512-y9xCjw1P23Awk8EvTpcyL2NIr1j7wJ39f+k6lvRnSMz+mz9CGz9NYPelDk42kOz6+ql8xjfK8oYzy3jAP5QU5A==", + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3" + } + }, + "string.prototype.trimstart": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/string.prototype.trimstart/-/string.prototype.trimstart-1.0.4.tgz", + "integrity": "sha512-jh6e984OBfvxS50tdY2nRZnoC5/mLFKOREQfw8t5yytkoUsJRNxvI/E39qu1sD0OtWI3OC0XgKSmcWwziwYuZw==", + "requires": { + "call-bind": "^1.0.2", + "define-properties": "^1.1.3" + } + }, + "strip-ansi": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "requires": { + "ansi-regex": "^5.0.1" + } + }, + "strip-ansi-cjs": { + "version": "npm:strip-ansi@6.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz", + "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==", + "requires": { + "ansi-regex": "^5.0.1" + } + }, + "strip-final-newline": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/strip-final-newline/-/strip-final-newline-2.0.0.tgz", + "integrity": "sha512-BrpvfNAE3dcvq7ll3xVumzjKjZQ5tI1sEUIKr3Uoks0XUl45St3FlatVqef9prk4jRDzhW6WZg+3bk93y6pLjA==" + }, + "strip-json-comments": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", + "integrity": "sha512-6fPc+R4ihwqP6N/aIv2f1gMH8lOVtWQHoqC4yK6oSDVVocumAsfCqjkXnqiYMhmMwS/mEHLp7Vehlt3ql6lEig==", + "dev": true + }, + "subarg": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/subarg/-/subarg-1.0.0.tgz", + "integrity": "sha1-9izxdYHplrSPyWVpn1TAauJouNI=", + "requires": { + "minimist": "^1.1.0" + } + }, + "supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "requires": { + "has-flag": "^3.0.0" + } + }, + "supports-preserve-symlinks-flag": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz", + "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==" + }, + "symbol-observable": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/symbol-observable/-/symbol-observable-4.0.0.tgz", + "integrity": "sha512-b19dMThMV4HVFynSAM1++gBHAbk2Tc/osgLIBZMKsyqh34jb2e8Os7T6ZW/Bt3pJFdBTd2JwAnAAEQV7rSNvcQ==" + }, + "syntax-error": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/syntax-error/-/syntax-error-1.4.0.tgz", + "integrity": "sha512-YPPlu67mdnHGTup2A8ff7BC2Pjq0e0Yp/IyTFN03zWO0RcK07uLcbi7C2KpGR2FvWbaB0+bfE27a+sBKebSo7w==", + "requires": { + "acorn-node": "^1.2.0" + } + }, + "tapable": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/tapable/-/tapable-2.2.1.tgz", + "integrity": "sha512-GNzQvQTOIP6RyTfE2Qxb8ZVlNmw0n88vp1szwWRimP02mnTsx3Wtn5qRdqY9w2XduFNUgvOwhNnQsjwCp+kqaQ==" + }, + "tar": { + "version": "6.2.1", + "resolved": "https://registry.npmjs.org/tar/-/tar-6.2.1.tgz", + "integrity": "sha512-DZ4yORTwrbTj/7MZYq2w+/ZFdI6OZ/f9SFHR+71gIVUZhOQPHzVCLpvRnPgyaMpfWxxk/4ONva3GQSyNIKRv6A==", + "requires": { + "chownr": "^2.0.0", + "fs-minipass": "^2.0.0", + "minipass": "^5.0.0", + "minizlib": "^2.1.1", + "mkdirp": "^1.0.3", + "yallist": "^4.0.0" + }, + "dependencies": { + "fs-minipass": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-2.1.0.tgz", + "integrity": "sha512-V/JgOLFCS+R6Vcq0slCuaeWEdNC3ouDlJMNIsacH2VtALiu9mV4LPrHc5cDl8k5aw6J8jwgWWpiTo5RYhmIzvg==", + "requires": { + "minipass": "^3.0.0" + }, + "dependencies": { + "minipass": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-3.3.6.tgz", + "integrity": "sha512-DxiNidxSEK+tHG6zOIklvNOwm3hvCrbUrdtzY74U6HKTJxvIDfOUL5W5P2Ghd3DTkhhKPYGqeNUIh5qcM4YBfw==", + "requires": { + "yallist": "^4.0.0" + } + } + } + }, + "minipass": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-5.0.0.tgz", + "integrity": "sha512-3FnjYuehv9k6ovOEbyOswadCDPX1piCfhV8ncmYtHOjuPwylVWsghTLo7rabjC3Rx5xD4HDx8Wm1xnMF7S5qFQ==" + }, + "mkdirp": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz", + "integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==" + } + } + }, + "terser": { + "version": "5.29.1", + "resolved": "https://registry.npmjs.org/terser/-/terser-5.29.1.tgz", + "integrity": "sha512-lZQ/fyaIGxsbGxApKmoPTODIzELy3++mXhS5hOqaAWZjQtpq/hFHAc+rm29NND1rYRxRWKcjuARNwULNXa5RtQ==", + "requires": { + "@jridgewell/source-map": "^0.3.3", + "acorn": "^8.8.2", + "commander": "^2.20.0", + "source-map-support": "~0.5.20" + }, + "dependencies": { + "acorn": { + "version": "8.10.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.10.0.tgz", + "integrity": "sha512-F0SAmZ8iUtS//m8DmCTA0jlh6TDKkHQyK6xc6V4KDTyZKA9dnvX9/3sRTVQrWm79glUAZbnmmNcdYwUIHWVybw==" + } + } + }, + "terser-webpack-plugin": { + "version": "5.3.10", + "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-5.3.10.tgz", + "integrity": "sha512-BKFPWlPDndPs+NGGCr1U59t0XScL5317Y0UReNrHaw9/FwhPENlq6bfgs+4yPfyP51vqC1bQ4rp1EfXW5ZSH9w==", + "requires": { + "@jridgewell/trace-mapping": "^0.3.20", + "jest-worker": "^27.4.5", + "schema-utils": "^3.1.1", + "serialize-javascript": "^6.0.1", + "terser": "^5.26.0" + }, + "dependencies": { + "@jridgewell/trace-mapping": { + "version": "0.3.25", + "resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.25.tgz", + "integrity": "sha512-vNk6aEwybGtawWmy/PzwnGDOjCkLWSD2wqvjGGAgOAwCGWySYXfYoxt00IJkTF+8Lb57DwOb3Aa0o9CApepiYQ==", + "requires": { + "@jridgewell/resolve-uri": "^3.1.0", + "@jridgewell/sourcemap-codec": "^1.4.14" + } + }, + "schema-utils": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.3.0.tgz", + "integrity": "sha512-pN/yOAvcC+5rQ5nERGuwrjLlYvLTbCibnZ1I7B1LaiAz9BRBlE9GMgE/eqV30P7aJQUf7Ddimy/RsbYO/GrVGg==", + "requires": { + "@types/json-schema": "^7.0.8", + "ajv": "^6.12.5", + "ajv-keywords": "^3.5.2" + } + } + } + }, + "test-exclude": { + "version": "6.0.0", + "resolved": "https://registry.npmjs.org/test-exclude/-/test-exclude-6.0.0.tgz", + "integrity": "sha512-cAGWPIyOHU6zlmg88jwm7VRyXnMN7iV68OGAbYDk/Mh/xC/pzVPlQtY6ngoIH/5/tciuhGfvESU8GrHrcxD56w==", + "requires": { + "@istanbuljs/schema": "^0.1.2", + "glob": "^7.1.4", + "minimatch": "^3.0.4" + } + }, + "text-table": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", + "integrity": "sha512-N+8UisAXDGk8PFXP4HAzVR9nbfmVJ3zYLAWiTIoqC5v5isinhr+r5uaO8+7r3BMfuNIufIsA7RdpVgacC2cSpw==", + "dev": true + }, + "throttleit": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/throttleit/-/throttleit-1.0.0.tgz", + "integrity": "sha1-nnhYNtr0Z0MUWlmEtiaNgoUorGw=", + "optional": true + }, + "through": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", + "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=" + }, + "through2": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.5.tgz", + "integrity": "sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==", + "requires": { + "readable-stream": "~2.3.6", + "xtend": "~4.0.1" + } + }, + "thunky": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/thunky/-/thunky-1.1.0.tgz", + "integrity": "sha512-eHY7nBftgThBqOyHGVN+l8gF0BucP09fMo0oO/Lb0w1OF80dJv+lDVpXG60WMQvkcxAkNybKsrEIE3ZtKGmPrA==" + }, + "tiny-emitter": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/tiny-emitter/-/tiny-emitter-2.1.0.tgz", + "integrity": "sha512-NB6Dk1A9xgQPMoGqC5CVXn123gWyte215ONT5Pp5a0yt4nlEoO1ZWeCwpncaekPHXO60i47ihFnZPiRPjRMq4Q==" + }, + "tinyify": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/tinyify/-/tinyify-4.0.0.tgz", + "integrity": "sha512-jNDxImwUrJJAU2NyGG144J8aWx2ni39UuBo7ppCXFRmhSH0CbpWL4HgjNvrsAW05WQAgNZePwAlEemNuB+byaA==", + "requires": { + "@browserify/envify": "^6.0.0", + "@browserify/uglifyify": "^6.0.0", + "browser-pack-flat": "^3.0.9", + "bundle-collapser": "^1.3.0", + "common-shakeify": "^1.1.1", + "minify-stream": "^2.0.1", + "multisplice": "^1.0.0", + "terser": "3.16.1", + "through2": "^4.0.2", + "unassertify": "^3.0.1" + }, + "dependencies": { + "commander": { + "version": "2.17.1", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.17.1.tgz", + "integrity": "sha512-wPMUt6FnH2yzG95SA6mzjQOEKUU3aLaDEmzs1ti+1E9h+CsrZghRlqEM/EJ4KscsQVG8uNN4uVreUeT8+drlgg==" + }, + "readable-stream": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz", + "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==", + "requires": { + "inherits": "^2.0.3", + "string_decoder": "^1.1.1", + "util-deprecate": "^1.0.1" + } + }, + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==" + }, + "terser": { + "version": "3.16.1", + "resolved": "https://registry.npmjs.org/terser/-/terser-3.16.1.tgz", + "integrity": "sha512-JDJjgleBROeek2iBcSNzOHLKsB/MdDf+E/BOAJ0Tk9r7p9/fVobfv7LMJ/g/k3v9SXdmjZnIlFd5nfn/Rt0Xow==", + "requires": { + "commander": "~2.17.1", + "source-map": "~0.6.1", + "source-map-support": "~0.5.9" + } + }, + "through2": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/through2/-/through2-4.0.2.tgz", + "integrity": "sha512-iOqSav00cVxEEICeD7TjLB1sueEL+81Wpzp2bY17uZjZN0pWZPuo4suZ/61VujxmqSGFfgOcNuTZ85QJwNZQpw==", + "requires": { + "readable-stream": "3" + } + } + } + }, + "tlite": { + "version": "0.1.9", + "resolved": "https://registry.npmjs.org/tlite/-/tlite-0.1.9.tgz", + "integrity": "sha512-5QOBAvDxZZwW1i+2YXMgF6/PuV/KhA0LyE9PyVi8Ywr3bfIPziZcQD+RpdJaQurCU8zIGtBo/XuPCEHdvyeFuQ==" + }, + "tmp": { + "version": "0.0.33", + "resolved": "https://registry.npmjs.org/tmp/-/tmp-0.0.33.tgz", + "integrity": "sha512-jRCJlojKnZ3addtTOjdIqoRuPEKBvNXcGYqzO6zWZX8KfKEpnGY5jfggJQ3EjKuu8D4bJRr0y+cYJFmYbImXGw==", + "requires": { + "os-tmpdir": "~1.0.2" + } + }, + "to-fast-properties": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", + "integrity": "sha512-/OaKK0xYrs3DmxRYqL/yDc+FxFUVYhDlXMhRmv3z915w2HF1tnN1omB354j8VUGO/hbRzyD6Y3sA7v7GS/ceog==" + }, + "to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "requires": { + "is-number": "^7.0.0" + } + }, + "toidentifier": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/toidentifier/-/toidentifier-1.0.1.tgz", + "integrity": "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA==" + }, + "tough-cookie": { + "version": "4.1.3", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-4.1.3.tgz", + "integrity": "sha512-aX/y5pVRkfRnfmuX+OdbSdXvPe6ieKX/G2s7e98f4poJHnqH3281gDPm/metm6E/WRamfx7WC4HUqkWHfQHprw==", + "optional": true, + "requires": { + "psl": "^1.1.33", + "punycode": "^2.1.1", + "universalify": "^0.2.0", + "url-parse": "^1.5.3" + }, + "dependencies": { + "universalify": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-0.2.0.tgz", + "integrity": "sha512-CJ1QgKmNg3CwvAv/kOFmtnEN05f0D/cn9QntgNOQlQF9dgvVTHj3t+8JPdjqawCHk7V/KA+fbUqzZ9XWhcqPUg==", + "optional": true + } + } + }, + "transform-ast": { + "version": "2.4.4", + "resolved": "https://registry.npmjs.org/transform-ast/-/transform-ast-2.4.4.tgz", + "integrity": "sha512-AxjeZAcIOUO2lev2GDe3/xZ1Q0cVGjIMk5IsriTy8zbWlsEnjeB025AhkhBJHoy997mXpLd4R+kRbvnnQVuQHQ==", + "requires": { + "acorn-node": "^1.3.0", + "convert-source-map": "^1.5.1", + "dash-ast": "^1.0.0", + "is-buffer": "^2.0.0", + "magic-string": "^0.23.2", + "merge-source-map": "1.0.4", + "nanobench": "^2.1.1" + }, + "dependencies": { + "is-buffer": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-2.0.5.tgz", + "integrity": "sha512-i2R6zNFDwgEHJyQUtJEk0XFi1i0dPFn/oqjK3/vPCcDeJvW5NQ83V8QbicfF1SupOaB0h8ntgBC2YiE7dfyctQ==" + }, + "magic-string": { + "version": "0.23.2", + "resolved": "https://registry.npmjs.org/magic-string/-/magic-string-0.23.2.tgz", + "integrity": "sha512-oIUZaAxbcxYIp4AyLafV6OVKoB3YouZs0UTCJ8mOKBHNyJgGDaMJ4TgA+VylJh6fx7EQCC52XkbURxxG9IoJXA==", + "requires": { + "sourcemap-codec": "^1.4.1" + } + }, + "merge-source-map": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/merge-source-map/-/merge-source-map-1.0.4.tgz", + "integrity": "sha1-pd5GU42uhNQRTMXqArR3KmNGcB8=", + "requires": { + "source-map": "^0.5.6" + } + }, + "source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=" + } + } + }, + "tree-kill": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/tree-kill/-/tree-kill-1.2.2.tgz", + "integrity": "sha512-L0Orpi8qGpRG//Nd+H90vFB+3iHnue1zSSGmNOOCh1GLJ7rUKVwV2HvijphGQS2UmhUZewS9VgvxYIdgr+fG1A==" + }, + "ts-api-utils": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-1.3.0.tgz", + "integrity": "sha512-UQMIo7pb8WRomKR1/+MFVLTroIvDVtMX3K6OUir8ynLyzB8Jeriont2bTAtmNPa1ekAgN7YPDyf6V+ygrdU+eQ==", + "dev": true, + "requires": {} + }, + "ts-node": { + "version": "10.9.1", + "resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.1.tgz", + "integrity": "sha512-NtVysVPkxxrwFGUUxGYhfux8k78pQB3JqYBXlLRZgdGUqTO5wU/UyHop5p70iEbGhB7q5KmiZiU0Y3KlJrScEw==", + "dev": true, + "requires": { + "@cspotcode/source-map-support": "^0.8.0", + "@tsconfig/node10": "^1.0.7", + "@tsconfig/node12": "^1.0.7", + "@tsconfig/node14": "^1.0.0", + "@tsconfig/node16": "^1.0.2", + "acorn": "^8.4.1", + "acorn-walk": "^8.1.1", + "arg": "^4.1.0", + "create-require": "^1.1.0", + "diff": "^4.0.1", + "make-error": "^1.1.1", + "v8-compile-cache-lib": "^3.0.1", + "yn": "3.1.1" + }, + "dependencies": { + "acorn": { + "version": "8.7.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.7.1.tgz", + "integrity": "sha512-Xx54uLJQZ19lKygFXOWsscKUbsBZW0CPykPhVQdhIeIwrbPmJzqeASDInc8nKBnp/JT6igTs82qPXz069H8I/A==", + "dev": true + }, + "acorn-walk": { + "version": "8.2.0", + "resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.2.0.tgz", + "integrity": "sha512-k+iyHEuPgSw6SbuDpGQM+06HQUa04DZ3o+F6CSzXMvvI5KMvnaEqXe+YVe555R9nn6GPt404fos4wcgpw12SDA==", + "dev": true + } + } + }, + "tslib": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz", + "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==" + }, + "tuf-js": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/tuf-js/-/tuf-js-2.2.0.tgz", + "integrity": "sha512-ZSDngmP1z6zw+FIkIBjvOp/II/mIub/O7Pp12j1WNsiCpg5R5wAc//i555bBQsE44O94btLt0xM/Zr2LQjwdCg==", + "requires": { + "@tufjs/models": "2.0.0", + "debug": "^4.3.4", + "make-fetch-happen": "^13.0.0" + } + }, + "tunnel-agent": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", + "integrity": "sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==", + "optional": true, + "requires": { + "safe-buffer": "^5.0.1" + } + }, + "tweetnacl": { + "version": "0.14.5", + "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz", + "integrity": "sha512-KXXFFdAbFXY4geFIwoyNK+f5Z1b7swfXABfL7HXCmoIWMKU3dmS26672A4EeQtDzLKy7SXmfBu51JolvEKwtGA==", + "optional": true + }, + "type": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/type/-/type-1.2.0.tgz", + "integrity": "sha512-+5nt5AAniqsCnu2cEQQdpzCAh33kVx8n0VoFidKpB1dVVLAN/F+bgVOqOJqOnEnrhp222clB5p3vUlD+1QAnfg==" + }, + "type-check": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", + "integrity": "sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==", + "dev": true, + "requires": { + "prelude-ls": "^1.2.1" + } + }, + "type-detect": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/type-detect/-/type-detect-4.0.8.tgz", + "integrity": "sha512-0fr/mIH1dlO+x7TlcMy+bIDqKPsw/70tVyeHW787goQjhmqaZe10uwLujubK9q9Lg6Fiho1KUKDYz0Z7k7g5/g==", + "optional": true + }, + "type-fest": { + "version": "0.21.3", + "resolved": "https://registry.npmjs.org/type-fest/-/type-fest-0.21.3.tgz", + "integrity": "sha512-t0rzBq87m3fVcduHDUFhKmyyX+9eo6WQjZvf51Ea/M0Q7+T374Jp1aUiyUl0GKxp8M/OETVHSDvmkyPgvX+X2w==" + }, + "type-is": { + "version": "1.6.18", + "resolved": "https://registry.npmjs.org/type-is/-/type-is-1.6.18.tgz", + "integrity": "sha512-TkRKr9sUTxEH8MdfuCSP7VizJyzRNMjj2J2do2Jr3Kym598JVdEksuzPQCnlFPW4ky9Q+iA+ma9BGm06XQBy8g==", + "requires": { + "media-typer": "0.3.0", + "mime-types": "~2.1.24" + } + }, + "typed-assert": { + "version": "1.0.9", + "resolved": "https://registry.npmjs.org/typed-assert/-/typed-assert-1.0.9.tgz", + "integrity": "sha512-KNNZtayBCtmnNmbo5mG47p1XsCyrx6iVqomjcZnec/1Y5GGARaxPs6r49RnSPeUP3YjNYiU9sQHAtY4BBvnZwg==" + }, + "typedarray": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", + "integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=" + }, + "typescript": { + "version": "5.4.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.4.3.tgz", + "integrity": "sha512-KrPd3PKaCLr78MalgiwJnA25Nm8HAmdwN3mYUYZgG/wizIo9EainNVQI9/yDavtVFRN2h3k8uf3GLHuhDMgEHg==" + }, + "ua-parser-js": { + "version": "0.7.35", + "resolved": "https://registry.npmjs.org/ua-parser-js/-/ua-parser-js-0.7.35.tgz", + "integrity": "sha512-veRf7dawaj9xaWEu9HoTVn5Pggtc/qj+kqTOFvNiN1l0YdxwC1kvel57UCjThjGa3BHBihE8/UJAHI+uQHmd/g==", + "optional": true, + "peer": true + }, + "umd": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/umd/-/umd-3.0.3.tgz", + "integrity": "sha512-4IcGSufhFshvLNcMCV80UnQVlZ5pMOC8mvNPForqwA4+lzYQuetTESLDQkeLmihq8bRcnpbQa48Wb8Lh16/xow==" + }, + "unassert": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/unassert/-/unassert-2.0.2.tgz", + "integrity": "sha512-P6OOg/aRdQmWH+b0g+T4U+9MgL+DG7w6oQPG+N3F2IMuvvd1WfZ5alT/Rjik2lMFVyhfACUxF7PGP1VCwSHlQA==", + "requires": { + "estraverse": "^5.0.0" + }, + "dependencies": { + "estraverse": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-5.3.0.tgz", + "integrity": "sha512-MMdARuVEQziNTeJD8DgMqmhwR11BRQ/cBP+pLtYdSTnf3MIO8fFeiINEbX36ZdNlfU/7A9f3gUw49B3oQsvwBA==" + } + } + }, + "unassertify": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/unassertify/-/unassertify-3.0.1.tgz", + "integrity": "sha512-461ykSPY3oWU+39J5haiq7S/hcYy1oGJ2nHU92lqdL3jft+pSU6oAbb7o6VVmM7nZGLqppszgyzfpCnRBFgFtw==", + "requires": { + "acorn": "^8.0.0", + "convert-source-map": "^1.1.1", + "escodegen": "^2.0.0", + "multi-stage-sourcemap": "^0.3.1", + "through": "^2.3.7", + "unassert": "^2.0.0" + }, + "dependencies": { + "acorn": { + "version": "8.11.3", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.11.3.tgz", + "integrity": "sha512-Y9rRfJG5jcKOE0CLisYbojUjIrIEE7AGMzA/Sm4BslANhbS+cDMpgBdcPT91oJ7OuJ9hYJBx59RjbhxVnrF8Xg==" + } + } + }, + "unbox-primitive": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.1.tgz", + "integrity": "sha512-tZU/3NqK3dA5gpE1KtyiJUrEB0lxnGkMFHptJ7q6ewdZ8s12QrODwNbhIJStmJkd1QDXa1NRA8aF2A1zk/Ypyw==", + "requires": { + "function-bind": "^1.1.1", + "has-bigints": "^1.0.1", + "has-symbols": "^1.0.2", + "which-boxed-primitive": "^1.0.2" + } + }, + "undeclared-identifiers": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/undeclared-identifiers/-/undeclared-identifiers-1.1.3.tgz", + "integrity": "sha512-pJOW4nxjlmfwKApE4zvxLScM/njmwj/DiUBv7EabwE4O8kRUy+HIwxQtZLBPll/jx1LJyBcqNfB3/cpv9EZwOw==", + "requires": { + "acorn-node": "^1.3.0", + "dash-ast": "^1.0.0", + "get-assigned-identifiers": "^1.2.0", + "simple-concat": "^1.0.0", + "xtend": "^4.0.1" + } + }, + "undici": { + "version": "6.7.1", + "resolved": "https://registry.npmjs.org/undici/-/undici-6.7.1.tgz", + "integrity": "sha512-+Wtb9bAQw6HYWzCnxrPTMVEV3Q1QjYanI0E4q02ehReMuquQdLTEFEYbfs7hcImVYKcQkWSwT6buEmSVIiDDtQ==" + }, + "unicode-canonical-property-names-ecmascript": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-2.0.0.tgz", + "integrity": "sha512-yY5PpDlfVIU5+y/BSCxAJRBIS1Zc2dDG3Ujq+sR0U+JjUevW2JhocOF+soROYDSaAezOzOKuyyixhD6mBknSmQ==" + }, + "unicode-match-property-ecmascript": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/unicode-match-property-ecmascript/-/unicode-match-property-ecmascript-2.0.0.tgz", + "integrity": "sha512-5kaZCrbp5mmbz5ulBkDkbY0SsPOjKqVS35VpL9ulMPfSl0J0Xsm+9Evphv9CoIZFwre7aJoa94AY6seMKGVN5Q==", + "requires": { + "unicode-canonical-property-names-ecmascript": "^2.0.0", + "unicode-property-aliases-ecmascript": "^2.0.0" + } + }, + "unicode-match-property-value-ecmascript": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/unicode-match-property-value-ecmascript/-/unicode-match-property-value-ecmascript-2.1.0.tgz", + "integrity": "sha512-qxkjQt6qjg/mYscYMC0XKRn3Rh0wFPlfxB0xkt9CfyTvpX1Ra0+rAmdX2QyAobptSEvuy4RtpPRui6XkV+8wjA==" + }, + "unicode-property-aliases-ecmascript": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/unicode-property-aliases-ecmascript/-/unicode-property-aliases-ecmascript-2.1.0.tgz", + "integrity": "sha512-6t3foTQI9qne+OZoVQB/8x8rk2k1eVy1gRXhV3oFQ5T6R1dqQ1xtin3XqSlx3+ATBkliTaR/hHyJBm+LVPNM8w==" + }, + "unique-filename": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/unique-filename/-/unique-filename-3.0.0.tgz", + "integrity": "sha512-afXhuC55wkAmZ0P18QsVE6kp8JaxrEokN2HGIoIVv2ijHQd419H0+6EigAFcIzXeMIkcIkNBpB3L/DXB3cTS/g==", + "requires": { + "unique-slug": "^4.0.0" + } + }, + "unique-slug": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/unique-slug/-/unique-slug-4.0.0.tgz", + "integrity": "sha512-WrcA6AyEfqDX5bWige/4NQfPZMtASNVxdmWR76WESYQVAACSgWcR6e9i0mofqqBxYFtL4oAxPIptY73/0YE1DQ==", + "requires": { + "imurmurhash": "^0.1.4" + } + }, + "universalify": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.0.tgz", + "integrity": "sha512-hAZsKq7Yy11Zu1DE0OzWjw7nnLZmJZYTDZZyEFHZdUhV8FkH5MCfoU1XMaxXovpyW5nq5scPqq0ZDP9Zyl04oQ==", + "optional": true + }, + "unpipe": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unpipe/-/unpipe-1.0.0.tgz", + "integrity": "sha1-sr9O6FFKrmFltIF4KdIbLvSZBOw=" + }, + "untildify": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/untildify/-/untildify-4.0.0.tgz", + "integrity": "sha512-KK8xQ1mkzZeg9inewmFVDNkg3l5LUhoq9kN6iWYB/CC9YMG8HA+c1Q8HwDe6dEX7kErrEVNVBO3fWsVq5iDgtw==", + "optional": true + }, + "update-browserslist-db": { + "version": "1.0.13", + "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.0.13.tgz", + "integrity": "sha512-xebP81SNcPuNpPP3uzeW1NYXxI3rxyJzF3pD6sH4jE7o/IX+WtSpwnVU+qIsDPyk0d3hmFQ7mjqc6AtV604hbg==", + "requires": { + "escalade": "^3.1.1", + "picocolors": "^1.0.0" + } + }, + "uri-js": { + "version": "4.4.0", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.0.tgz", + "integrity": "sha512-B0yRTzYdUCCn9n+F4+Gh4yIDtMQcaJsmYBDsTSG8g/OejKBodLQ2IHfN3bM7jUsRXndopT7OIXWdYqc1fjmV6g==", + "requires": { + "punycode": "^2.1.0" + } + }, + "url": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/url/-/url-0.11.0.tgz", + "integrity": "sha1-ODjpfPxgUh63PFJajlW/3Z4uKPE=", + "requires": { + "punycode": "1.3.2", + "querystring": "0.2.0" + }, + "dependencies": { + "punycode": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.3.2.tgz", + "integrity": "sha1-llOgNvt8HuQjQvIyXM7v6jkmxI0=" + } + } + }, + "url-parse": { + "version": "1.5.10", + "resolved": "https://registry.npmjs.org/url-parse/-/url-parse-1.5.10.tgz", + "integrity": "sha512-WypcfiRhfeUP9vvF0j6rw0J3hrWrw6iZv3+22h6iRMJ/8z1Tj6XfLP4DsUix5MhMPnXpiHDoKyoZ/bdCkwBCiQ==", + "optional": true, + "requires": { + "querystringify": "^2.1.1", + "requires-port": "^1.0.0" + } + }, + "util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=" + }, + "utils-merge": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/utils-merge/-/utils-merge-1.0.1.tgz", + "integrity": "sha1-n5VxD1CiZ5R7LMwSR0HBAoQn5xM=" + }, + "uuid": { + "version": "8.3.2", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-8.3.2.tgz", + "integrity": "sha512-+NYs2QeMWy+GWFOEm9xnn6HCDp0l7QBD7ml8zLUmJ+93Q5NF0NocErnwkTkXVFNiX3/fpC6afS8Dhb/gz7R7eg==" + }, + "v8-compile-cache-lib": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz", + "integrity": "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==", + "dev": true + }, + "validate-npm-package-license": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", + "integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==", + "requires": { + "spdx-correct": "^3.0.0", + "spdx-expression-parse": "^3.0.0" + } + }, + "validate-npm-package-name": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/validate-npm-package-name/-/validate-npm-package-name-5.0.0.tgz", + "integrity": "sha512-YuKoXDAhBYxY7SfOKxHBDoSyENFeW5VvIIQp2TGQuit8gpK6MnWaQelBKxso72DoxTZfZdcP3W90LqpSkgPzLQ==", + "requires": { + "builtins": "^5.0.0" + } + }, + "vary": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", + "integrity": "sha1-IpnwLG3tMNSllhsLn3RSShj2NPw=" + }, + "verror": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz", + "integrity": "sha512-ZZKSmDAEFOijERBLkmYfJ+vmk3w+7hOLYDNkRCuRuMJGEmqYNCNLyBBFwWKVMhfwaEF3WOd0Zlw86U/WC/+nYw==", + "optional": true, + "requires": { + "assert-plus": "^1.0.0", + "core-util-is": "1.0.2", + "extsprintf": "^1.2.0" + } + }, + "vite": { + "version": "5.1.5", + "resolved": "https://registry.npmjs.org/vite/-/vite-5.1.5.tgz", + "integrity": "sha512-BdN1xh0Of/oQafhU+FvopafUp6WaYenLU/NFoL5WyJL++GxkNfieKzBhM24H3HVsPQrlAqB7iJYTHabzaRed5Q==", + "requires": { + "esbuild": "^0.19.3", + "fsevents": "~2.3.3", + "postcss": "^8.4.35", + "rollup": "^4.2.0" + }, + "dependencies": { + "@esbuild/aix-ppc64": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/aix-ppc64/-/aix-ppc64-0.19.12.tgz", + "integrity": "sha512-bmoCYyWdEL3wDQIVbcyzRyeKLgk2WtWLTWz1ZIAZF/EGbNOwSA6ew3PftJ1PqMiOOGu0OyFMzG53L0zqIpPeNA==", + "optional": true + }, + "@esbuild/android-arm": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm/-/android-arm-0.19.12.tgz", + "integrity": "sha512-qg/Lj1mu3CdQlDEEiWrlC4eaPZ1KztwGJ9B6J+/6G+/4ewxJg7gqj8eVYWvao1bXrqGiW2rsBZFSX3q2lcW05w==", + "optional": true + }, + "@esbuild/android-arm64": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/android-arm64/-/android-arm64-0.19.12.tgz", + "integrity": "sha512-P0UVNGIienjZv3f5zq0DP3Nt2IE/3plFzuaS96vihvD0Hd6H/q4WXUGpCxD/E8YrSXfNyRPbpTq+T8ZQioSuPA==", + "optional": true + }, + "@esbuild/android-x64": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/android-x64/-/android-x64-0.19.12.tgz", + "integrity": "sha512-3k7ZoUW6Q6YqhdhIaq/WZ7HwBpnFBlW905Fa4s4qWJyiNOgT1dOqDiVAQFwBH7gBRZr17gLrlFCRzF6jFh7Kew==", + "optional": true + }, + "@esbuild/darwin-arm64": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-arm64/-/darwin-arm64-0.19.12.tgz", + "integrity": "sha512-B6IeSgZgtEzGC42jsI+YYu9Z3HKRxp8ZT3cqhvliEHovq8HSX2YX8lNocDn79gCKJXOSaEot9MVYky7AKjCs8g==", + "optional": true + }, + "@esbuild/darwin-x64": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/darwin-x64/-/darwin-x64-0.19.12.tgz", + "integrity": "sha512-hKoVkKzFiToTgn+41qGhsUJXFlIjxI/jSYeZf3ugemDYZldIXIxhvwN6erJGlX4t5h417iFuheZ7l+YVn05N3A==", + "optional": true + }, + "@esbuild/freebsd-arm64": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-arm64/-/freebsd-arm64-0.19.12.tgz", + "integrity": "sha512-4aRvFIXmwAcDBw9AueDQ2YnGmz5L6obe5kmPT8Vd+/+x/JMVKCgdcRwH6APrbpNXsPz+K653Qg8HB/oXvXVukA==", + "optional": true + }, + "@esbuild/freebsd-x64": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/freebsd-x64/-/freebsd-x64-0.19.12.tgz", + "integrity": "sha512-EYoXZ4d8xtBoVN7CEwWY2IN4ho76xjYXqSXMNccFSx2lgqOG/1TBPW0yPx1bJZk94qu3tX0fycJeeQsKovA8gg==", + "optional": true + }, + "@esbuild/linux-arm": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm/-/linux-arm-0.19.12.tgz", + "integrity": "sha512-J5jPms//KhSNv+LO1S1TX1UWp1ucM6N6XuL6ITdKWElCu8wXP72l9MM0zDTzzeikVyqFE6U8YAV9/tFyj0ti+w==", + "optional": true + }, + "@esbuild/linux-arm64": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-arm64/-/linux-arm64-0.19.12.tgz", + "integrity": "sha512-EoTjyYyLuVPfdPLsGVVVC8a0p1BFFvtpQDB/YLEhaXyf/5bczaGeN15QkR+O4S5LeJ92Tqotve7i1jn35qwvdA==", + "optional": true + }, + "@esbuild/linux-ia32": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ia32/-/linux-ia32-0.19.12.tgz", + "integrity": "sha512-Thsa42rrP1+UIGaWz47uydHSBOgTUnwBwNq59khgIwktK6x60Hivfbux9iNR0eHCHzOLjLMLfUMLCypBkZXMHA==", + "optional": true + }, + "@esbuild/linux-loong64": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-loong64/-/linux-loong64-0.19.12.tgz", + "integrity": "sha512-LiXdXA0s3IqRRjm6rV6XaWATScKAXjI4R4LoDlvO7+yQqFdlr1Bax62sRwkVvRIrwXxvtYEHHI4dm50jAXkuAA==", + "optional": true + }, + "@esbuild/linux-mips64el": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-mips64el/-/linux-mips64el-0.19.12.tgz", + "integrity": "sha512-fEnAuj5VGTanfJ07ff0gOA6IPsvrVHLVb6Lyd1g2/ed67oU1eFzL0r9WL7ZzscD+/N6i3dWumGE1Un4f7Amf+w==", + "optional": true + }, + "@esbuild/linux-ppc64": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-ppc64/-/linux-ppc64-0.19.12.tgz", + "integrity": "sha512-nYJA2/QPimDQOh1rKWedNOe3Gfc8PabU7HT3iXWtNUbRzXS9+vgB0Fjaqr//XNbd82mCxHzik2qotuI89cfixg==", + "optional": true + }, + "@esbuild/linux-riscv64": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-riscv64/-/linux-riscv64-0.19.12.tgz", + "integrity": "sha512-2MueBrlPQCw5dVJJpQdUYgeqIzDQgw3QtiAHUC4RBz9FXPrskyyU3VI1hw7C0BSKB9OduwSJ79FTCqtGMWqJHg==", + "optional": true + }, + "@esbuild/linux-s390x": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-s390x/-/linux-s390x-0.19.12.tgz", + "integrity": "sha512-+Pil1Nv3Umes4m3AZKqA2anfhJiVmNCYkPchwFJNEJN5QxmTs1uzyy4TvmDrCRNT2ApwSari7ZIgrPeUx4UZDg==", + "optional": true + }, + "@esbuild/linux-x64": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/linux-x64/-/linux-x64-0.19.12.tgz", + "integrity": "sha512-B71g1QpxfwBvNrfyJdVDexenDIt1CiDN1TIXLbhOw0KhJzE78KIFGX6OJ9MrtC0oOqMWf+0xop4qEU8JrJTwCg==", + "optional": true + }, + "@esbuild/netbsd-x64": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/netbsd-x64/-/netbsd-x64-0.19.12.tgz", + "integrity": "sha512-3ltjQ7n1owJgFbuC61Oj++XhtzmymoCihNFgT84UAmJnxJfm4sYCiSLTXZtE00VWYpPMYc+ZQmB6xbSdVh0JWA==", + "optional": true + }, + "@esbuild/openbsd-x64": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/openbsd-x64/-/openbsd-x64-0.19.12.tgz", + "integrity": "sha512-RbrfTB9SWsr0kWmb9srfF+L933uMDdu9BIzdA7os2t0TXhCRjrQyCeOt6wVxr79CKD4c+p+YhCj31HBkYcXebw==", + "optional": true + }, + "@esbuild/sunos-x64": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/sunos-x64/-/sunos-x64-0.19.12.tgz", + "integrity": "sha512-HKjJwRrW8uWtCQnQOz9qcU3mUZhTUQvi56Q8DPTLLB+DawoiQdjsYq+j+D3s9I8VFtDr+F9CjgXKKC4ss89IeA==", + "optional": true + }, + "@esbuild/win32-arm64": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/win32-arm64/-/win32-arm64-0.19.12.tgz", + "integrity": "sha512-URgtR1dJnmGvX864pn1B2YUYNzjmXkuJOIqG2HdU62MVS4EHpU2946OZoTMnRUHklGtJdJZ33QfzdjGACXhn1A==", + "optional": true + }, + "@esbuild/win32-ia32": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/win32-ia32/-/win32-ia32-0.19.12.tgz", + "integrity": "sha512-+ZOE6pUkMOJfmxmBZElNOx72NKpIa/HFOMGzu8fqzQJ5kgf6aTGrcJaFsNiVMH4JKpMipyK+7k0n2UXN7a8YKQ==", + "optional": true + }, + "@esbuild/win32-x64": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/@esbuild/win32-x64/-/win32-x64-0.19.12.tgz", + "integrity": "sha512-T1QyPSDCyMXaO3pzBkF96E8xMkiRYbUEZADd29SyPGabqxMViNoii+NcK7eWJAEoU6RZyEm5lVSIjTmcdoB9HA==", + "optional": true + }, + "esbuild": { + "version": "0.19.12", + "resolved": "https://registry.npmjs.org/esbuild/-/esbuild-0.19.12.tgz", + "integrity": "sha512-aARqgq8roFBj054KvQr5f1sFu0D65G+miZRCuJyJ0G13Zwx7vRar5Zhn2tkQNzIXcBrNVsv/8stehpj+GAjgbg==", + "requires": { + "@esbuild/aix-ppc64": "0.19.12", + "@esbuild/android-arm": "0.19.12", + "@esbuild/android-arm64": "0.19.12", + "@esbuild/android-x64": "0.19.12", + "@esbuild/darwin-arm64": "0.19.12", + "@esbuild/darwin-x64": "0.19.12", + "@esbuild/freebsd-arm64": "0.19.12", + "@esbuild/freebsd-x64": "0.19.12", + "@esbuild/linux-arm": "0.19.12", + "@esbuild/linux-arm64": "0.19.12", + "@esbuild/linux-ia32": "0.19.12", + "@esbuild/linux-loong64": "0.19.12", + "@esbuild/linux-mips64el": "0.19.12", + "@esbuild/linux-ppc64": "0.19.12", + "@esbuild/linux-riscv64": "0.19.12", + "@esbuild/linux-s390x": "0.19.12", + "@esbuild/linux-x64": "0.19.12", + "@esbuild/netbsd-x64": "0.19.12", + "@esbuild/openbsd-x64": "0.19.12", + "@esbuild/sunos-x64": "0.19.12", + "@esbuild/win32-arm64": "0.19.12", + "@esbuild/win32-ia32": "0.19.12", + "@esbuild/win32-x64": "0.19.12" + } + } + } + }, + "vm-browserify": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/vm-browserify/-/vm-browserify-1.1.2.tgz", + "integrity": "sha512-2ham8XPWTONajOR0ohOKOHXkm3+gaBmGut3SRuu75xLd/RRaY6vqgh8NBYYk7+RW3u5AtzPQZG8F10LHkl0lAQ==" + }, + "void-elements": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/void-elements/-/void-elements-2.0.1.tgz", + "integrity": "sha1-wGavtYK7HLQSjWDqkjkulNXp2+w=", + "optional": true, + "peer": true + }, + "wait-on": { + "version": "7.2.0", + "resolved": "https://registry.npmjs.org/wait-on/-/wait-on-7.2.0.tgz", + "integrity": "sha512-wCQcHkRazgjG5XoAq9jbTMLpNIjoSlZslrJ2+N9MxDsGEv1HnFoVjOCexL0ESva7Y9cu350j+DWADdk54s4AFQ==", + "optional": true, + "requires": { + "axios": "^1.6.1", + "joi": "^17.11.0", + "lodash": "^4.17.21", + "minimist": "^1.2.8", + "rxjs": "^7.8.1" + }, + "dependencies": { + "axios": { + "version": "1.6.2", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.6.2.tgz", + "integrity": "sha512-7i24Ri4pmDRfJTR7LDBhsOTtcm+9kjX5WiY1X3wIisx6G9So3pfMkEiU7emUBe46oceVImccTEM3k6C5dbVW8A==", + "optional": true, + "requires": { + "follow-redirects": "^1.15.0", + "form-data": "^4.0.0", + "proxy-from-env": "^1.1.0" + } + }, + "form-data": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz", + "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==", + "optional": true, + "requires": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "mime-types": "^2.1.12" + } + }, + "proxy-from-env": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", + "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==", + "optional": true + } + } + }, + "watchpack": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-2.4.0.tgz", + "integrity": "sha512-Lcvm7MGST/4fup+ifyKi2hjyIAwcdI4HRgtvTpIUxBRhB+RFtUh8XtDOxUfctVCnhVi+QQj49i91OyvzkJl6cg==", + "requires": { + "glob-to-regexp": "^0.4.1", + "graceful-fs": "^4.1.2" + } + }, + "wbuf": { + "version": "1.7.3", + "resolved": "https://registry.npmjs.org/wbuf/-/wbuf-1.7.3.tgz", + "integrity": "sha512-O84QOnr0icsbFGLS0O3bI5FswxzRr8/gHwWkDlQFskhSPryQXvrTMxjxGP4+iWYoauLoBvfDpkrOauZ+0iZpDA==", + "requires": { + "minimalistic-assert": "^1.0.0" + } + }, + "wcwidth": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/wcwidth/-/wcwidth-1.0.1.tgz", + "integrity": "sha1-8LDc+RW8X/FSivrbLA4XtTLaL+g=", + "requires": { + "defaults": "^1.0.3" + } + }, + "webpack": { + "version": "5.90.3", + "resolved": "https://registry.npmjs.org/webpack/-/webpack-5.90.3.tgz", + "integrity": "sha512-h6uDYlWCctQRuXBs1oYpVe6sFcWedl0dpcVaTf/YF67J9bKvwJajFulMVSYKHrksMB3I/pIagRzDxwxkebuzKA==", + "requires": { + "@types/eslint-scope": "^3.7.3", + "@types/estree": "^1.0.5", + "@webassemblyjs/ast": "^1.11.5", + "@webassemblyjs/wasm-edit": "^1.11.5", + "@webassemblyjs/wasm-parser": "^1.11.5", + "acorn": "^8.7.1", + "acorn-import-assertions": "^1.9.0", + "browserslist": "^4.21.10", + "chrome-trace-event": "^1.0.2", + "enhanced-resolve": "^5.15.0", + "es-module-lexer": "^1.2.1", + "eslint-scope": "5.1.1", + "events": "^3.2.0", + "glob-to-regexp": "^0.4.1", + "graceful-fs": "^4.2.9", + "json-parse-even-better-errors": "^2.3.1", + "loader-runner": "^4.2.0", + "mime-types": "^2.1.27", + "neo-async": "^2.6.2", + "schema-utils": "^3.2.0", + "tapable": "^2.1.1", + "terser-webpack-plugin": "^5.3.10", + "watchpack": "^2.4.0", + "webpack-sources": "^3.2.3" + }, + "dependencies": { + "acorn": { + "version": "8.10.0", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-8.10.0.tgz", + "integrity": "sha512-F0SAmZ8iUtS//m8DmCTA0jlh6TDKkHQyK6xc6V4KDTyZKA9dnvX9/3sRTVQrWm79glUAZbnmmNcdYwUIHWVybw==" + }, + "acorn-import-assertions": { + "version": "1.9.0", + "resolved": "https://registry.npmjs.org/acorn-import-assertions/-/acorn-import-assertions-1.9.0.tgz", + "integrity": "sha512-cmMwop9x+8KFhxvKrKfPYmN6/pKTYYHBqLa0DfvVZcKMJWNyWLnaqND7dx/qn66R7ewM1UX5XMaDVP5wlVTaVA==", + "requires": {} + }, + "schema-utils": { + "version": "3.3.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-3.3.0.tgz", + "integrity": "sha512-pN/yOAvcC+5rQ5nERGuwrjLlYvLTbCibnZ1I7B1LaiAz9BRBlE9GMgE/eqV30P7aJQUf7Ddimy/RsbYO/GrVGg==", + "requires": { + "@types/json-schema": "^7.0.8", + "ajv": "^6.12.5", + "ajv-keywords": "^3.5.2" + } + } + } + }, + "webpack-dev-middleware": { + "version": "6.1.1", + "resolved": "https://registry.npmjs.org/webpack-dev-middleware/-/webpack-dev-middleware-6.1.1.tgz", + "integrity": "sha512-y51HrHaFeeWir0YO4f0g+9GwZawuigzcAdRNon6jErXy/SqV/+O6eaVAzDqE6t3e3NpGeR5CS+cCDaTC+V3yEQ==", + "requires": { + "colorette": "^2.0.10", + "memfs": "^3.4.12", + "mime-types": "^2.1.31", + "range-parser": "^1.2.1", + "schema-utils": "^4.0.0" + } + }, + "webpack-dev-server": { + "version": "4.15.1", + "resolved": "https://registry.npmjs.org/webpack-dev-server/-/webpack-dev-server-4.15.1.tgz", + "integrity": "sha512-5hbAst3h3C3L8w6W4P96L5vaV0PxSmJhxZvWKYIdgxOQm8pNZ5dEOmmSLBVpP85ReeyRt6AS1QJNyo/oFFPeVA==", + "requires": { + "@types/bonjour": "^3.5.9", + "@types/connect-history-api-fallback": "^1.3.5", + "@types/express": "^4.17.13", + "@types/serve-index": "^1.9.1", + "@types/serve-static": "^1.13.10", + "@types/sockjs": "^0.3.33", + "@types/ws": "^8.5.5", + "ansi-html-community": "^0.0.8", + "bonjour-service": "^1.0.11", + "chokidar": "^3.5.3", + "colorette": "^2.0.10", + "compression": "^1.7.4", + "connect-history-api-fallback": "^2.0.0", + "default-gateway": "^6.0.3", + "express": "^4.17.3", + "graceful-fs": "^4.2.6", + "html-entities": "^2.3.2", + "http-proxy-middleware": "^2.0.3", + "ipaddr.js": "^2.0.1", + "launch-editor": "^2.6.0", + "open": "^8.0.9", + "p-retry": "^4.5.0", + "rimraf": "^3.0.2", + "schema-utils": "^4.0.0", + "selfsigned": "^2.1.1", + "serve-index": "^1.9.1", + "sockjs": "^0.3.24", + "spdy": "^4.0.2", + "webpack-dev-middleware": "^5.3.1", + "ws": "^8.13.0" + }, + "dependencies": { + "connect-history-api-fallback": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/connect-history-api-fallback/-/connect-history-api-fallback-2.0.0.tgz", + "integrity": "sha512-U73+6lQFmfiNPrYbXqr6kZ1i1wiRqXnp2nhMsINseWXO8lDau0LGEffJ8kQi4EjLZympVgRdvqjAgiZ1tgzDDA==" + }, + "webpack-dev-middleware": { + "version": "5.3.4", + "resolved": "https://registry.npmjs.org/webpack-dev-middleware/-/webpack-dev-middleware-5.3.4.tgz", + "integrity": "sha512-BVdTqhhs+0IfoeAf7EoH5WE+exCmqGerHfDM0IL096Px60Tq2Mn9MAbnaGUe6HiMa41KMCYF19gyzZmBcq/o4Q==", + "requires": { + "colorette": "^2.0.10", + "memfs": "^3.4.3", + "mime-types": "^2.1.31", + "range-parser": "^1.2.1", + "schema-utils": "^4.0.0" + } + } + } + }, + "webpack-merge": { + "version": "5.10.0", + "resolved": "https://registry.npmjs.org/webpack-merge/-/webpack-merge-5.10.0.tgz", + "integrity": "sha512-+4zXKdx7UnO+1jaN4l2lHVD+mFvnlZQP/6ljaJVb4SZiwIKeUnrT5l0gkT8z+n4hKpC+jpOv6O9R+gLtag7pSA==", + "requires": { + "clone-deep": "^4.0.1", + "flat": "^5.0.2", + "wildcard": "^2.0.0" + } + }, + "webpack-sources": { + "version": "3.2.3", + "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-3.2.3.tgz", + "integrity": "sha512-/DyMEOrDgLKKIG0fmvtz+4dUX/3Ghozwgm6iPp8KRhvn+eQf9+Q7GWxVNMk3+uCPWfdXYC4ExGBckIXdFEfH1w==" + }, + "webpack-subresource-integrity": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/webpack-subresource-integrity/-/webpack-subresource-integrity-5.1.0.tgz", + "integrity": "sha512-sacXoX+xd8r4WKsy9MvH/q/vBtEHr86cpImXwyg74pFIpERKt6FmB8cXpeuh0ZLgclOlHI4Wcll7+R5L02xk9Q==", + "requires": { + "typed-assert": "^1.0.8" + } + }, + "websocket-driver": { + "version": "0.7.4", + "resolved": "https://registry.npmjs.org/websocket-driver/-/websocket-driver-0.7.4.tgz", + "integrity": "sha512-b17KeDIQVjvb0ssuSDF2cYXSg2iztliJ4B9WdsuB6J952qCPKmnVq4DyW5motImXHDC1cBT/1UezrJVsKw5zjg==", + "requires": { + "http-parser-js": ">=0.5.1", + "safe-buffer": ">=5.1.0", + "websocket-extensions": ">=0.1.1" + } + }, + "websocket-extensions": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/websocket-extensions/-/websocket-extensions-0.1.4.tgz", + "integrity": "sha512-OqedPIGOfsDlo31UNwYbCFMSaO9m9G/0faIHj5/dZFDMFqPTcx6UwqyOy3COEaEOg/9VsGIpdqn62W5KhoKSpg==" + }, + "which": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/which/-/which-2.0.2.tgz", + "integrity": "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA==", + "requires": { + "isexe": "^2.0.0" + } + }, + "which-boxed-primitive": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/which-boxed-primitive/-/which-boxed-primitive-1.0.2.tgz", + "integrity": "sha512-bwZdv0AKLpplFY2KZRX6TvyuN7ojjr7lwkg6ml0roIy9YeuSr7JS372qlNW18UQYzgYK9ziGcerWqZOmEn9VNg==", + "requires": { + "is-bigint": "^1.0.1", + "is-boolean-object": "^1.1.0", + "is-number-object": "^1.0.4", + "is-string": "^1.0.5", + "is-symbol": "^1.0.3" + } + }, + "which-module": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/which-module/-/which-module-2.0.0.tgz", + "integrity": "sha1-2e8H3Od7mQK4o6j6SzHD4/fm6Ho=" + }, + "which-typed-array": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/which-typed-array/-/which-typed-array-1.1.4.tgz", + "integrity": "sha512-49E0SpUe90cjpoc7BOJwyPHRqSAd12c10Qm2amdEZrJPCY2NDxaW01zHITrem+rnETY3dwrbH3UUrUwagfCYDA==", + "requires": { + "available-typed-arrays": "^1.0.2", + "call-bind": "^1.0.0", + "es-abstract": "^1.18.0-next.1", + "foreach": "^2.0.5", + "function-bind": "^1.1.1", + "has-symbols": "^1.0.1", + "is-typed-array": "^1.1.3" + } + }, + "wildcard": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/wildcard/-/wildcard-2.0.1.tgz", + "integrity": "sha512-CC1bOL87PIWSBhDcTrdeLo6eGT7mCFtrg0uIJtqJUFyK+eJnzl8A1niH56uu7KMa5XFrtiV+AQuHO3n7DsHnLQ==" + }, + "wrap-ansi": { + "version": "6.2.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-6.2.0.tgz", + "integrity": "sha512-r6lPcBGxZXlIcymEu7InxDMhdW0KDxpLgoFLcguasxCaJ/SOIZwINatK9KY/tf+ZrlywOKU0UDj3ATXUBfxJXA==", + "requires": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "requires": { + "color-convert": "^2.0.1" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + } + } + }, + "wrap-ansi-cjs": { + "version": "npm:wrap-ansi@7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "requires": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + }, + "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "requires": { + "color-convert": "^2.0.1" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==" + } + } + }, + "wrap-comment": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/wrap-comment/-/wrap-comment-1.0.1.tgz", + "integrity": "sha512-APccrMwl/ont0RHFTXNAQfM647duYYEfs6cngrIyTByTI0xbWnDnPSptFZhS68L4WCjt2ZxuhCFwuY6Pe88KZQ==" + }, + "wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=" + }, + "ws": { + "version": "8.16.0", + "resolved": "https://registry.npmjs.org/ws/-/ws-8.16.0.tgz", + "integrity": "sha512-HS0c//TP7Ina87TfiPUz1rQzMhHrl/SG2guqRcTOIUYD2q8uhUdNHZYJUaQ8aTGPzCh+c6oawMKW35nFl1dxyQ==", + "requires": {} + }, + "xhr2": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/xhr2/-/xhr2-0.2.1.tgz", + "integrity": "sha512-sID0rrVCqkVNUn8t6xuv9+6FViXjUVXq8H5rWOH2rz9fDNQEd4g0EA2XlcEdJXRz5BMEn4O1pJFdT+z4YHhoWw==" + }, + "xmlhttprequest-ssl": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/xmlhttprequest-ssl/-/xmlhttprequest-ssl-2.0.0.tgz", + "integrity": "sha512-QKxVRxiRACQcVuQEYFsI1hhkrMlrXHPegbbd1yn9UHOmRxY+si12nQYzri3vbzt8VdTTRviqcKxcyllFas5z2A==", + "devOptional": true + }, + "xtend": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", + "integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==" + }, + "y18n": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.1.tgz", + "integrity": "sha512-wNcy4NvjMYL8gogWWYAO7ZFWFfHcbdbE57tZO8e4cbpj8tfUcwrwqSl3ad8HxpYWCdXcJUCeKKZS62Av1affwQ==" + }, + "yallist": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" + }, + "yargs": { + "version": "16.2.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz", + "integrity": "sha512-D1mvvtDG0L5ft/jGWkLpG1+m0eQxOfaBvTNELraWj22wSVUMWxZUvYgJYcKh6jGGIkJFhH4IZPQhR4TKpc8mBw==", + "optional": true, + "peer": true, + "requires": { + "cliui": "^7.0.2", + "escalade": "^3.1.1", + "get-caller-file": "^2.0.5", + "require-directory": "^2.1.1", + "string-width": "^4.2.0", + "y18n": "^5.0.5", + "yargs-parser": "^20.2.2" + }, + "dependencies": { + "ansi-styles": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", + "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==", + "optional": true, + "peer": true, + "requires": { + "color-convert": "^2.0.1" + } + }, + "cliui": { + "version": "7.0.4", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz", + "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==", + "optional": true, + "peer": true, + "requires": { + "string-width": "^4.2.0", + "strip-ansi": "^6.0.0", + "wrap-ansi": "^7.0.0" + } + }, + "color-convert": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz", + "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==", + "optional": true, + "peer": true, + "requires": { + "color-name": "~1.1.4" + } + }, + "color-name": { + "version": "1.1.4", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz", + "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", + "optional": true, + "peer": true + }, + "wrap-ansi": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz", + "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==", + "optional": true, + "peer": true, + "requires": { + "ansi-styles": "^4.0.0", + "string-width": "^4.1.0", + "strip-ansi": "^6.0.0" + } + }, + "y18n": { + "version": "5.0.6", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-5.0.6.tgz", + "integrity": "sha512-PlVX4Y0lDTN6E2V4ES2tEdyvXkeKzxa8c/vo0pxPr/TqbztddTP0yn7zZylIyiAuxerqj0Q5GhpJ1YJCP8LaZQ==", + "optional": true, + "peer": true + }, + "yargs-parser": { + "version": "20.2.7", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-20.2.7.tgz", + "integrity": "sha512-FiNkvbeHzB/syOjIUxFDCnhSfzAL8R5vs40MgLFBorXACCOAEaWu0gRZl14vG8MR9AOJIZbmkjhusqBYZ3HTHw==", + "optional": true, + "peer": true + } + } + }, + "yargs-parser": { + "version": "18.1.3", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-18.1.3.tgz", + "integrity": "sha512-o50j0JeToy/4K6OZcaQmW6lyXXKhq7csREXcDwk2omFPJEwUNOVtJKvmDr9EI1fAJZUyZcRF7kxGBWmRXudrCQ==", + "requires": { + "camelcase": "^5.0.0", + "decamelize": "^1.2.0" + } + }, + "yauzl": { + "version": "2.10.0", + "resolved": "https://registry.npmjs.org/yauzl/-/yauzl-2.10.0.tgz", + "integrity": "sha512-p4a9I6X6nu6IhoGmBqAcbJy1mlC4j27vEPZX9F4L4/vZT3Lyq1VkFHw/V/PUcB9Buo+DG3iHkT0x3Qya58zc3g==", + "optional": true, + "requires": { + "buffer-crc32": "~0.2.3", + "fd-slicer": "~1.1.0" + } + }, + "yn": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", + "integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==", + "dev": true + }, + "yocto-queue": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/yocto-queue/-/yocto-queue-0.1.0.tgz", + "integrity": "sha512-rVksvsnNCdJ/ohGc6xgPwyN8eheCxsiLM8mxuE/t/mOVqJewPuO1miLpTHQiRgTKCLexL4MeAFVagts7HmNZ2Q==", + "dev": true + }, + "zone.js": { + "version": "0.14.4", + "resolved": "https://registry.npmjs.org/zone.js/-/zone.js-0.14.4.tgz", + "integrity": "sha512-NtTUvIlNELez7Q1DzKVIFZBzNb646boQMgpATo9z3Ftuu/gWvzxCW7jdjcUDoRGxRikrhVHB/zLXh1hxeJawvw==", + "requires": { + "tslib": "^2.3.0" + } + }, + "zrender": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/zrender/-/zrender-5.5.0.tgz", + "integrity": "sha512-O3MilSi/9mwoovx77m6ROZM7sXShR/O/JIanvzTwjN3FORfLSr81PsUGd7jlaYOeds9d8tw82oP44+3YucVo+w==", + "requires": { + "tslib": "2.3.0" + }, + "dependencies": { + "tslib": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.3.0.tgz", + "integrity": "sha512-N82ooyxVNm6h1riLCoyS9e3fuJ3AMG2zIZs2Gd1ATcSFjSA23Q0fzjjZeh0jbJvWVDZ0cJT8yaNNaaXHzueNjg==" + } + } + } + } +} diff --git a/frontend/package.json b/frontend/package.json index 7de1adf272..59f0eb39e6 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -1,8 +1,8 @@ { "name": "mempool-frontend", - "version": "2.0.0", + "version": "3.0.0-dev", "description": "Bitcoin mempool visualizer and blockchain explorer backend", - "license": "MIT", + "license": "GNU Affero General Public License v3.0", "homepage": "https://mempool.space", "repository": { "type": "git", @@ -20,61 +20,108 @@ ], "main": "index.ts", "scripts": { - "ng": "ng", - "start": "npm run generate-config && npm run sync-assets-dev && ng serve --proxy-config proxy.conf.json", - "build": "npm run generate-config && ng build --prod && npm run sync-assets", - "sync-assets": "node sync-assets.js", - "sync-assets-dev": "node sync-assets.js dev", + "ng": "./node_modules/@angular/cli/bin/ng.js", + "tsc": "./node_modules/typescript/bin/tsc", + "i18n-extract-from-source": "npm run ng -- extract-i18n --out-file ./src/locale/messages.xlf", + "i18n-pull-from-transifex": "tx pull -a --parallel --minimum-perc 1 --force", + "serve": "npm run generate-config && npm run ng -- serve -c local", + "serve:stg": "npm run generate-config && npm run ng -- serve -c staging", + "serve:local-prod": "npm run generate-config && npm run ng -- serve -c local-prod", + "serve:local-staging": "npm run generate-config && npm run ng -- serve -c local-staging", + "start": "npm run generate-config && npm run sync-assets-dev && npm run ng -- serve -c local", + "start:local-esplora": "npm run generate-config && npm run sync-assets-dev && npm run ng -- serve -c local-esplora", + "start:stg": "npm run generate-config && npm run sync-assets-dev && npm run ng -- serve -c staging", + "start:local-prod": "npm run generate-config && npm run sync-assets-dev && npm run ng -- serve -c local-prod", + "start:local-staging": "npm run generate-config && npm run sync-assets-dev && npm run ng -- serve -c local-staging", + "start:mixed": "npm run generate-config && npm run sync-assets-dev && npm run ng -- serve -c mixed", + "build": "npm run generate-config && npm run ng -- build --configuration production --localize && npm run sync-assets-dev && npm run sync-assets && npm run build-mempool.js", + "sync-assets": "rsync -av ./src/resources ./dist/mempool/browser && node sync-assets.js 'dist/mempool/browser/resources/'", + "sync-assets-dev": "node sync-assets.js 'src/resources/'", "generate-config": "node generate-config.js", - "test": "ng test", - "lint": "ng lint", - "e2e": "ng e2e" + "build-mempool.js": "npm run build-mempool-js && npm run build-mempool-liquid-js", + "build-mempool-js": "browserify -p tinyify ./node_modules/@mempool/mempool.js/lib/index.js --standalone mempoolJS > ./dist/mempool/browser/en-US/mempool.js", + "build-mempool-liquid-js": "browserify -p tinyify ./node_modules/@mempool/mempool.js/lib/index-liquid.js --standalone liquidJS > ./dist/mempool/browser/en-US/liquid.js", + "test": "npm run ng -- test", + "lint": "./node_modules/.bin/eslint . --ext .ts", + "lint:fix": "./node_modules/.bin/eslint . --ext .ts --fix", + "prettier": "prettier --write \"src/app/**/*.{js,json,css,scss,less,md,ts,html,component.html}\"", + "e2e": "npm run generate-config && npm run ng -- e2e", + "e2e:ci": "npm run cypress:run:ci", + "dev:ssr": "npm run generate-config && ng run mempool:serve-ssr", + "serve:ssr": "npm run generate-config && node server.run.js", + "build:ssr": "npm run build && ng run mempool:server:production && ./node_modules/typescript/bin/tsc server.run.ts", + "config:defaults:mempool": "node update-config.js TESTNET_ENABLED=true TESTNET4_ENABLED=true SIGNET_ENABLED=true LIQUID_ENABLED=true LIQUID_TESTNET_ENABLED=true ITEMS_PER_PAGE=25 BASE_MODULE=mempool BLOCK_WEIGHT_UNITS=4000000 && npm run generate-config", + "config:defaults:liquid": "node update-config.js TESTNET_ENABLED=true TESTNET4_ENABLED=true SIGNET_ENABLED=true LIQUID_ENABLED=true LIQUID_TESTNET_ENABLED=true ITEMS_PER_PAGE=25 BASE_MODULE=liquid BLOCK_WEIGHT_UNITS=300000 && npm run generate-config", + "prerender": "npm run ng -- run mempool:prerender", + "cypress:open": "cypress open", + "cypress:run": "cypress run", + "cypress:run:record": "cypress run --record", + "cypress:open:ci": "node update-config.js TESTNET_ENABLED=true TESTNET4_ENABLED=true SIGNET_ENABLED=true LIQUID_ENABLED=true ITEMS_PER_PAGE=25 && npm run generate-config && start-server-and-test serve:local-prod 4200 cypress:open", + "cypress:run:ci": "node update-config.js TESTNET_ENABLED=true TESTNET4_ENABLED=true SIGNET_ENABLED=true LIQUID_ENABLED=true ITEMS_PER_PAGE=25 && npm run generate-config && start-server-and-test serve:local-prod 4200 cypress:run:record", + "cypress:open:ci:staging": "node update-config.js TESTNET_ENABLED=true TESTNET4_ENABLED=true SIGNET_ENABLED=true LIQUID_ENABLED=true ITEMS_PER_PAGE=25 && npm run generate-config && start-server-and-test serve:local-staging 4200 cypress:open", + "cypress:run:ci:staging": "node update-config.js TESTNET_ENABLED=true TESTNET4_ENABLED=true SIGNET_ENABLED=true LIQUID_ENABLED=true ITEMS_PER_PAGE=25 && npm run generate-config && start-server-and-test serve:local-staging 4200 cypress:run:record" }, "dependencies": { - "@angular/animations": "~10.0.4", - "@angular/common": "~10.0.4", - "@angular/compiler": "~10.0.4", - "@angular/core": "~10.0.4", - "@angular/forms": "~10.0.4", - "@angular/localize": "^10.0.4", - "@angular/platform-browser": "~10.0.4", - "@angular/platform-browser-dynamic": "~10.0.4", - "@angular/router": "~10.0.4", - "@fortawesome/angular-fontawesome": "^0.7.0", - "@fortawesome/fontawesome-common-types": "^0.2.30", - "@fortawesome/fontawesome-svg-core": "^1.2.30", - "@fortawesome/free-solid-svg-icons": "^5.14.0", - "@ng-bootstrap/ng-bootstrap": "^7.0.0", - "@types/qrcode": "^1.3.4", - "bootstrap": "4.5.0", - "chartist": "^0.11.4", - "clipboard": "^2.0.4", - "ngx-infinite-scroll": "^9.0.0", - "qrcode": "^1.4.4", - "rxjs": "^6.6.0", + "@angular-devkit/build-angular": "^17.3.1", + "@angular/animations": "^17.3.1", + "@angular/cli": "^17.3.1", + "@angular/common": "^17.3.1", + "@angular/compiler": "^17.3.1", + "@angular/core": "^17.3.1", + "@angular/forms": "^17.3.1", + "@angular/localize": "^17.3.1", + "@angular/platform-browser": "^17.3.1", + "@angular/platform-browser-dynamic": "^17.3.1", + "@angular/platform-server": "^17.3.1", + "@angular/router": "^17.3.1", + "@angular/ssr": "^17.3.1", + "@fortawesome/angular-fontawesome": "~0.14.1", + "@fortawesome/fontawesome-common-types": "~6.6.0", + "@fortawesome/fontawesome-svg-core": "~6.6.0", + "@fortawesome/free-solid-svg-icons": "~6.6.0", + "@mempool/mempool.js": "2.3.0", + "@ng-bootstrap/ng-bootstrap": "^16.0.0", + "@types/qrcode": "~1.5.0", + "bootstrap": "~4.6.2", + "browserify": "^17.0.0", + "clipboard": "^2.0.11", + "domino": "^2.1.6", + "echarts": "~5.5.0", + "lightweight-charts": "~3.8.0", + "ngx-echarts": "~17.2.0", + "ngx-infinite-scroll": "^17.0.0", + "qrcode": "1.5.1", + "rxjs": "~7.8.1", + "esbuild": "^0.23.0", + "tinyify": "^4.0.0", "tlite": "^0.1.9", - "tslib": "^2.0.0", - "zone.js": "~0.10.3" + "tslib": "~2.6.0", + "zone.js": "~0.14.4" }, "devDependencies": { - "@angular-devkit/build-angular": "~0.1000.3", - "@angular/cli": "~10.0.3", - "@angular/compiler-cli": "~10.0.4", - "@angular/language-service": "~10.0.4", - "@types/jasmine": "~3.3.8", - "@types/jasminewd2": "~2.0.3", - "@types/node": "^12.11.1", - "codelyzer": "^6.0.0", - "jasmine-core": "~3.5.0", - "jasmine-spec-reporter": "~5.0.0", - "karma": "~5.0.0", - "karma-chrome-launcher": "~3.1.0", - "karma-coverage-istanbul-reporter": "~3.0.2", - "karma-jasmine": "~3.3.0", - "karma-jasmine-html-reporter": "^1.5.0", - "protractor": "~7.0.0", - "ts-node": "~7.0.0", - "tslint": "~6.1.0", - "typescript": "~3.9.7" + "@angular/compiler-cli": "^17.3.1", + "@angular/language-service": "^17.3.1", + "@types/node": "^18.11.9", + "@typescript-eslint/eslint-plugin": "^7.4.0", + "@typescript-eslint/parser": "^7.4.0", + "eslint": "^8.57.0", + "browser-sync": "^3.0.0", + "http-proxy-middleware": "~2.0.6", + "prettier": "^3.0.0", + "source-map-support": "^0.5.21", + "ts-node": "~10.9.1", + "typescript": "~5.4.3" + }, + "optionalDependencies": { + "@cypress/schematic": "^2.5.0", + "@types/cypress": "^1.1.3", + "cypress": "^13.13.0", + "cypress-fail-on-console-error": "~5.1.0", + "cypress-wait-until": "^2.0.1", + "mock-socket": "~9.3.1", + "start-server-and-test": "~2.0.0" + }, + "scarfSettings": { + "enabled": false } -} \ No newline at end of file +} diff --git a/frontend/proxy.conf.js b/frontend/proxy.conf.js new file mode 100644 index 0000000000..05f7550e06 --- /dev/null +++ b/frontend/proxy.conf.js @@ -0,0 +1,84 @@ +const fs = require('fs'); + +let PROXY_CONFIG; +let configContent; + +const CONFIG_FILE_NAME = 'mempool-frontend-config.json'; + +try { + const rawConfig = fs.readFileSync(CONFIG_FILE_NAME); + configContent = JSON.parse(rawConfig); + console.log(`${CONFIG_FILE_NAME} file found, using provided config`); +} catch (e) { + console.log(e); + if (e.code !== 'ENOENT') { + throw new Error(e); + } else { + console.log(`${CONFIG_FILE_NAME} file not found, using default config`); + } +} + +PROXY_CONFIG = [ + { + context: ['*', + '/api/**', '!/api/v1/ws', + '!/liquid', '!/liquid/**', '!/liquid/', + '!/liquidtestnet', '!/liquidtestnet/**', '!/liquidtestnet/', + '/testnet/api/**', '/signet/api/**', '/testnet4/api/**' + ], + target: "https://mempool.space", + ws: true, + secure: false, + changeOrigin: true + }, + { + context: ['/api/v1/ws'], + target: "https://mempool.space", + ws: true, + secure: false, + changeOrigin: true, + }, + { + context: ['/api/liquid**', '/liquid/api/**'], + target: "https://liquid.network", + pathRewrite: { + "^/api/liquid/": "/liquid/api" + }, + ws: true, + secure: false, + changeOrigin: true + }, + { + context: ['/api/liquidtestnet**', '/liquidtestnet/api/**'], + target: "https://liquid.network", + ws: true, + secure: false, + changeOrigin: true + }, + { + context: ['/resources/mining-pools/**'], + target: "https://mempool.space", + secure: false, + changeOrigin: true + } +]; + +if (configContent && configContent.BASE_MODULE == "liquid") { + PROXY_CONFIG.push({ + context: [ + '/resources/assets.json', '/resources/assets.minimal.json', + '/resources/assets-testnet.json', '/resources/assets-testnet.minimal.json'], + target: "https://liquid.network", + secure: false, + changeOrigin: true, + }); +} else { + PROXY_CONFIG.push({ + context: ['/resources/assets.json', '/resources/assets.minimal.json', '/resources/worldmap.json'], + target: "https://mempool.space", + secure: false, + changeOrigin: true, + }); +} + +module.exports = PROXY_CONFIG; diff --git a/frontend/proxy.conf.json b/frontend/proxy.conf.json deleted file mode 100644 index 2e161a18d5..0000000000 --- a/frontend/proxy.conf.json +++ /dev/null @@ -1,25 +0,0 @@ -{ - "/api/v1": { - "target": "http://localhost:8999/", - "secure": false - }, - "/api/v1/ws": { - "target": "http://localhost:8999/", - "secure": false, - "ws": true - }, - "/bisq/api": { - "target": "http://localhost:8999/", - "secure": false, - "pathRewrite": { - "^/bisq/api": "/api/v1/bisq" - } - }, - "/api": { - "target": "http://localhost:50001/", - "secure": false, - "pathRewrite": { - "^/api": "" - } - } -} \ No newline at end of file diff --git a/frontend/proxy.conf.local-esplora.js b/frontend/proxy.conf.local-esplora.js new file mode 100644 index 0000000000..9059102942 --- /dev/null +++ b/frontend/proxy.conf.local-esplora.js @@ -0,0 +1,123 @@ +const fs = require('fs'); + +const FRONTEND_CONFIG_FILE_NAME = 'mempool-frontend-config.json'; + +let configContent; + +// Read frontend config +try { + const rawConfig = fs.readFileSync(FRONTEND_CONFIG_FILE_NAME); + configContent = JSON.parse(rawConfig); + console.log(`${FRONTEND_CONFIG_FILE_NAME} file found, using provided config`); +} catch (e) { + console.log(e); + if (e.code !== 'ENOENT') { + throw new Error(e); + } else { + console.log(`${FRONTEND_CONFIG_FILE_NAME} file not found, using default config`); + } +} + +let PROXY_CONFIG = []; + +if (configContent && configContent.BASE_MODULE === 'liquid') { + PROXY_CONFIG.push(...[ + { + context: ['/liquid/api/v1/**'], + target: `http://127.0.0.1:8999`, + secure: false, + ws: true, + changeOrigin: true, + proxyTimeout: 30000, + pathRewrite: { + "^/liquid": "" + }, + }, + { + context: ['/liquid/api/**'], + target: `http://127.0.0.1:3000`, + secure: false, + changeOrigin: true, + proxyTimeout: 30000, + pathRewrite: { + "^/liquid/api/": "" + }, + }, + { + context: ['/liquidtestnet/api/v1/**'], + target: `http://127.0.0.1:8999`, + secure: false, + ws: true, + changeOrigin: true, + proxyTimeout: 30000, + pathRewrite: { + "^/liquidtestnet": "" + }, + }, + { + context: ['/liquidtestnet/api/**'], + target: `http://127.0.0.1:3000`, + secure: false, + changeOrigin: true, + proxyTimeout: 30000, + pathRewrite: { + "^/liquidtestnet/api/": "/" + }, + }, + ]); +} + +PROXY_CONFIG.push(...[ + { + context: ['/testnet/api/v1/lightning/**'], + target: `http://127.0.0.1:8999`, + secure: false, + changeOrigin: true, + proxyTimeout: 30000, + pathRewrite: { + "^/testnet": "" + }, + }, + /* Optional proxy to route dev to official acceleration services + { + context: ['/api/v1/services/accelerator/**'], + target: `https://mempool.space/api/v1/services/accelerator/`, + secure: false, + changeOrigin: true, + proxyTimeout: 30000, + pathRewrite: { + "^/api/v1/services/accelerator": "" + }, + }, + */ + { + context: ['/api/v1/services/**'], + target: `http://localhost:9000`, + secure: false, + ws: true, + changeOrigin: true, + proxyTimeout: 30000, + }, + { + context: ['/api/v1/**'], + target: `http://127.0.0.1:8999`, + secure: false, + ws: true, + changeOrigin: true, + proxyTimeout: 30000, + }, + { + context: ['/api/**'], + target: `http://127.0.0.1:3000`, + secure: false, + changeOrigin: true, + proxyTimeout: 30000, + pathRewrite: { + "^/api": "" + }, + } +]); + +console.log(PROXY_CONFIG); + +module.exports = PROXY_CONFIG; \ No newline at end of file diff --git a/frontend/proxy.conf.local.js b/frontend/proxy.conf.local.js new file mode 100644 index 0000000000..e7bfeee70c --- /dev/null +++ b/frontend/proxy.conf.local.js @@ -0,0 +1,111 @@ +const fs = require('fs'); + +const FRONTEND_CONFIG_FILE_NAME = 'mempool-frontend-config.json'; + +let configContent; + +// Read frontend config +try { + const rawConfig = fs.readFileSync(FRONTEND_CONFIG_FILE_NAME); + configContent = JSON.parse(rawConfig); + console.log(`${FRONTEND_CONFIG_FILE_NAME} file found, using provided config`); +} catch (e) { + console.log(e); + if (e.code !== 'ENOENT') { + throw new Error(e); + } else { + console.log(`${FRONTEND_CONFIG_FILE_NAME} file not found, using default config`); + } +} + +let PROXY_CONFIG = []; + +if (configContent && configContent.BASE_MODULE === 'liquid') { + PROXY_CONFIG.push(...[ + { + context: ['/liquid/api/v1/**'], + target: `http://localhost:8999`, + secure: false, + ws: true, + changeOrigin: true, + proxyTimeout: 30000, + pathRewrite: { + "^/liquid": "" + }, + }, + { + context: ['/liquid/api/**'], + target: `http://localhost:8999`, + secure: false, + changeOrigin: true, + proxyTimeout: 30000, + pathRewrite: { + "^/liquid/api/": "/api/v1/" + }, + }, + { + context: ['/liquidtestnet/api/v1/**'], + target: `http://localhost:8999`, + secure: false, + ws: true, + changeOrigin: true, + proxyTimeout: 30000, + pathRewrite: { + "^/liquidtestnet": "" + }, + }, + { + context: ['/liquidtestnet/api/**'], + target: `http://localhost:8999`, + secure: false, + changeOrigin: true, + proxyTimeout: 30000, + pathRewrite: { + "^/liquidtestnet/api/": "/api/v1/" + }, + }, + ]); +} + +PROXY_CONFIG.push(...[ + { + context: ['/testnet/api/v1/lightning/**'], + target: `http://localhost:8999`, + secure: false, + changeOrigin: true, + proxyTimeout: 30000, + pathRewrite: { + "^/testnet": "" + }, + }, + { + context: ['/api/v1/services/**'], + target: `http://localhost:9000`, + secure: false, + ws: true, + changeOrigin: true, + proxyTimeout: 30000, + }, + { + context: ['/api/v1/**'], + target: `http://localhost:8999`, + secure: false, + ws: true, + changeOrigin: true, + proxyTimeout: 30000, + }, + { + context: ['/api/**'], + target: `http://localhost:8999`, + secure: false, + changeOrigin: true, + proxyTimeout: 30000, + pathRewrite: { + "^/api/": "/api/v1/" + }, + } +]); + +console.log(PROXY_CONFIG); + +module.exports = PROXY_CONFIG; \ No newline at end of file diff --git a/frontend/proxy.conf.mixed.js b/frontend/proxy.conf.mixed.js new file mode 100644 index 0000000000..db8af5d95b --- /dev/null +++ b/frontend/proxy.conf.mixed.js @@ -0,0 +1,92 @@ +const fs = require('fs'); + +const FRONTEND_CONFIG_FILE_NAME = 'mempool-frontend-config.json'; + +let configContent; + +// Read frontend config +try { + const rawConfig = fs.readFileSync(FRONTEND_CONFIG_FILE_NAME); + configContent = JSON.parse(rawConfig); + console.log(`${FRONTEND_CONFIG_FILE_NAME} file found, using provided config`); +} catch (e) { + console.log(e); + if (e.code !== 'ENOENT') { + throw new Error(e); + } else { + console.log(`${FRONTEND_CONFIG_FILE_NAME} file not found, using default config`); + } +} + +let PROXY_CONFIG = []; + +if (configContent && configContent.BASE_MODULE === 'liquid') { + PROXY_CONFIG.push(...[ + { + context: ['/liquid/api/v1/**'], + target: `http://localhost:8999`, + secure: false, + ws: true, + changeOrigin: true, + proxyTimeout: 30000, + pathRewrite: { + "^/liquid": "" + }, + }, + { + context: ['/liquid/api/**'], + target: `https://liquid.network`, + secure: false, + changeOrigin: true, + proxyTimeout: 30000, + }, + { + context: ['/liquidtestnet/api/v1/**'], + target: `http://localhost:8999`, + secure: false, + ws: true, + changeOrigin: true, + proxyTimeout: 30000, + pathRewrite: { + "^/liquidtestnet": "" + }, + }, + { + context: ['/liquidtestnet/api/**'], + target: `https://liquid.network`, + secure: false, + changeOrigin: true, + proxyTimeout: 30000, + }, + ]); +} + +PROXY_CONFIG.push(...[ + { + context: ['/api/v1/services/**'], + target: `http://localhost:9000`, + secure: false, + ws: true, + changeOrigin: true, + proxyTimeout: 30000, + }, + { + context: ['/api/v1/**'], + target: `http://localhost:8999`, + secure: false, + ws: true, + changeOrigin: true, + proxyTimeout: 30000, + }, + { + context: ['/api/**'], + target: `https://mempool.space`, + secure: false, + changeOrigin: true, + proxyTimeout: 30000, + } +]); + +console.log(PROXY_CONFIG); + +module.exports = PROXY_CONFIG; \ No newline at end of file diff --git a/frontend/proxy.conf.staging.js b/frontend/proxy.conf.staging.js new file mode 100644 index 0000000000..e24662038e --- /dev/null +++ b/frontend/proxy.conf.staging.js @@ -0,0 +1,10 @@ +const fs = require('fs'); + +let PROXY_CONFIG = require('./proxy.conf'); + +PROXY_CONFIG.forEach(entry => { + entry.target = entry.target.replace("mempool.space", "mempool-staging.fra.mempool.space"); + entry.target = entry.target.replace("liquid.network", "liquid-staging.fra.mempool.space"); +}); + +module.exports = PROXY_CONFIG; diff --git a/frontend/server.run.ts b/frontend/server.run.ts new file mode 100644 index 0000000000..692af70231 --- /dev/null +++ b/frontend/server.run.ts @@ -0,0 +1,104 @@ +import './src/resources/config.js'; + +import * as domino from 'domino'; +import * as express from 'express'; +import * as fs from 'fs'; +import * as path from 'path'; + +const {readFileSync, existsSync} = require('fs'); +const {createProxyMiddleware} = require('http-proxy-middleware'); + +const template = fs.readFileSync(path.join(process.cwd(), 'dist/mempool/browser/en-US/', 'index.html')).toString(); +const win = domino.createWindow(template); + +// @ts-ignore +win.__env = global.__env; + +// @ts-ignore +win.matchMedia = () => { + return { + matches: true + }; +}; +// @ts-ignore +win.setTimeout = (fn) => { fn(); }; +win.document.body.scrollTo = (() => {}); +// @ts-ignore +global['window'] = win; +global['document'] = win.document; +// @ts-ignore +global['history'] = { state: { } }; + +global['localStorage'] = { + getItem: () => '', + setItem: () => {}, + removeItem: () => {}, + clear: () => {}, + length: 0, + key: () => '', +}; + +/** + * Return the list of supported and actually active locales + */ +function getActiveLocales() { + const angularConfig = JSON.parse(readFileSync('angular.json', 'utf8')); + + const supportedLocales = [ + angularConfig.projects.mempool.i18n.sourceLocale, + ...Object.keys(angularConfig.projects.mempool.i18n.locales), + ]; + + return supportedLocales.filter(locale => locale === 'en-US' && existsSync(`./dist/mempool/server/${locale}`)); + // return supportedLocales.filter(locale => existsSync(`./dist/mempool/server/${locale}`)); +} + +function app() { + const server = express(); + + // proxy websocket + server.get('/api/v1/ws', createProxyMiddleware({ + target: 'ws://localhost:4200/api/v1/ws', + changeOrigin: true, + ws: true, + logLevel: 'debug' + })); + // proxy API to nginx + server.get('/api/**', createProxyMiddleware({ + // @ts-ignore + target: win.__env.NGINX_PROTOCOL + '://' + win.__env.NGINX_HOSTNAME + ':' + win.__env.NGINX_PORT, + changeOrigin: true, + })); + server.get('/resources/**', express.static('./src')); + + + // map / and /en to en-US + const defaultLocale = 'en-US'; + console.log(`serving default locale: ${defaultLocale}`); + const appServerModule = require(`./dist/mempool/server/${defaultLocale}/main.js`); + server.use('/', appServerModule.app(defaultLocale)); + server.use('/en', appServerModule.app(defaultLocale)); + + // map each locale to its localized main.js + getActiveLocales().forEach(locale => { + console.log('serving locale:', locale); + const appServerModule = require(`./dist/mempool/server/${locale}/main.js`); + + // map everything to itself + server.use(`/${locale}`, appServerModule.app(locale)); + + }); + + return server; +} + +function run() { + const port = process.env.PORT || 4000; + + // Start up the Node server + app().listen(port, () => { + console.log(`Node Express server listening on port ${port}`); + }); +} + +run(); \ No newline at end of file diff --git a/frontend/server.ts b/frontend/server.ts new file mode 100644 index 0000000000..8e6c6b634c --- /dev/null +++ b/frontend/server.ts @@ -0,0 +1,108 @@ +import 'zone.js'; +import './src/resources/config.js'; + +import { CommonEngine } from '@angular/ssr'; +import * as express from 'express'; +import * as fs from 'fs'; +import * as path from 'path'; +import * as domino from 'domino'; + +import { join } from 'path'; +import { AppServerModule } from './src/main.server'; +import { APP_BASE_HREF } from '@angular/common'; +import { existsSync } from 'fs'; + +import { ResizeObserver } from './shims'; + +const commonEngine = new CommonEngine(); + +const template = fs.readFileSync(path.join(process.cwd(), 'dist/mempool/browser/en-US/', 'index.html')).toString(); +const win = domino.createWindow(template); + +// @ts-ignore +win.__env = global.__env; + +// @ts-ignore +win.matchMedia = (media) => { + return { + media, + matches: true, + }; +}; + +// @ts-ignore +win.setTimeout = (fn) => { fn(); }; +win.document.body.scrollTo = (() => {}); +win['ResizeObserver'] = ResizeObserver; +// @ts-ignore +global['window'] = win; +// @ts-ignore +global['document'] = win.document; +// @ts-ignore +global['history'] = { state: { } }; +// @ts-ignore +Object.defineProperty(global, 'navigator', { + value: win.navigator, + writable: true +}); + +global['localStorage'] = { + getItem: () => '', + setItem: () => {}, + removeItem: () => {}, + clear: () => {}, + length: 0, + key: () => '', +}; + +// The Express app is exported so that it can be used by serverless Functions. +export function app(locale: string): express.Express { + const server = express(); + const distFolder = join(process.cwd(), `dist/mempool/browser/${locale}`); + const indexHtml = join(distFolder, 'index.html'); + + server.set('view engine', 'html'); + server.set('views', distFolder); + + // static file handler so we send HTTP 404 to nginx + server.get('/**.(css|js|json|ico|webmanifest|png|jpg|jpeg|svg|mp4)*', express.static(distFolder, { maxAge: '1y', fallthrough: false })); + // handle page routes + server.get('*', (req, res, next) => { + const { protocol, originalUrl, baseUrl, headers } = req; + + commonEngine + .render({ + bootstrap: AppServerModule, + documentFilePath: indexHtml, + url: `${protocol}://${headers.host}${originalUrl}`, + publicPath: distFolder, + providers: [{ provide: APP_BASE_HREF, useValue: baseUrl }], + }) + .then((html) => res.send(html)) + .catch((err) => next(err)); + }); + + return server; +} + + +// only used for development mode +function run(): void { + const port = process.env.PORT || 4000; + + // Start up the Node server + const server = app('en-US'); + server.listen(port, () => { + console.log(`Node Express server listening on port ${port}`); + }); +} + +// Webpack will replace 'require' with '__webpack_require__' +// '__non_webpack_require__' is a proxy to Node 'require' +// The below code is to ensure that the server is run only when not requiring the bundle. +declare const __non_webpack_require__: NodeRequire; +const mainModule = __non_webpack_require__.main; +const moduleFilename = mainModule && mainModule.filename || ''; +if (moduleFilename === __filename || moduleFilename.includes('iisnode')) { + run(); +} \ No newline at end of file diff --git a/frontend/shims.ts b/frontend/shims.ts new file mode 100644 index 0000000000..50f1b6f338 --- /dev/null +++ b/frontend/shims.ts @@ -0,0 +1,7 @@ +export class ResizeObserver { + constructor() {} + + disconnect() {} + observe() {} + unobserve() {} +} \ No newline at end of file diff --git a/frontend/src/app/app-routing.module.ts b/frontend/src/app/app-routing.module.ts index b401bbd4fd..8e996953d5 100644 --- a/frontend/src/app/app-routing.module.ts +++ b/frontend/src/app/app-routing.module.ts @@ -1,205 +1,319 @@ import { NgModule } from '@angular/core'; import { Routes, RouterModule } from '@angular/router'; -import { StartComponent } from './components/start/start.component'; -import { TransactionComponent } from './components/transaction/transaction.component'; -import { BlockComponent } from './components/block/block.component'; -import { AddressComponent } from './components/address/address.component'; -import { MasterPageComponent } from './components/master-page/master-page.component'; -import { AboutComponent } from './components/about/about.component'; -import { TelevisionComponent } from './components/television/television.component'; -import { StatisticsComponent } from './components/statistics/statistics.component'; -import { MempoolBlockComponent } from './components/mempool-block/mempool-block.component'; -import { LatestBlocksComponent } from './components/latest-blocks/latest-blocks.component'; -import { AssetComponent } from './components/asset/asset.component'; -import { AssetsComponent } from './assets/assets.component'; +import { AppPreloadingStrategy } from './app.preloading-strategy' +import { BlockViewComponent } from './components/block-view/block-view.component'; +import { EightBlocksComponent } from './components/eight-blocks/eight-blocks.component'; +import { MempoolBlockViewComponent } from './components/mempool-block-view/mempool-block-view.component'; +import { ClockComponent } from './components/clock/clock.component'; import { StatusViewComponent } from './components/status-view/status-view.component'; +import { AddressGroupComponent } from './components/address-group/address-group.component'; +import { TrackerComponent } from './components/tracker/tracker.component'; +import { AccelerateCheckout } from './components/accelerate-checkout/accelerate-checkout.component'; -const routes: Routes = [ +const browserWindow = window || {}; +// @ts-ignore +const browserWindowEnv = browserWindow.__env || {}; + +let routes: Routes = [ { - path: '', - component: MasterPageComponent, + path: 'testnet', children: [ { path: '', - component: StartComponent, - children: [ - { - path: '', - component: LatestBlocksComponent - }, - { - path: 'tx/:id', - component: TransactionComponent - }, - { - path: 'block/:id', - component: BlockComponent - }, - { - path: 'mempool-block/:id', - component: MempoolBlockComponent - }, - ], - }, - { - path: 'graphs', - component: StatisticsComponent, - }, - { - path: 'about', - component: AboutComponent, - }, - { - path: 'address/:id', + pathMatch: 'full', + loadChildren: () => import('./bitcoin-graphs.module').then(m => m.BitcoinGraphsModule), + data: { preload: true }, + }, + { + path: '', + loadChildren: () => import('./master-page.module').then(m => m.MasterPageModule), + data: { preload: true }, + }, + { + path: 'wallet', children: [], - component: AddressComponent + component: AddressGroupComponent, + data: { + networkSpecific: true, + } }, - ], + { + path: 'status', + data: { networks: ['bitcoin', 'liquid'] }, + component: StatusViewComponent + }, + { + path: '', + loadChildren: () => import('./bitcoin-graphs.module').then(m => m.BitcoinGraphsModule), + data: { preload: true }, + }, + { + path: '**', + redirectTo: '/testnet' + }, + ] }, { - path: 'liquid', + path: 'testnet4', children: [ { path: '', - component: MasterPageComponent, - children: [ - { - path: '', - component: StartComponent, - children: [ - { - path: '', - component: LatestBlocksComponent - }, - { - path: 'tx/:id', - component: TransactionComponent - }, - { - path: 'block/:id', - component: BlockComponent - }, - { - path: 'mempool-block/:id', - component: MempoolBlockComponent - }, - ], - }, - { - path: 'graphs', - component: StatisticsComponent, - }, - { - path: 'about', - component: AboutComponent, - }, - { - path: 'address/:id', - component: AddressComponent - }, - { - path: 'asset/:id', - component: AssetComponent - }, - { - path: 'assets', - component: AssetsComponent, - }, - ], - }, - { - path: 'tv', - component: TelevisionComponent + pathMatch: 'full', + loadChildren: () => import('./bitcoin-graphs.module').then(m => m.BitcoinGraphsModule), + data: { preload: true }, + }, + { + path: '', + loadChildren: () => import('./master-page.module').then(m => m.MasterPageModule), + data: { preload: true }, + }, + { + path: 'wallet', + children: [], + component: AddressGroupComponent, + data: { + networkSpecific: true, + } }, { path: 'status', + data: { networks: ['bitcoin', 'liquid'] }, component: StatusViewComponent }, + { + path: '', + loadChildren: () => import('./bitcoin-graphs.module').then(m => m.BitcoinGraphsModule), + data: { preload: true }, + }, { path: '**', - redirectTo: '' + redirectTo: '/testnet4' }, ] }, { - path: 'testnet', + path: 'signet', children: [ + { + path: 'mining/blocks', + redirectTo: 'blocks', + pathMatch: 'full' + }, { path: '', - component: MasterPageComponent, - children: [ - { - path: '', - component: StartComponent, - children: [ - { - path: '', - component: LatestBlocksComponent - }, - { - path: 'tx/:id', - component: TransactionComponent - }, - { - path: 'block/:id', - component: BlockComponent - }, - { - path: 'mempool-block/:id', - component: MempoolBlockComponent - }, - ], - }, - { - path: 'graphs', - component: StatisticsComponent, - }, - { - path: 'about', - component: AboutComponent, - }, - { - path: 'address/:id', - children: [], - component: AddressComponent - }, - ], - }, - { - path: 'tv', - component: TelevisionComponent + pathMatch: 'full', + loadChildren: () => import('./bitcoin-graphs.module').then(m => m.BitcoinGraphsModule), + data: { preload: true }, + }, + { + path: '', + loadChildren: () => import('./master-page.module').then(m => m.MasterPageModule), + data: { preload: true }, + }, + { + path: 'wallet', + children: [], + component: AddressGroupComponent, + data: { + networkSpecific: true, + } }, { path: 'status', + data: { networks: ['bitcoin', 'liquid'] }, component: StatusViewComponent }, + { + path: '', + loadChildren: () => import('./bitcoin-graphs.module').then(m => m.BitcoinGraphsModule), + data: { preload: true }, + }, { path: '**', - redirectTo: '' + redirectTo: '/signet' }, ] }, { - path: 'bisq', - component: MasterPageComponent, - loadChildren: () => import('./bisq/bisq.module').then(m => m.BisqModule) + path: '', + pathMatch: 'full', + loadChildren: () => import('./bitcoin-graphs.module').then(m => m.BitcoinGraphsModule), + data: { preload: true }, + }, + { + path: '', + loadChildren: () => import('./master-page.module').then(m => m.MasterPageModule), + data: { preload: true }, + }, + { + path: 'tracker', + data: { networkSpecific: true }, + loadChildren: () => import('./components/tracker/tracker.module').then(m => m.TrackerModule), + }, + { + path: 'wallet', + children: [], + component: AddressGroupComponent, + data: { + networkSpecific: true, + } + }, + { + path: 'preview', + children: [ + { + path: '', + loadChildren: () => import('./previews.module').then(m => m.PreviewsModule) + }, + { + path: 'testnet', + loadChildren: () => import('./previews.module').then(m => m.PreviewsModule) + }, + { + path: 'testnet4', + loadChildren: () => import('./previews.module').then(m => m.PreviewsModule) + }, + { + path: 'signet', + loadChildren: () => import('./previews.module').then(m => m.PreviewsModule) + }, + ], + }, + { + path: 'clock', + redirectTo: 'clock/mempool/0' }, { - path: 'tv', - component: TelevisionComponent, + path: 'clock/:mode', + redirectTo: 'clock/:mode/0' + }, + { + path: 'clock/:mode/:index', + component: ClockComponent, + }, + { + path: 'view/block/:id', + component: BlockViewComponent, + }, + { + path: 'view/mempool-block/:index', + component: MempoolBlockViewComponent, + }, + { + path: 'view/blocks', + component: EightBlocksComponent, }, { path: 'status', + data: { networks: ['bitcoin', 'liquid'] }, component: StatusViewComponent }, + { + path: '', + loadChildren: () => import('./bitcoin-graphs.module').then(m => m.BitcoinGraphsModule), + data: { preload: true }, + }, { path: '**', redirectTo: '' }, ]; +if (browserWindowEnv && browserWindowEnv.BASE_MODULE === 'liquid') { + routes = [ + { + path: 'testnet', + children: [ + { + path: '', + pathMatch: 'full', + loadChildren: () => import('./liquid/liquid-graphs.module').then(m => m.LiquidGraphsModule), + data: { preload: true }, + }, + { + path: '', + loadChildren: () => import ('./liquid/liquid-master-page.module').then(m => m.LiquidMasterPageModule), + data: { preload: true }, + }, + { + path: 'wallet', + children: [], + component: AddressGroupComponent, + data: { + networkSpecific: true, + } + }, + { + path: 'status', + data: { networks: ['bitcoin', 'liquid'] }, + component: StatusViewComponent + }, + { + path: '', + loadChildren: () => import('./liquid/liquid-graphs.module').then(m => m.LiquidGraphsModule), + data: { preload: true }, + }, + { + path: '**', + redirectTo: '/signet' + }, + ] + }, + { + path: '', + pathMatch: 'full', + loadChildren: () => import('./liquid/liquid-graphs.module').then(m => m.LiquidGraphsModule), + data: { preload: true }, + }, + { + path: '', + loadChildren: () => import ('./liquid/liquid-master-page.module').then(m => m.LiquidMasterPageModule), + data: { preload: true }, + }, + { + path: 'wallet', + children: [], + component: AddressGroupComponent, + data: { + networkSpecific: true, + } + }, + { + path: 'preview', + children: [ + { + path: '', + loadChildren: () => import('./previews.module').then(m => m.PreviewsModule) + }, + { + path: 'testnet', + loadChildren: () => import('./previews.module').then(m => m.PreviewsModule) + }, + ], + }, + { + path: 'status', + data: { networks: ['bitcoin', 'liquid']}, + component: StatusViewComponent + }, + { + path: '', + loadChildren: () => import('./liquid/liquid-graphs.module').then(m => m.LiquidGraphsModule), + data: { preload: true }, + }, + { + path: '**', + redirectTo: '' + }, + ]; +} + @NgModule({ - imports: [RouterModule.forRoot(routes)], - exports: [RouterModule] + imports: [RouterModule.forRoot(routes, { + initialNavigation: 'enabledBlocking', + scrollPositionRestoration: 'enabled', + anchorScrolling: 'disabled', + preloadingStrategy: AppPreloadingStrategy + })], }) export class AppRoutingModule { } diff --git a/frontend/src/app/app.constants.ts b/frontend/src/app/app.constants.ts index ab880cf9c4..aaa53b8bae 100644 --- a/frontend/src/app/app.constants.ts +++ b/frontend/src/app/app.constants.ts @@ -1,4 +1,4 @@ -export const mempoolFeeColors = [ +export const defaultMempoolFeeColors = [ '557d00', '5d7d01', '637d02', @@ -29,28 +29,414 @@ export const mempoolFeeColors = [ 'ba3243', 'b92b48', 'b9254b', + 'b8214d', + 'b71d4f', + 'b61951', + 'b41453', + 'b30e55', + 'b10857', + 'b00259', + 'ae005b', ]; +export const contrastMempoolFeeColors = [ + '0082e6', + '0984df', + '1285d9', + '1a87d2', + '2388cb', + '2c8ac5', + '358bbe', + '3e8db7', + '468eb0', + '4f90aa', + '5892a3', + '61939c', + '6a9596', + '72968f', + '7b9888', + '849982', + '8d9b7b', + '959c74', + '9e9e6e', + 'a79f67', + 'b0a160', + 'b9a35a', + 'c1a453', + 'caa64c', + 'd3a745', + 'dca93f', + 'e5aa38', + 'edac31', + 'f6ad2b', + 'ffaf24', + 'ffb01e', + 'ffb118', + 'ffb212', + 'ffb30c', + 'ffb406', + 'ffb500', + 'ffb600', + 'ffb700', + ]; + +export const chartColors = [ + "#D81B60", + "#8E24AA", + "#5E35B1", + "#3949AB", + "#1E88E5", + "#039BE5", + "#00ACC1", + "#00897B", + "#43A047", + "#7CB342", + "#C0CA33", + "#FDD835", + "#FFB300", + "#FB8C00", + "#F4511E", + "#6D4C41", + "#757575", + "#546E7A", + "#b71c1c", + "#880E4F", + "#4A148C", + "#311B92", + "#1A237E", + "#0D47A1", + "#01579B", + "#006064", + "#004D40", + "#1B5E20", + "#33691E", + "#827717", + "#F57F17", + "#FF6F00", + "#E65100", + "#BF360C", + "#3E2723", + "#212121", + "#263238", + "#801313", +]; + +export const poolsColor = { + 'unknown': '#FDD835', +}; + export const feeLevels = [1, 2, 3, 4, 5, 6, 8, 10, 12, 15, 20, 30, 40, 50, 60, 70, 80, 90, 100, 125, 150, 175, 200, 250, 300, 350, 400, 500, 600, 700, 800, 900, 1000, 1200, 1400, 1600, 1800, 2000]; -interface Env { - TESTNET_ENABLED: boolean; - LIQUID_ENABLED: boolean; - BISQ_ENABLED: boolean; - ELCTRS_ITEMS_PER_PAGE: number; - KEEP_BLOCKS_AMOUNT: number; +export interface Language { + code: string; + name: string; } -const defaultEnv: Env = { - 'TESTNET_ENABLED': false, - 'LIQUID_ENABLED': false, - 'BISQ_ENABLED': false, - 'ELCTRS_ITEMS_PER_PAGE': 25, - 'KEEP_BLOCKS_AMOUNT': 8 +export const languages: Language[] = [ + { code: 'ar', name: 'العربية' }, // Arabic +// { code: 'bg', name: 'Български' }, // Bulgarian +// { code: 'bs', name: 'Bosanski' }, // Bosnian +// { code: 'ca', name: 'Català' }, // Catalan + { code: 'cs', name: 'Čeština' }, // Czech + { code: 'da', name: 'Dansk' }, // Danish + { code: 'de', name: 'Deutsch' }, // German +// { code: 'et', name: 'Eesti' }, // Estonian +// { code: 'el', name: 'Ελληνικά' }, // Greek + { code: 'en', name: 'English' }, // English + { code: 'es', name: 'Español' }, // Spanish +// { code: 'eo', name: 'Esperanto' }, // Esperanto +// { code: 'eu', name: 'Euskara' }, // Basque + { code: 'fa', name: 'فارسی' }, // Persian + { code: 'fr', name: 'Français' }, // French +// { code: 'gl', name: 'Galego' }, // Galician + { code: 'ko', name: '한국어' }, // Korean +// { code: 'hr', name: 'Hrvatski' }, // Croatian +// { code: 'id', name: 'Bahasa Indonesia' },// Indonesian + { code: 'hi', name: 'हिन्दी' }, // Hindi + { code: 'ne', name: 'नेपाली' }, // Nepalese + { code: 'it', name: 'Italiano' }, // Italian + { code: 'he', name: 'עברית' }, // Hebrew + { code: 'ka', name: 'ქართული' }, // Georgian +// { code: 'lv', name: 'Latviešu' }, // Latvian + { code: 'lt', name: 'Lietuvių' }, // Lithuanian + { code: 'hu', name: 'Magyar' }, // Hungarian + { code: 'mk', name: 'Македонски' }, // Macedonian +// { code: 'ms', name: 'Bahasa Melayu' }, // Malay + { code: 'nl', name: 'Nederlands' }, // Dutch + { code: 'ja', name: '日本語' }, // Japanese + { code: 'nb', name: 'Norsk' }, // Norwegian Bokmål +// { code: 'nn', name: 'Norsk Nynorsk' }, // Norwegian Nynorsk + { code: 'pl', name: 'Polski' }, // Polish + { code: 'pt', name: 'Português' }, // Portuguese +// { code: 'pt-BR', name: 'Português (Brazil)' }, // Portuguese (Brazil) + { code: 'ro', name: 'Română' }, // Romanian + { code: 'ru', name: 'Русский' }, // Russian +// { code: 'sk', name: 'Slovenčina' }, // Slovak + { code: 'sl', name: 'Slovenščina' }, // Slovenian +// { code: 'sr', name: 'Српски / srpski' }, // Serbian +// { code: 'sh', name: 'Srpskohrvatski / српскохрватски' },// Serbo-Croatian + { code: 'fi', name: 'Suomi' }, // Finnish + { code: 'sv', name: 'Svenska' }, // Swedish + { code: 'th', name: 'ไทย' }, // Thai + { code: 'tr', name: 'Türkçe' }, // Turkish + { code: 'uk', name: 'Українська' }, // Ukrainian + { code: 'vi', name: 'Tiếng Việt' }, // Vietnamese + { code: 'zh', name: '中文' }, // Chinese +]; + +export const specialBlocks = { + '0': { + labelEvent: 'Genesis', + labelEventCompleted: 'The Genesis of Bitcoin', + networks: ['mainnet', 'testnet', 'testnet4'], + }, + '210000': { + labelEvent: 'Bitcoin\'s 1st Halving', + labelEventCompleted: 'Block Subsidy has halved to 25 BTC per block', + networks: ['mainnet', 'testnet', 'testnet4'], + }, + '420000': { + labelEvent: 'Bitcoin\'s 2nd Halving', + labelEventCompleted: 'Block Subsidy has halved to 12.5 BTC per block', + networks: ['mainnet', 'testnet', 'testnet4'], + }, + '630000': { + labelEvent: 'Bitcoin\'s 3rd Halving', + labelEventCompleted: 'Block Subsidy has halved to 6.25 BTC per block', + networks: ['mainnet', 'testnet', 'testnet4'], + }, + '709632': { + labelEvent: 'Taproot 🌱 activation', + labelEventCompleted: 'Taproot 🌱 has been activated!', + networks: ['mainnet'], + }, + '840000': { + labelEvent: 'Bitcoin\'s 4th Halving', + labelEventCompleted: 'Block Subsidy has halved to 3.125 BTC per block', + networks: ['mainnet', 'testnet', 'testnet4'], + }, + '1050000': { + labelEvent: 'Bitcoin\'s 5th Halving', + labelEventCompleted: 'Block Subsidy has halved to 1.5625 BTC per block', + networks: ['mainnet', 'testnet', 'testnet4'], + }, + '1260000': { + labelEvent: 'Bitcoin\'s 6th Halving', + labelEventCompleted: 'Block Subsidy has halved to 0.78125 BTC per block', + networks: ['mainnet', 'testnet', 'testnet4'], + }, + '1470000': { + labelEvent: 'Bitcoin\'s 7th Halving', + labelEventCompleted: 'Block Subsidy has halved to 0.390625 BTC per block', + networks: ['mainnet', 'testnet', 'testnet4'], + }, + '1680000': { + labelEvent: 'Bitcoin\'s 8th Halving', + labelEventCompleted: 'Block Subsidy has halved to 0.1953125 BTC per block', + networks: ['mainnet', 'testnet', 'testnet4'], + }, + '1890000': { + labelEvent: 'Bitcoin\'s 9th Halving', + labelEventCompleted: 'Block Subsidy has halved to 0.09765625 BTC per block', + networks: ['mainnet', 'testnet', 'testnet4'], + }, + '2100000': { + labelEvent: 'Bitcoin\'s 10th Halving', + labelEventCompleted: 'Block Subsidy has halved to 0.04882812 BTC per block', + networks: ['mainnet', 'testnet', 'testnet4'], + }, + '2310000': { + labelEvent: 'Bitcoin\'s 11th Halving', + labelEventCompleted: 'Block Subsidy has halved to 0.02441406 BTC per block', + networks: ['mainnet', 'testnet', 'testnet4'], + }, + '2520000': { + labelEvent: 'Bitcoin\'s 12th Halving', + labelEventCompleted: 'Block Subsidy has halved to 0.01220703 BTC per block', + networks: ['mainnet', 'testnet', 'testnet4'], + }, + '2730000': { + labelEvent: 'Bitcoin\'s 13th Halving', + labelEventCompleted: 'Block Subsidy has halved to 0.00610351 BTC per block', + networks: ['mainnet', 'testnet', 'testnet4'], + }, + '2940000': { + labelEvent: 'Bitcoin\'s 14th Halving', + labelEventCompleted: 'Block Subsidy has halved to 0.00305175 BTC per block', + networks: ['mainnet', 'testnet', 'testnet4'], + }, + '3150000': { + labelEvent: 'Bitcoin\'s 15th Halving', + labelEventCompleted: 'Block Subsidy has halved to 0.00152587 BTC per block', + networks: ['mainnet', 'testnet', 'testnet4'], + } }; -const browserWindow = window || {}; -// @ts-ignore -const browserWindowEnv = browserWindow.__env || {}; -export const env: Env = Object.assign(defaultEnv, browserWindowEnv); +export const fiatCurrencies = { + AUD: { + name: 'Australian Dollar', + code: 'AUD', + indexed: true, + }, + CAD: { + name: 'Canadian Dollar', + code: 'CAD', + indexed: true, + }, + CHF: { + name: 'Swiss Franc', + code: 'CHF', + indexed: true, + }, + EUR: { + name: 'Euro', + code: 'EUR', + indexed: true, + }, + GBP: { + name: 'Pound Sterling', + code: 'GBP', + indexed: true, + }, + JPY: { + name: 'Japanese Yen', + code: 'JPY', + indexed: true, + }, + USD: { + name: 'US Dollar', + code: 'USD', + indexed: true, + }, + BGN: { + name: 'Bulgarian Lev', + code: 'BGN', + indexed: true, + }, + BRL: { + name: 'Brazilian Real', + code: 'BRL', + indexed: true, + }, + CNY: { + name: 'Chinese Yuan', + code: 'CNY', + indexed: true, + }, + CZK: { + name: 'Czech Koruna', + code: 'CZK', + indexed: true, + }, + DKK: { + name: 'Danish Krone', + code: 'DKK', + indexed: true, + }, + HKD: { + name: 'Hong Kong Dollar', + code: 'HKD', + indexed: true, + }, + HRK: { + name: 'Croatian Kuna', + code: 'HRK', + indexed: true, + }, + HUF: { + name: 'Hungarian Forint', + code: 'HUF', + indexed: true, + }, + IDR: { + name: 'Indonesian Rupiah', + code: 'IDR', + indexed: true, + }, + ILS: { + name: 'Israeli Shekel', + code: 'ILS', + indexed: true, + }, + INR: { + name: 'Indian Rupee', + code: 'INR', + indexed: true, + }, + ISK: { + name: 'Icelandic Krona', + code: 'ISK', + indexed: true, + }, + KRW: { + name: 'South Korean Won', + code: 'KRW', + indexed: true, + }, + MXN: { + name: 'Mexican Peso', + code: 'MXN', + indexed: true, + }, + MYR: { + name: 'Malaysian Ringgit', + code: 'MYR', + indexed: true, + }, + NOK: { + name: 'Norwegian Krone', + code: 'NOK', + indexed: true, + }, + NZD: { + name: 'New Zealand Dollar', + code: 'NZD', + indexed: true, + }, + PHP: { + name: 'Philippine Peso', + code: 'PHP', + indexed: true, + }, + PLN: { + name: 'Polish Zloty', + code: 'PLN', + indexed: true, + }, + RON: { + name: 'Romanian Leu', + code: 'RON', + indexed: true, + }, + RUB: { + name: 'Russian Ruble', + code: 'RUB', + indexed: true, + }, + SEK: { + name: 'Swedish Krona', + code: 'SEK', + indexed: true, + }, + SGD: { + name: 'Singapore Dollar', + code: 'SGD', + indexed: true, + }, + THB: { + name: 'Thai Baht', + code: 'THB', + indexed: true, + }, + TRY: { + name: 'Turkish Lira', + code: 'TRY', + indexed: true, + }, + ZAR: { + name: 'South African Rand', + code: 'ZAR', + indexed: true, + }, +}; \ No newline at end of file diff --git a/frontend/src/app/app.module.server.ts b/frontend/src/app/app.module.server.ts new file mode 100644 index 0000000000..4149fa5938 --- /dev/null +++ b/frontend/src/app/app.module.server.ts @@ -0,0 +1,23 @@ +import { HTTP_INTERCEPTORS } from '@angular/common/http'; +import { NgModule } from '@angular/core'; +import { ServerModule } from '@angular/platform-server'; + +import { ZONE_SERVICE } from './injection-tokens'; +import { AppModule } from './app.module'; +import { AppComponent } from './components/app/app.component'; +import { HttpCacheInterceptor } from './services/http-cache.interceptor'; +import { ZoneService } from './services/zone.service'; + + +@NgModule({ + imports: [ + AppModule, + ServerModule, + ], + providers: [ + { provide: HTTP_INTERCEPTORS, useClass: HttpCacheInterceptor, multi: true }, + { provide: ZONE_SERVICE, useClass: ZoneService }, + ], + bootstrap: [AppComponent], +}) +export class AppServerModule {} \ No newline at end of file diff --git a/frontend/src/app/app.module.ts b/frontend/src/app/app.module.ts index 5b3680f3da..50bbd88b90 100644 --- a/frontend/src/app/app.module.ts +++ b/frontend/src/app/app.module.ts @@ -1,96 +1,81 @@ import { BrowserModule } from '@angular/platform-browser'; -import { NgModule } from '@angular/core'; -import { HttpClientModule } from '@angular/common/http'; -import { ReactiveFormsModule } from '@angular/forms'; +import { ModuleWithProviders, NgModule } from '@angular/core'; +import { HttpClientModule, HTTP_INTERCEPTORS } from '@angular/common/http'; import { BrowserAnimationsModule } from '@angular/platform-browser/animations'; -import { NgbButtonsModule, NgbPaginationModule, NgbDropdownModule } from '@ng-bootstrap/ng-bootstrap'; -import { InfiniteScrollModule } from 'ngx-infinite-scroll'; - +import { ZONE_SERVICE } from './injection-tokens'; import { AppRoutingModule } from './app-routing.module'; import { AppComponent } from './components/app/app.component'; - -import { StartComponent } from './components/start/start.component'; import { ElectrsApiService } from './services/electrs-api.service'; -import { TransactionComponent } from './components/transaction/transaction.component'; -import { TransactionsListComponent } from './components/transactions-list/transactions-list.component'; -import { AmountComponent } from './components/amount/amount.component'; import { StateService } from './services/state.service'; -import { BlockComponent } from './components/block/block.component'; -import { AddressComponent } from './components/address/address.component'; -import { SearchFormComponent } from './components/search-form/search-form.component'; -import { LatestBlocksComponent } from './components/latest-blocks/latest-blocks.component'; +import { CacheService } from './services/cache.service'; +import { PriceService } from './services/price.service'; +import { EnterpriseService } from './services/enterprise.service'; import { WebsocketService } from './services/websocket.service'; -import { AddressLabelsComponent } from './components/address-labels/address-labels.component'; -import { MempoolBlocksComponent } from './components/mempool-blocks/mempool-blocks.component'; -import { MasterPageComponent } from './components/master-page/master-page.component'; -import { AboutComponent } from './components/about/about.component'; -import { TelevisionComponent } from './components/television/television.component'; -import { StatisticsComponent } from './components/statistics/statistics.component'; -import { ChartistComponent } from './components/statistics/chartist.component'; -import { BlockchainBlocksComponent } from './components/blockchain-blocks/blockchain-blocks.component'; -import { BlockchainComponent } from './components/blockchain/blockchain.component'; -import { FooterComponent } from './components/footer/footer.component'; import { AudioService } from './services/audio.service'; -import { MempoolBlockComponent } from './components/mempool-block/mempool-block.component'; -import { FeeDistributionGraphComponent } from './components/fee-distribution-graph/fee-distribution-graph.component'; -import { TimespanComponent } from './components/timespan/timespan.component'; +import { PreloadService } from './services/preload.service'; import { SeoService } from './services/seo.service'; -import { MempoolGraphComponent } from './components/mempool-graph/mempool-graph.component'; -import { AssetComponent } from './components/asset/asset.component'; -import { AssetsComponent } from './assets/assets.component'; -import { StatusViewComponent } from './components/status-view/status-view.component'; -import { MinerComponent } from './components/miner/miner.component'; +import { OpenGraphService } from './services/opengraph.service'; +import { ZoneService } from './services/zone-shim.service'; import { SharedModule } from './shared/shared.module'; +import { StorageService } from './services/storage.service'; +import { HttpCacheInterceptor } from './services/http-cache.interceptor'; +import { LanguageService } from './services/language.service'; +import { ThemeService } from './services/theme.service'; +import { FiatShortenerPipe } from './shared/pipes/fiat-shortener.pipe'; +import { FiatCurrencyPipe } from './shared/pipes/fiat-currency.pipe'; +import { ShortenStringPipe } from './shared/pipes/shorten-string-pipe/shorten-string.pipe'; +import { CapAddressPipe } from './shared/pipes/cap-address-pipe/cap-address-pipe'; +import { AppPreloadingStrategy } from './app.preloading-strategy'; +import { ServicesApiServices } from './services/services-api.service'; +import { DatePipe } from '@angular/common'; + +const providers = [ + ElectrsApiService, + StateService, + CacheService, + PriceService, + WebsocketService, + AudioService, + SeoService, + OpenGraphService, + StorageService, + EnterpriseService, + LanguageService, + ThemeService, + ShortenStringPipe, + FiatShortenerPipe, + FiatCurrencyPipe, + CapAddressPipe, + DatePipe, + AppPreloadingStrategy, + ServicesApiServices, + PreloadService, + { provide: HTTP_INTERCEPTORS, useClass: HttpCacheInterceptor, multi: true }, + { provide: ZONE_SERVICE, useClass: ZoneService }, +]; @NgModule({ declarations: [ AppComponent, - AboutComponent, - MasterPageComponent, - TelevisionComponent, - BlockchainComponent, - StartComponent, - BlockchainBlocksComponent, - StatisticsComponent, - TransactionComponent, - BlockComponent, - TransactionsListComponent, - AddressComponent, - AmountComponent, - SearchFormComponent, - LatestBlocksComponent, - TimespanComponent, - AddressLabelsComponent, - MempoolBlocksComponent, - ChartistComponent, - FooterComponent, - MempoolBlockComponent, - FeeDistributionGraphComponent, - MempoolGraphComponent, - AssetComponent, - AssetsComponent, - MinerComponent, - StatusViewComponent, ], imports: [ BrowserModule, AppRoutingModule, HttpClientModule, - ReactiveFormsModule, BrowserAnimationsModule, - NgbButtonsModule, - NgbPaginationModule, - NgbDropdownModule, - InfiniteScrollModule, SharedModule, ], - providers: [ - ElectrsApiService, - StateService, - WebsocketService, - AudioService, - SeoService, - ], + providers: providers, bootstrap: [AppComponent] }) export class AppModule { } + +@NgModule({}) +export class MempoolSharedModule{ + static forRoot(): ModuleWithProviders { + return { + ngModule: AppModule, + providers: providers + }; + } +} diff --git a/frontend/src/app/app.preloading-strategy.ts b/frontend/src/app/app.preloading-strategy.ts new file mode 100644 index 0000000000..f62d072da2 --- /dev/null +++ b/frontend/src/app/app.preloading-strategy.ts @@ -0,0 +1,10 @@ +import { PreloadingStrategy, Route } from '@angular/router'; +import { Observable, timer, mergeMap, of } from 'rxjs'; + +export class AppPreloadingStrategy implements PreloadingStrategy { + preload(route: Route, load: Function): Observable { + return route.data && route.data.preload + ? timer(1500).pipe(mergeMap(() => load())) + : of(null); + } +} diff --git a/frontend/src/app/assets/assets.component.html b/frontend/src/app/assets/assets.component.html deleted file mode 100644 index e2c97c4003..0000000000 --- a/frontend/src/app/assets/assets.component.html +++ /dev/null @@ -1,75 +0,0 @@ -
-

Registered assets

-
- -
- -
-
- -
- -
-
-
- - - - - - - - - - - - - - - - - - - -
NameTickerIssuer domainAsset IDIssuance TX
{{ asset.name }}{{ asset.ticker }}{{ asset.entity.domain }}{{ asset.asset_id | shortenString : 13 }} {{ asset.issuance_txin.txid | shortenString : 13 }}
- -
- - - -
- - - - - - - - - - - - - - - - - - - - -
NameTickerIssuer domainAsset IDIssuance TX
- -
- - -
- Error loading assets data. -
- {{ error.error }} -
-
- -
- -
\ No newline at end of file diff --git a/frontend/src/app/assets/assets.component.spec.ts b/frontend/src/app/assets/assets.component.spec.ts deleted file mode 100644 index ed39b7122a..0000000000 --- a/frontend/src/app/assets/assets.component.spec.ts +++ /dev/null @@ -1,25 +0,0 @@ -import { async, ComponentFixture, TestBed } from '@angular/core/testing'; - -import { AssetsComponent } from './assets.component'; - -describe('AssetsComponent', () => { - let component: AssetsComponent; - let fixture: ComponentFixture; - - beforeEach(async(() => { - TestBed.configureTestingModule({ - declarations: [ AssetsComponent ] - }) - .compileComponents(); - })); - - beforeEach(() => { - fixture = TestBed.createComponent(AssetsComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); - - it('should create', () => { - expect(component).toBeTruthy(); - }); -}); diff --git a/frontend/src/app/assets/assets.component.ts b/frontend/src/app/assets/assets.component.ts deleted file mode 100644 index 3e003945d4..0000000000 --- a/frontend/src/app/assets/assets.component.ts +++ /dev/null @@ -1,89 +0,0 @@ -import { Component, OnInit } from '@angular/core'; -import { AssetsService } from '../services/assets.service'; -import { environment } from 'src/environments/environment'; -import { FormGroup, FormBuilder, Validators } from '@angular/forms'; -import { distinctUntilChanged } from 'rxjs/operators'; - -@Component({ - selector: 'app-assets', - templateUrl: './assets.component.html', - styleUrls: ['./assets.component.scss'] -}) -export class AssetsComponent implements OnInit { - nativeAssetId = environment.nativeAssetId; - assets: any[]; - assetsCache: any[]; - filteredAssets: any[]; - searchForm: FormGroup; - - isLoading = true; - error: any; - - page = 1; - itemsPerPage: number; - contentSpace = window.innerHeight - (250 + 200); - fiveItemsPxSize = 250; - - constructor( - private assetsService: AssetsService, - private formBuilder: FormBuilder, - ) { } - - ngOnInit() { - this.itemsPerPage = Math.max(Math.round(this.contentSpace / this.fiveItemsPxSize) * 5, 10); - - this.searchForm = this.formBuilder.group({ - searchText: [{ value: '', disabled: true }, Validators.required] - }); - - this.searchForm.get('searchText').valueChanges - .pipe( - distinctUntilChanged(), - ) - .subscribe((searchText) => { - this.page = 1; - if (searchText.length ) { - this.filteredAssets = this.assetsCache.filter((asset) => asset.name.toLowerCase().indexOf(searchText.toLowerCase()) > -1 - || asset.ticker.toLowerCase().indexOf(searchText.toLowerCase()) > -1); - this.assets = this.filteredAssets; - this.filteredAssets = this.filteredAssets.slice(0, this.itemsPerPage); - } else { - this.assets = this.assetsCache; - this.filteredAssets = this.assets.slice(0, this.itemsPerPage); - } - }); - - this.getAssets(); - } - - getAssets() { - this.assetsService.getAssetsJson$ - .subscribe((assets) => { - this.assets = Object.values(assets); - this.assets.push({ - name: 'Liquid Bitcoin', - ticker: 'L-BTC', - asset_id: this.nativeAssetId, - }); - this.assets = this.assets.sort((a: any, b: any) => a.name.localeCompare(b.name)); - this.assetsCache = this.assets; - this.searchForm.get('searchText').enable(); - this.filteredAssets = this.assets.slice(0, this.itemsPerPage); - this.isLoading = false; - }, - (error) => { - console.log(error); - this.error = error; - this.isLoading = false; - }); - } - - pageChange(page: number) { - const start = (page - 1) * this.itemsPerPage; - this.filteredAssets = this.assets.slice(start, this.itemsPerPage + start); - } - - trackByAsset(index: number, asset: any) { - return asset.asset_id; - } -} diff --git a/frontend/src/app/bisq/bisq-address/bisq-address.component.html b/frontend/src/app/bisq/bisq-address/bisq-address.component.html deleted file mode 100644 index 2413b90a00..0000000000 --- a/frontend/src/app/bisq/bisq-address/bisq-address.component.html +++ /dev/null @@ -1,106 +0,0 @@ -
-

Address

- - {{ addressString | shortenString : 24 }} - {{ addressString }} - - -
- -
- - -
- -
-
- - - - - - - - - - - - - - - -
Total received{{ totalReceived / 100 | number: '1.2-2' }} BSQ
Total sent{{ totalSent / 100 | number: '1.2-2' }} BSQ
Final balance{{ (totalReceived - totalSent) / 100 | number: '1.2-2' }} BSQ ()
-
-
-
-
- -
-
-
- -
- -
- -

{{ transactions.length | number }} transactions

- - - -
- - {{ tx.id | shortenString : 16 }} - {{ tx.id }} - -
- {{ tx.time | date:'yyyy-MM-dd HH:mm' }} -
-
-
- - - -
-
- -
- - - -
-
-
- - - - - - - - - - - - -
-
-
-
- -
-
-
- -
- - -
- Error loading address data. -
- {{ error.error }} -
-
- -
- -
\ No newline at end of file diff --git a/frontend/src/app/bisq/bisq-address/bisq-address.component.scss b/frontend/src/app/bisq/bisq-address/bisq-address.component.scss deleted file mode 100644 index c5961e4282..0000000000 --- a/frontend/src/app/bisq/bisq-address/bisq-address.component.scss +++ /dev/null @@ -1,23 +0,0 @@ -.qr-wrapper { - background-color: #FFF; - padding: 10px; - padding-bottom: 5px; - display: inline-block; - margin-right: 25px; -} - -@media (min-width: 576px) { - .qrcode-col { - text-align: right; - } -} -@media (max-width: 575.98px) { - .qrcode-col { - text-align: center; - } - - .qrcode-col > div { - margin-top: 20px; - margin-right: 0px; - } -} \ No newline at end of file diff --git a/frontend/src/app/bisq/bisq-address/bisq-address.component.ts b/frontend/src/app/bisq/bisq-address/bisq-address.component.ts deleted file mode 100644 index a82a31e582..0000000000 --- a/frontend/src/app/bisq/bisq-address/bisq-address.component.ts +++ /dev/null @@ -1,82 +0,0 @@ -import { Component, OnInit, OnDestroy } from '@angular/core'; -import { SeoService } from 'src/app/services/seo.service'; -import { switchMap, filter, catchError } from 'rxjs/operators'; -import { ParamMap, ActivatedRoute } from '@angular/router'; -import { Subscription, of } from 'rxjs'; -import { BisqTransaction } from '../bisq.interfaces'; -import { BisqApiService } from '../bisq-api.service'; - -@Component({ - selector: 'app-bisq-address', - templateUrl: './bisq-address.component.html', - styleUrls: ['./bisq-address.component.scss'] -}) -export class BisqAddressComponent implements OnInit, OnDestroy { - transactions: BisqTransaction[]; - addressString: string; - isLoadingAddress = true; - error: any; - mainSubscription: Subscription; - - totalReceived = 0; - totalSent = 0; - - constructor( - private route: ActivatedRoute, - private seoService: SeoService, - private bisqApiService: BisqApiService, - ) { } - - ngOnInit() { - this.mainSubscription = this.route.paramMap - .pipe( - switchMap((params: ParamMap) => { - this.error = undefined; - this.isLoadingAddress = true; - this.transactions = null; - document.body.scrollTo(0, 0); - this.addressString = params.get('id') || ''; - this.seoService.setTitle('Address: ' + this.addressString, true); - - return this.bisqApiService.getAddress$(this.addressString) - .pipe( - catchError((err) => { - this.isLoadingAddress = false; - this.error = err; - console.log(err); - return of(null); - }) - ); - }), - filter((transactions) => transactions !== null) - ) - .subscribe((transactions: BisqTransaction[]) => { - this.transactions = transactions; - this.updateChainStats(); - this.isLoadingAddress = false; - }, - (error) => { - console.log(error); - this.error = error; - this.isLoadingAddress = false; - }); - } - - updateChainStats() { - const shortenedAddress = this.addressString.substr(1); - - this.totalSent = this.transactions.reduce((acc, tx) => - acc + tx.inputs - .filter((input) => input.address === shortenedAddress) - .reduce((a, input) => a + input.bsqAmount, 0), 0); - - this.totalReceived = this.transactions.reduce((acc, tx) => - acc + tx.outputs - .filter((output) => output.address === shortenedAddress) - .reduce((a, output) => a + output.bsqAmount, 0), 0); - } - - ngOnDestroy() { - this.mainSubscription.unsubscribe(); - } -} diff --git a/frontend/src/app/bisq/bisq-api.service.ts b/frontend/src/app/bisq/bisq-api.service.ts deleted file mode 100644 index f5690d5eac..0000000000 --- a/frontend/src/app/bisq/bisq-api.service.ts +++ /dev/null @@ -1,41 +0,0 @@ -import { Injectable } from '@angular/core'; -import { HttpClient, HttpResponse } from '@angular/common/http'; -import { Observable } from 'rxjs'; -import { BisqTransaction, BisqBlock, BisqStats } from './bisq.interfaces'; - -const API_BASE_URL = '/bisq/api'; - -@Injectable({ - providedIn: 'root' -}) -export class BisqApiService { - apiBaseUrl: string; - - constructor( - private httpClient: HttpClient, - ) { } - - getStats$(): Observable { - return this.httpClient.get(API_BASE_URL + '/stats'); - } - - getTransaction$(txId: string): Observable { - return this.httpClient.get(API_BASE_URL + '/tx/' + txId); - } - - listTransactions$(start: number, length: number): Observable> { - return this.httpClient.get(API_BASE_URL + `/txs/${start}/${length}`, { observe: 'response' }); - } - - getBlock$(hash: string): Observable { - return this.httpClient.get(API_BASE_URL + '/block/' + hash); - } - - listBlocks$(start: number, length: number): Observable> { - return this.httpClient.get(API_BASE_URL + `/blocks/${start}/${length}`, { observe: 'response' }); - } - - getAddress$(address: string): Observable { - return this.httpClient.get(API_BASE_URL + '/address/' + address); - } -} diff --git a/frontend/src/app/bisq/bisq-block/bisq-block.component.html b/frontend/src/app/bisq/bisq-block/bisq-block.component.html deleted file mode 100644 index 4e1c7b95c3..0000000000 --- a/frontend/src/app/bisq/bisq-block/bisq-block.component.html +++ /dev/null @@ -1,108 +0,0 @@ -
- -
-

Block {{ blockHeight }}

-
- -
- - - -
-
-
- - - - - - - - - - -
Hash{{ block.hash | shortenString : 13 }}
Timestamp - {{ block.time | date:'yyyy-MM-dd HH:mm' }} -
- ( ago) -
-
-
- -
-
- -
- -
- -

{{ block.txs.length | number }} transactions

- - - -
- - {{ tx.id | shortenString : 16 }} - {{ tx.id }} - -
- {{ tx.time | date:'yyyy-MM-dd HH:mm' }} -
-
-
- - - -
-
- -
- - -
-
-
- - - - - - - - - - -
Hash
Timestamp
-
-
- - - - - - -
Previous hash
-
-
-
-
- - -
- -
- Error loading block -
- {{ error.status }}: {{ error.statusText }} -
-
- -
\ No newline at end of file diff --git a/frontend/src/app/bisq/bisq-block/bisq-block.component.scss b/frontend/src/app/bisq/bisq-block/bisq-block.component.scss deleted file mode 100644 index 0fc8e761ed..0000000000 --- a/frontend/src/app/bisq/bisq-block/bisq-block.component.scss +++ /dev/null @@ -1,10 +0,0 @@ - -.td-width { - width: 175px; -} - -@media (max-width: 767.98px) { - .td-width { - width: 140px; - } -} diff --git a/frontend/src/app/bisq/bisq-block/bisq-block.component.ts b/frontend/src/app/bisq/bisq-block/bisq-block.component.ts deleted file mode 100644 index 9ce3be8fb3..0000000000 --- a/frontend/src/app/bisq/bisq-block/bisq-block.component.ts +++ /dev/null @@ -1,98 +0,0 @@ -import { Component, OnInit, OnDestroy } from '@angular/core'; -import { BisqBlock } from 'src/app/bisq/bisq.interfaces'; -import { Location } from '@angular/common'; -import { BisqApiService } from '../bisq-api.service'; -import { ActivatedRoute, ParamMap, Router } from '@angular/router'; -import { Subscription, of } from 'rxjs'; -import { switchMap, catchError } from 'rxjs/operators'; -import { SeoService } from 'src/app/services/seo.service'; -import { ElectrsApiService } from 'src/app/services/electrs-api.service'; -import { HttpErrorResponse } from '@angular/common/http'; - -@Component({ - selector: 'app-bisq-block', - templateUrl: './bisq-block.component.html', - styleUrls: ['./bisq-block.component.scss'] -}) -export class BisqBlockComponent implements OnInit, OnDestroy { - block: BisqBlock; - subscription: Subscription; - blockHash = ''; - blockHeight = 0; - isLoading = true; - error: HttpErrorResponse | null; - - constructor( - private bisqApiService: BisqApiService, - private route: ActivatedRoute, - private seoService: SeoService, - private electrsApiService: ElectrsApiService, - private router: Router, - private location: Location, - ) { } - - ngOnInit(): void { - this.subscription = this.route.paramMap - .pipe( - switchMap((params: ParamMap) => { - const blockHash = params.get('id') || ''; - document.body.scrollTo(0, 0); - this.isLoading = true; - this.error = null; - if (history.state.data && history.state.data.blockHeight) { - this.blockHeight = history.state.data.blockHeight; - } - if (history.state.data && history.state.data.block) { - this.blockHeight = history.state.data.block.height; - return of(history.state.data.block); - } - - let isBlockHeight = false; - if (/^[0-9]+$/.test(blockHash)) { - isBlockHeight = true; - } else { - this.blockHash = blockHash; - } - - if (isBlockHeight) { - return this.electrsApiService.getBlockHashFromHeight$(parseInt(blockHash, 10)) - .pipe( - switchMap((hash) => { - if (!hash) { - return; - } - this.blockHash = hash; - this.location.replaceState( - this.router.createUrlTree(['/bisq/block/', hash]).toString() - ); - return this.bisqApiService.getBlock$(this.blockHash) - .pipe(catchError(this.caughtHttpError.bind(this))); - }), - catchError(this.caughtHttpError.bind(this)) - ); - } - - return this.bisqApiService.getBlock$(this.blockHash) - .pipe(catchError(this.caughtHttpError.bind(this))); - }) - ) - .subscribe((block: BisqBlock) => { - if (!block) { - return; - } - this.isLoading = false; - this.blockHeight = block.height; - this.seoService.setTitle('Block: #' + block.height + ': ' + block.hash, true); - this.block = block; - }); - } - - ngOnDestroy() { - this.subscription.unsubscribe(); - } - - caughtHttpError(err: HttpErrorResponse){ - this.error = err; - return of(null); - } -} diff --git a/frontend/src/app/bisq/bisq-blocks/bisq-blocks.component.html b/frontend/src/app/bisq/bisq-blocks/bisq-blocks.component.html deleted file mode 100644 index 48deff2dae..0000000000 --- a/frontend/src/app/bisq/bisq-blocks/bisq-blocks.component.html +++ /dev/null @@ -1,36 +0,0 @@ -
-

Blocks

-
- -
- -
- - - - - - - - - - - - - - - -
HeightConfirmedTotal SentTransactions
{{ block.height }} ago{{ calculateTotalOutput(block) / 100 | number: '1.2-2' }} BSQ{{ block.txs.length }}
-
- -
- - - -
- - - - - - diff --git a/frontend/src/app/bisq/bisq-blocks/bisq-blocks.component.ts b/frontend/src/app/bisq/bisq-blocks/bisq-blocks.component.ts deleted file mode 100644 index 2c1631de7d..0000000000 --- a/frontend/src/app/bisq/bisq-blocks/bisq-blocks.component.ts +++ /dev/null @@ -1,71 +0,0 @@ -import { Component, OnInit } from '@angular/core'; -import { BisqApiService } from '../bisq-api.service'; -import { switchMap, tap } from 'rxjs/operators'; -import { Subject } from 'rxjs'; -import { BisqBlock, BisqOutput, BisqTransaction } from '../bisq.interfaces'; -import { SeoService } from 'src/app/services/seo.service'; - -@Component({ - selector: 'app-bisq-blocks', - templateUrl: './bisq-blocks.component.html', - styleUrls: ['./bisq-blocks.component.scss'] -}) -export class BisqBlocksComponent implements OnInit { - blocks: BisqBlock[]; - totalCount: number; - page = 1; - itemsPerPage: number; - contentSpace = window.innerHeight - (165 + 75); - fiveItemsPxSize = 250; - loadingItems: number[]; - isLoading = true; - // @ts-ignore - paginationSize: 'sm' | 'lg' = 'md'; - paginationMaxSize = 10; - - pageSubject$ = new Subject(); - - constructor( - private bisqApiService: BisqApiService, - private seoService: SeoService, - ) { } - - ngOnInit(): void { - this.seoService.setTitle('Blocks', true); - this.itemsPerPage = Math.max(Math.round(this.contentSpace / this.fiveItemsPxSize) * 5, 10); - this.loadingItems = Array(this.itemsPerPage); - if (document.body.clientWidth < 768) { - this.paginationSize = 'sm'; - this.paginationMaxSize = 3; - } - - this.pageSubject$ - .pipe( - tap(() => this.isLoading = true), - switchMap((page) => this.bisqApiService.listBlocks$((page - 1) * this.itemsPerPage, this.itemsPerPage)) - ) - .subscribe((response) => { - this.isLoading = false; - this.blocks = response.body; - this.totalCount = parseInt(response.headers.get('x-total-count'), 10); - }, (error) => { - console.log(error); - }); - - this.pageSubject$.next(1); - } - - calculateTotalOutput(block: BisqBlock): number { - return block.txs.reduce((a: number, tx: BisqTransaction) => - a + tx.outputs.reduce((acc: number, output: BisqOutput) => acc + output.bsqAmount, 0), 0 - ); - } - - trackByFn(index: number) { - return index; - } - - pageChange(page: number) { - this.pageSubject$.next(page); - } -} diff --git a/frontend/src/app/bisq/bisq-explorer/bisq-explorer.component.ts b/frontend/src/app/bisq/bisq-explorer/bisq-explorer.component.ts deleted file mode 100644 index bb9a378096..0000000000 --- a/frontend/src/app/bisq/bisq-explorer/bisq-explorer.component.ts +++ /dev/null @@ -1,18 +0,0 @@ -import { Component, OnInit } from '@angular/core'; -import { WebsocketService } from 'src/app/services/websocket.service'; - -@Component({ - selector: 'app-bisq-explorer', - templateUrl: './bisq-explorer.component.html', - styleUrls: ['./bisq-explorer.component.scss'] -}) -export class BisqExplorerComponent implements OnInit { - - constructor( - private websocketService: WebsocketService, - ) { } - - ngOnInit(): void { - this.websocketService.want(['blocks']); - } -} diff --git a/frontend/src/app/bisq/bisq-icon/bisq-icon.component.html b/frontend/src/app/bisq/bisq-icon/bisq-icon.component.html deleted file mode 100644 index 5ea603892c..0000000000 --- a/frontend/src/app/bisq/bisq-icon/bisq-icon.component.html +++ /dev/null @@ -1 +0,0 @@ - diff --git a/frontend/src/app/bisq/bisq-icon/bisq-icon.component.ts b/frontend/src/app/bisq/bisq-icon/bisq-icon.component.ts deleted file mode 100644 index 455b6b2efd..0000000000 --- a/frontend/src/app/bisq/bisq-icon/bisq-icon.component.ts +++ /dev/null @@ -1,81 +0,0 @@ -import { Component, ChangeDetectionStrategy, Input, OnChanges } from '@angular/core'; -import { IconPrefix, IconName } from '@fortawesome/fontawesome-common-types'; - -@Component({ - selector: 'app-bisq-icon', - templateUrl: './bisq-icon.component.html', - styleUrls: ['./bisq-icon.component.scss'], - changeDetection: ChangeDetectionStrategy.OnPush, -}) -export class BisqIconComponent implements OnChanges { - @Input() txType: string; - - iconProp: [IconPrefix, IconName] = ['fas', 'leaf']; - color: string; - - constructor() { } - - ngOnChanges() { - switch (this.txType) { - case 'UNVERIFIED': - this.iconProp[1] = 'question'; - this.color = 'ffac00'; - break; - case 'INVALID': - this.iconProp[1] = 'exclamation-triangle'; - this.color = 'ff4500'; - break; - case 'GENESIS': - this.iconProp[1] = 'rocket'; - this.color = '25B135'; - break; - case 'TRANSFER_BSQ': - this.iconProp[1] = 'retweet'; - this.color = 'a3a3a3'; - break; - case 'PAY_TRADE_FEE': - this.iconProp[1] = 'leaf'; - this.color = '689f43'; - break; - case 'PROPOSAL': - this.iconProp[1] = 'file-alt'; - this.color = '6c8b3b'; - break; - case 'COMPENSATION_REQUEST': - this.iconProp[1] = 'money-bill'; - this.color = '689f43'; - break; - case 'REIMBURSEMENT_REQUEST': - this.iconProp[1] = 'money-bill'; - this.color = '04a908'; - break; - case 'BLIND_VOTE': - this.iconProp[1] = 'eye-slash'; - this.color = '07579a'; - break; - case 'VOTE_REVEAL': - this.iconProp[1] = 'eye'; - this.color = '4AC5FF'; - break; - case 'LOCKUP': - this.iconProp[1] = 'lock'; - this.color = '0056c4'; - break; - case 'UNLOCK': - this.iconProp[1] = 'lock-open'; - this.color = '1d965f'; - break; - case 'ASSET_LISTING_FEE': - this.iconProp[1] = 'file-alt'; - this.color = '6c8b3b'; - break; - case 'PROOF_OF_BURN': - this.iconProp[1] = 'file-alt'; - this.color = '6c8b3b'; - break; - default: - this.iconProp[1] = 'question'; - this.color = 'ffac00'; - } - } -} diff --git a/frontend/src/app/bisq/bisq-stats/bisq-stats.component.html b/frontend/src/app/bisq/bisq-stats/bisq-stats.component.html deleted file mode 100644 index b34cc17ceb..0000000000 --- a/frontend/src/app/bisq/bisq-stats/bisq-stats.component.html +++ /dev/null @@ -1,90 +0,0 @@ -
-

BSQ Statistics

-
- -
- -
-
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
PropertyValue
Existing amount{{ (stats.minted - stats.burnt) / 100 | number: '1.2-2' }} BSQ
Minted amount{{ stats.minted | number: '1.2-2' }} BSQ
Burnt amount{{ stats.burnt | number: '1.2-2' }} BSQ
Addresses{{ stats.addresses | number }}
Unspent TXOs{{ stats.unspent_txos | number }}
Spent TXOs{{ stats.spent_txos | number }}
Price
Market cap
- -
-
-
-
- - - - - Existing amount - - - - Minted amount - - - - Burnt amount - - - - Addresses - - - - Unspent TXOs - - - - Spent TXOs - - - - Price - - - - Market cap - - - - \ No newline at end of file diff --git a/frontend/src/app/bisq/bisq-stats/bisq-stats.component.scss b/frontend/src/app/bisq/bisq-stats/bisq-stats.component.scss deleted file mode 100644 index e1f02094fe..0000000000 --- a/frontend/src/app/bisq/bisq-stats/bisq-stats.component.scss +++ /dev/null @@ -1,9 +0,0 @@ -.td-width { - width: 250px; -} - -@media (max-width: 767.98px) { - .td-width { - width: 175px; - } -} diff --git a/frontend/src/app/bisq/bisq-stats/bisq-stats.component.ts b/frontend/src/app/bisq/bisq-stats/bisq-stats.component.ts deleted file mode 100644 index 787cad58c6..0000000000 --- a/frontend/src/app/bisq/bisq-stats/bisq-stats.component.ts +++ /dev/null @@ -1,38 +0,0 @@ -import { Component, OnInit } from '@angular/core'; -import { BisqApiService } from '../bisq-api.service'; -import { BisqStats } from '../bisq.interfaces'; -import { SeoService } from 'src/app/services/seo.service'; -import { StateService } from 'src/app/services/state.service'; - -@Component({ - selector: 'app-bisq-stats', - templateUrl: './bisq-stats.component.html', - styleUrls: ['./bisq-stats.component.scss'] -}) -export class BisqStatsComponent implements OnInit { - isLoading = true; - stats: BisqStats; - price: number; - - constructor( - private bisqApiService: BisqApiService, - private seoService: SeoService, - private stateService: StateService, - ) { } - - ngOnInit() { - this.seoService.setTitle('BSQ Statistics', false); - - this.stateService.bsqPrice$ - .subscribe((bsqPrice) => { - this.price = bsqPrice; - }); - - this.bisqApiService.getStats$() - .subscribe((stats) => { - this.isLoading = false; - this.stats = stats; - }); - } - -} diff --git a/frontend/src/app/bisq/bisq-transaction-details/bisq-transaction-details.component.html b/frontend/src/app/bisq/bisq-transaction-details/bisq-transaction-details.component.html deleted file mode 100644 index fd605fb8d2..0000000000 --- a/frontend/src/app/bisq/bisq-transaction-details/bisq-transaction-details.component.html +++ /dev/null @@ -1,36 +0,0 @@ -
-
-
- - - - - - - - - - - - - - - -
Inputs{{ totalInput / 100 | number: '1.2-2' }} BSQ
Outputs{{ totalOutput / 100 | number: '1.2-2' }} BSQ
Issuance{{ totalIssued / 100 | number: '1.2-2' }} BSQ
-
-
- - - - - - - - - - - -
Type {{ tx.txTypeDisplayString }}
Version{{ tx.txVersion }}
-
-
-
\ No newline at end of file diff --git a/frontend/src/app/bisq/bisq-transaction-details/bisq-transaction-details.component.scss b/frontend/src/app/bisq/bisq-transaction-details/bisq-transaction-details.component.scss deleted file mode 100644 index ee64d3473c..0000000000 --- a/frontend/src/app/bisq/bisq-transaction-details/bisq-transaction-details.component.scss +++ /dev/null @@ -1,11 +0,0 @@ -@media (max-width: 767.98px) { - .td-width { - width: 150px; - } - .mobile-even tr:nth-of-type(even) { - background-color: #181b2d; - } - .mobile-even tr:nth-of-type(odd) { - background-color: inherit; - } -} \ No newline at end of file diff --git a/frontend/src/app/bisq/bisq-transaction-details/bisq-transaction-details.component.ts b/frontend/src/app/bisq/bisq-transaction-details/bisq-transaction-details.component.ts deleted file mode 100644 index d10d0507e1..0000000000 --- a/frontend/src/app/bisq/bisq-transaction-details/bisq-transaction-details.component.ts +++ /dev/null @@ -1,26 +0,0 @@ -import { Component, ChangeDetectionStrategy, Input, OnChanges } from '@angular/core'; -import { BisqTransaction } from 'src/app/bisq/bisq.interfaces'; - -@Component({ - selector: 'app-bisq-transaction-details', - templateUrl: './bisq-transaction-details.component.html', - styleUrls: ['./bisq-transaction-details.component.scss'], - changeDetection: ChangeDetectionStrategy.OnPush, -}) -export class BisqTransactionDetailsComponent implements OnChanges { - @Input() tx: BisqTransaction; - - totalInput: number; - totalOutput: number; - totalIssued: number; - - constructor() { } - - ngOnChanges() { - this.totalInput = this.tx.inputs.filter((input) => input.isVerified).reduce((acc, input) => acc + input.bsqAmount, 0); - this.totalOutput = this.tx.outputs.filter((output) => output.isVerified).reduce((acc, output) => acc + output.bsqAmount, 0); - this.totalIssued = this.tx.outputs - .filter((output) => output.isVerified && output.txOutputType === 'ISSUANCE_CANDIDATE_OUTPUT') - .reduce((acc, output) => acc + output.bsqAmount, 0); - } -} diff --git a/frontend/src/app/bisq/bisq-transaction/bisq-transaction.component.html b/frontend/src/app/bisq/bisq-transaction/bisq-transaction.component.html deleted file mode 100644 index b2a949321c..0000000000 --- a/frontend/src/app/bisq/bisq-transaction/bisq-transaction.component.html +++ /dev/null @@ -1,164 +0,0 @@ -
- -

Transaction

- - - - - - -
- -
-
-
- - - - - - - - - - - -
Included in block - {{ bisqTx.blockHeight }} - ( ago) -
Features - - - - -
-
-
- - - - - - - - - - - - - -
Burnt - {{ bisqTx.burntFee / 100 | number: '1.2-2' }} BSQ () -
Fee per vByte - {{ tx.fee / (tx.weight / 4) | number : '1.1-1' }} sat/vB -   - -
-
- -
-
- -
- -

Details

- - - - -
- -

Inputs & Outputs

- - - -
- -
- - - -
- -
-
-
- - - - - - - -
-
-
- - - - - - - -
-
-
-
- -
- -

Details

-
- - - - - - - - - - - - - - -
-
- -
- -

Inputs & Outputs

- -
-
- - - - - - - -
-
-
- -
- - -
- -
- Error loading transaction -

- {{ error.status }}: {{ error.statusText }} -
-
- -
\ No newline at end of file diff --git a/frontend/src/app/bisq/bisq-transaction/bisq-transaction.component.scss b/frontend/src/app/bisq/bisq-transaction/bisq-transaction.component.scss deleted file mode 100644 index 35000b90e1..0000000000 --- a/frontend/src/app/bisq/bisq-transaction/bisq-transaction.component.scss +++ /dev/null @@ -1,9 +0,0 @@ -.td-width { - width: 175px; -} - -@media (max-width: 767.98px) { - .td-width { - width: 150px; - } -} \ No newline at end of file diff --git a/frontend/src/app/bisq/bisq-transaction/bisq-transaction.component.ts b/frontend/src/app/bisq/bisq-transaction/bisq-transaction.component.ts deleted file mode 100644 index 6da3c369f9..0000000000 --- a/frontend/src/app/bisq/bisq-transaction/bisq-transaction.component.ts +++ /dev/null @@ -1,118 +0,0 @@ -import { Component, OnInit, OnDestroy } from '@angular/core'; -import { ActivatedRoute, ParamMap, Router } from '@angular/router'; -import { BisqTransaction } from 'src/app/bisq/bisq.interfaces'; -import { switchMap, map, catchError } from 'rxjs/operators'; -import { of, Observable, Subscription } from 'rxjs'; -import { StateService } from 'src/app/services/state.service'; -import { Block, Transaction } from 'src/app/interfaces/electrs.interface'; -import { BisqApiService } from '../bisq-api.service'; -import { SeoService } from 'src/app/services/seo.service'; -import { ElectrsApiService } from 'src/app/services/electrs-api.service'; -import { HttpErrorResponse } from '@angular/common/http'; - -@Component({ - selector: 'app-bisq-transaction', - templateUrl: './bisq-transaction.component.html', - styleUrls: ['./bisq-transaction.component.scss'] -}) -export class BisqTransactionComponent implements OnInit, OnDestroy { - bisqTx: BisqTransaction; - tx: Transaction; - latestBlock$: Observable; - txId: string; - price: number; - isLoading = true; - isLoadingTx = true; - error = null; - subscription: Subscription; - - constructor( - private route: ActivatedRoute, - private bisqApiService: BisqApiService, - private electrsApiService: ElectrsApiService, - private stateService: StateService, - private seoService: SeoService, - private router: Router, - ) { } - - ngOnInit(): void { - this.subscription = this.route.paramMap.pipe( - switchMap((params: ParamMap) => { - this.isLoading = true; - this.isLoadingTx = true; - this.error = null; - document.body.scrollTo(0, 0); - this.txId = params.get('id') || ''; - this.seoService.setTitle('Transaction: ' + this.txId, true); - if (history.state.data) { - return of(history.state.data); - } - return this.bisqApiService.getTransaction$(this.txId) - .pipe( - catchError((bisqTxError: HttpErrorResponse) => { - if (bisqTxError.status === 404) { - return this.electrsApiService.getTransaction$(this.txId) - .pipe( - map((tx) => { - if (tx.status.confirmed) { - this.error = { - status: 200, - statusText: 'Transaction is confirmed but not available in the Bisq database, please try reloading this page.' - }; - return null; - } - return tx; - }), - catchError((txError: HttpErrorResponse) => { - console.log(txError); - this.error = txError; - return of(null); - }) - ); - } - this.error = bisqTxError; - return of(null); - }) - ); - }), - switchMap((tx) => { - if (!tx) { - return of(null); - } - - if (tx.version) { - this.router.navigate(['/tx/', this.txId], { state: { data: tx, bsqTx: true }}); - return of(null); - } - - this.bisqTx = tx; - this.isLoading = false; - - return this.electrsApiService.getTransaction$(this.txId); - }), - ) - .subscribe((tx) => { - this.isLoadingTx = false; - - if (!tx) { - return; - } - - this.tx = tx; - }, - (error) => { - this.error = error; - }); - - this.latestBlock$ = this.stateService.blocks$.pipe(map((([block]) => block))); - - this.stateService.bsqPrice$ - .subscribe((bsqPrice) => { - this.price = bsqPrice; - }); - } - - ngOnDestroy() { - this.subscription.unsubscribe(); - } -} diff --git a/frontend/src/app/bisq/bisq-transactions/bisq-transactions.component.html b/frontend/src/app/bisq/bisq-transactions/bisq-transactions.component.html deleted file mode 100644 index 7cfa7a4078..0000000000 --- a/frontend/src/app/bisq/bisq-transactions/bisq-transactions.component.html +++ /dev/null @@ -1,47 +0,0 @@ -
-

Transactions

-
- -
- - - - - - - - - - - - - - - - - - -
TransactionTypeAmountConfirmedHeight
{{ tx.id | slice : 0 : 8 }} - - {{ tx.txTypeDisplayString }} - - - - {{ tx.burntFee / 100 | number: '1.2-2' }} BSQ - - - {{ calculateTotalOutput(tx.outputs) / 100 | number: '1.2-2' }} BSQ - - ago{{ tx.blockHeight }}
- -
- - - -
- - - - - - \ No newline at end of file diff --git a/frontend/src/app/bisq/bisq-transactions/bisq-transactions.component.ts b/frontend/src/app/bisq/bisq-transactions/bisq-transactions.component.ts deleted file mode 100644 index 96977ce51c..0000000000 --- a/frontend/src/app/bisq/bisq-transactions/bisq-transactions.component.ts +++ /dev/null @@ -1,71 +0,0 @@ -import { Component, OnInit } from '@angular/core'; -import { BisqTransaction, BisqOutput } from '../bisq.interfaces'; -import { Subject } from 'rxjs'; -import { switchMap, tap } from 'rxjs/operators'; -import { BisqApiService } from '../bisq-api.service'; -import { SeoService } from 'src/app/services/seo.service'; - -@Component({ - selector: 'app-bisq-transactions', - templateUrl: './bisq-transactions.component.html', - styleUrls: ['./bisq-transactions.component.scss'] -}) -export class BisqTransactionsComponent implements OnInit { - transactions: BisqTransaction[]; - totalCount: number; - page = 1; - itemsPerPage: number; - contentSpace = window.innerHeight - (165 + 75); - fiveItemsPxSize = 250; - isLoading = true; - loadingItems: number[]; - pageSubject$ = new Subject(); - - // @ts-ignore - paginationSize: 'sm' | 'lg' = 'md'; - paginationMaxSize = 10; - - constructor( - private bisqApiService: BisqApiService, - private seoService: SeoService, - ) { } - - ngOnInit(): void { - this.seoService.setTitle('Transactions', true); - - this.itemsPerPage = Math.max(Math.round(this.contentSpace / this.fiveItemsPxSize) * 5, 10); - this.loadingItems = Array(this.itemsPerPage); - - if (document.body.clientWidth < 768) { - this.paginationSize = 'sm'; - this.paginationMaxSize = 3; - } - - this.pageSubject$ - .pipe( - tap(() => this.isLoading = true), - switchMap((page) => this.bisqApiService.listTransactions$((page - 1) * this.itemsPerPage, this.itemsPerPage)) - ) - .subscribe((response) => { - this.isLoading = false; - this.transactions = response.body; - this.totalCount = parseInt(response.headers.get('x-total-count'), 10); - }, (error) => { - console.log(error); - }); - - this.pageSubject$.next(1); - } - - pageChange(page: number) { - this.pageSubject$.next(page); - } - - calculateTotalOutput(outputs: BisqOutput[]): number { - return outputs.reduce((acc: number, output: BisqOutput) => acc + output.bsqAmount, 0); - } - - trackByFn(index: number) { - return index; - } -} diff --git a/frontend/src/app/bisq/bisq-transfers/bisq-transfers.component.html b/frontend/src/app/bisq/bisq-transfers/bisq-transfers.component.html deleted file mode 100644 index d2da552f2e..0000000000 --- a/frontend/src/app/bisq/bisq-transfers/bisq-transfers.component.html +++ /dev/null @@ -1,77 +0,0 @@ -
- - -
-
- Burnt: {{ tx.burntFee / 100 | number: '1.2-2' }} BSQ () -
- -
- - -   - - -
-
-
- -
\ No newline at end of file diff --git a/frontend/src/app/bisq/bisq-transfers/bisq-transfers.component.scss b/frontend/src/app/bisq/bisq-transfers/bisq-transfers.component.scss deleted file mode 100644 index 3f78768ca0..0000000000 --- a/frontend/src/app/bisq/bisq-transfers/bisq-transfers.component.scss +++ /dev/null @@ -1,84 +0,0 @@ -.arrow-td { - width: 22px; -} - -.arrow { - display: inline-block!important; - position: relative; - width: 14px; - height: 22px; - box-sizing: content-box -} - -.arrow:before { - position: absolute; - content: ''; - margin: auto; - top: 0; - bottom: 0; - left: 0; - right: calc(-1*30px/3); - width: 0; - height: 0; - border-top: 6.66px solid transparent; - border-bottom: 6.66px solid transparent -} - -.arrow:after { - position: absolute; - content: ''; - margin: auto; - top: 0; - bottom: 0; - left: 0; - right: calc(30px/6); - width: calc(30px/3); - height: calc(20px/3); - background: rgba(0, 0, 0, 0); -} - -.arrow.green:before { - border-left: 10px solid #28a745; -} -.arrow.green:after { - background-color:#28a745; -} - -.arrow.red:before { - border-left: 10px solid #dc3545; -} -.arrow.red:after { - background-color:#dc3545; -} - -.arrow.grey:before { - border-left: 10px solid #6c757d; -} - -.arrow.grey:after { - background-color:#6c757d; -} - -.scriptmessage { - max-width: 280px; - overflow: hidden; - text-overflow: ellipsis; - vertical-align: middle; -} - -.scriptmessage.longer { - max-width: 500px; -} - -@media (max-width: 767.98px) { - .mobile-bottomcol { - margin-top: 15px; - } - - .scriptmessage { - max-width: 90px !important; - } - .scriptmessage.longer { - max-width: 280px !important; - } -} \ No newline at end of file diff --git a/frontend/src/app/bisq/bisq-transfers/bisq-transfers.component.ts b/frontend/src/app/bisq/bisq-transfers/bisq-transfers.component.ts deleted file mode 100644 index be391305c7..0000000000 --- a/frontend/src/app/bisq/bisq-transfers/bisq-transfers.component.ts +++ /dev/null @@ -1,42 +0,0 @@ -import { Component, OnInit, ChangeDetectionStrategy, Input, OnChanges } from '@angular/core'; -import { BisqTransaction } from 'src/app/bisq/bisq.interfaces'; -import { StateService } from 'src/app/services/state.service'; -import { map } from 'rxjs/operators'; -import { Observable } from 'rxjs'; -import { Block } from 'src/app/interfaces/electrs.interface'; - -@Component({ - selector: 'app-bisq-transfers', - templateUrl: './bisq-transfers.component.html', - styleUrls: ['./bisq-transfers.component.scss'], - changeDetection: ChangeDetectionStrategy.OnPush -}) -export class BisqTransfersComponent implements OnInit, OnChanges { - @Input() tx: BisqTransaction; - @Input() showConfirmations = false; - - totalOutput: number; - latestBlock$: Observable; - - constructor( - private stateService: StateService, - ) { } - - trackByIndexFn(index: number) { - return index; - } - - ngOnInit() { - this.latestBlock$ = this.stateService.blocks$.pipe(map(([block]) => block)); - } - - ngOnChanges() { - this.totalOutput = this.tx.outputs.filter((output) => output.isVerified).reduce((acc, output) => acc + output.bsqAmount, 0);; - } - - switchCurrency() { - const oldvalue = !this.stateService.viewFiat$.value; - this.stateService.viewFiat$.next(oldvalue); - } - -} diff --git a/frontend/src/app/bisq/bisq.interfaces.ts b/frontend/src/app/bisq/bisq.interfaces.ts deleted file mode 100644 index 710bada2a3..0000000000 --- a/frontend/src/app/bisq/bisq.interfaces.ts +++ /dev/null @@ -1,82 +0,0 @@ - -export interface BisqBlocks { - chainHeight: number; - blocks: BisqBlock[]; -} - -export interface BisqBlock { - height: number; - time: number; - hash: string; - previousBlockHash: string; - txs: BisqTransaction[]; -} - -export interface BisqTransaction { - txVersion: string; - id: string; - blockHeight: number; - blockHash: string; - time: number; - inputs: BisqInput[]; - outputs: BisqOutput[]; - txType: string; - txTypeDisplayString: string; - burntFee: number; - invalidatedBsq: number; - unlockBlockHeight: number; -} - -interface BisqInput { - spendingTxOutputIndex: number; - spendingTxId: string; - bsqAmount: number; - isVerified: boolean; - address: string; - time: number; -} - -export interface BisqOutput { - txVersion: string; - txId: string; - index: number; - bsqAmount: number; - btcAmount: number; - height: number; - isVerified: boolean; - burntFee: number; - invalidatedBsq: number; - address: string; - scriptPubKey: BisqScriptPubKey; - spentInfo?: SpentInfo; - time: any; - txType: string; - txTypeDisplayString: string; - txOutputType: string; - txOutputTypeDisplayString: string; - lockTime: number; - isUnspent: boolean; - opReturn?: string; -} - -export interface BisqStats { - minted: number; - burnt: number; - addresses: number; - unspent_txos: number; - spent_txos: number; -} - -interface BisqScriptPubKey { - addresses: string[]; - asm: string; - hex: string; - reqSigs: number; - type: string; -} - -interface SpentInfo { - height: number; - inputIndex: number; - txId: string; -} diff --git a/frontend/src/app/bisq/bisq.module.ts b/frontend/src/app/bisq/bisq.module.ts deleted file mode 100644 index 29dd1c0c02..0000000000 --- a/frontend/src/app/bisq/bisq.module.ts +++ /dev/null @@ -1,60 +0,0 @@ -import { NgModule } from '@angular/core'; -import { BisqRoutingModule } from './bisq.routing.module'; -import { SharedModule } from '../shared/shared.module'; -import { BisqTransactionsComponent } from './bisq-transactions/bisq-transactions.component'; -import { NgbPaginationModule } from '@ng-bootstrap/ng-bootstrap'; -import { BisqTransactionComponent } from './bisq-transaction/bisq-transaction.component'; -import { BisqBlockComponent } from './bisq-block/bisq-block.component'; -import { BisqIconComponent } from './bisq-icon/bisq-icon.component'; -import { BisqTransactionDetailsComponent } from './bisq-transaction-details/bisq-transaction-details.component'; -import { BisqTransfersComponent } from './bisq-transfers/bisq-transfers.component'; -import { FontAwesomeModule, FaIconLibrary } from '@fortawesome/angular-fontawesome'; -import { faLeaf, faQuestion, faExclamationTriangle, faRocket, faRetweet, faFileAlt, faMoneyBill, - faEye, faEyeSlash, faLock, faLockOpen } from '@fortawesome/free-solid-svg-icons'; -import { BisqBlocksComponent } from './bisq-blocks/bisq-blocks.component'; -import { BisqExplorerComponent } from './bisq-explorer/bisq-explorer.component'; -import { BisqApiService } from './bisq-api.service'; -import { BisqAddressComponent } from './bisq-address/bisq-address.component'; -import { BisqStatsComponent } from './bisq-stats/bisq-stats.component'; -import { BsqAmountComponent } from './bsq-amount/bsq-amount.component'; - -@NgModule({ - declarations: [ - BisqTransactionsComponent, - BisqTransactionComponent, - BisqBlockComponent, - BisqTransactionComponent, - BisqIconComponent, - BisqTransactionDetailsComponent, - BisqTransfersComponent, - BisqBlocksComponent, - BisqExplorerComponent, - BisqAddressComponent, - BisqStatsComponent, - BsqAmountComponent, - ], - imports: [ - BisqRoutingModule, - SharedModule, - NgbPaginationModule, - FontAwesomeModule, - ], - providers: [ - BisqApiService, - ] -}) -export class BisqModule { - constructor(library: FaIconLibrary) { - library.addIcons(faQuestion); - library.addIcons(faExclamationTriangle); - library.addIcons(faRocket); - library.addIcons(faRetweet); - library.addIcons(faLeaf); - library.addIcons(faFileAlt); - library.addIcons(faMoneyBill); - library.addIcons(faEye); - library.addIcons(faEyeSlash); - library.addIcons(faLock); - library.addIcons(faLockOpen); - } -} diff --git a/frontend/src/app/bisq/bisq.routing.module.ts b/frontend/src/app/bisq/bisq.routing.module.ts deleted file mode 100644 index fdac7de60e..0000000000 --- a/frontend/src/app/bisq/bisq.routing.module.ts +++ /dev/null @@ -1,59 +0,0 @@ -import { NgModule } from '@angular/core'; -import { RouterModule, Routes } from '@angular/router'; -import { AboutComponent } from '../components/about/about.component'; -import { AddressComponent } from '../components/address/address.component'; -import { BisqTransactionsComponent } from './bisq-transactions/bisq-transactions.component'; -import { BisqTransactionComponent } from './bisq-transaction/bisq-transaction.component'; -import { BisqBlockComponent } from './bisq-block/bisq-block.component'; -import { BisqBlocksComponent } from './bisq-blocks/bisq-blocks.component'; -import { BisqExplorerComponent } from './bisq-explorer/bisq-explorer.component'; -import { BisqAddressComponent } from './bisq-address/bisq-address.component'; -import { BisqStatsComponent } from './bisq-stats/bisq-stats.component'; - -const routes: Routes = [ - { - path: '', - component: BisqExplorerComponent, - children: [ - { - path: '', - component: BisqTransactionsComponent - }, - { - path: 'tx/:id', - component: BisqTransactionComponent - }, - { - path: 'blocks', - children: [], - component: BisqBlocksComponent - }, - { - path: 'block/:id', - component: BisqBlockComponent, - }, - { - path: 'address/:id', - component: BisqAddressComponent, - }, - { - path: 'stats', - component: BisqStatsComponent, - }, - { - path: 'about', - component: AboutComponent, - }, - { - path: '**', - redirectTo: '' - } - ] - } -]; - -@NgModule({ - imports: [RouterModule.forChild(routes)], - exports: [RouterModule] -}) -export class BisqRoutingModule { } diff --git a/frontend/src/app/bisq/bsq-amount/bsq-amount.component.html b/frontend/src/app/bisq/bsq-amount/bsq-amount.component.html deleted file mode 100644 index f5de4cea6a..0000000000 --- a/frontend/src/app/bisq/bsq-amount/bsq-amount.component.html +++ /dev/null @@ -1,6 +0,0 @@ - - {{ conversions.USD * bsq / 100 * (bsqPrice$ | async) / 100000000 | currency:'USD':'symbol':'1.2-2' }} - - - {{ bsq / 100 | number : digitsInfo }} BSQ - diff --git a/frontend/src/app/bisq/bsq-amount/bsq-amount.component.scss b/frontend/src/app/bisq/bsq-amount/bsq-amount.component.scss deleted file mode 100644 index 843bd58b6c..0000000000 --- a/frontend/src/app/bisq/bsq-amount/bsq-amount.component.scss +++ /dev/null @@ -1,3 +0,0 @@ -.green-color { - color: #3bcc49; -} diff --git a/frontend/src/app/bisq/bsq-amount/bsq-amount.component.ts b/frontend/src/app/bisq/bsq-amount/bsq-amount.component.ts deleted file mode 100644 index 263b9d7f77..0000000000 --- a/frontend/src/app/bisq/bsq-amount/bsq-amount.component.ts +++ /dev/null @@ -1,30 +0,0 @@ -import { Component, OnInit, ChangeDetectionStrategy, Input } from '@angular/core'; -import { StateService } from 'src/app/services/state.service'; -import { Observable } from 'rxjs'; - -@Component({ - selector: 'app-bsq-amount', - templateUrl: './bsq-amount.component.html', - styleUrls: ['./bsq-amount.component.scss'], - changeDetection: ChangeDetectionStrategy.OnPush, -}) -export class BsqAmountComponent implements OnInit { - conversions$: Observable; - viewFiat$: Observable; - bsqPrice$: Observable; - - @Input() bsq: number; - @Input() digitsInfo = '1.2-2'; - @Input() forceFiat = false; - @Input() green = false; - - constructor( - private stateService: StateService, - ) { } - - ngOnInit() { - this.viewFiat$ = this.stateService.viewFiat$.asObservable(); - this.conversions$ = this.stateService.conversions$.asObservable(); - this.bsqPrice$ = this.stateService.bsqPrice$; - } -} diff --git a/frontend/src/app/bitcoin-graphs.module.ts b/frontend/src/app/bitcoin-graphs.module.ts new file mode 100644 index 0000000000..7107432450 --- /dev/null +++ b/frontend/src/app/bitcoin-graphs.module.ts @@ -0,0 +1,37 @@ +import { NgModule } from '@angular/core'; +import { CommonModule } from '@angular/common'; +import { Routes, RouterModule } from '@angular/router'; +import { MasterPageComponent } from './components/master-page/master-page.component'; + +const routes: Routes = [ + { + path: '', + component: MasterPageComponent, + loadChildren: () => import('./graphs/graphs.module').then(m => m.GraphsModule), + data: { preload: true }, + } +]; + +@NgModule({ + imports: [ + RouterModule.forChild(routes) + ], + exports: [ + RouterModule + ] +}) +export class BitcoinGraphsRoutingModule { } + +@NgModule({ + imports: [ + CommonModule, + BitcoinGraphsRoutingModule, + ], +}) +export class BitcoinGraphsModule { } + + + + + + diff --git a/frontend/src/app/bitcoin.utils.ts b/frontend/src/app/bitcoin.utils.ts index b023ac2b14..92d3de7f39 100644 --- a/frontend/src/app/bitcoin.utils.ts +++ b/frontend/src/app/bitcoin.utils.ts @@ -1,68 +1,306 @@ import { Transaction, Vin } from './interfaces/electrs.interface'; +import { Hash } from './shared/sha256'; const P2SH_P2WPKH_COST = 21 * 4; // the WU cost for the non-witness part of P2SH-P2WPKH const P2SH_P2WSH_COST = 35 * 4; // the WU cost for the non-witness part of P2SH-P2WSH export function calcSegwitFeeGains(tx: Transaction) { // calculated in weight units - let realizedGains = 0; - let potentialBech32Gains = 0; - let potentialP2shGains = 0; + let realizedSegwitGains = 0; + let potentialSegwitGains = 0; + let potentialP2shSegwitGains = 0; + let potentialTaprootGains = 0; + let realizedTaprootGains = 0; for (const vin of tx.vin) { if (!vin.prevout) { continue; } - const isP2pkh = vin.prevout.scriptpubkey_type === 'p2pkh'; - const isP2sh = vin.prevout.scriptpubkey_type === 'p2sh'; - const isP2wsh = vin.prevout.scriptpubkey_type === 'v0_p2wsh'; - const isP2wpkh = vin.prevout.scriptpubkey_type === 'v0_p2wpkh'; + const isP2pk = vin.prevout.scriptpubkey_type === 'p2pk'; + // const isBareMultisig = vin.prevout.scriptpubkey_type === 'multisig'; // type will be unknown, so use the multisig helper from the address labels + const isBareMultisig = !!parseMultisigScript(vin.prevout.scriptpubkey_asm); + const isP2pkh = vin.prevout.scriptpubkey_type === 'p2pkh'; + const isP2sh = vin.prevout.scriptpubkey_type === 'p2sh'; + const isP2wsh = vin.prevout.scriptpubkey_type === 'v0_p2wsh'; + const isP2wpkh = vin.prevout.scriptpubkey_type === 'v0_p2wpkh'; + const isP2tr = vin.prevout.scriptpubkey_type === 'v1_p2tr'; const op = vin.scriptsig ? vin.scriptsig_asm.split(' ')[0] : null; - const isP2sh2Wpkh = isP2sh && !!vin.witness && op === 'OP_PUSHBYTES_22'; - const isP2sh2Wsh = isP2sh && !!vin.witness && op === 'OP_PUSHBYTES_34'; + const isP2shP2Wpkh = isP2sh && !!vin.witness && op === 'OP_PUSHBYTES_22'; + const isP2shP2Wsh = isP2sh && !!vin.witness && op === 'OP_PUSHBYTES_34'; switch (true) { - // Native Segwit - P2WPKH/P2WSH (Bech32) + // Native Segwit - P2WPKH/P2WSH/P2TR case isP2wpkh: case isP2wsh: + case isP2tr: // maximal gains: the scriptSig is moved entirely to the witness part - realizedGains += witnessSize(vin) * 3; + // if taproot is used savings are 42 WU higher because it produces smaller signatures and doesn't require a pubkey in the witness + // this number is explained above `realizedTaprootGains += 42;` + realizedSegwitGains += (witnessSize(vin) + (isP2tr ? 42 : 0)) * 3; // XXX P2WSH output creation is more expensive, should we take this into consideration? break; // Backward compatible Segwit - P2SH-P2WPKH - case isP2sh2Wpkh: - // the scriptSig is moved to the witness, but we have extra 21 extra non-witness bytes (48 WU) - realizedGains += witnessSize(vin) * 3 - P2SH_P2WPKH_COST; - potentialBech32Gains += P2SH_P2WPKH_COST; + case isP2shP2Wpkh: + // the scriptSig is moved to the witness, but we have extra 21 extra non-witness bytes (84 WU) + realizedSegwitGains += witnessSize(vin) * 3 - P2SH_P2WPKH_COST; + potentialSegwitGains += P2SH_P2WPKH_COST; break; // Backward compatible Segwit - P2SH-P2WSH - case isP2sh2Wsh: - // the scriptSig is moved to the witness, but we have extra 35 extra non-witness bytes - realizedGains += witnessSize(vin) * 3 - P2SH_P2WSH_COST; - potentialBech32Gains += P2SH_P2WSH_COST; + case isP2shP2Wsh: + // the scriptSig is moved to the witness, but we have extra 35 extra non-witness bytes (140 WU) + realizedSegwitGains += witnessSize(vin) * 3 - P2SH_P2WSH_COST; + potentialSegwitGains += P2SH_P2WSH_COST; break; - // Non-segwit P2PKH/P2SH + // Non-segwit P2PKH/P2SH/P2PK/bare multisig case isP2pkh: case isP2sh: - const fullGains = scriptSigSize(vin) * 3; - potentialBech32Gains += fullGains; - potentialP2shGains += fullGains - (isP2pkh ? P2SH_P2WPKH_COST : P2SH_P2WSH_COST); + case isP2pk: + case isBareMultisig: { + let fullGains = scriptSigSize(vin) * 3; + if (isBareMultisig) { + // a _bare_ multisig has the keys in the output script, but P2SH and P2WSH require them to be in the scriptSig/scriptWitness + fullGains -= vin.prevout.scriptpubkey.length / 2; + } + potentialSegwitGains += fullGains; + potentialP2shSegwitGains += fullGains - (isP2pkh ? P2SH_P2WPKH_COST : P2SH_P2WSH_COST); break; + } + } - // TODO: should we also consider P2PK and pay-to-bare-script (non-p2sh-wrapped) as upgradable to P2WPKH and P2WSH? + if (isP2tr) { + // every valid taproot input has at least one witness item, however transactions + // created before taproot activation don't need to have any witness data + // (see https://mempool.space/tx/b10c007c60e14f9d087e0291d4d0c7869697c6681d979c6639dbd960792b4d41) + if (vin.witness?.length) { + if (vin.witness.length === 1) { + // key path spend + // we don't know if this was a multisig or single sig (the goal of taproot :)), + // so calculate fee savings by comparing to the cheapest single sig input type: P2WPKH and say "saved at least ...%" + // the witness size of P2WPKH is 1 (stack size) + 1 (size) + 72 (low s signature) + 1 (size) + 33 (pubkey) = 108 WU + // the witness size of key path P2TR is 1 (stack size) + 1 (size) + 64 (signature) = 66 WU + realizedTaprootGains += 42; + } else { + // script path spend + // complex scripts with multiple spending paths can often be made around 2x to 3x smaller with the Taproot script tree + // because only the hash of the alternative spending path has the be in the witness data, not the entire script, + // but only assumptions can be made because the scripts themselves are unknown (again, the goal of taproot :)) + // TODO maybe add some complex scripts that are specified somewhere, so that size is known, such as lightning scripts + } + } + } else { + const script = isP2shP2Wsh || isP2wsh ? vin.inner_witnessscript_asm : vin.inner_redeemscript_asm; + let replacementSize: number; + if ( + // single sig + isP2pk || isP2pkh || isP2wpkh || isP2shP2Wpkh || + // multisig + isBareMultisig || parseMultisigScript(script) + ) { + // the scriptSig and scriptWitness can all be replaced by a 66 witness WU with taproot + replacementSize = 66; + } else if (script) { + // not single sig, not multisig: the complex scripts + // rough calculations on spending paths + // every OP_IF and OP_NOTIF indicates an _extra_ spending path, so add 1 + const spendingPaths = script.split(' ').filter(op => /^(OP_IF|OP_NOTIF)$/g.test(op)).length + 1; + // now assume the script could have been split in ${spendingPaths} equal tapleaves + replacementSize = script.length / 2 / spendingPaths + + // but account for the leaf and branch hashes and internal key in the control block + 32 * Math.log2((spendingPaths - 1) || 1) + 33; + } + potentialTaprootGains += witnessSize(vin) + scriptSigSize(vin) * 4 - replacementSize; } } // returned as percentage of the total tx weight - return { realizedGains: realizedGains / (tx.weight + realizedGains) // percent of the pre-segwit tx size - , potentialBech32Gains: potentialBech32Gains / tx.weight - , potentialP2shGains: potentialP2shGains / tx.weight - }; + return { + realizedSegwitGains: realizedSegwitGains / (tx.weight + realizedSegwitGains), // percent of the pre-segwit tx size + potentialSegwitGains: potentialSegwitGains / tx.weight, + potentialP2shSegwitGains: potentialP2shSegwitGains / tx.weight, + potentialTaprootGains: potentialTaprootGains / tx.weight, + realizedTaprootGains: realizedTaprootGains / (tx.weight + realizedTaprootGains) + }; +} + +/** extracts m and n from a multisig script (asm), returns nothing if it is not a multisig script */ +export function parseMultisigScript(script: string): void | { m: number, n: number } { + if (!script) { + return; + } + const ops = script.split(' '); + if (ops.length < 3 || ops.pop() !== 'OP_CHECKMULTISIG') { + return; + } + const opN = ops.pop(); + if (!opN.startsWith('OP_PUSHNUM_')) { + return; + } + const n = parseInt(opN.match(/[0-9]+/)[0], 10); + if (ops.length < n * 2 + 1) { + return; + } + // pop n public keys + for (let i = 0; i < n; i++) { + if (!/^0((2|3)\w{64}|4\w{128})$/.test(ops.pop())) { + return; + } + if (!/^OP_PUSHBYTES_(33|65)$/.test(ops.pop())) { + return; + } + } + const opM = ops.pop(); + if (!opM.startsWith('OP_PUSHNUM_')) { + return; + } + const m = parseInt(opM.match(/[0-9]+/)[0], 10); + + if (ops.length) { + return; + } + + return { m, n }; +} + +// https://github.com/shesek/move-decimal-point +export function moveDec(num: number, n: number) { + let frac, int, neg, ref; + if (n === 0) { + return num.toString(); + } + ref = ('' + num).split('.'), int = ref[0], frac = ref[1]; + int || (int = '0'); + frac || (frac = '0'); + neg = (int[0] === '-' ? '-' : ''); + if (neg) { + int = int.slice(1); + } + if (n > 0) { + if (n > frac.length) { + frac += zeros(n - frac.length); + } + int += frac.slice(0, n); + frac = frac.slice(n); + } else { + n = n * -1; + if (n > int.length) { + int = (zeros(n - int.length)) + int; + } + frac = int.slice(n * -1) + frac; + int = int.slice(0, n * -1); + } + while (int[0] === '0') { + int = int.slice(1); + } + while (frac[frac.length - 1] === '0') { + frac = frac.slice(0, -1); + } + return neg + (int || '0') + (frac.length ? '.' + frac : ''); +} + +function zeros(n: number) { + return new Array(n + 1).join('0'); } +// Formats a number for display. Treats the number as a string to avoid rounding errors. +export const formatNumber = (s: number | string, precision: number | null = null) => { + let [ whole, dec ] = s.toString().split('.'); + + // divide numbers into groups of three separated with a thin space (U+202F, "NARROW NO-BREAK SPACE"), + // but only when there are more than a total of 5 non-decimal digits. + if (whole.length >= 5) { + whole = whole.replace(/\B(?=(\d{3})+(?!\d))/g, '\u202F'); + } + + if (precision != null && precision > 0) { + if (dec == null) { + dec = '0'.repeat(precision); + } + else if (dec.length < precision) { + dec += '0'.repeat(precision - dec.length); + } + } + + return whole + (dec != null ? '.' + dec : ''); +}; + // Utilities for segwitFeeGains -const witnessSize = (vin: Vin) => vin.witness.reduce((S, w) => S + (w.length / 2), 0); +const witnessSize = (vin: Vin) => vin.witness ? vin.witness.reduce((S, w) => S + (w.length / 2), 0) : 0; const scriptSigSize = (vin: Vin) => vin.scriptsig ? vin.scriptsig.length / 2 : 0; + +// Power of ten wrapper +export function selectPowerOfTen(val: number, multiplier = 1): { divider: number, unit: string } { + const powerOfTen = { + exa: Math.pow(10, 18), + peta: Math.pow(10, 15), + tera: Math.pow(10, 12), + giga: Math.pow(10, 9), + mega: Math.pow(10, 6), + kilo: Math.pow(10, 3), + }; + + let selectedPowerOfTen: { divider: number, unit: string }; + if (val < powerOfTen.kilo * multiplier) { + selectedPowerOfTen = { divider: 1, unit: '' }; // no scaling + } else if (val < powerOfTen.mega * multiplier) { + selectedPowerOfTen = { divider: powerOfTen.kilo, unit: 'k' }; + } else if (val < powerOfTen.giga * multiplier) { + selectedPowerOfTen = { divider: powerOfTen.mega, unit: 'M' }; + } else if (val < powerOfTen.tera * multiplier) { + selectedPowerOfTen = { divider: powerOfTen.giga, unit: 'G' }; + } else if (val < powerOfTen.peta * multiplier) { + selectedPowerOfTen = { divider: powerOfTen.tera, unit: 'T' }; + } else if (val < powerOfTen.exa * multiplier) { + selectedPowerOfTen = { divider: powerOfTen.peta, unit: 'P' }; + } else { + selectedPowerOfTen = { divider: powerOfTen.exa, unit: 'E' }; + } + + return selectedPowerOfTen; +} + +const featureActivation = { + mainnet: { + rbf: 399701, + segwit: 477120, + taproot: 709632, + }, + testnet: { + rbf: 720255, + segwit: 872730, + taproot: 2032291, + }, + testnet4: { + rbf: 0, + segwit: 0, + taproot: 0, + }, + signet: { + rbf: 0, + segwit: 0, + taproot: 0, + }, +}; + +export function isFeatureActive(network: string, height: number, feature: 'rbf' | 'segwit' | 'taproot'): boolean { + const activationHeight = featureActivation[network || 'mainnet']?.[feature]; + if (activationHeight != null) { + return height >= activationHeight; + } else { + return false; + } +} + +export async function calcScriptHash$(script: string): Promise { + if (!/^[0-9a-fA-F]*$/.test(script) || script.length % 2 !== 0) { + throw new Error('script is not a valid hex string'); + } + const buf = Uint8Array.from(script.match(/.{2}/g).map((byte) => parseInt(byte, 16))); + const hash = new Hash().update(buf).digest(); + const hashArray = Array.from(new Uint8Array(hash)); + return hashArray + .map((bytes) => bytes.toString(16).padStart(2, '0')) + .join(''); +} \ No newline at end of file diff --git a/frontend/src/app/components/about/about-sponsors.component.html b/frontend/src/app/components/about/about-sponsors.component.html new file mode 100644 index 0000000000..9471fc78f9 --- /dev/null +++ b/frontend/src/app/components/about/about-sponsors.component.html @@ -0,0 +1,16 @@ +
+
+

If you're an individual...

+ Become a Community Sponsor + + + +
+
+

If you're a business...

+ Become an Enterprise Sponsor + + + +
+
diff --git a/frontend/src/app/components/about/about-sponsors.component.scss b/frontend/src/app/components/about/about-sponsors.component.scss new file mode 100644 index 0000000000..0ee27d1f54 --- /dev/null +++ b/frontend/src/app/components/about/about-sponsors.component.scss @@ -0,0 +1,50 @@ +#become-sponsor-container { + display: flex; + flex-direction: row; + flex-wrap: nowrap; + justify-content: center; + align-items: center; + gap: 20px; + margin: 68px auto; + text-align: center; +} + +#become-sponsor-container.account { + margin: 20px auto; +} + +.become-sponsor { + background-color: var(--bg); + border-radius: 16px; + padding: 12px 20px; + width: 400px; + padding: 40px 20px; +} + +.become-sponsor a { + margin-top: 10px; +} + +#become-sponsor-container .btn { + margin-bottom: 24px; +} + +#become-sponsor-container .ng-fa-icon { + color: #2ecc71; + margin-right: 5px; +} + +#become-sponsor-container .sponsor-feature { + text-align: left; + width: 250px; + margin: 12px auto; + white-space: nowrap; +} + +@media (max-width: 992px) { + + #become-sponsor-container { + flex-wrap: wrap; + } + +} diff --git a/frontend/src/app/components/about/about-sponsors.component.ts b/frontend/src/app/components/about/about-sponsors.component.ts new file mode 100644 index 0000000000..6a47c3bd4b --- /dev/null +++ b/frontend/src/app/components/about/about-sponsors.component.ts @@ -0,0 +1,25 @@ +import { Component, Input } from '@angular/core'; +import { EnterpriseService } from '../../services/enterprise.service'; + +@Component({ + selector: 'app-about-sponsors', + templateUrl: './about-sponsors.component.html', + styleUrls: ['./about-sponsors.component.scss'], +}) +export class AboutSponsorsComponent { + @Input() host = 'https://mempool.space'; + @Input() context = 'about'; + + constructor(private enterpriseService: EnterpriseService) { + } + + onSponsorClick(e): boolean { + this.enterpriseService.goal(5); + return true; + } + + onEnterpriseClick(e): boolean { + this.enterpriseService.goal(6); + return true; + } +} diff --git a/frontend/src/app/components/about/about.component.html b/frontend/src/app/components/about/about.component.html index 78aacaf48c..41c0ce47f3 100644 --- a/frontend/src/app/components/about/about.component.html +++ b/frontend/src/app/components/about/about.component.html @@ -1,116 +1,453 @@ -
-
-
- -

+
-

Contributors

+
+ ® + +
+ v{{ packetJsonVersion }} [{{ frontendGitCommitHash }}] + [{{ stateService.env.GIT_COMMIT_HASH_MEMPOOL_SPACE }}] +
+
+ +
+
The Mempool Open Source Project ®
+

Our mempool and blockchain explorer for the Bitcoin community, focusing on the transaction fee market and multi-layer ecosystem, completely self-hosted without any trusted third-parties.

+
-

Development @softsimon_ -
Operations @wiz + -

+ + + -

Open source

+ -

+ +
+
+

Whale Sponsors

+
+ + + + + + + +
+
+ +
+

Chad Sponsors

+
+ + + + + +
+
+
+
-
-

API

+
+

OG Sponsors ❤️

+
+ + + + + +
- - -
- -

+ +
+

Community Alliances

+ +
+ + +
+

Project Translators

+
+ + + + + +
+
+
+
+ + +
+

Project Contributors

+ +
+ +
+

Project Members

+ +
+
+ +
+

Project Maintainers

+ +
+ + + +
+ + + +
+
+
+ diff --git a/frontend/src/app/components/about/about.component.scss b/frontend/src/app/components/about/about.component.scss index 5e208bcf83..a360e180cb 100644 --- a/frontend/src/app/components/about/about.component.scss +++ b/frontend/src/app/components/about/about.component.scss @@ -1,16 +1,256 @@ -.text-small { - font-size: 12px; + +.about-page { + text-align: center; + + .image { + width: 80px; + height: 80px; + background-size: 100%, 100%; + border-radius: 50%; + margin: 25px; + line-height: 32px; + } + + .image.not-rounded { + border-radius: 0; + width: 60px; + height: 60px; + } + + .intro { + margin: 25px auto 30px; + margin-top: 25px; + width: 250px; + display: flex; + flex-direction: column; + .logo { + height: 62.5px; + width: 250px; + margin: auto; + } + .version { + text-align: right; + font-size: 10px; + margin-top: -10px; + } + } + + .about-text { + max-width: 550px; + margin: auto; + padding: 10px 15px 15px; + } + + video { + width: 640px; + max-width: 90%; + margin-top: 0; + @media (min-width: 768px) { + height: 360px; + } + } + + .social-icons { + a { + margin: auto 10px; + } + } + + .alliances, + .enterprise-sponsor, + .community-integrations-sponsor, + .maintainers { + margin-top: 30px; + margin-bottom: 68px; + scroll-margin: 30px; + + @media (min-width: 768px) { + margin-top: 68px; + } + } + + .maintainers { + margin-bottom: 50px; + } + + .community-sponsor, .project-translators { + display: flex; + flex-direction: column; + .wrapper { + margin: 20px auto; + } + .btn-primary { + max-width: 250px; + margin: auto; + height: 45px; + width: 100%; + } + } + + .community-sponsor { + img { + width: 57px; + height: 57px; + } + } + + .alliances { + margin-bottom: 100px; + a { + &:nth-child(3) { + position: relative; + top: 10px; + } + } + img { + display: inline-block; + margin: 15px auto; + height: 62px; + @media (min-width: 425px) { + margin: 15px 60px; + } + @media (min-width: 576px) { + margin: 15px 120px; + } + @media (min-width: 850px) { + margin: 50px 30px 0px; + } + } + .liquid { + top: 7px; + position: relative; + } + .copa { + height: auto; + top: 23px; + position: relative; + width: 300px; + } + .sv { + height: 85px; + width: auto; + position: relative; + } + } + + .enterprise-sponsor, + .contributors, + .community-sponsor, + .project-translators, + .community-integrations-sponsor, + .maintainers { + scroll-margin: 30px; + .wrapper { + display: inline-block; + a { + display: inline-block; + &:hover { + text-decoration: none; + img, svg { + transform: scale(1.1); + } + } + img, svg, span { + display: block; + transition: 150ms all; + } + img, svg { + margin: 40px 29px 10px; + &.image.coldcard { + border-radius: 0; + width: auto; + max-height: 50px; + margin: 40px 29px 14px 29px; + } + } + } + } + } + + .community-sponsor .wrapper, .project-translators .wrapper { + margin: 10px auto 20px; + a img { + margin: 6px; + } + } + + .project-translators .wrapper { + a img { + width: 72px; + height: 72px; + } + } + + #project-members a.project-member-avatar img { + margin: 40px 20px 10px; + } + + .copyright { + text-align: left; + max-width: 620px; + padding: 0px 15px; + margin: auto; + line-height: 1.8; + font-size: 87.5%; + color: #e83e8c; + word-wrap: break-word; + font-family: SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,monospace; + ul { + list-style: none; + padding-left: 30px; + li { + margin-bottom: 20px; + margin-top: 20px; + } + } + .title { + text-align: center; + margin-bottom: 25px; + } + } + + .footer-links { + display: flex; + flex-direction: column; + a { + display: inline-block; + margin: 15px auto 0px; + &:last-child { + margin: 20px auto 30px; + } + } + .social-icons { + a { + margin: 45px 10px; + } + .bitcointv svg { + width: 36px; + height: auto; + vertical-align: bottom; + margin-bottom: 2px; + margin-left: 5px; + } + .bitcointv svg:hover { + opacity: 0.75; + } + } + } + + .footer-version { + font-size: 12px; + } } -.code { - background-color: #1d1f31; - font-family: Consolas,Monaco,Lucida Console,Liberation Mono,DejaVu Sans Mono,Bitstream Vera Sans Mono,Courier New; +.no-about-margin { + height: 10px; } -tr { - white-space: inherit; +.community-integrations-sponsor { + max-width: 1110px; + margin: auto; } -.nowrap { - white-space: nowrap; +.community-integrations-sponsor img.image { + width: 64px; + height: 64px; } diff --git a/frontend/src/app/components/about/about.component.ts b/frontend/src/app/components/about/about.component.ts index 9b2f31adf0..44bee58280 100644 --- a/frontend/src/app/components/about/about.component.ts +++ b/frontend/src/app/components/about/about.component.ts @@ -1,32 +1,139 @@ -import { Component, OnInit } from '@angular/core'; +import { ChangeDetectionStrategy, Component, ElementRef, Inject, LOCALE_ID, OnInit, ViewChild } from '@angular/core'; import { WebsocketService } from '../../services/websocket.service'; -import { SeoService } from 'src/app/services/seo.service'; -import { StateService } from 'src/app/services/state.service'; +import { SeoService } from '../../services/seo.service'; +import { OpenGraphService } from '../../services/opengraph.service'; +import { StateService } from '../../services/state.service'; +import { Observable } from 'rxjs'; +import { ApiService } from '../../services/api.service'; +import { IBackendInfo } from '../../interfaces/websocket.interface'; +import { Router, ActivatedRoute } from '@angular/router'; +import { map, share, tap } from 'rxjs/operators'; +import { ITranslators } from '../../interfaces/node-api.interface'; +import { DOCUMENT } from '@angular/common'; +import { EnterpriseService } from '../../services/enterprise.service'; @Component({ selector: 'app-about', templateUrl: './about.component.html', - styleUrls: ['./about.component.scss'] + styleUrls: ['./about.component.scss'], + changeDetection: ChangeDetectionStrategy.OnPush, }) export class AboutComponent implements OnInit { - active = 1; - hostname = document.location.hostname; + @ViewChild('promoVideo') promoVideo: ElementRef; + backendInfo$: Observable; + frontendGitCommitHash = this.stateService.env.GIT_COMMIT_HASH; + packetJsonVersion = this.stateService.env.PACKAGE_JSON_VERSION; + officialMempoolSpace = this.stateService.env.OFFICIAL_MEMPOOL_SPACE; + showNavigateToSponsor = false; + profiles$: Observable; + translators$: Observable; + allContributors$: Observable; + ogs$: Observable; constructor( private websocketService: WebsocketService, private seoService: SeoService, - private stateService: StateService, + private ogService: OpenGraphService, + public stateService: StateService, + private enterpriseService: EnterpriseService, + private apiService: ApiService, + private router: Router, + private route: ActivatedRoute, + @Inject(LOCALE_ID) public locale: string, + @Inject(DOCUMENT) private document: Document, ) { } ngOnInit() { - this.seoService.setTitle('Contributors'); + this.backendInfo$ = this.stateService.backendInfo$; + this.seoService.setTitle($localize`:@@004b222ff9ef9dd4771b777950ca1d0e4cd4348a:About`); + this.seoService.setDescription($localize`:@@meta.description.about:Learn more about The Mempool Open Source Project®\: enterprise sponsors, individual sponsors, integrations, who contributes, FOSS licensing, and more.`); + this.ogService.setManualOgImage('about.jpg'); this.websocketService.want(['blocks']); - if (this.stateService.network === 'bisq') { - this.active = 2; + + this.profiles$ = this.apiService.getAboutPageProfiles$().pipe( + tap((profiles: any) => { + const scrollToSponsors = this.route.snapshot.fragment === 'community-sponsors'; + if (scrollToSponsors && !profiles?.whales?.length && !profiles?.chads?.length) { + return; + } else { + this.goToAnchor(scrollToSponsors) + } + }), + share(), + ) + + this.translators$ = this.apiService.getTranslators$() + .pipe( + map((translators) => { + for (const t in translators) { + if (translators[t] === '') { + delete translators[t]; + } + } + return translators; + }), + tap(() => this.goToAnchor()) + ); + + this.ogs$ = this.apiService.getOgs$(); + + this.allContributors$ = this.apiService.getContributor$().pipe( + map((contributors) => { + return { + regular: contributors.filter((user) => !user.core_constributor), + core: contributors.filter((user) => user.core_constributor), + }; + }), + tap(() => this.goToAnchor()) + ); + } + + ngAfterViewInit() { + this.goToAnchor(); + } + + goToAnchor(scrollToSponsor = false) { + if (!scrollToSponsor) { + return; } - if (document.location.port !== '') { - this.hostname = this.hostname + ':' + document.location.port; + setTimeout(() => { + if (this.route.snapshot.fragment) { + const el = scrollToSponsor ? this.document.getElementById('community-sponsors-anchor') : this.document.getElementById(this.route.snapshot.fragment); + if (el) { + if (scrollToSponsor) { + el.scrollIntoView({behavior: 'smooth', block: 'center', inline: 'center'}); + } else { + el.scrollIntoView({behavior: 'smooth'}); + } + } + } + }, 1); + } + + sponsor(): void { + if (this.officialMempoolSpace && this.stateService.env.BASE_MODULE === 'mempool') { + this.router.navigateByUrl('/enterprise'); + } else { + this.showNavigateToSponsor = true; } } + + showSubtitles(language): boolean { + return ( this.locale.startsWith( language ) && !this.locale.startsWith('en') ); + } + + unmutePromoVideo(): void { + this.promoVideo.nativeElement.muted = false; + } + + onSponsorClick(e): boolean { + this.enterpriseService.goal(5); + return true; + } + + onEnterpriseClick(e): boolean { + this.enterpriseService.goal(6); + return true; + } } diff --git a/frontend/src/app/components/about/about.module.ts b/frontend/src/app/components/about/about.module.ts new file mode 100644 index 0000000000..7e8ed42d04 --- /dev/null +++ b/frontend/src/app/components/about/about.module.ts @@ -0,0 +1,45 @@ +import { NgModule } from '@angular/core'; +import { CommonModule } from '@angular/common'; +import { Routes, RouterModule } from '@angular/router'; +import { AboutComponent } from './about.component'; +import { AboutSponsorsComponent } from './about-sponsors.component'; +import { SharedModule } from '../../shared/shared.module'; + +const routes: Routes = [ + { + path: '', + component: AboutComponent, + } +]; + +@NgModule({ + imports: [ + RouterModule.forChild(routes) + ], + exports: [ + RouterModule + ] +}) +export class AboutRoutingModule { } + +@NgModule({ + imports: [ + CommonModule, + AboutRoutingModule, + SharedModule, + ], + declarations: [ + AboutComponent, + AboutSponsorsComponent, + ], + exports: [ + AboutSponsorsComponent, + ] +}) +export class AboutModule { } + + + + + + diff --git a/frontend/src/app/components/accelerate-checkout/accelerate-checkout.component.html b/frontend/src/app/components/accelerate-checkout/accelerate-checkout.component.html new file mode 100644 index 0000000000..aa45d7bd53 --- /dev/null +++ b/frontend/src/app/components/accelerate-checkout/accelerate-checkout.component.html @@ -0,0 +1,580 @@ +
+ @if (accelerateError) { +
+
+

Sorry, something went wrong!

+
+
+
+
+
+ We were not able to accelerate this transaction. Please try again later. +
+
+
+
+
+
+ +
+
+ } @else if (step === 'quote') { +
+ + + + + +
+ @if (showDetails) { +
Your transaction
+
+
+ + Plus {{ estimate.txSummary.ancestorCount - 1 }} unconfirmed ancestor(s) + + + + + + + + + + + + + + + + + + +
Virtual size
+ Size in vbytes of this transaction (including unconfirmed ancestors) +
In-band fees + {{ estimate.txSummary.effectiveFee | number : '1.0-0' }} sats +
+ Fees already paid by this transaction (including unconfirmed ancestors) +
+
+
+
+ } +
How much faster?
+
+
+ + + This will reduce your expected waiting time until the first confirmation to + +
+
+ +
+
+
+
+
+
+
+ + + +
+
+
+
+
+ +
Summary
+
+
+ + + + + @if (hasAccessToBalanceMode) { + + + + + + + + + + + } + @else { + + + + + + + + + + + + } + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Next block market rate + {{ estimate.targetFeeRate | number : '1.0-0' }} + sat/vB
+ Estimated extra fee required + + {{ math.max(0, estimate.nextBlockFee - estimate.txSummary.effectiveFee) | number }} + + sats + +
Target rate + {{ maxRateOptions[selectFeeRateIndex].rate | number : '1.0-0' }} + sat/vB
+ Extra fee required + + {{ maxRateOptions[selectFeeRateIndex].fee | number }} + + sats + +
Mempool Accelerator™ fees
+ Accelerator Service Fee + + +{{ estimate.mempoolBaseFee | number }} + + sats + +
+ Transaction Size Surcharge + + +{{ estimate.vsizeFee | number }} + + sats + +
+ Estimated acceleration cost ~{{ estimate.targetFeeRate | number : '1.0-0' }} sat/vB + + + {{ estimate.cost + estimate.mempoolBaseFee + estimate.vsizeFee | number }} + + + sats + +
+ @if (hasAccessToBalanceMode) { + Maximum acceleration cost + } @else { + Acceleration cost + } + + + {{ cost | number }} + + + sats + + + +
Available balance + {{ estimate.userBalance | number }} + + sats + + + +
+
+ +
+
+
+
+
+
+
+ +
+
+
+ +
+
+ + +
+
+
+ } + @else if (step === 'summary') { + + + @if (!noCTA) { +
+
+

Accelerate your Bitcoin transaction?

+
+
+ } + + @if (!advancedEnabled) { +
+
+
+
+ + +
+
+ + +
+
+
+
+
+ +
+
+
+ } @else { +
+
+
+
+
+ +
+
+
+
+ + +
+ +
+
+ } +
+ +
+
+
+
+
+
+
+
+ } @else if (step === 'checkout') { + +
+
+
+ + + @if (!calculating) { + For an additional ({{ cost | number }} sats) + } @else { + Calculating cost... + } + + + Reducing expected confirmation time to + +
+
+
+ + +
+
+
+
+

Payment to mempool.space for acceleration of txid {{ tx.txid.substr(0, 10) }}..{{ tx.txid.substr(-10) }}

+
+ @if (canPayWithBalance || !(canPayWithBitcoin || canPayWithCashapp)) { +
+
+

Your account will be debited no more than {{ cost | number }} sats

+
+ +
+
+
+ } @else { +
+ @if (canPayWithBitcoin) { +
+ @if (invoice) { +

Pay {{ ((invoice.btcDue * 100_000_000) || cost) | number }} sats

+ + } @else if (btcpayInvoiceFailed) { +

Failed to load invoice

+
+ +
+ } @else { +

Loading invoice...

+
+
+
+ } +
+ @if (canPayWithCashapp) { +
+

OR

+
+ } + } + @if (canPayWithCashapp) { +
+

Pay  with

+ +
+ } +
+ } +
+
+ +
+
+
+
+
+
+
+
+ +
+
+
+ +
+
+ } @else if (step === 'cashapp') { + +
+
+

Confirm your payment

+
+
+ +
+
+
+ Payment to mempool.space for acceleration of txid {{ tx.txid.substr(0, 10) }}..{{ tx.txid.substr(-10) }} +
+
+
+ + @if (!loadingCashapp) { +
+
+
+ Total additional cost
+ + Pay + + with + +
+
+
+
+ } + +
+
+
+
+ @if (loadingCashapp) { +
+ Loading payment method... +
+
+ } +
+
+
+ +
+
+
+ +
+
+ } + @else if (step === 'processing') { +
+
+

Confirming your payment

+
+
+ +
+
+
+ +
+
+ We are processing your payment... +
+
+
+
+
+ } + @else if (step === 'paid') { +
+
+

Accelerating your transaction

+
+
+ +
+
+
+ Confirming your acceleration with our mining pool partners... + @if (timeSincePaid > 20000) { + ...sorry, this is taking longer than expected... + } +
+
+
+
+ } @else if (step === 'success') { +
+
+

Your transaction is being accelerated!

+
+
+
+
+
+ Your transaction has been accepted for acceleration by our mining pool partners. +
+
+
+
+
+
+ +
+
+ } +
+ + + + Confirmation expected 
+ @if (!calculating) { + ({{ cost | number }} sats) + } @else { + Calculating cost... + } +
+
+ + + + + +Accelerate to ~{{ x | number : '1.0-0' }} sat/vB + + +
+ + @if (quoteError || cantPayReason) { +
+ } +
+
+ + + @if (hasAccessToBalanceMode) { + + } @else { + + } + + +Your transaction will be prioritized by up to {{ i | number : '1.1-1' }}% of miners. diff --git a/frontend/src/app/components/accelerate-checkout/accelerate-checkout.component.scss b/frontend/src/app/components/accelerate-checkout/accelerate-checkout.component.scss new file mode 100644 index 0000000000..4e7be26916 --- /dev/null +++ b/frontend/src/app/components/accelerate-checkout/accelerate-checkout.component.scss @@ -0,0 +1,205 @@ +.close-button { + position: absolute; + top: 0.5em; + right: 0.5em; +} + +.estimating { + color: var(--green) +} + +.paymentMethod { + padding: 10px; + background-color: var(--secondary); + border-radius: 15px; + border: 2px solid var(--bg); + cursor: pointer; +} + +.default-slot:not(:only-child) { + display: none; +} + +.pie { + display: flex; + align-items: center; + max-width: 330px; +} + +.fee-card { + padding: 15px; + background-color: var(--bg); + + .feerate { + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + + .rate { + font-size: 0.9em; + .symbol { + color: white; + } + } + } +} + +.btn-border { + border: solid 1px black; + background-color: #0c4a87; +} + +.feerate.active { + background-color: var(--primary) !important; + opacity: 1; + border: 1px solid #007fff !important; +} +.feerate:focus { + box-shadow: none !important; +} + +.grayOut { + opacity: 0.5; +} + +.disabled { + opacity: 0.5; + pointer-events: none; +} + +.table-toggle { + width: 100%; + margin-top: 0.5em; +} + +.tab { + &:first-child { + margin-right: 1px; + } + border: solid 1px black; + border-bottom: none; + background-color: #323655; + border-top-left-radius: 10px !important; + border-top-right-radius: 10px !important; +} +.tab.active { + background-color: #5d659d !important; + opacity: 1; +} +.tab:focus { + box-shadow: none !important; +} + +.table-accelerator { + tr { + td { + padding-top: 0; + padding-bottom: 0; + vertical-align: baseline; + } + + &.group-first { + td { + padding-top: 0.75rem; + } + } + &.group-last, &:last-child { + td { + padding-bottom: 0.75rem; + } + } + &.dashed-top { + border-top: 1px dashed grey; + } + &.dashed-bottom { + border-bottom: 1px dashed grey + } + } + td { + &:first-child { + width: 100vw; + } + &.info { + color: #6c757d; + white-space: initial; + } + &.amt { + text-align: right; + padding-right: 0.2em; + } + &.units { + padding-left: 0.2em; + white-space: nowrap; + display: flex; + justify-content: space-between; + align-items: center; + } + } +} + +.accelerate-cols { + display: flex; + flex-direction: row; + align-items: stretch; + margin-top: 1em; +} + +.payment-area { + background: var(--bg); +} + +.col.pie { + flex-grow: 0; + padding: 0 1em; + position: relative; + top: -15px; +} + +.item { + white-space: initial; +} + +.table-background { + background-color: var(--bg); +} + +.checkout-text { + color: rgb(186, 186, 186); + font-size: 14px; +} + +.btn-accelerate { + background-color: var(--tertiary); +} + +.btn-small-height { + line-height: 1; +} + +.summary-row { + display: flex; + flex-direction: row; + justify-content: space-between; + align-items: center; + padding: 0 2em; + flex-wrap: wrap; + + @media (max-width: 640px) { + flex-direction: column; + } +} + +.btn-error { + position: absolute; + right: 0; + font-size: 12px; + color: var(--red); + text-align: center; + width: 200px; + white-space: normal; +} + +.btn-error-wrapper { + height: 26px; +} \ No newline at end of file diff --git a/frontend/src/app/components/accelerate-checkout/accelerate-checkout.component.ts b/frontend/src/app/components/accelerate-checkout/accelerate-checkout.component.ts new file mode 100644 index 0000000000..49b12bbeeb --- /dev/null +++ b/frontend/src/app/components/accelerate-checkout/accelerate-checkout.component.ts @@ -0,0 +1,624 @@ +import { Component, OnInit, OnDestroy, Output, EventEmitter, Input, ChangeDetectorRef, SimpleChanges, HostListener } from '@angular/core'; +import { Subscription, tap, of, catchError, Observable, switchMap } from 'rxjs'; +import { ServicesApiServices } from '../../services/services-api.service'; +import { nextRoundNumber } from '../../shared/common.utils'; +import { StateService } from '../../services/state.service'; +import { AudioService } from '../../services/audio.service'; +import { ETA, EtaService } from '../../services/eta.service'; +import { Transaction } from '../../interfaces/electrs.interface'; +import { MiningStats } from '../../services/mining.service'; +import { IAuth, AuthServiceMempool } from '../../services/auth.service'; +import { EnterpriseService } from '../../services/enterprise.service'; + +export type PaymentMethod = 'balance' | 'bitcoin' | 'cashapp'; + +export type AccelerationEstimate = { + hasAccess: boolean; + txSummary: TxSummary; + nextBlockFee: number; + targetFeeRate: number; + userBalance: number; + enoughBalance: boolean; + cost: number; + mempoolBaseFee: number; + vsizeFee: number; + pools: number[]; + availablePaymentMethods: {[method: string]: {min: number, max: number}}; + unavailable?: boolean; + options: { // recommended bid options + fee: number; // recommended userBid in sats + }[]; +} +export type TxSummary = { + txid: string; // txid of the current transaction + effectiveVsize: number; // Total vsize of the dependency tree + effectiveFee: number; // Total fee of the dependency tree in sats + ancestorCount: number; // Number of ancestors +} + +export interface RateOption { + fee: number; + rate: number; + index: number; +} + +export const MIN_BID_RATIO = 1; +export const DEFAULT_BID_RATIO = 2; +export const MAX_BID_RATIO = 4; + +type CheckoutStep = 'quote' | 'summary' | 'checkout' | 'cashapp' | 'processing' | 'paid' | 'success'; + +@Component({ + selector: 'app-accelerate-checkout', + templateUrl: './accelerate-checkout.component.html', + styleUrls: ['./accelerate-checkout.component.scss'] +}) +export class AccelerateCheckout implements OnInit, OnDestroy { + @Input() tx: Transaction; + @Input() accelerating: boolean = false; + @Input() miningStats: MiningStats; + @Input() eta: ETA; + @Input() scrollEvent: boolean; + @Input() cashappEnabled: boolean = true; + @Input() advancedEnabled: boolean = false; + @Input() forceMobile: boolean = false; + @Input() showDetails: boolean = false; + @Input() noCTA: boolean = false; + @Output() unavailable = new EventEmitter(); + @Output() completed = new EventEmitter(); + @Output() hasDetails = new EventEmitter(); + @Output() changeMode = new EventEmitter(); + + calculating = true; + selectedOption: 'wait' | 'accel'; + cantPayReason = ''; + quoteError = ''; // error fetching estimate or initial data + accelerateError = ''; // error executing acceleration + btcpayInvoiceFailed = false; + timePaid: number = 0; // time acceleration requested + math = Math; + isMobile: boolean = window.innerWidth <= 767.98; + + private _step: CheckoutStep = 'summary'; + simpleMode: boolean = true; + paymentMethod: 'cashapp' | 'btcpay'; + timeoutTimer: any; + + authSubscription$: Subscription; + auth: IAuth | null = null; + + // accelerator stuff + square: { appId: string, locationId: string}; + accelerationUUID: string; + accelerationSubscription: Subscription; + difficultySubscription: Subscription; + estimateSubscription: Subscription; + estimate: AccelerationEstimate; + maxBidBoost: number; // sats + cost: number; // sats + etaInfo$: Observable<{ hashratePercentage: number, ETA: number, acceleratedETA: number }>; + showSuccess = false; + hasAncestors: boolean = false; + minExtraCost = 0; + minBidAllowed = 0; + maxBidAllowed = 0; + defaultBid = 0; + userBid = 0; + selectFeeRateIndex = 1; + maxRateOptions: RateOption[] = []; + + // square + loadingCashapp = false; + cashappError = false; + cashappSubmit: any; + payments: any; + cashAppPay: any; + cashAppSubscription: Subscription; + conversionsSubscription: Subscription; + conversions: any; + + // btcpay + loadingBtcpayInvoice = false; + invoice = undefined; + + constructor( + public stateService: StateService, + private servicesApiService: ServicesApiServices, + private etaService: EtaService, + private audioService: AudioService, + private cd: ChangeDetectorRef, + private authService: AuthServiceMempool, + private enterpriseService: EnterpriseService, + ) { + this.accelerationUUID = window.crypto.randomUUID(); + } + + ngOnInit() { + this.authSubscription$ = this.authService.getAuth$().subscribe((auth) => { + if (this.auth?.user?.userId !== auth?.user?.userId) { + this.auth = auth; + this.estimate = null; + this.quoteError = null; + this.accelerateError = null; + this.timePaid = 0; + this.btcpayInvoiceFailed = false; + this.moveToStep('summary'); + } else { + this.auth = auth; + } + }); + this.authService.refreshAuth$().subscribe(); + + const urlParams = new URLSearchParams(window.location.search); + if (urlParams.get('cash_request_id')) { // Redirected from cashapp + this.moveToStep('processing'); + this.insertSquare(); + this.setupSquare(); + } else { + this.moveToStep('summary'); + } + + this.servicesApiService.setupSquare$().subscribe(ids => { + this.square = { + appId: ids.squareAppId, + locationId: ids.squareLocationId + }; + }); + + this.conversionsSubscription = this.stateService.conversions$.subscribe( + async (conversions) => { + this.conversions = conversions; + } + ); + } + + ngOnDestroy() { + if (this.estimateSubscription) { + this.estimateSubscription.unsubscribe(); + } + if (this.authSubscription$) { + this.authSubscription$.unsubscribe(); + } + } + + ngOnChanges(changes: SimpleChanges): void { + if (changes.scrollEvent && this.scrollEvent) { + this.scrollToElement('acceleratePreviewAnchor', 'start'); + } + if (changes.accelerating) { + if ((this.step === 'processing' || this.step === 'paid') && this.accelerating) { + this.moveToStep('success'); + } + } + } + + moveToStep(step: CheckoutStep) { + this._step = step; + if (this.timeoutTimer) { + clearTimeout(this.timeoutTimer); + } + if (!this.estimate && ['quote', 'summary', 'checkout'].includes(this.step)) { + this.fetchEstimate(); + } + if (this._step === 'checkout') { + this.enterpriseService.goal(8); + } + if (this._step === 'checkout' && this.canPayWithBitcoin) { + this.btcpayInvoiceFailed = false; + this.loadingBtcpayInvoice = true; + this.invoice = null; + this.requestBTCPayInvoice(); + } else if (this._step === 'cashapp' && this.cashappEnabled) { + this.loadingCashapp = true; + this.insertSquare(); + this.setupSquare(); + } else if (this._step === 'paid') { + this.timePaid = Date.now(); + this.timeoutTimer = setTimeout(() => { + if (this.step === 'paid') { + this.accelerateError = 'internal_server_error'; + } + }, 120000) + } + this.hasDetails.emit(this._step === 'quote'); + } + + closeModal(): void { + this.completed.emit(true); + this.moveToStep('summary'); + } + + /** + * Scroll to element id with or without setTimeout + */ + scrollToElementWithTimeout(id: string, position: ScrollLogicalPosition, timeout: number = 1000): void { + setTimeout(() => { + this.scrollToElement(id, position); + }, timeout); + } + scrollToElement(id: string, position: ScrollLogicalPosition) { + const acceleratePreviewAnchor = document.getElementById(id); + if (acceleratePreviewAnchor) { + this.cd.markForCheck(); + acceleratePreviewAnchor.scrollIntoView({ + behavior: 'smooth', + inline: position, + block: position, + }); + } + } + + /** + * Accelerator + */ + fetchEstimate() { + if (this.estimateSubscription) { + this.estimateSubscription.unsubscribe(); + } + this.calculating = true; + this.quoteError = null; + this.accelerateError = null; + this.estimateSubscription = this.servicesApiService.estimate$(this.tx.txid).pipe( + tap((response) => { + if (response.status === 204) { + this.quoteError = `cannot_accelerate_tx`; + if (this.step === 'summary') { + this.unavailable.emit(true); + } + } else { + this.estimate = response.body; + if (!this.estimate) { + this.quoteError = `cannot_accelerate_tx`; + if (this.step === 'summary') { + this.unavailable.emit(true); + } + return; + } + if (this.estimate.hasAccess === true && this.estimate.userBalance <= 0) { + if (this.isLoggedIn()) { + this.quoteError = `not_enough_balance`; + } + } + if (this.estimate.unavailable) { + this.quoteError = `temporarily_unavailable`; + } + this.hasAncestors = this.estimate.txSummary.ancestorCount > 1; + this.etaInfo$ = this.etaService.getProjectedEtaObservable(this.estimate, this.miningStats); + + this.maxRateOptions = this.estimate.options.map((option, index) => ({ + fee: option.fee, + rate: (this.estimate.txSummary.effectiveFee + option.fee) / this.estimate.txSummary.effectiveVsize, + index + })); + + this.defaultBid = this.maxRateOptions[1].fee; + this.userBid = this.defaultBid; + this.cost = this.userBid + this.estimate.mempoolBaseFee + this.estimate.vsizeFee; + + this.validateChoice(); + + if (!this.couldPay) { + this.quoteError = `cannot_accelerate_tx`; + if (this.step === 'summary') { + this.unavailable.emit(true); + } + return; + } + + if (this.step === 'checkout' && this.canPayWithBitcoin && !this.loadingBtcpayInvoice) { + this.loadingBtcpayInvoice = true; + this.requestBTCPayInvoice(); + } + + this.calculating = false; + this.cd.markForCheck(); + } + }), + + catchError((response) => { + this.estimate = undefined; + this.quoteError = `cannot_accelerate_tx`; + this.estimateSubscription.unsubscribe(); + if (this.step === 'summary') { + this.unavailable.emit(true); + } else { + this.accelerateError = 'cannot_accelerate_tx'; + } + return of(null); + }) + ).subscribe(); + } + + validateChoice(): void { + if (!this.canPay) { + if (this.estimate?.availablePaymentMethods?.balance) { + if (this.cost >= this.estimate?.userBalance) { + this.cantPayReason = 'not_enough_balance'; + } + } else { + this.cantPayReason = 'cannot_accelerate_tx'; + } + } else { + this.cantPayReason = ''; + } + } + + /** + * User changed his bid + */ + setUserBid({ fee, index }: { fee: number, index: number}): void { + if (this.estimate) { + this.selectFeeRateIndex = index; + this.userBid = Math.max(0, fee); + this.cost = this.userBid + this.estimate.mempoolBaseFee + this.estimate.vsizeFee; + } + } + + /** + * Account-based acceleration request + */ + accelerateWithMempoolAccount(): void { + if (!this.canPay || this.calculating) { + return; + } + if (this.accelerationSubscription) { + this.accelerationSubscription.unsubscribe(); + } + this.accelerationSubscription = this.servicesApiService.accelerate$( + this.tx.txid, + this.userBid, + this.accelerationUUID + ).subscribe({ + next: () => { + this.audioService.playSound('ascend-chime-cartoon'); + this.showSuccess = true; + this.estimateSubscription.unsubscribe(); + this.moveToStep('paid') + }, + error: (response) => { + this.accelerateError = response.error; + } + }); + } + + /** + * Square + */ + insertSquare(): void { + //@ts-ignore + if (window.Square) { + return; + } + let statsUrl = 'https://sandbox.web.squarecdn.com/v1/square.js'; + if (document.location.hostname === 'mempool-staging.fmt.mempool.space' || + document.location.hostname === 'mempool-staging.va1.mempool.space' || + document.location.hostname === 'mempool-staging.fra.mempool.space' || + document.location.hostname === 'mempool-staging.tk7.mempool.space' || + document.location.hostname === 'mempool.space') { + statsUrl = 'https://web.squarecdn.com/v1/square.js'; + } + + (function() { + const d=document, g=d.createElement('script'), s=d.getElementsByTagName('script')[0]; + // @ts-ignore + g.type='text/javascript'; g.src=statsUrl; s.parentNode.insertBefore(g, s); + })(); + } + setupSquare() { + const init = () => { + this.initSquare(); + }; + + //@ts-ignore + if (!window.Square) { + console.debug('Square.js failed to load properly. Retrying in 1 second.'); + setTimeout(init, 1000); + } else { + init(); + } + } + async initSquare(): Promise { + try { + //@ts-ignore + this.payments = window.Square.payments(this.square.appId, this.square.locationId) + await this.requestCashAppPayment(); + } catch (e) { + console.debug('Error loading Square Payments', e); + this.cashappError = true; + return; + } + } + async requestCashAppPayment() { + if (this.cashAppSubscription) { + this.cashAppSubscription.unsubscribe(); + } + if (this.conversionsSubscription) { + this.conversionsSubscription.unsubscribe(); + } + + this.conversionsSubscription = this.stateService.conversions$.subscribe( + async (conversions) => { + this.conversions = conversions; + if (this.cashAppPay) { + this.cashAppPay.destroy(); + } + + const redirectHostname = document.location.hostname === 'localhost' ? `http://localhost:4200`: `https://${document.location.hostname}`; + const costUSD = this.step === 'processing' ? 69.69 : (this.cost / 100_000_000 * conversions.USD); // When we're redirected to this component, the payment data is already linked to the payment token, so does not matter what amonut we put in there, therefore it's 69.69 + const paymentRequest = this.payments.paymentRequest({ + countryCode: 'US', + currencyCode: 'USD', + total: { + amount: costUSD.toString(), + label: 'Total', + pending: true, + productUrl: `${redirectHostname}/tracker/${this.tx.txid}`, + }, + button: { shape: 'semiround', size: 'small', theme: 'light'} + }); + this.cashAppPay = await this.payments.cashAppPay(paymentRequest, { + redirectURL: `${redirectHostname}/tracker/${this.tx.txid}`, + referenceId: `accelerator-${this.tx.txid.substring(0, 15)}-${Math.round(new Date().getTime() / 1000)}`, + button: { shape: 'semiround', size: 'small', theme: 'light'} + }); + + if (this.step === 'cashapp') { + await this.cashAppPay.attach(`#cash-app-pay`, { theme: 'light', size: 'small', shape: 'semiround' }) + } + this.loadingCashapp = false; + + const that = this; + this.cashAppPay.addEventListener('ontokenization', function (event) { + const { tokenResult, error } = event.detail; + if (error) { + this.accelerateError = error; + } else if (tokenResult.status === 'OK') { + that.servicesApiService.accelerateWithCashApp$( + that.tx.txid, + tokenResult.token, + tokenResult.details.cashAppPay.cashtag, + tokenResult.details.cashAppPay.referenceId, + that.accelerationUUID + ).subscribe({ + next: () => { + that.audioService.playSound('ascend-chime-cartoon'); + if (that.cashAppPay) { + that.cashAppPay.destroy(); + } + setTimeout(() => { + this.moveToStep('paid'); + if (window.history.replaceState) { + const urlParams = new URLSearchParams(window.location.search); + window.history.replaceState(null, null, window.location.toString().replace(`?cash_request_id=${urlParams.get('cash_request_id')}`, '')); + } + }, 1000); + }, + error: (response) => { + that.accelerateError = response.error; + if (!(response.status === 403 && response.error === 'not_available')) { + setTimeout(() => { + // Reset everything by reloading the page :D, can be improved + const urlParams = new URLSearchParams(window.location.search); + window.location.assign(window.location.toString().replace(`?cash_request_id=${urlParams.get('cash_request_id')}`, ``)); + }, 3000); + } + } + }); + } + }); + } + ); + } + + /** + * BTCPay + */ + async requestBTCPayInvoice() { + this.servicesApiService.generateBTCPayAcceleratorInvoice$(this.tx.txid, this.userBid).pipe( + switchMap(response => { + return this.servicesApiService.retreiveInvoice$(response.btcpayInvoiceId); + }), + catchError(error => { + console.log(error); + this.btcpayInvoiceFailed = true; + return of(null); + }) + ).subscribe((invoice) => { + this.invoice = invoice; + this.cd.markForCheck(); + }); + } + + bitcoinPaymentCompleted(): void { + this.audioService.playSound('ascend-chime-cartoon'); + this.estimateSubscription.unsubscribe(); + this.moveToStep('paid') + } + + isLoggedIn(): boolean { + return this.auth !== null; + } + + /** + * UI events + */ + selectedOptionChanged(event) { + this.selectedOption = event.target.id; + } + + get step() { + return this._step; + } + + get paymentMethods() { + return Object.keys(this.estimate?.availablePaymentMethods || {}); + } + + get couldPayWithBitcoin() { + return !!this.estimate?.availablePaymentMethods?.bitcoin; + } + + get couldPayWithCashapp() { + if (!this.cashappEnabled) { + return false; + } + return !!this.estimate?.availablePaymentMethods?.cashapp; + } + + get couldPayWithBalance() { + if (!this.hasAccessToBalanceMode) { + return false; + } + return !!this.estimate?.availablePaymentMethods?.balance; + } + + get couldPay() { + return this.couldPayWithBalance || this.couldPayWithBitcoin || this.couldPayWithCashapp; + } + + get canPayWithBitcoin() { + const paymentMethod = this.estimate?.availablePaymentMethods?.bitcoin; + return paymentMethod && this.cost >= paymentMethod.min && this.cost <= paymentMethod.max; + } + + get canPayWithCashapp() { + if (!this.cashappEnabled || !this.conversions) { + return false; + } + + const paymentMethod = this.estimate?.availablePaymentMethods?.cashapp; + if (paymentMethod) { + const costUSD = (this.cost / 100_000_000 * this.conversions.USD); + if (costUSD >= paymentMethod.min && costUSD <= paymentMethod.max) { + return true; + } + } + + return false; + } + + get canPayWithBalance() { + if (!this.hasAccessToBalanceMode) { + return false; + } + const paymentMethod = this.estimate?.availablePaymentMethods?.balance; + return paymentMethod && this.cost >= paymentMethod.min && this.cost <= paymentMethod.max && this.cost <= this.estimate?.userBalance; + } + + get canPay() { + return this.canPayWithBalance || this.canPayWithBitcoin || this.canPayWithCashapp; + } + + get hasAccessToBalanceMode() { + return this.isLoggedIn() && this.estimate?.hasAccess; + } + + get timeSincePaid(): number { + return Date.now() - this.timePaid; + } + + @HostListener('window:resize', ['$event']) + onResize(): void { + this.isMobile = window.innerWidth <= 767.98; + } +} diff --git a/frontend/src/app/components/accelerate-checkout/accelerate-fee-graph.component.html b/frontend/src/app/components/accelerate-checkout/accelerate-fee-graph.component.html new file mode 100644 index 0000000000..a5e258210e --- /dev/null +++ b/frontend/src/app/components/accelerate-checkout/accelerate-fee-graph.component.html @@ -0,0 +1,21 @@ +
+
+ +
+
+
+

+ {{ bar.label }} + + + +

+
+
+ {{ bar.class === 'tx' ? '' : '+' }}{{ bar.fee | number }} sat +
+
+
+
+
+
diff --git a/frontend/src/app/components/accelerate-checkout/accelerate-fee-graph.component.scss b/frontend/src/app/components/accelerate-checkout/accelerate-fee-graph.component.scss new file mode 100644 index 0000000000..919fdec4a1 --- /dev/null +++ b/frontend/src/app/components/accelerate-checkout/accelerate-fee-graph.component.scss @@ -0,0 +1,156 @@ +.fee-graph { + height: 100%; + min-width: 120px; + width: 120px; + margin-left: 4em; + margin-right: 1.5em; + + .column { + width: 100%; + height: 100%; + position: relative; + background: var(--stat-box-bg); + + .bar { + position: absolute; + bottom: 0; + left: 0; + right: 0; + min-height: 30px; + display: flex; + flex-direction: column; + justify-content: center; + align-items: center; + + .fill { + position: absolute; + left: 0; + right: 0; + top: 0; + bottom: 0; + opacity: 0.75; + pointer-events: none; + } + + .fee { + font-size: 0.9em; + opacity: 0; + pointer-events: none; + } + + .spacer { + width: 100%; + height: 1px; + flex-grow: 1; + pointer-events: none; + } + + .line { + position: absolute; + right: 0; + top: 0; + left: -4.5em; + border-top: dashed white 1.5px; + + .fee-rate { + width: 100%; + position: absolute; + left: 0; + right: 0.2em; + font-size: 0.8em; + display: flex; + flex-direction: row-reverse; + justify-content: space-between; + margin: 0; + + .label { + margin-right: .2em; + } + + .rate .symbol { + color: white; + } + } + } + + &.tx { + .fill { + background: var(--green); + } + .line { + .fee-rate { + top: 0; + } + } + .fee { + position: absolute; + opacity: 1; + z-index: 11; + } + } + + &.target { + .fill { + background: var(--tertiary); + } + .fee { + position: absolute; + opacity: 1; + z-index: 11; + } + .line .fee-rate { + bottom: 2px; + } + } + + &.max { + cursor: pointer; + .line .fee-rate { + .label { + opacity: 0; + } + bottom: 2px; + } + &.active, &:hover { + .fill { + background: var(--primary); + } + .line { + .fee-rate .label { + opacity: 1; + } + } + } + } + + &:hover { + .fill { + z-index: 10; + } + .line { + z-index: 11; + } + .fee { + opacity: 1; + z-index: 12; + } + } + } + + &:hover > .bar:not(:hover) { + &.target, &.max { + .fee { + opacity: 0; + } + .line .fee-rate .label { + opacity: 0; + } + } + &.max { + .fill { + background: none; + } + } + } + } +} \ No newline at end of file diff --git a/frontend/src/app/components/accelerate-checkout/accelerate-fee-graph.component.ts b/frontend/src/app/components/accelerate-checkout/accelerate-fee-graph.component.ts new file mode 100644 index 0000000000..393add6ca7 --- /dev/null +++ b/frontend/src/app/components/accelerate-checkout/accelerate-fee-graph.component.ts @@ -0,0 +1,152 @@ +import { Component, Input, Output, OnChanges, EventEmitter, HostListener, OnInit, ViewChild, ElementRef, AfterViewInit, OnDestroy, ChangeDetectorRef } from '@angular/core'; +import { Transaction } from '../../interfaces/electrs.interface'; +import { AccelerationEstimate, RateOption } from './accelerate-checkout.component'; + +interface GraphBar { + rate: number; + style?: Record; + class: 'tx' | 'target' | 'max'; + label: string; + active?: boolean; + rateIndex?: number; + fee?: number; + height?: number; +} + +@Component({ + selector: 'app-accelerate-fee-graph', + templateUrl: './accelerate-fee-graph.component.html', + styleUrls: ['./accelerate-fee-graph.component.scss'], +}) +export class AccelerateFeeGraphComponent implements OnInit, AfterViewInit, OnChanges, OnDestroy { + @Input() tx: Transaction; + @Input() estimate: AccelerationEstimate; + @Input() showEstimate = false; + @Input() maxRateOptions: RateOption[] = []; + @Input() maxRateIndex: number = 0; + @Output() setUserBid = new EventEmitter<{ fee: number, index: number }>(); + + @ViewChild('feeGraph') + container: ElementRef; + height: number; + observer: ResizeObserver; + stopResizeLoop = false; + + bars: GraphBar[] = []; + tooltipPosition = { x: 0, y: 0 }; + + constructor( + private cd: ChangeDetectorRef, + ) {} + + ngOnInit(): void { + this.initGraph(); + } + + ngAfterViewInit(): void { + if (ResizeObserver) { + this.observer = new ResizeObserver(entries => { + for (const entry of entries) { + this.height = entry.contentRect.height; + this.initGraph(); + } + }); + this.observer.observe(this.container.nativeElement); + } else { + this.startResizeFallbackLoop(); + } + } + + ngOnChanges(): void { + this.initGraph(); + } + + initGraph(): void { + if (!this.tx || !this.estimate) { + return; + } + const hasNextBlockRate = (this.estimate.nextBlockFee > this.estimate.txSummary.effectiveFee); + const numBars = hasNextBlockRate ? 4 : 3; + const maxRate = Math.max(...this.maxRateOptions.map(option => option.rate)); + const baseRate = this.estimate.txSummary.effectiveFee / this.estimate.txSummary.effectiveVsize; + let baseHeight = Math.max(this.height - (numBars * 30), this.height * (baseRate / maxRate)); + const bars: GraphBar[] = []; + let lastHeight = 0; + if (hasNextBlockRate) { + lastHeight = Math.max(lastHeight + 30, (this.height * ((this.estimate.targetFeeRate - baseRate) / maxRate))); + bars.push({ + rate: this.estimate.targetFeeRate, + height: lastHeight, + class: 'target', + label: $localize`:@@bdf0e930eb22431140a2eaeacd809cc5f8ebd38c:Next Block`.toLowerCase(), + fee: this.estimate.nextBlockFee - this.estimate.txSummary.effectiveFee + }); + } + this.maxRateOptions.forEach((option, index) => { + lastHeight = Math.max(lastHeight + 30, (this.height * ((option.rate - baseRate) / maxRate))); + bars.push({ + rate: option.rate, + height: lastHeight, + class: 'max', + label: this.showEstimate ? $localize`maximum` : $localize`accelerated`, + active: option.index === this.maxRateIndex, + rateIndex: option.index, + fee: option.fee, + }) + }) + + bars.reverse(); + + baseHeight = this.height - lastHeight; + + for (const bar of bars) { + bar.style = this.getStyle(bar.height, baseHeight); + } + + bars.push({ + rate: baseRate, + style: this.getStyle(baseHeight, 0), + height: baseHeight, + class: 'tx', + label: '', + fee: this.estimate.txSummary.effectiveFee, + }); + + this.bars = bars; + this.cd.detectChanges(); + } + + getStyle(height: number, base: number): Record { + return { + height: `${height}px`, + bottom: base ? `${base}px` : '0', + } + } + + onClick(event, bar): void { + if (bar.rateIndex != null) { + this.setUserBid.emit({ fee: bar.fee, index: bar.rateIndex }); + } + } + + @HostListener('pointermove', ['$event']) + onPointerMove(event) { + this.tooltipPosition = { x: event.offsetX, y: event.offsetY }; + } + + startResizeFallbackLoop(): void { + if (this.stopResizeLoop) { + return; + } + requestAnimationFrame(() => { + this.height = this.container?.nativeElement?.clientHeight || 0; + this.initGraph(); + this.startResizeFallbackLoop(); + }); + } + + ngOnDestroy(): void { + this.stopResizeLoop = true; + this.observer.disconnect(); + } +} diff --git a/frontend/src/app/components/acceleration-timeline/acceleration-timeline.component.html b/frontend/src/app/components/acceleration-timeline/acceleration-timeline.component.html new file mode 100644 index 0000000000..28076efa52 --- /dev/null +++ b/frontend/src/app/components/acceleration-timeline/acceleration-timeline.component.html @@ -0,0 +1,133 @@ +
+
+ @if (!tx.status.confirmed) { +
+
+
+
+
+
+
+ @if (eta) { + ~ + } +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Mined
+
+
+
+ } +
+
+
+
+
+ +
+
+
+
+
+ @if (tx.status.confirmed) { +
+ +
+ } @else if (standardETA && !tx.status.confirmed) { + + } +
+
+
+
+
+
+
+
+
+
+
First seen
+
+ @if (useAbsoluteTime) { + {{ transactionTime * 1000 | date }} + } @else { + + } +
+
+
+
+
+
+
+ @if (tx.status.confirmed) { +
+ } @else { +
+ } +
+
+ @if (!tx.status.confirmed) { +
+ } +
+ @if (tx.status.confirmed) { +
Accelerated
+ } +
+ @if (!tx.status.confirmed) { + Accelerated{{ "" }} + } + @if (useAbsoluteTime) { + {{ acceleratedAt * 1000 | date }} + } @else { + + } +
+
+
+ @if (tx.status.confirmed) { +
+ } @else { +
+ } +
+
+ @if (tx.status.confirmed) { +
+ } @else { +
+ } +
+
+
+ @if (tx.status.confirmed) { +
Mined
+
+ @if (useAbsoluteTime) { + {{ tx.status.block_time * 1000 | date }} + } @else { + + } +
+ } +
+
+
+
+
diff --git a/frontend/src/app/components/acceleration-timeline/acceleration-timeline.component.scss b/frontend/src/app/components/acceleration-timeline/acceleration-timeline.component.scss new file mode 100644 index 0000000000..93a0cdba1e --- /dev/null +++ b/frontend/src/app/components/acceleration-timeline/acceleration-timeline.component.scss @@ -0,0 +1,265 @@ +.acceleration-timeline { + position: relative; + width: 100%; + padding: 1em 0; + &.lower-padding { + padding: 0.5em 0 1em; + } + + &::after, &::before { + content: ''; + display: block; + position: absolute; + top: 0; + bottom: 0; + width: 2em; + z-index: 2; + } + + &::before { + left: 0; + background: linear-gradient(to right, var(--box-bg), var(--box-bg), transparent); + } + + &::after { + right: 0; + background: linear-gradient(to left, var(--box-bg), var(--box-bg), transparent); + } + + .timeline-wrapper { + position: relative; + width: calc(100% - 2em); + margin: auto; + overflow-x: auto; + -ms-overflow-style: none; + scrollbar-width: none; + + &::-webkit-scrollbar { + display: none; + } + } + + .intervals, .nodes { + min-width: 100%; + display: flex; + flex-direction: row; + justify-content: space-between; + align-items: flex-start; + text-align: center; + + .node, .node-spacer { + width: 6em; + min-width: 6em; + flex-grow: 1; + } + + .interval, .interval-spacer { + width: 8em; + min-width: 8em; + max-width: 8em; + height: 32px; + display: flex; + flex-direction: row; + justify-content: center; + align-items: flex-end; + } + + .interval { + overflow: visible; + } + + .interval-time { + font-size: 12px; + line-height: 16px; + white-space: nowrap; + + .compare { + font-style: italic; + color: var(--mainnet-alt); + font-weight: 600; + @media (max-width: 600px) { + display: none; + } + } + } + } + + .node, .interval-spacer { + position: relative; + .seen-to-acc { + position: absolute; + height: 10px; + left: -5px; + right: -5px; + top: 0; + transform: translateY(-50%); + background: var(--primary); + border-radius: 5px; + + &.left { + right: 50%; + } + + &.right { + left: 50%; + } + } + + .acc-to-confirmed { + position: absolute; + height: 10px; + left: -5px; + right: -5px; + top: 0; + transform: translateY(-50%); + background: var(--tertiary); + border-radius: 5px; + + &.go-faster { + background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='20' height='10'%3E%3Cpath style='fill:%239339f4;' d='M 0,0 5,5 0,10 Z'/%3E%3Cpath style='fill:%23653b9c;' d='M 0,0 10,0 15,5 10,10 0,10 5,5 Z'/%3E%3Cpath style='fill:%239339f4;' d='M 10,0 20,0 20,10 10,10 15,5 Z'/%3E%3C/svg%3E%0A"); background-size: 20px 10px; + border-radius: 0; + + &.right { + left: calc(50% + 5px); + margin-right: calc(-4em + 5px); + animation: goFasterRight 0.8s infinite linear; + } + &.left { + right: calc(50% + 5px); + margin-left: calc(-4em + 5px); + animation: goFasterLeft 0.8s infinite linear; + } + } + + &.left { + right: 50%; + } + &.right { + left: 50%; + } + } + } + + .nodes { + position: relative; + margin-top: 1em; + .node { + .shape-border { + display: block; + margin: auto; + height: calc(1em + 8px); + width: calc(1em + 8px); + margin-bottom: -8px; + transform: translateY(-50%); + border-radius: 50%; + cursor: pointer; + padding: 4px; + background: transparent; + + .shape { + position: relative; + width: 100%; + height: 100%; + border-radius: 50%; + background: white; + z-index: 1; + } + + &.waiting { + .shape { + background: var(--grey); + } + } + + .connector { + position: absolute; + z-index: 0; + height: 88px; + width: 10px; + left: -5px; + top: -73px; + transform: translateX(120%); + background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' width='10' height='20'%3E%3Cpath style='fill:%239339f4;' d='M 0,20 5,15 10,20 Z'/%3E%3Cpath style='fill:%23653b9c;' d='M 0,20 5,15 10,20 10,10 5,5 0,10 Z'/%3E%3Cpath style='fill:%239339f4;' d='M 0,10 5,5 10,10 10,0 0,0 Z'/%3E%3C/svg%3E%0A"); // linear-gradient(135deg, var(--tertiary) 34%, transparent 34%), + background-size: 10px 20px; + + &.down { + border-top-left-radius: 10px; + } + + &.up { + border-top-right-radius: 10px; + } + + &.loading { + animation: goFasterUp 0.8s infinite linear; + } + } + } + + &.accelerated { + .shape-border { + animation: acceleratePulse 0.4s infinite; + } + } + + &.selected { + .shape-border { + background: var(--mainnet-alt); + } + } + + .status { + margin-top: -66px; + + .badge.badge-waiting { + opacity: 0.5; + background-color: var(--grey); + color: white; + } + + .badge.badge-accelerated { + background-color: var(--tertiary); + color: white; + } + } + + .time { + margin-top: 32px; + font-size: 12px; + line-height: 16px; + white-space: nowrap; + + &.offset-left { + @media (max-width: 650px) { + margin-left: -20px; + } + } + + &.no-margin { + margin-top: 0px; + } + } + } + } +} + +@keyframes acceleratePulse { + 0% { background-color: var(--tertiary) } + 50% { background-color: var(--mainnet-alt) } + 100% { background-color: var(--tertiary) } +} + +@keyframes goFasterUp { + 0% { background-position-y: 0; } + 100% { background-position-y: -40px; } +} + +@keyframes goFasterLeft { + 0% { background-position: left 0px bottom 0px } + 100% { background-position: left 40px bottom 0px; } +} + +@keyframes goFasterRight { + 0% { background-position: right 0 bottom 0px; } + 100% { background-position: right -40px bottom 0px; } +} diff --git a/frontend/src/app/components/acceleration-timeline/acceleration-timeline.component.ts b/frontend/src/app/components/acceleration-timeline/acceleration-timeline.component.ts new file mode 100644 index 0000000000..c8dbed72b9 --- /dev/null +++ b/frontend/src/app/components/acceleration-timeline/acceleration-timeline.component.ts @@ -0,0 +1,55 @@ +import { Component, Input, OnInit, OnChanges } from '@angular/core'; +import { ETA } from '../../services/eta.service'; +import { Transaction } from '../../interfaces/electrs.interface'; + +@Component({ + selector: 'app-acceleration-timeline', + templateUrl: './acceleration-timeline.component.html', + styleUrls: ['./acceleration-timeline.component.scss'], +}) +export class AccelerationTimelineComponent implements OnInit, OnChanges { + @Input() transactionTime: number; + @Input() tx: Transaction; + @Input() eta: ETA; + // A mined transaction has standard ETA and accelerated ETA undefined + // A transaction in mempool has either standardETA defined (if accelerated) or acceleratedETA defined (if not accelerated yet) + @Input() standardETA: number; + @Input() acceleratedETA: number; + + acceleratedAt: number; + now: number; + accelerateRatio: number; + useAbsoluteTime: boolean = false; + interval: number; + + constructor() {} + + ngOnInit(): void { + this.acceleratedAt = this.tx.acceleratedAt ?? new Date().getTime() / 1000; + this.now = Math.floor(new Date().getTime() / 1000); + this.useAbsoluteTime = this.tx.status.block_time < this.now - 7 * 24 * 3600; + + this.interval = window.setInterval(() => { + this.now = Math.floor(new Date().getTime() / 1000); + this.useAbsoluteTime = this.tx.status.block_time < this.now - 7 * 24 * 3600; + }, 60000); + } + + ngOnChanges(changes): void { + // Hide standard ETA while we don't have a proper standard ETA calculation, see https://github.com/mempool/mempool/issues/65 + + // if (changes?.eta?.currentValue || changes?.standardETA?.currentValue || changes?.acceleratedETA?.currentValue) { + // if (changes?.eta?.currentValue) { + // if (changes?.acceleratedETA?.currentValue) { + // this.accelerateRatio = Math.floor((Math.floor(changes.eta.currentValue.time / 1000) - this.now) / (Math.floor(changes.acceleratedETA.currentValue / 1000) - this.now)); + // } else if (changes?.standardETA?.currentValue) { + // this.accelerateRatio = Math.floor((Math.floor(changes.standardETA.currentValue / 1000) - this.now) / (Math.floor(changes.eta.currentValue.time / 1000) - this.now)); + // } + // } + // } + } + + ngOnDestroy(): void { + clearInterval(this.interval); + } +} diff --git a/frontend/src/app/components/acceleration/acceleration-fees-graph/acceleration-fees-graph.component.html b/frontend/src/app/components/acceleration/acceleration-fees-graph/acceleration-fees-graph.component.html new file mode 100644 index 0000000000..9146c8e34a --- /dev/null +++ b/frontend/src/app/components/acceleration/acceleration-fees-graph/acceleration-fees-graph.component.html @@ -0,0 +1,54 @@ + + +
+
+
+ Acceleration Fees + +
+ +
+
+ + + + + + + + + + +
+
+
+ +
+
+
+
+
+
diff --git a/frontend/src/app/components/acceleration/acceleration-fees-graph/acceleration-fees-graph.component.scss b/frontend/src/app/components/acceleration/acceleration-fees-graph/acceleration-fees-graph.component.scss new file mode 100644 index 0000000000..0b7c170fc6 --- /dev/null +++ b/frontend/src/app/components/acceleration/acceleration-fees-graph/acceleration-fees-graph.component.scss @@ -0,0 +1,67 @@ +.card-header { + border-bottom: 0; + font-size: 18px; + @media (min-width: 465px) { + font-size: 20px; + } + @media (min-width: 992px) { + height: 40px; + } +} + +.main-title { + position: relative; + color: var(--fg); + opacity: var(--opacity); + margin-top: -13px; + font-size: 10px; + text-transform: uppercase; + font-weight: 500; + text-align: center; + padding-bottom: 3px; +} + +.full-container { + display: flex; + flex-direction: column; + padding: 0px 15px; + width: 100%; + height: calc(100vh - 225px); + min-height: 400px; + @media (min-width: 992px) { + height: calc(100vh - 150px); + } +} + +.chart { + display: flex; + flex: 1; + width: 100%; + height: 100%; + padding-bottom: 20px; + padding-right: 10px; + @media (max-width: 992px) { + padding-bottom: 25px; + } + @media (max-width: 829px) { + padding-bottom: 50px; + } + @media (max-width: 767px) { + padding-bottom: 25px; + } + @media (max-width: 629px) { + padding-bottom: 55px; + } + @media (max-width: 567px) { + padding-bottom: 55px; + } +} + +h5 { + margin-bottom: 10px; +} + +.card-title { + font-size: 1rem; + color: var(--title-fg); +} diff --git a/frontend/src/app/components/acceleration/acceleration-fees-graph/acceleration-fees-graph.component.ts b/frontend/src/app/components/acceleration/acceleration-fees-graph/acceleration-fees-graph.component.ts new file mode 100644 index 0000000000..b5e575409e --- /dev/null +++ b/frontend/src/app/components/acceleration/acceleration-fees-graph/acceleration-fees-graph.component.ts @@ -0,0 +1,342 @@ +import { ChangeDetectionStrategy, ChangeDetectorRef, Component, Inject, Input, LOCALE_ID, NgZone, OnChanges, OnDestroy, OnInit, SimpleChanges } from '@angular/core'; +import { EChartsOption } from '../../../graphs/echarts'; +import { Observable, Subject, Subscription, combineLatest, fromEvent, merge, share } from 'rxjs'; +import { startWith, switchMap, tap } from 'rxjs/operators'; +import { SeoService } from '../../../services/seo.service'; +import { formatNumber } from '@angular/common'; +import { UntypedFormBuilder, UntypedFormGroup } from '@angular/forms'; +import { download, formatterXAxis, formatterXAxisLabel, formatterXAxisTimeCategory } from '../../../shared/graphs.utils'; +import { StorageService } from '../../../services/storage.service'; +import { MiningService } from '../../../services/mining.service'; +import { ActivatedRoute, Router } from '@angular/router'; +import { Acceleration } from '../../../interfaces/node-api.interface'; +import { ServicesApiServices } from '../../../services/services-api.service'; +import { StateService } from '../../../services/state.service'; +import { RelativeUrlPipe } from '../../../shared/pipes/relative-url/relative-url.pipe'; + +@Component({ + selector: 'app-acceleration-fees-graph', + templateUrl: './acceleration-fees-graph.component.html', + styleUrls: ['./acceleration-fees-graph.component.scss'], + styles: [` + .loadingGraphs { + position: absolute; + top: 50%; + left: calc(50% - 15px); + z-index: 100; + } + `], + changeDetection: ChangeDetectionStrategy.OnPush, +}) +export class AccelerationFeesGraphComponent implements OnInit, OnChanges, OnDestroy { + @Input() widget: boolean = false; + @Input() height: number = 300; + @Input() right: number | string = 45; + @Input() left: number | string = 75; + @Input() period: '24h' | '3d' | '1w' | '1m' | 'all' = '1w'; + @Input() accelerations$: Observable; + + miningWindowPreference: string; + radioGroupForm: UntypedFormGroup; + + chartOptions: EChartsOption = {}; + chartInitOptions = { + renderer: 'svg', + }; + + aggregatedHistory$: Observable; + statsSubscription: Subscription; + isLoading = true; + formatNumber = formatNumber; + timespan = ''; + periodSubject$: Subject<'24h' | '3d' | '1w' | '1m' | 'all'> = new Subject(); + chartInstance: any = undefined; + daysAvailable: number = 0; + + constructor( + @Inject(LOCALE_ID) public locale: string, + private seoService: SeoService, + private servicesApiService: ServicesApiServices, + private formBuilder: UntypedFormBuilder, + private storageService: StorageService, + private miningService: MiningService, + private route: ActivatedRoute, + public stateService: StateService, + private cd: ChangeDetectorRef, + private router: Router, + private zone: NgZone, + ) { + this.radioGroupForm = this.formBuilder.group({ dateSpan: '1w' }); + this.radioGroupForm.controls.dateSpan.setValue('1w'); + } + + ngOnInit(): void { + if (this.widget) { + this.miningWindowPreference = this.period; + } else { + this.seoService.setTitle($localize`:@@bcf34abc2d9ed8f45a2f65dd464c46694e9a181e:Acceleration Fees`); + this.miningWindowPreference = this.miningService.getDefaultTimespan('1w'); + } + this.radioGroupForm = this.formBuilder.group({ dateSpan: this.miningWindowPreference }); + this.radioGroupForm.controls.dateSpan.setValue(this.miningWindowPreference); + + this.route.fragment.subscribe((fragment) => { + if (['24h', '3d', '1w', '1m', '3m', 'all'].indexOf(fragment) > -1) { + this.radioGroupForm.controls.dateSpan.setValue(fragment, { emitEvent: false }); + } + }); + this.aggregatedHistory$ = combineLatest([ + merge( + this.radioGroupForm.get('dateSpan').valueChanges.pipe( + startWith(this.radioGroupForm.controls.dateSpan.value), + ), + this.periodSubject$ + ).pipe( + switchMap((timespan) => { + if (!this.widget) { + this.storageService.setValue('miningWindowPreference', timespan); + } + this.isLoading = true; + this.timespan = timespan; + return this.servicesApiService.getAggregatedAccelerationHistory$({timeframe: this.timespan}); + }) + ), + fromEvent(window, 'resize').pipe(startWith(null)), + ]).pipe( + tap(([response]) => { + const history: Acceleration[] = response.body; + this.daysAvailable = (new Date().getTime() / 1000 - response.headers.get('x-oldest-accel')) / (24 * 3600); + this.isLoading = false; + this.prepareChartOptions(history); + this.cd.markForCheck(); + }), + share(), + ); + + this.aggregatedHistory$.subscribe(); + } + + ngOnChanges(changes: SimpleChanges): void { + if (changes.period) { + this.periodSubject$.next(this.period); + } + } + + prepareChartOptions(data) { + let title: object; + if (data.length === 0) { + title = { + textStyle: { + color: 'grey', + fontSize: 15 + }, + text: $localize`No accelerated transaction for this timeframe`, + left: 'center', + top: 'center' + }; + } + + this.chartOptions = { + title: title, + color: [ + '#8F5FF6', + '#6b6b6b', + ], + animation: false, + grid: { + height: (this.widget && this.height) ? this.height - 30 : undefined, + top: this.widget ? 20 : 40, + bottom: this.widget ? 30 : 80, + right: this.right, + left: this.left, + }, + tooltip: { + show: !this.isMobile(), + trigger: 'axis', + axisPointer: { + type: 'line' + }, + backgroundColor: 'rgba(17, 19, 31, 1)', + borderRadius: 4, + shadowColor: 'rgba(0, 0, 0, 0.5)', + textStyle: { + color: '#b1b1b1', + align: 'left', + }, + borderColor: '#000', + formatter: (ticks) => { + let tooltip = `${formatterXAxis(this.locale, this.timespan, parseInt(ticks[0].axisValue, 10))}
`; + + if (ticks[0].data[1] > 10_000_000) { + tooltip += `${ticks[0].marker} ${ticks[0].seriesName}: ${formatNumber(ticks[0].data[1] / 100_000_000, this.locale, '1.0-8')} BTC
`; + } else { + tooltip += `${ticks[0].marker} ${ticks[0].seriesName}: ${formatNumber(ticks[0].data[1], this.locale, '1.0-0')} sats
`; + } + + if (['24h', '3d'].includes(this.timespan)) { + tooltip += `` + $localize`At block: ${ticks[0].data[2]}` + ``; + } else { + tooltip += `` + $localize`Around block: ${ticks[0].data[2]}` + ``; + } + + return tooltip; + } + }, + xAxis: data.length === 0 ? undefined : + { + name: this.widget ? undefined : formatterXAxisLabel(this.locale, this.timespan), + nameLocation: 'middle', + nameTextStyle: { + padding: [10, 0, 0, 0], + }, + type: 'time', + boundaryGap: [0, 0], + axisLine: { onZero: true }, + axisLabel: { + formatter: (val): string => formatterXAxisTimeCategory(this.locale, this.timespan, val), + align: 'center', + fontSize: 11, + lineHeight: 12, + hideOverlap: true, + padding: [0, 5], + }, + }, + legend: { + data: [ + { + name: 'Total bid boost', + inactiveColor: 'rgb(110, 112, 121)', + textStyle: { + color: 'white', + }, + icon: 'roundRect', + }, + ], + selected: { + 'Total bid boost': true, + }, + show: !this.widget, + }, + yAxis: data.length === 0 ? undefined : [ + { + type: 'value', + axisLabel: { + color: 'rgb(110, 112, 121)', + formatter: (val) => { + if (val >= 100_000) { + return `${(val / 100_000_000).toFixed(3)} BTC`; + } else { + return `${val} sats`; + } + } + }, + splitLine: { + lineStyle: { + type: 'dotted', + color: 'var(--transparent-fg)', + opacity: 0.25, + } + }, + }, + { + type: 'value', + position: 'right', + axisLabel: { + color: 'rgb(110, 112, 121)', + formatter: function(val) { + return `${val}`; + }.bind(this) + }, + splitLine: { + show: false, + }, + }, + ], + series: data.length === 0 ? undefined : [ + { + legendHoverLink: false, + zlevel: 1, + name: 'Total bid boost', + data: data.map(h => { + return [h.timestamp * 1000, h.sumBidBoost, h.avgHeight] + }), + stack: 'Total', + type: 'bar', + barWidth: '90%', + large: true, + barMinHeight: 1, + }, + ], + dataZoom: (this.widget || data.length === 0 )? undefined : [{ + type: 'inside', + realtime: true, + zoomLock: true, + maxSpan: 100, + minSpan: 5, + moveOnMouseMove: false, + }, { + showDetail: false, + show: true, + type: 'slider', + brushSelect: false, + realtime: true, + left: 20, + right: 15, + selectedDataBackground: { + lineStyle: { + color: '#fff', + opacity: 0.45, + }, + areaStyle: { + opacity: 0, + } + }, + }], + }; + } + + onChartInit(ec) { + this.chartInstance = ec; + + this.chartInstance.on('click', (e) => { + this.zone.run(() => { + if (['24h', '3d'].includes(this.timespan)) { + const url = new RelativeUrlPipe(this.stateService).transform(`/block/${e.data[2]}`); + if (e.event.event.shiftKey || e.event.event.ctrlKey || e.event.event.metaKey) { + window.open(url); + } else { + this.router.navigate([url]); + } + } + }); + }); + } + + isMobile() { + return (window.innerWidth <= 767.98); + } + + onSaveChart() { + // @ts-ignore + const prevBottom = this.chartOptions.grid.bottom; + const now = new Date(); + // @ts-ignore + this.chartOptions.grid.bottom = 40; + this.chartOptions.backgroundColor = '#11131f'; + this.chartInstance.setOption(this.chartOptions); + download(this.chartInstance.getDataURL({ + pixelRatio: 2, + excludeComponents: ['dataZoom'], + }), `acceleration-fees-${this.timespan}-${Math.round(now.getTime() / 1000)}.svg`); + // @ts-ignore + this.chartOptions.grid.bottom = prevBottom; + this.chartOptions.backgroundColor = 'none'; + this.chartInstance.setOption(this.chartOptions); + } + + ngOnDestroy(): void { + if (this.statsSubscription) { + this.statsSubscription.unsubscribe(); + } + } +} diff --git a/frontend/src/app/components/acceleration/acceleration-stats/acceleration-stats.component.html b/frontend/src/app/components/acceleration/acceleration-stats/acceleration-stats.component.html new file mode 100644 index 0000000000..c3c0e51349 --- /dev/null +++ b/frontend/src/app/components/acceleration/acceleration-stats/acceleration-stats.component.html @@ -0,0 +1,53 @@ +
+
+
+
Requests
+
+
{{ stats.totalRequested }}
+
accelerated
+
+
+
+
Total Bid Boost
+
+
{{ stats.totalBidBoost / 100_000_000 | amountShortener: 4 }} BTC
+ + + +
+
+
+
Total vSize
+
+
+
{{ (stats.totalVsize / (1_000_000 * blocksInPeriod) * 100).toFixed(2) }}% of blocks
+
+
+
+
+ + +
+
+
Requests
+
+
+
+
+
+
+
Total Bid Boost
+
+
+
+
+
+
+
Total vSize
+
+
+
+
+
+
+
diff --git a/frontend/src/app/components/acceleration/acceleration-stats/acceleration-stats.component.scss b/frontend/src/app/components/acceleration/acceleration-stats/acceleration-stats.component.scss new file mode 100644 index 0000000000..7331167765 --- /dev/null +++ b/frontend/src/app/components/acceleration/acceleration-stats/acceleration-stats.component.scss @@ -0,0 +1,88 @@ +.card-title { + color: var(--title-fg); + font-size: 10px; + margin-bottom: 4px; + font-size: 1rem; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; +} + +.card-text { + font-size: 22px; + span { + font-size: 11px; + position: relative; + top: -2px; + display: inline-flex; + } + .green-color { + display: block; + } +} + +.stats-container { + display: flex; + justify-content: space-between; + @media (min-width: 376px) { + flex-direction: row; + } + .item { + max-width: 150px; + margin: 0; + width: -webkit-fill-available; + @media (min-width: 376px) { + margin: 0 auto 0px; + } + &:last-child{ + display: none; + @media (min-width: 485px) { + display: block; + } + @media (min-width: 768px) { + display: none; + } + @media (min-width: 992px) { + display: block; + } + } + &:last-child { + margin-bottom: 0; + } + .card-text span { + color: var(--transparent-fg); + font-size: 12px; + top: 0px; + } + .fee-text{ + border-bottom: 1px solid #ffffff1c; + width: fit-content; + margin: auto; + line-height: 1.45; + padding: 0px 2px; + } + .fiat { + display: block; + font-size: 14px !important; + } + } +} + +.loading-container{ + min-height: 76px; +} + +.card-text { + .skeleton-loader { + width: 100%; + display: block; + &:first-child { + max-width: 90px; + margin: 15px auto 3px; + } + &:last-child { + margin: 10px auto 3px; + max-width: 55px; + } + } +} \ No newline at end of file diff --git a/frontend/src/app/components/acceleration/acceleration-stats/acceleration-stats.component.ts b/frontend/src/app/components/acceleration/acceleration-stats/acceleration-stats.component.ts new file mode 100644 index 0000000000..392f1392b3 --- /dev/null +++ b/frontend/src/app/components/acceleration/acceleration-stats/acceleration-stats.component.ts @@ -0,0 +1,55 @@ +import { ChangeDetectionStrategy, Component, Input, OnChanges, OnInit } from '@angular/core'; +import { Observable } from 'rxjs'; +import { ServicesApiServices } from '../../../services/services-api.service'; + +export type AccelerationStats = { + totalRequested: number; + totalBidBoost: number; + successRate: number; + totalVsize: number; +} + +@Component({ + selector: 'app-acceleration-stats', + templateUrl: './acceleration-stats.component.html', + styleUrls: ['./acceleration-stats.component.scss'], + changeDetection: ChangeDetectionStrategy.OnPush, +}) +export class AccelerationStatsComponent implements OnInit, OnChanges { + @Input() timespan: '24h' | '3d' | '1w' | '1m' | 'all' = '1w'; + accelerationStats$: Observable; + blocksInPeriod: number = 7 * 144; + + constructor( + private servicesApiService: ServicesApiServices + ) { } + + ngOnInit(): void { + this.updateStats(); + } + + ngOnChanges(): void { + this.updateStats(); + } + + updateStats(): void { + this.accelerationStats$ = this.servicesApiService.getAccelerationStats$({ timeframe: this.timespan }); + switch (this.timespan) { + case '24h': + this.blocksInPeriod = 144; + break; + case '3d': + this.blocksInPeriod = 3 * 144; + break; + case '1w': + this.blocksInPeriod = 7 * 144; + break; + case '1m': + this.blocksInPeriod = 30 * 144; + break; + case 'all': + this.blocksInPeriod = Infinity; + break; + } + } +} diff --git a/frontend/src/app/components/acceleration/accelerations-list/accelerations-list.component.html b/frontend/src/app/components/acceleration/accelerations-list/accelerations-list.component.html new file mode 100644 index 0000000000..df915c286a --- /dev/null +++ b/frontend/src/app/components/acceleration/accelerations-list/accelerations-list.component.html @@ -0,0 +1,101 @@ +
+

Accelerations

+
+ +
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
TXIDFee rateBidRequestedBid BoostBlockStatusRequested
+ + + + + + + {{ (acceleration.feeDelta) | number }} sat + + + + {{ acceleration.boost | number }} sat + + ~ + + {{ acceleration.blockHeight }} + ~ + + Pending + Completed 🔄 + Failed 🔄 + + +
+ + + + + + + +
+ + + + + +
+
+
+
+ + +
+ There are no active accelerations + There are no recent accelerations +
+
+ +
diff --git a/frontend/src/app/components/acceleration/accelerations-list/accelerations-list.component.scss b/frontend/src/app/components/acceleration/accelerations-list/accelerations-list.component.scss new file mode 100644 index 0000000000..d4579bcf68 --- /dev/null +++ b/frontend/src/app/components/acceleration/accelerations-list/accelerations-list.component.scss @@ -0,0 +1,186 @@ +.spinner-border { + height: 25px; + width: 25px; + margin-top: 13px; +} + +.container-xl { + max-width: 1400px; +} +.container-xl.widget { + padding-left: 0px; + padding-bottom: 0px; +} +.container-xl.legacy { + max-width: 1140px; +} +.container-xl.widget-container { + min-height: 335px; + @media (max-width: 767px) { + min-height: auto; + } +} + +.container { + max-width: 100%; +} + +.acceleration-list { + min-height: 295px; + @media (max-width: 767px) { + min-height: auto; + } +} + +tr, td, th { + border: 0px; + padding-top: 0.65rem !important; + padding-bottom: 0.8rem !important; + + .difference { + margin-left: 0.5em; + + &.positive { + color: rgb(66, 183, 71); + } + &.negative { + color: rgb(183, 66, 66); + } + } +} + +.clear-link { + color: white; +} + +.disabled { + pointer-events: none; + opacity: 0.5; +} + +.progress { + background-color: var(--secondary); +} + +.txid { + width: 20%; +} + +.fee { + width: 15%; +} + +.block { + width: 15%; + @media (max-width: 700px) { + display: none; + } +} + +.status { + width: 13%; +} + +.date { + width: 20%; + @media (max-width: 600px) { + display: none; + } +} + +.widget { + .txid { + width: 30%; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + max-width: 30%; + } + + .fee-rate { + width: 20%; + text-align: end !important; + @media (max-width: 975px) and (min-width: 768px) { + display: none; + } + @media (max-width: 410px) { + display: none; + } + } + + .bid { + text-align: end !important; + width: 30%; + min-width: 150px; + } + + .time { + width: 25%; + @media (max-width: 600px) { + display: none; + } + @media (max-width: 1200px) and (min-width: 768px) { + display: none; + } + } + + .fee { + width: 30%; + text-align: end !important; + } + + .block { + width: 20%; + @media (max-width: 1200px) and (min-width: 768px) { + display: none; + } + } + + .status { + width: 20% + } +} + +/* Tooltip text */ +.tooltip-custom { + position: relative; +} + +.tooltip-custom .tooltiptext { + visibility: hidden; + color: var(--fg); + text-align: center; + padding: 5px 0; + border-radius: 6px; + position: absolute; + z-index: 1; + top: -40px; + left: 0; +} + +/* Show the tooltip text when you mouse over the tooltip container */ +.tooltip-custom:hover .tooltiptext { + visibility: visible; +} + +.scriptmessage { + overflow: hidden; + display: inline-block; + text-overflow: ellipsis; + vertical-align: middle; + max-width: 50vw; + text-align: left; +} + +.no-data { + color: rgba(255, 255, 255, 0.4); + display: flex; + height: 280px; + width: 100%; + flex-direction: row; + align-items: center; + justify-content: center; + @media (max-width: 767px) { + height: 100px; + } +} diff --git a/frontend/src/app/components/acceleration/accelerations-list/accelerations-list.component.ts b/frontend/src/app/components/acceleration/accelerations-list/accelerations-list.component.ts new file mode 100644 index 0000000000..c236032e2c --- /dev/null +++ b/frontend/src/app/components/acceleration/accelerations-list/accelerations-list.component.ts @@ -0,0 +1,140 @@ +import { Component, OnInit, ChangeDetectionStrategy, Input, ChangeDetectorRef, OnDestroy, Inject, LOCALE_ID } from '@angular/core'; +import { BehaviorSubject, Observable, Subscription, catchError, filter, of, switchMap, tap, throttleTime } from 'rxjs'; +import { Acceleration, BlockExtended } from '../../../interfaces/node-api.interface'; +import { StateService } from '../../../services/state.service'; +import { WebsocketService } from '../../../services/websocket.service'; +import { ServicesApiServices } from '../../../services/services-api.service'; +import { SeoService } from '../../../services/seo.service'; +import { ActivatedRoute, Router } from '@angular/router'; + +@Component({ + selector: 'app-accelerations-list', + templateUrl: './accelerations-list.component.html', + styleUrls: ['./accelerations-list.component.scss'], + changeDetection: ChangeDetectionStrategy.OnPush, +}) +export class AccelerationsListComponent implements OnInit, OnDestroy { + @Input() widget: boolean = false; + @Input() pending: boolean = false; + @Input() accelerations$: Observable; + + accelerationList$: Observable = undefined; + + isLoading = true; + paginationMaxSize: number; + page = 1; + accelerationCount: number; + maxSize = window.innerWidth <= 767.98 ? 3 : 5; + skeletonLines: number[] = []; + pageSubject: BehaviorSubject = new BehaviorSubject(this.page); + keyNavigationSubscription: Subscription; + dir: 'rtl' | 'ltr' = 'ltr'; + paramSubscription: Subscription; + + constructor( + private servicesApiService: ServicesApiServices, + private websocketService: WebsocketService, + public stateService: StateService, + private cd: ChangeDetectorRef, + private seoService: SeoService, + private route: ActivatedRoute, + private router: Router, + @Inject(LOCALE_ID) private locale: string, + ) { + if (this.locale.startsWith('ar') || this.locale.startsWith('fa') || this.locale.startsWith('he')) { + this.dir = 'rtl'; + } + } + + ngOnInit(): void { + if (!this.widget) { + this.websocketService.want(['blocks']); + this.seoService.setTitle($localize`:@@02573b6980a2d611b4361a2595a4447e390058cd:Accelerations`); + + this.paramSubscription = this.route.params.pipe( + tap(params => { + this.page = +params['page'] || 1; + this.pageSubject.next(this.page); + }) + ).subscribe(); + + const prevKey = this.dir === 'ltr' ? 'ArrowLeft' : 'ArrowRight'; + const nextKey = this.dir === 'ltr' ? 'ArrowRight' : 'ArrowLeft'; + + this.keyNavigationSubscription = this.stateService.keyNavigation$.pipe( + filter((event) => event.key === prevKey || event.key === nextKey), + tap((event) => { + if (event.key === prevKey && this.page > 1) { + this.page--; + this.isLoading = true; + this.cd.markForCheck(); + } + if (event.key === nextKey && this.page * 15 < this.accelerationCount) { + this.page++; + this.isLoading = true; + this.cd.markForCheck(); + } + }), + throttleTime(1000, undefined, { leading: true, trailing: true }), + ).subscribe(() => { + this.pageChange(this.page); + }); + } + + this.skeletonLines = this.widget === true ? [...Array(6).keys()] : [...Array(15).keys()]; + this.paginationMaxSize = window.matchMedia('(max-width: 670px)').matches ? 3 : 5; + + this.accelerationList$ = this.pageSubject.pipe( + switchMap((page) => { + this.isLoading = true; + const accelerationObservable$ = this.accelerations$ || (this.pending ? this.stateService.liveAccelerations$ : this.servicesApiService.getAccelerationHistoryObserveResponse$({ page: page })); + if (!this.accelerations$ && this.pending) { + this.websocketService.ensureTrackAccelerations(); + } + return accelerationObservable$.pipe( + switchMap(response => { + let accelerations = response; + if (response.body) { + accelerations = response.body; + this.accelerationCount = parseInt(response.headers.get('x-total-count'), 10); + } + if (this.pending) { + for (const acceleration of accelerations) { + acceleration.status = acceleration.status || 'accelerating'; + } + } + for (const acc of accelerations) { + acc.boost = acc.boostCost != null ? acc.boostCost : acc.bidBoost; + } + if (this.widget) { + return of(accelerations.slice(0, 6)); + } else { + return of(accelerations); + } + }), + catchError((err) => { + this.isLoading = false; + return of([]); + }), + tap(() => { + this.isLoading = false; + }) + ); + }) + ); + } + + pageChange(page: number): void { + this.router.navigate(['acceleration', 'list', page]); + } + + trackByBlock(index: number, block: BlockExtended): number { + return block.height; + } + + ngOnDestroy(): void { + this.websocketService.stopTrackAccelerations(); + this.paramSubscription?.unsubscribe(); + this.keyNavigationSubscription?.unsubscribe(); + } +} \ No newline at end of file diff --git a/frontend/src/app/components/acceleration/accelerator-dashboard/accelerator-dashboard.component.html b/frontend/src/app/components/acceleration/accelerator-dashboard/accelerator-dashboard.component.html new file mode 100644 index 0000000000..9095a81298 --- /dev/null +++ b/frontend/src/app/components/acceleration/accelerator-dashboard/accelerator-dashboard.component.html @@ -0,0 +1,122 @@ + + +
+ +
+ + +
+
+ Active Accelerations +
+
+
+
+ +
+
+
+
+ + +
+
+ Acceleration stats  + @switch (timespan) { + @case ('24h') { + (1 day) + } + @case ('1w') { + (1 week) + } + @case ('1m') { + (1 month) + } + @case ('all') { + (all time) + } + } +
+
+
+
+ +
+ 24h + | + 1w + | + 1m + | + all +
+
+
+
+
+ + + + + +
+
+
+
Total Bid Boost
+
+ +
+ +
+
+
+ + +
+
+
+ + +
+
+
+ + + +
+
diff --git a/frontend/src/app/components/acceleration/accelerator-dashboard/accelerator-dashboard.component.scss b/frontend/src/app/components/acceleration/accelerator-dashboard/accelerator-dashboard.component.scss new file mode 100644 index 0000000000..e6763f60a4 --- /dev/null +++ b/frontend/src/app/components/acceleration/accelerator-dashboard/accelerator-dashboard.component.scss @@ -0,0 +1,192 @@ +.dashboard-container { + text-align: center; + margin-top: 0.5rem; + .col { + margin-bottom: 1.5rem; + } +} + +.card { + background-color: var(--bg); +} + +.graph-card { + height: 100%; + @media (min-width: 992px) { + height: 385px; + } +} + +.mempool-graph { + height: 295px; + @media (min-width: 768px) { + height: 325px; + } + @media (min-width: 992px) { + height: 409px; + } +} + +.card-title { + font-size: 1rem; + color: var(--title-fg); +} +.card-title > a { + color: var(--title-fg); +} + +.card-body.pool-ranking { + padding: 1.25rem 0.25rem 0.75rem 0.25rem; +} +.card-text { + font-size: 22px; +} + +#blockchain-container { + position: relative; + overflow-x: scroll; + overflow-y: hidden; + scrollbar-width: none; + -ms-overflow-style: none; +} + +#blockchain-container::-webkit-scrollbar { + display: none; +} + +.fade-border { + -webkit-mask-image: linear-gradient(to right, transparent 0%, black 10%, black 80%, transparent 100%) +} + +.main-title { + position: relative; + color: var(--fg); + opacity: var(--opacity); + margin-top: -13px; + font-size: 10px; + text-transform: uppercase; + font-weight: 500; + text-align: center; + padding-bottom: 3px; +} + +.more-padding { + padding: 24px 20px !important; +} + +.card-wrapper { + .card { + height: auto !important; + } + .card-body { + display: flex; + flex: inherit; + text-align: center; + flex-direction: column; + justify-content: space-around; + padding: 22px 20px; + } +} + +.skeleton-loader { + width: 100%; + display: block; + &:first-child { + max-width: 90px; + margin: 15px auto 3px; + } + &:last-child { + margin: 10px auto 3px; + max-width: 55px; + } +} + +.card-text { + font-size: 22px; +} + +.title-link, .title-link:hover, .title-link:focus, .title-link:active { + display: block; + margin-bottom: 10px; + text-decoration: none; + color: inherit; +} + +.lastest-blocks-table { + width: 100%; + text-align: left; + tr, td, th { + border: 0px; + padding-top: 0.65rem !important; + padding-bottom: 0.8rem !important; + } + .table-cell-height { + width: 25%; + } + .table-cell-fee { + width: 25%; + text-align: right; + } + .table-cell-pool { + text-align: left; + width: 30%; + + @media (max-width: 875px) { + display: none; + } + + .pool-name { + margin-left: 1em; + } + } + .table-cell-acceleration-count { + text-align: right; + width: 20%; + } +} + +.card { + @media (min-width: 768px) { + height: 420px; + } + @media (min-width: 992px) { + height: 510px; + } +} +.list-card { + height: 410px; + @media (max-width: 767px) { + height: auto; + } +} + +.mempool-block-wrapper { + max-height: 430px; + max-width: 430px; + margin: auto; + + @media (min-width: 768px) { + max-height: 344px; + max-width: 344px; + } + @media (min-width: 992px) { + max-height: 430px; + max-width: 430px; + } +} + +.widget-toggler { + font-size: 12px; + position: absolute; + top: -20px; + right: 3px; + text-align: right; +} + +.toggler-option { + text-decoration: none; +} + +.inactive { + color: #ffffff66; +} \ No newline at end of file diff --git a/frontend/src/app/components/acceleration/accelerator-dashboard/accelerator-dashboard.component.ts b/frontend/src/app/components/acceleration/accelerator-dashboard/accelerator-dashboard.component.ts new file mode 100644 index 0000000000..d84c6e97ce --- /dev/null +++ b/frontend/src/app/components/acceleration/accelerator-dashboard/accelerator-dashboard.component.ts @@ -0,0 +1,181 @@ +import { ChangeDetectionStrategy, Component, HostListener, Inject, OnDestroy, OnInit, PLATFORM_ID } from '@angular/core'; +import { SeoService } from '../../../services/seo.service'; +import { OpenGraphService } from '../../../services/opengraph.service'; +import { WebsocketService } from '../../../services/websocket.service'; +import { Acceleration, BlockExtended } from '../../../interfaces/node-api.interface'; +import { StateService } from '../../../services/state.service'; +import { Observable, Subscription, catchError, combineLatest, distinctUntilChanged, map, of, share, switchMap, tap } from 'rxjs'; +import { Color } from '../../block-overview-graph/sprite-types'; +import { hexToColor } from '../../block-overview-graph/utils'; +import TxView from '../../block-overview-graph/tx-view'; +import { feeLevels, defaultMempoolFeeColors, contrastMempoolFeeColors } from '../../../app.constants'; +import { ServicesApiServices } from '../../../services/services-api.service'; +import { detectWebGL } from '../../../shared/graphs.utils'; +import { AudioService } from '../../../services/audio.service'; +import { ThemeService } from '../../../services/theme.service'; + +const acceleratedColor: Color = hexToColor('8F5FF6'); +const normalColors = defaultMempoolFeeColors.map(hex => hexToColor(hex + '5F')); +const contrastColors = contrastMempoolFeeColors.map(hex => hexToColor(hex.slice(0,6) + '5F')); + +interface AccelerationBlock extends BlockExtended { + accelerationCount: number, +} + +@Component({ + selector: 'app-accelerator-dashboard', + templateUrl: './accelerator-dashboard.component.html', + styleUrls: ['./accelerator-dashboard.component.scss'], + changeDetection: ChangeDetectionStrategy.OnPush, +}) +export class AcceleratorDashboardComponent implements OnInit, OnDestroy { + blocks$: Observable; + accelerations$: Observable; + pendingAccelerations$: Observable; + minedAccelerations$: Observable; + loadingBlocks: boolean = true; + webGlEnabled = true; + seen: Set = new Set(); + firstLoad = true; + timespan: '24h' | '3d' | '1w' | '1m' | 'all' = '1w'; + + accelerationDeltaSubscription: Subscription; + + graphHeight: number = 300; + theme: ThemeService; + + constructor( + private seoService: SeoService, + private ogService: OpenGraphService, + private websocketService: WebsocketService, + private serviceApiServices: ServicesApiServices, + private audioService: AudioService, + private stateService: StateService, + @Inject(PLATFORM_ID) private platformId: Object, + ) { + this.webGlEnabled = this.stateService.isBrowser && detectWebGL(); + this.seoService.setTitle($localize`:@@6b867dc61c6a92f3229f1950f9f2d414790cce95:Accelerator Dashboard`); + this.ogService.setManualOgImage('accelerator.jpg'); + } + + ngOnInit(): void { + this.onResize(); + this.websocketService.want(['blocks', 'mempool-blocks', 'stats']); + this.websocketService.startTrackAccelerations(); + + this.pendingAccelerations$ = this.stateService.liveAccelerations$.pipe( + share(), + ); + this.accelerationDeltaSubscription = this.stateService.accelerations$.subscribe((delta) => { + if (!delta.reset) { + let hasNewAcceleration = false; + for (const acc of delta.added) { + if (!this.seen.has(acc.txid)) { + hasNewAcceleration = true; + } + this.seen.add(acc.txid); + } + for (const txid of delta.removed) { + this.seen.delete(txid); + } + if (hasNewAcceleration) { + this.audioService.playSound('bright-harmony'); + } + } + }); + + this.accelerations$ = this.stateService.chainTip$.pipe( + distinctUntilChanged(), + switchMap(() => { + return this.serviceApiServices.getAccelerationHistory$({}).pipe( + catchError(() => { + return of([]); + }), + ); + }), + share(), + ); + + this.minedAccelerations$ = this.stateService.chainTip$.pipe( + distinctUntilChanged(), + switchMap(() => { + return this.serviceApiServices.getAccelerationHistory$({ status: 'completed_provisional,completed', pageLength: 6 }).pipe( + catchError(() => { + return of([]); + }), + ); + }), + share(), + ); + + this.blocks$ = combineLatest([ + this.accelerations$, + this.stateService.blocks$.pipe( + switchMap((blocks) => { + if (this.stateService.env.MINING_DASHBOARD === true) { + for (const block of blocks) { + // @ts-ignore: Need to add an extra field for the template + block.extras.pool.logo = `/resources/mining-pools/` + + block.extras.pool.name.toLowerCase().replace(' ', '').replace('.', '') + '.svg'; + } + } + return of(blocks as AccelerationBlock[]); + }), + tap(() => { + this.loadingBlocks = false; + }) + ) + ]).pipe( + switchMap(([accelerations, blocks]) => { + const blockMap = {}; + for (const block of blocks) { + blockMap[block.height] = block; + } + const accelerationsByBlock: { [ height: number ]: Acceleration[] } = {}; + for (const acceleration of accelerations) { + if (['completed_provisional', 'failed_provisional', 'completed'].includes(acceleration.status) && acceleration.pools.includes(blockMap[acceleration.blockHeight]?.extras.pool.id)) { + if (!accelerationsByBlock[acceleration.blockHeight]) { + accelerationsByBlock[acceleration.blockHeight] = []; + } + accelerationsByBlock[acceleration.blockHeight].push(acceleration); + } + } + return of(blocks.slice(0, 6).map(block => { + block.accelerationCount = (accelerationsByBlock[block.id] || []).length; + return block; + })); + }) + ); + } + + getAcceleratorColor(tx: TxView): Color { + if (tx.status === 'accelerated' || tx.acc) { + return acceleratedColor; + } else { + const rate = tx.fee / tx.vsize; // color by simple single-tx fee rate + const feeLevelIndex = feeLevels.findIndex((feeLvl) => Math.max(1, rate) < feeLvl) - 1; + return this.theme.theme === 'contrast' || this.theme.theme === 'bukele' ? contrastColors[feeLevelIndex] || contrastColors[contrastColors.length - 1] : normalColors[feeLevelIndex] || normalColors[normalColors.length - 1]; + } + } + + setTimespan(timespan): boolean { + this.timespan = timespan; + return false; + } + + ngOnDestroy(): void { + this.accelerationDeltaSubscription.unsubscribe(); + this.websocketService.stopTrackAccelerations(); + } + + @HostListener('window:resize', ['$event']) + onResize(): void { + if (window.innerWidth >= 992) { + this.graphHeight = 380; + } else if (window.innerWidth >= 768) { + this.graphHeight = 300; + } else { + this.graphHeight = 270; + } + } +} diff --git a/frontend/src/app/components/acceleration/active-acceleration-box/active-acceleration-box.component.html b/frontend/src/app/components/acceleration/active-acceleration-box/active-acceleration-box.component.html new file mode 100644 index 0000000000..83ecad4596 --- /dev/null +++ b/frontend/src/app/components/acceleration/active-acceleration-box/active-acceleration-box.component.html @@ -0,0 +1,66 @@ +@if (chartOnly) { + +} @else { + + + + + + + + + + + + + @if (hasCpfp && chartPositionLeft) { + + + + } + +
Accelerated to + + +
+ @if (accelerationInfo?.acceleratedFeeRate && (!tx.effectiveFeePerVsize || accelerationInfo.acceleratedFeeRate >= tx.effectiveFeePerVsize)) { + + } @else { + + } +
+
+
+ @if (hasCpfp) { + + } + +
+
Accelerated by + {{ acceleratedByPercentage }} of hashrate +
+
+ +
+
+} + + +
+ @if (chartOptions && miningStats) { +
+ } @else { +
+
+
+ } +
+
\ No newline at end of file diff --git a/frontend/src/app/components/acceleration/active-acceleration-box/active-acceleration-box.component.scss b/frontend/src/app/components/acceleration/active-acceleration-box/active-acceleration-box.component.scss new file mode 100644 index 0000000000..b01a902a43 --- /dev/null +++ b/frontend/src/app/components/acceleration/active-acceleration-box/active-acceleration-box.component.scss @@ -0,0 +1,64 @@ +.td-width { + width: 150px; + min-width: 150px; + + @media (max-width: 768px) { + width: 175px; + min-width: 175px; + } +} + +.field-label { + @media (max-width: 849px) { + text-align: left; + } + @media (max-width: 649px) { + width: auto; + min-width: auto; + } + &.chart-left { + width: 100%; + } +} + +.field-value { + @media (max-width: 849px) { + width: 100%; + } + + &.chart-left { + width: auto; + } + + .hashrate-label { + @media (max-width: 420px) { + display: none; + } + } +} + +.pie-chart { + width: 100%; + vertical-align: middle; + text-align: center; + + .chart-container { + width: 72px; + height: 100%; + margin-left: auto; + } + + @media (max-width: 850px) { + width: 150px; + } + @media (max-width: 420px) { + padding-left: 0; + } +} + +::ng-deep .chart { + overflow: visible; + & > div, & > div > svg { + overflow: visible !important; + } +} \ No newline at end of file diff --git a/frontend/src/app/components/acceleration/active-acceleration-box/active-acceleration-box.component.ts b/frontend/src/app/components/acceleration/active-acceleration-box/active-acceleration-box.component.ts new file mode 100644 index 0000000000..46ba128165 --- /dev/null +++ b/frontend/src/app/components/acceleration/active-acceleration-box/active-acceleration-box.component.ts @@ -0,0 +1,142 @@ +import { Component, ChangeDetectionStrategy, Input, Output, OnChanges, SimpleChanges, EventEmitter } from '@angular/core'; +import { Transaction } from '../../../interfaces/electrs.interface'; +import { Acceleration, SinglePoolStats } from '../../../interfaces/node-api.interface'; +import { EChartsOption, PieSeriesOption } from '../../../graphs/echarts'; +import { MiningStats } from '../../../services/mining.service'; + +function lighten(color, p): { r, g, b } { + return { + r: color.r + ((255 - color.r) * p), + g: color.g + ((255 - color.g) * p), + b: color.b + ((255 - color.b) * p), + }; +} + +function toRGB({r,g,b}): string { + return `rgb(${r},${g},${b})`; +} + +@Component({ + selector: 'app-active-acceleration-box', + templateUrl: './active-acceleration-box.component.html', + styleUrls: ['./active-acceleration-box.component.scss'], + changeDetection: ChangeDetectionStrategy.OnPush, +}) +export class ActiveAccelerationBox implements OnChanges { + @Input() tx: Transaction; + @Input() accelerationInfo: Acceleration; + @Input() miningStats: MiningStats; + @Input() pools: number[]; + @Input() hasCpfp: boolean = false; + @Input() chartOnly: boolean = false; + @Input() chartPositionLeft: boolean = false; + @Output() toggleCpfp = new EventEmitter(); + + acceleratedByPercentage: string = ''; + + chartOptions: EChartsOption; + chartInitOptions = { + renderer: 'svg', + }; + timespan = ''; + chartInstance: any = undefined; + + constructor() {} + + ngOnChanges(changes: SimpleChanges): void { + const pools = this.pools || this.accelerationInfo?.pools || this.tx.acceleratedBy; + if (pools && this.miningStats) { + this.prepareChartOptions(pools); + } + } + + getChartData(poolList: number[]) { + const data: object[] = []; + const pools: { [id: number]: SinglePoolStats } = {}; + for (const pool of this.miningStats.pools) { + pools[pool.poolUniqueId] = pool; + } + + const getDataItem = (value, color, tooltip, emphasis) => ({ + value, + name: tooltip, + itemStyle: { + color, + }, + }); + + const acceleratingPools = (poolList || []).filter(id => pools[id]).sort((a,b) => pools[a].lastEstimatedHashrate - pools[b].lastEstimatedHashrate); + const totalAcceleratedHashrate = acceleratingPools.reduce((total, pool) => total + pools[pool].lastEstimatedHashrate, 0); + acceleratingPools.forEach((poolId, index) => { + const pool = pools[poolId]; + const poolShare = ((pool.lastEstimatedHashrate / this.miningStats.lastEstimatedHashrate) * 100).toFixed(1); + data.push(getDataItem( + pool.lastEstimatedHashrate, + toRGB(lighten({ r: 147, g: 57, b: 244 }, index * .08)), + `${pool.name} (${poolShare}%)`, + true, + ) as PieSeriesOption); + }) + this.acceleratedByPercentage = ((totalAcceleratedHashrate / this.miningStats.lastEstimatedHashrate) * 100).toFixed(1) + '%'; + const notAcceleratedByPercentage = ((1 - (totalAcceleratedHashrate / this.miningStats.lastEstimatedHashrate)) * 100).toFixed(1) + '%'; + data.push(getDataItem( + (this.miningStats.lastEstimatedHashrate - totalAcceleratedHashrate), + 'rgba(127, 127, 127, 0.3)', + $localize`not accelerating` + ` (${notAcceleratedByPercentage})`, + false, + ) as PieSeriesOption); + + return data; + } + + prepareChartOptions(pools: number[]) { + this.chartOptions = { + animation: false, + grid: { + top: 0, + right: 0, + bottom: 0, + left: 0, + }, + tooltip: { + show: true, + trigger: 'item', + backgroundColor: 'rgba(17, 19, 31, 1)', + borderRadius: 4, + shadowColor: 'rgba(0, 0, 0, 0.5)', + textStyle: { + color: 'var(--tooltip-grey)', + }, + borderColor: '#000', + formatter: (item) => { + return item.name; + } + }, + series: [ + { + type: 'pie', + radius: '100%', + label: { + show: false + }, + labelLine: { + show: false + }, + animationDuration: 0, + data: this.getChartData(pools), + } + ] + }; + } + + onChartInit(ec) { + if (this.chartInstance !== undefined) { + return; + } + this.chartInstance = ec; + } + + onToggleCpfp(): void { + this.toggleCpfp.emit(); + } +} \ No newline at end of file diff --git a/frontend/src/app/components/acceleration/pending-stats/pending-stats.component.html b/frontend/src/app/components/acceleration/pending-stats/pending-stats.component.html new file mode 100644 index 0000000000..be2bed1347 --- /dev/null +++ b/frontend/src/app/components/acceleration/pending-stats/pending-stats.component.html @@ -0,0 +1,53 @@ +
+
+
+
Requests
+
+
{{ stats.count }}
+
pending
+
+
+
+
Avg Max Bid
+
+
{{ stats.avgFeeDelta / 100_000_000 | amountShortener: 4 }} BTC
+ + + +
+
+
+
Total vSize
+
+
+
{{ (stats.totalVsize / 1_000_000 * 100).toFixed(2) }}% of block
+
+
+
+
+ + +
+
+
Requests
+
+
+
+
+
+
+
Avg Max Bid
+
+
+
+
+
+
+
Total vSize
+
+
+
+
+
+
+
diff --git a/frontend/src/app/components/acceleration/pending-stats/pending-stats.component.scss b/frontend/src/app/components/acceleration/pending-stats/pending-stats.component.scss new file mode 100644 index 0000000000..7331167765 --- /dev/null +++ b/frontend/src/app/components/acceleration/pending-stats/pending-stats.component.scss @@ -0,0 +1,88 @@ +.card-title { + color: var(--title-fg); + font-size: 10px; + margin-bottom: 4px; + font-size: 1rem; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; +} + +.card-text { + font-size: 22px; + span { + font-size: 11px; + position: relative; + top: -2px; + display: inline-flex; + } + .green-color { + display: block; + } +} + +.stats-container { + display: flex; + justify-content: space-between; + @media (min-width: 376px) { + flex-direction: row; + } + .item { + max-width: 150px; + margin: 0; + width: -webkit-fill-available; + @media (min-width: 376px) { + margin: 0 auto 0px; + } + &:last-child{ + display: none; + @media (min-width: 485px) { + display: block; + } + @media (min-width: 768px) { + display: none; + } + @media (min-width: 992px) { + display: block; + } + } + &:last-child { + margin-bottom: 0; + } + .card-text span { + color: var(--transparent-fg); + font-size: 12px; + top: 0px; + } + .fee-text{ + border-bottom: 1px solid #ffffff1c; + width: fit-content; + margin: auto; + line-height: 1.45; + padding: 0px 2px; + } + .fiat { + display: block; + font-size: 14px !important; + } + } +} + +.loading-container{ + min-height: 76px; +} + +.card-text { + .skeleton-loader { + width: 100%; + display: block; + &:first-child { + max-width: 90px; + margin: 15px auto 3px; + } + &:last-child { + margin: 10px auto 3px; + max-width: 55px; + } + } +} \ No newline at end of file diff --git a/frontend/src/app/components/acceleration/pending-stats/pending-stats.component.ts b/frontend/src/app/components/acceleration/pending-stats/pending-stats.component.ts new file mode 100644 index 0000000000..568e60d7e1 --- /dev/null +++ b/frontend/src/app/components/acceleration/pending-stats/pending-stats.component.ts @@ -0,0 +1,43 @@ +import { ChangeDetectionStrategy, Component, Input, OnInit } from '@angular/core'; +import { Observable, of } from 'rxjs'; +import { switchMap } from 'rxjs/operators'; +import { Acceleration } from '../../../interfaces/node-api.interface'; +import { StateService } from '../../../services/state.service'; +import { WebsocketService } from '../../../services/websocket.service'; + +@Component({ + selector: 'app-pending-stats', + templateUrl: './pending-stats.component.html', + styleUrls: ['./pending-stats.component.scss'], + changeDetection: ChangeDetectionStrategy.OnPush, +}) +export class PendingStatsComponent implements OnInit { + @Input() accelerations$: Observable; + public accelerationStats$: Observable; + + constructor( + private stateService: StateService, + private websocketService: WebsocketService, + ) { } + + ngOnInit(): void { + this.accelerationStats$ = (this.accelerations$ || this.stateService.liveAccelerations$).pipe( + switchMap(accelerations => { + let totalAccelerations = 0; + let totalFeeDelta = 0; + let totalVsize = 0; + for (const acceleration of accelerations) { + totalAccelerations++; + totalFeeDelta += acceleration.feeDelta || 0; + totalVsize += acceleration.effectiveVsize || 0; + } + return of({ + count: totalAccelerations, + totalFeeDelta, + avgFeeDelta: totalAccelerations ? totalFeeDelta / totalAccelerations : 0, + totalVsize, + }); + }) + ); + } +} diff --git a/frontend/src/app/components/address-graph/address-graph.component.html b/frontend/src/app/components/address-graph/address-graph.component.html new file mode 100644 index 0000000000..c9dd072c84 --- /dev/null +++ b/frontend/src/app/components/address-graph/address-graph.component.html @@ -0,0 +1,21 @@ + + +
+ +
+
+
+
+
+
+ +
+

{{ error }}

+
+
+ +
+
+
+
diff --git a/frontend/src/app/components/address-graph/address-graph.component.scss b/frontend/src/app/components/address-graph/address-graph.component.scss new file mode 100644 index 0000000000..1b5e0320da --- /dev/null +++ b/frontend/src/app/components/address-graph/address-graph.component.scss @@ -0,0 +1,59 @@ +.card-header { + border-bottom: 0; + font-size: 18px; + @media (min-width: 465px) { + font-size: 20px; + } + @media (min-width: 992px) { + height: 40px; + } +} + +.main-title { + position: relative; + color: var(--fg); + opacity: var(--opacity); + margin-top: -13px; + font-size: 10px; + text-transform: uppercase; + font-weight: 500; + text-align: center; + padding-bottom: 3px; +} + +.full-container { + display: flex; + flex-direction: column; + padding: 0px; + width: 100%; + height: 400px; +} + +.error-wrapper { + display: flex; + flex-direction: column; + width: 100%; + height: 100%; + align-items: center; + justify-content: center; + + font-size: 15px; + color: grey; + font-weight: bold; +} + +.chart { + display: flex; + flex: 1; + width: 100%; + padding-right: 10px; +} +.chart-widget { + width: 100%; + height: 100%; +} + +.disabled { + pointer-events: none; + opacity: 0.5; +} \ No newline at end of file diff --git a/frontend/src/app/components/address-graph/address-graph.component.ts b/frontend/src/app/components/address-graph/address-graph.component.ts new file mode 100644 index 0000000000..9793c6a2e1 --- /dev/null +++ b/frontend/src/app/components/address-graph/address-graph.component.ts @@ -0,0 +1,487 @@ +import { ChangeDetectionStrategy, ChangeDetectorRef, Component, Inject, Input, LOCALE_ID, NgZone, OnChanges, OnDestroy, SimpleChanges } from '@angular/core'; +import { echarts, EChartsOption } from '../../graphs/echarts'; +import { BehaviorSubject, Observable, Subscription, combineLatest, of } from 'rxjs'; +import { catchError, map, switchMap, tap } from 'rxjs/operators'; +import { AddressTxSummary, ChainStats } from '../../interfaces/electrs.interface'; +import { ElectrsApiService } from '../../services/electrs-api.service'; +import { AmountShortenerPipe } from '../../shared/pipes/amount-shortener.pipe'; +import { Router } from '@angular/router'; +import { RelativeUrlPipe } from '../../shared/pipes/relative-url/relative-url.pipe'; +import { StateService } from '../../services/state.service'; +import { PriceService } from '../../services/price.service'; +import { FiatCurrencyPipe } from '../../shared/pipes/fiat-currency.pipe'; +import { FiatShortenerPipe } from '../../shared/pipes/fiat-shortener.pipe'; + +const periodSeconds = { + '1d': (60 * 60 * 24), + '3d': (60 * 60 * 24 * 3), + '1w': (60 * 60 * 24 * 7), + '1m': (60 * 60 * 24 * 30), + '6m': (60 * 60 * 24 * 180), + '1y': (60 * 60 * 24 * 365), +}; + +@Component({ + selector: 'app-address-graph', + templateUrl: './address-graph.component.html', + styleUrls: ['./address-graph.component.scss'], + styles: [` + .loadingGraphs { + position: absolute; + top: 50%; + left: calc(50% - 15px); + z-index: 100; + } + `], + changeDetection: ChangeDetectionStrategy.OnPush, +}) +export class AddressGraphComponent implements OnChanges, OnDestroy { + @Input() address: string; + @Input() isPubkey: boolean = false; + @Input() stats: ChainStats; + @Input() addressSummary$: Observable | null; + @Input() period: '1d' | '3d' | '1w' | '1m' | '6m' | '1y' | 'all' = 'all'; + @Input() height: number = 200; + @Input() right: number | string = 10; + @Input() left: number | string = 70; + @Input() widget: boolean = false; + + data: any[] = []; + fiatData: any[] = []; + hoverData: any[] = []; + conversions: any; + allowZoom: boolean = false; + initialRight = this.right; + initialLeft = this.left; + selected = { [$localize`:@@7e69426bd97a606d8ae6026762858e6e7c86a1fd:Balance`]: true, 'Fiat': false }; + + subscription: Subscription; + redraw$: BehaviorSubject = new BehaviorSubject(false); + + chartOptions: EChartsOption = {}; + chartInitOptions = { + renderer: 'svg', + }; + + error: any; + isLoading = true; + chartInstance: any = undefined; + + constructor( + @Inject(LOCALE_ID) public locale: string, + public stateService: StateService, + private electrsApiService: ElectrsApiService, + private router: Router, + private amountShortenerPipe: AmountShortenerPipe, + private cd: ChangeDetectorRef, + private relativeUrlPipe: RelativeUrlPipe, + private priceService: PriceService, + private fiatCurrencyPipe: FiatCurrencyPipe, + private fiatShortenerPipe: FiatShortenerPipe, + private zone: NgZone, + ) {} + + ngOnChanges(changes: SimpleChanges): void { + this.isLoading = true; + if (!this.address || !this.stats) { + return; + } + if (changes.address || changes.isPubkey || changes.addressSummary$ || changes.stats) { + if (this.subscription) { + this.subscription.unsubscribe(); + } + this.subscription = combineLatest([ + this.redraw$, + (this.addressSummary$ || (this.isPubkey + ? this.electrsApiService.getScriptHashSummary$((this.address.length === 66 ? '21' : '41') + this.address + 'ac') + : this.electrsApiService.getAddressSummary$(this.address)).pipe( + catchError(e => { + this.error = `Failed to fetch address balance history: ${e?.status || ''} ${e?.statusText || 'unknown error'}`; + return of(null); + }), + )), + this.stateService.conversions$ + ]).pipe( + switchMap(([redraw, addressSummary, conversions]) => { + this.conversions = conversions; + if (addressSummary) { + let extendedSummary = this.extendSummary(addressSummary); + return this.priceService.getPriceByBulk$(extendedSummary.map(d => d.time), 'USD').pipe( + tap((prices) => { + if (prices.length !== extendedSummary.length) { + extendedSummary = extendedSummary.map(item => ({ ...item, price: 0 })); + } else { + extendedSummary = extendedSummary.map((item, index) => { + let price = 0; + if (prices[index].price) { + price = prices[index].price['USD']; + } else if (this.conversions && this.conversions['USD']) { + price = this.conversions['USD']; + } + return { ...item, price: price } + }); + } + }), + map(() => [redraw, extendedSummary, conversions]) + ) + } else { + return of([redraw, addressSummary, conversions]); + } + }) + ).subscribe(([redraw, addressSummary, conversions]) => { + if (addressSummary) { + this.error = null; + this.allowZoom = addressSummary.length > 100 && !this.widget; + this.prepareChartOptions(addressSummary); + } + this.isLoading = false; + this.cd.markForCheck(); + }); + } else { + // re-trigger subscription + this.redraw$.next(true); + } + } + + prepareChartOptions(summary: AddressTxSummary[]) { + if (!summary || !this.stats) { + return; + } + + let total = (this.stats.funded_txo_sum - this.stats.spent_txo_sum); + const processData = summary.map(d => { + const balance = total; + const fiatBalance = total * d.price / 100_000_000; + total -= d.value; + return { + time: d.time * 1000, + balance, + fiatBalance, + d + }; + }).reverse(); + + this.data = processData.filter(({ d }) => d.txid !== undefined).map(({ time, balance, d }) => [time, balance, d]); + this.fiatData = processData.map(({ time, fiatBalance, balance, d }) => [time, fiatBalance, d, balance]); + + const now = Date.now(); + if (this.period !== 'all') { + const start = now - (periodSeconds[this.period] * 1000); + this.data = this.data.filter(d => d[0] >= start); + const startFiat = this.data[0]?.[0] ?? start; // Make sure USD data starts at the same time as BTC data + this.fiatData = this.fiatData.filter(d => d[0] >= startFiat); + } + this.data.push( + {value: [now, this.stats.funded_txo_sum - this.stats.spent_txo_sum], symbol: 'none', tooltip: { show: false }} + ); + + const maxValue = this.data.reduce((acc, d) => Math.max(acc, Math.abs(d[1] ?? d.value[1])), 0); + const minValue = this.data.reduce((acc, d) => Math.min(acc, Math.abs(d[1] ?? d.value[1])), maxValue); + + this.chartOptions = { + color: [ + new echarts.graphic.LinearGradient(0, 0, 0, 1, [ + { offset: 0, color: '#FDD835' }, + { offset: 1, color: '#FB8C00' }, + ]), + new echarts.graphic.LinearGradient(0, 0, 0, 1, [ + { offset: 0, color: '#4CAF50' }, + { offset: 1, color: '#1B5E20' }, + ]), + ], + animation: false, + grid: { + top: 20, + bottom: this.allowZoom ? 65 : 20, + right: this.right, + left: this.left, + }, + legend: !this.stateService.isAnyTestnet() ? { + data: [ + { + name: $localize`:@@7e69426bd97a606d8ae6026762858e6e7c86a1fd:Balance`, + inactiveColor: 'var(--grey)', + textStyle: { + color: 'white', + }, + icon: 'roundRect', + }, + { + name: 'Fiat', + inactiveColor: 'var(--grey)', + textStyle: { + color: 'white', + }, + icon: 'roundRect', + } + ], + selected: this.selected, + formatter: function (name) { + return name === 'Fiat' ? 'USD' : 'BTC'; + } + } : undefined, + tooltip: { + show: !this.isMobile(), + trigger: 'axis', + axisPointer: { + type: 'line' + }, + backgroundColor: 'rgba(17, 19, 31, 1)', + borderRadius: 4, + shadowColor: 'rgba(0, 0, 0, 0.5)', + textStyle: { + color: '#b1b1b1', + align: 'left', + }, + borderColor: '#000', + formatter: function (data) { + const btcData = data.filter(d => d.seriesName !== 'Fiat'); + const fiatData = data.filter(d => d.seriesName === 'Fiat'); + data = btcData.length ? btcData : fiatData; + if ((!btcData.length || !btcData[0]?.data?.[2]?.txid) && !fiatData.length) { + return ''; + } + let tooltip = '
'; + + const hasTx = data[0].data[2].txid; + if (hasTx) { + const header = data.length === 1 + ? `${data[0].data[2].txid.slice(0, 6)}...${data[0].data[2].txid.slice(-6)}` + : `${data.length} transactions`; + tooltip += `${header}`; + } + + const date = new Date(data[0].data[0]).toLocaleTimeString(this.locale, { year: 'numeric', month: 'short', day: 'numeric' }); + + tooltip += `
+
`; + + const formatBTC = (val, decimal) => (val / 100_000_000).toFixed(decimal); + const formatFiat = (val) => this.fiatCurrencyPipe.transform(val, null, 'USD'); + + const btcVal = btcData.reduce((total, d) => total + d.data[2].value, 0); + const fiatVal = fiatData.reduce((total, d) => total + d.data[2].value * d.data[2].price / 100_000_000, 0); + const btcColor = btcVal === 0 ? '' : (btcVal > 0 ? 'var(--green)' : 'var(--red)'); + const fiatColor = fiatVal === 0 ? '' : (fiatVal > 0 ? 'var(--green)' : 'var(--red)'); + const btcSymbol = btcVal > 0 ? '+' : ''; + const fiatSymbol = fiatVal > 0 ? '+' : ''; + + if (btcData.length && fiatData.length) { + tooltip += `
+ ${btcSymbol} ${formatBTC(btcVal, 4)} BTC + ${fiatSymbol} ${formatFiat(fiatVal)} +
+
+ ${formatBTC(btcData[0].data[1], 4)} BTC + ${formatFiat(fiatData[0].data[1])} +
`; + } else if (btcData.length) { + tooltip += `${btcSymbol} ${formatBTC(btcVal, 8)} BTC
+ ${formatBTC(data[0].data[1], 8)} BTC`; + } else { + if (this.selected[$localize`:@@7e69426bd97a606d8ae6026762858e6e7c86a1fd:Balance`]) { + tooltip += `
+ ${formatBTC(data[0].data[3], 4)} BTC + ${formatFiat(data[0].data[1])} +
`; + } else { + tooltip += `${hasTx ? `${fiatSymbol} ${formatFiat(fiatVal)}
` : ''} + ${formatFiat(data[0].data[1])}`; + } + } + + tooltip += `
${date}
`; + return tooltip; + }.bind(this) + }, + xAxis: { + type: 'time', + splitNumber: this.isMobile() ? 5 : 10, + axisLabel: { + hideOverlap: true, + } + }, + yAxis: [ + { + type: 'value', + position: 'left', + axisLabel: { + color: 'rgb(110, 112, 121)', + formatter: (val): string => { + let valSpan = maxValue - (this.period === 'all' ? 0 : minValue); + if (valSpan > 100_000_000_000) { + return `${this.amountShortenerPipe.transform(Math.round(val / 100_000_000), 0)} BTC`; + } + else if (valSpan > 1_000_000_000) { + return `${this.amountShortenerPipe.transform(Math.round(val / 100_000_000), 2)} BTC`; + } else if (valSpan > 100_000_000) { + return `${(val / 100_000_000).toFixed(1)} BTC`; + } else if (valSpan > 10_000_000) { + return `${(val / 100_000_000).toFixed(2)} BTC`; + } else if (valSpan > 1_000_000) { + return `${(val / 100_000_000).toFixed(3)} BTC`; + } else { + return `${this.amountShortenerPipe.transform(val, 0)} sats`; + } + } + }, + splitLine: { + show: false, + }, + min: this.period === 'all' ? 0 : 'dataMin' + }, + { + type: 'value', + axisLabel: { + color: 'rgb(110, 112, 121)', + formatter: function(val) { + return this.fiatShortenerPipe.transform(val, null, 'USD'); + }.bind(this) + }, + splitLine: { + show: false, + }, + min: this.period === 'all' ? 0 : 'dataMin' + }, + ], + series: [ + { + name: $localize`:@@7e69426bd97a606d8ae6026762858e6e7c86a1fd:Balance`, + yAxisIndex: 0, + showSymbol: false, + symbol: 'circle', + symbolSize: 8, + data: this.data, + areaStyle: { + opacity: 0.5, + }, + triggerLineEvent: true, + type: 'line', + smooth: false, + step: 'end' + }, !this.stateService.isAnyTestnet() ? + { + name: 'Fiat', + yAxisIndex: 1, + showSymbol: false, + symbol: 'circle', + symbolSize: 8, + data: this.fiatData, + areaStyle: { + opacity: 0.5, + }, + triggerLineEvent: true, + type: 'line', + smooth: false, + step: 'end' + } : undefined + ], + dataZoom: this.allowZoom ? [{ + type: 'inside', + realtime: true, + zoomLock: true, + maxSpan: 100, + minSpan: 5, + moveOnMouseMove: false, + }, { + showDetail: false, + show: true, + type: 'slider', + brushSelect: false, + realtime: true, + left: this.left, + right: this.right, + selectedDataBackground: { + lineStyle: { + color: '#fff', + opacity: 0.45, + }, + }, + }] : undefined + }; + } + + onChartClick(e) { + if (this.hoverData?.length && this.hoverData[0]?.[2]?.txid) { + this.zone.run(() => { + const url = this.relativeUrlPipe.transform(`/tx/${this.hoverData[0][2].txid}`); + if (e.event.event.shiftKey || e.event.event.ctrlKey || e.event.event.metaKey) { + window.open(url); + } else { + this.router.navigate([url]); + } + }); + } + } + + onTooltip(e) { + this.hoverData = (e?.dataByCoordSys?.[0]?.dataByAxis?.[0]?.seriesDataIndices || []).map(indices => this.data[indices.dataIndex]); + } + + onLegendSelectChanged(e) { + this.selected = e.selected; + this.right = this.selected['Fiat'] ? +this.initialRight + 40 : this.initialRight; + this.left = this.selected[$localize`:@@7e69426bd97a606d8ae6026762858e6e7c86a1fd:Balance`] ? this.initialLeft : +this.initialLeft - 40; + + this.chartOptions = { + grid: { + right: this.right, + left: this.left, + }, + legend: { + selected: this.selected, + }, + dataZoom: this.allowZoom ? [{ + left: this.left, + right: this.right, + }, { + left: this.left, + right: this.right, + }] : undefined + }; + + if (this.chartInstance) { + this.chartInstance.setOption(this.chartOptions); + } + } + + onChartInit(ec) { + this.chartInstance = ec; + this.chartInstance.on('showTip', this.onTooltip.bind(this)); + this.chartInstance.on('click', 'series', this.onChartClick.bind(this)); + this.chartInstance.on('legendselectchanged', this.onLegendSelectChanged.bind(this)); + } + + ngOnDestroy(): void { + if (this.subscription) { + this.subscription.unsubscribe(); + } + } + + isMobile() { + return (window.innerWidth <= 767.98); + } + + extendSummary(summary) { + let extendedSummary = summary.slice(); + + // Add a point at today's date to make the graph end at the current time + extendedSummary.unshift({ time: Date.now() / 1000, value: 0 }); + extendedSummary.reverse(); + + let oneHour = 60 * 60; + // Fill gaps longer than interval + for (let i = 0; i < extendedSummary.length - 1; i++) { + let hours = Math.floor((extendedSummary[i + 1].time - extendedSummary[i].time) / oneHour); + if (hours > 1) { + for (let j = 1; j < hours; j++) { + let newTime = extendedSummary[i].time + oneHour * j; + extendedSummary.splice(i + j, 0, { time: newTime, value: 0 }); + } + i += hours - 1; + } + } + + return extendedSummary.reverse(); + } +} diff --git a/frontend/src/app/components/address-group/address-group.component.html b/frontend/src/app/components/address-group/address-group.component.html new file mode 100644 index 0000000000..174853600b --- /dev/null +++ b/frontend/src/app/components/address-group/address-group.component.html @@ -0,0 +1,24 @@ +
+
+ +

Balances

+
+
+ + + + + + + + + + + +
Total
+ +
+ +
diff --git a/frontend/src/app/components/address-group/address-group.component.scss b/frontend/src/app/components/address-group/address-group.component.scss new file mode 100644 index 0000000000..1785e2a8ef --- /dev/null +++ b/frontend/src/app/components/address-group/address-group.component.scss @@ -0,0 +1,101 @@ +.frame { + position: relative; + background: var(--box-bg); + padding: 0.5rem; + height: calc(100% + 60px); +} + +.heading { + display: flex; + flex-direction: row; + justify-content: space-between; + align-items: flex-start; + + & > * { + flex-basis: 0; + flex-grow: 1; + } + + h3 { + text-align: center; + margin: 0 1em; + } +} + +.pagination { + position: absolute; + bottom: 0.5rem; + right: 0.5rem; +} + +.table { + margin-top: 0.5em; + + td, th { + padding: 0.15rem 0.5rem; + + &.address { + width: auto; + } + &.btc { + width: 140px; + text-align: right; + } + &.fiat { + width: 142px; + text-align: right; + } + } + + tr { + border-collapse: collapse; + + &:first-child { + border-bottom: solid 1px white; + td, th { + padding-bottom: 0.3rem; + } + } + &:nth-child(2) { + td, th { + padding-top: 0.3rem; + } + } + &:nth-child(even) { + background: var(--stat-box-bg); + } + } + + @media (min-width: 528px) { + td, th { + &.btc { + width: 160px; + } + &.fiat { + width: 140px; + } + } + } + + @media (min-width: 576px) { + td, th { + &.btc { + width: 170px; + } + &.fiat { + width: 140px; + } + } + } + + @media (min-width: 992px) { + td, th { + &.btc { + width: 210px; + } + &.fiat { + width: 140px; + } + } + } +} \ No newline at end of file diff --git a/frontend/src/app/components/address-group/address-group.component.ts b/frontend/src/app/components/address-group/address-group.component.ts new file mode 100644 index 0000000000..30bee75437 --- /dev/null +++ b/frontend/src/app/components/address-group/address-group.component.ts @@ -0,0 +1,212 @@ +import { Component, OnInit, OnDestroy, ChangeDetectorRef, HostListener } from '@angular/core'; +import { ActivatedRoute, ParamMap } from '@angular/router'; +import { ElectrsApiService } from '../../services/electrs-api.service'; +import { switchMap, catchError } from 'rxjs/operators'; +import { Address, Transaction } from '../../interfaces/electrs.interface'; +import { WebsocketService } from '../../services/websocket.service'; +import { StateService } from '../../services/state.service'; +import { AudioService } from '../../services/audio.service'; +import { ApiService } from '../../services/api.service'; +import { of, Subscription, forkJoin } from 'rxjs'; +import { SeoService } from '../../services/seo.service'; +import { AddressInformation } from '../../interfaces/node-api.interface'; + +@Component({ + selector: 'app-address-group', + templateUrl: './address-group.component.html', + styleUrls: ['./address-group.component.scss'] +}) +export class AddressGroupComponent implements OnInit, OnDestroy { + network = ''; + + balance = 0; + confirmed = 0; + mempool = 0; + addresses: { [address: string]: number | null }; + addressStrings: string[] = []; + addressInfo: { [address: string]: AddressInformation | null }; + seenTxs: { [txid: string ]: boolean } = {}; + isLoadingAddress = true; + error: any; + mainSubscription: Subscription; + wsSubscription: Subscription; + + page: string[] = []; + pageIndex: number = 1; + itemsPerPage: number = 10; + + screenSize: 'lg' | 'md' | 'sm' = 'lg'; + digitsInfo: string = '1.8-8'; + + constructor( + private route: ActivatedRoute, + private electrsApiService: ElectrsApiService, + private websocketService: WebsocketService, + private stateService: StateService, + private audioService: AudioService, + private apiService: ApiService, + private seoService: SeoService, + private cd: ChangeDetectorRef, + ) { } + + ngOnInit(): void { + this.onResize(); + this.stateService.networkChanged$.subscribe((network) => this.network = network); + this.websocketService.want(['blocks']); + + this.mainSubscription = this.route.queryParamMap + .pipe( + switchMap((params: ParamMap) => { + this.error = undefined; + this.isLoadingAddress = true; + this.addresses = {}; + this.addressInfo = {}; + this.balance = 0; + + this.addressStrings = params.get('addresses').split(',').map(address => { + if (/^[A-Z]{2,5}1[AC-HJ-NP-Z02-9]{8,100}|04[a-fA-F0-9]{128}|(02|03)[a-fA-F0-9]{64}$/.test(address)) { + return address.toLowerCase(); + } else { + return address; + } + }); + + return forkJoin(this.addressStrings.map(address => { + const getLiquidInfo = ((this.stateService.network === 'liquid' || this.stateService.network === 'liquidtestnet') && /^([a-zA-HJ-NP-Z1-9]{26,35}|[a-z]{2,5}1[ac-hj-np-z02-9]{8,100}|[a-km-zA-HJ-NP-Z1-9]{80})$/.test(address)); + return forkJoin([ + of(address), + this.electrsApiService.getAddress$(address), + (getLiquidInfo ? this.apiService.validateAddress$(address) : of(null)), + ]); + })); + }), + catchError(e => { + this.error = e; + return of([]); + }) + ).subscribe((addresses) => { + for (const addressData of addresses) { + const address = addressData[0]; + const addressBalance = addressData[1] as Address; + if (addressBalance) { + this.addresses[address] = addressBalance.chain_stats.funded_txo_sum + + addressBalance.mempool_stats.funded_txo_sum + - addressBalance.chain_stats.spent_txo_sum + - addressBalance.mempool_stats.spent_txo_sum; + this.balance += this.addresses[address]; + this.confirmed += (addressBalance.chain_stats.funded_txo_sum - addressBalance.chain_stats.spent_txo_sum); + } + this.addressInfo[address] = addressData[2] ? addressData[2] as AddressInformation : null; + } + this.websocketService.startTrackAddresses(this.addressStrings); + this.isLoadingAddress = false; + this.pageChange(this.pageIndex); + }); + + this.wsSubscription = this.stateService.multiAddressTransactions$.subscribe(update => { + for (const address of Object.keys(update)) { + for (const tx of update[address].mempool) { + this.addTransaction(tx, false, false); + } + for (const tx of update[address].confirmed) { + this.addTransaction(tx, true, false); + } + for (const tx of update[address].removed) { + this.removeTransaction(tx, tx.status.confirmed); + } + } + }); + } + + pageChange(index): void { + this.page = this.addressStrings.slice((index - 1) * this.itemsPerPage, index * this.itemsPerPage); + } + + addTransaction(transaction: Transaction, confirmed = false, playSound: boolean = true): boolean { + if (this.seenTxs[transaction.txid]) { + this.removeTransaction(transaction, false); + } + this.seenTxs[transaction.txid] = true; + + let balance = 0; + transaction.vin.forEach((vin) => { + if (this.addressStrings.includes(vin?.prevout?.scriptpubkey_address)) { + this.addresses[vin?.prevout?.scriptpubkey_address] -= vin.prevout.value; + balance -= vin.prevout.value; + this.balance -= vin.prevout.value; + if (confirmed) { + this.confirmed -= vin.prevout.value; + } + } + }); + transaction.vout.forEach((vout) => { + if (this.addressStrings.includes(vout?.scriptpubkey_address)) { + this.addresses[vout?.scriptpubkey_address] += vout.value; + balance += vout.value; + this.balance += vout.value; + if (confirmed) { + this.confirmed += vout.value; + } + } + }); + + if (playSound) { + if (balance > 0) { + this.audioService.playSound('cha-ching'); + } else { + this.audioService.playSound('chime'); + } + } + + return true; + } + + removeTransaction(transaction: Transaction, confirmed = false): boolean { + transaction.vin.forEach((vin) => { + if (this.addressStrings.includes(vin?.prevout?.scriptpubkey_address)) { + this.addresses[vin?.prevout?.scriptpubkey_address] += vin.prevout.value; + this.balance += vin.prevout.value; + if (confirmed) { + this.confirmed += vin.prevout.value; + } + } + }); + transaction.vout.forEach((vout) => { + if (this.addressStrings.includes(vout?.scriptpubkey_address)) { + this.addresses[vout?.scriptpubkey_address] -= vout.value; + this.balance -= vout.value; + if (confirmed) { + this.confirmed -= vout.value; + } + } + }); + + return true; + } + + @HostListener('window:resize', ['$event']) + onResize(): void { + if (window.innerWidth >= 992) { + this.screenSize = 'lg'; + this.digitsInfo = '1.8-8'; + } else if (window.innerWidth >= 528) { + this.screenSize = 'md'; + this.digitsInfo = '1.4-4'; + } else { + this.screenSize = 'sm'; + this.digitsInfo = '1.2-2'; + } + const newItemsPerPage = Math.floor((window.innerHeight - 150) / 30); + if (newItemsPerPage !== this.itemsPerPage) { + this.itemsPerPage = newItemsPerPage; + this.pageIndex = 1; + this.pageChange(this.pageIndex); + } + } + + ngOnDestroy(): void { + this.mainSubscription.unsubscribe(); + this.wsSubscription.unsubscribe(); + this.websocketService.stopTrackingAddresses(); + } +} diff --git a/frontend/src/app/components/address-labels/address-labels.component.html b/frontend/src/app/components/address-labels/address-labels.component.html index 16deecabf3..b055cf606d 100644 --- a/frontend/src/app/components/address-labels/address-labels.component.html +++ b/frontend/src/app/components/address-labels/address-labels.component.html @@ -1,2 +1,20 @@ -multisig {{ multisigM }} of {{ multisigN }} -Layer{{ network === 'liquid' ? '3' : '2' }} Peg-out + +
+ +   +
+
+ + + {{ label }} + \ No newline at end of file diff --git a/frontend/src/app/components/address-labels/address-labels.component.scss b/frontend/src/app/components/address-labels/address-labels.component.scss index 21bc25b855..5556ab3e6a 100644 --- a/frontend/src/app/components/address-labels/address-labels.component.scss +++ b/frontend/src/app/components/address-labels/address-labels.component.scss @@ -1,3 +1,7 @@ .badge { margin-right: 2px; } + +.badge-positioner { + position: absolute; +} \ No newline at end of file diff --git a/frontend/src/app/components/address-labels/address-labels.component.spec.ts b/frontend/src/app/components/address-labels/address-labels.component.spec.ts deleted file mode 100644 index babcc824c6..0000000000 --- a/frontend/src/app/components/address-labels/address-labels.component.spec.ts +++ /dev/null @@ -1,25 +0,0 @@ -import { async, ComponentFixture, TestBed } from '@angular/core/testing'; - -import { AddressLabelsComponent } from './address-labels.component'; - -describe('AddressLabelsComponent', () => { - let component: AddressLabelsComponent; - let fixture: ComponentFixture; - - beforeEach(async(() => { - TestBed.configureTestingModule({ - declarations: [ AddressLabelsComponent ] - }) - .compileComponents(); - })); - - beforeEach(() => { - fixture = TestBed.createComponent(AddressLabelsComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); - - it('should create', () => { - expect(component).toBeTruthy(); - }); -}); diff --git a/frontend/src/app/components/address-labels/address-labels.component.ts b/frontend/src/app/components/address-labels/address-labels.component.ts index e7a48dc07b..dd81b98098 100644 --- a/frontend/src/app/components/address-labels/address-labels.component.ts +++ b/frontend/src/app/components/address-labels/address-labels.component.ts @@ -1,6 +1,7 @@ -import { Component, OnInit, ChangeDetectionStrategy, Input } from '@angular/core'; +import { Component, ChangeDetectionStrategy, Input, OnChanges } from '@angular/core'; import { Vin, Vout } from '../../interfaces/electrs.interface'; -import { StateService } from 'src/app/services/state.service'; +import { StateService } from '../../services/state.service'; +import { AddressType, AddressTypeInfo } from '../../shared/address-utils'; @Component({ selector: 'app-address-labels', @@ -8,17 +9,16 @@ import { StateService } from 'src/app/services/state.service'; styleUrls: ['./address-labels.component.scss'], changeDetection: ChangeDetectionStrategy.OnPush, }) -export class AddressLabelsComponent implements OnInit { +export class AddressLabelsComponent implements OnChanges { network = ''; + @Input() address: AddressTypeInfo; @Input() vin: Vin; @Input() vout: Vout; + @Input() channel: any; + @Input() class: string = ''; - multisig = false; - multisigM: number; - multisigN: number; - - secondLayerClose = false; + label?: string; constructor( stateService: StateService, @@ -26,53 +26,51 @@ export class AddressLabelsComponent implements OnInit { this.network = stateService.network; } - ngOnInit() { - if (this.vin) { + ngOnChanges() { + if (this.channel) { + this.handleChannel(); + } else if (this.address) { + this.handleAddress(); + } else if (this.vin) { this.handleVin(); } else if (this.vout) { this.handleVout(); } } - handleVin() { - if (this.vin.inner_witnessscript_asm) { - if (this.vin.inner_witnessscript_asm.indexOf('OP_CHECKMULTISIG') > -1) { - const matches = this.getMatches(this.vin.inner_witnessscript_asm, /OP_PUSHNUM_([0-9])/g, 1); - this.multisig = true; - this.multisigM = parseInt(matches[0], 10); - this.multisigN = parseInt(matches[1], 10); - - if (this.multisigM === 1 && this.multisigN === 1) { - this.multisig = false; - } - } + handleChannel() { + const type = this.vout ? 'open' : 'close'; + const leftNodeName = this.channel.node_left.alias || this.channel.node_left.public_key.substring(0, 10); + const rightNodeName = this.channel.node_right.alias || this.channel.node_right.public_key.substring(0, 10); + this.label = `Channel ${type}: ${leftNodeName} <> ${rightNodeName}`; + } - if (/OP_IF (.+) OP_ELSE (.+) OP_CSV OP_DROP/.test(this.vin.inner_witnessscript_asm)) { - this.secondLayerClose = true; + handleAddress() { + if (this.address?.scripts.size) { + const script = this.address?.scripts.values().next().value; + if (script.template?.label) { + this.label = script.template.label; } } + } - if (this.vin.inner_redeemscript_asm && this.vin.inner_redeemscript_asm.indexOf('OP_CHECKMULTISIG') > -1) { - const matches = this.getMatches(this.vin.inner_redeemscript_asm, /OP_PUSHNUM_([0-9])/g, 1); - this.multisig = true; - this.multisigM = matches[0]; - this.multisigN = matches[1]; + handleVin() { + const address = new AddressTypeInfo(this.network || 'mainnet', this.vin.prevout?.scriptpubkey_address, this.vin.prevout?.scriptpubkey_type as AddressType, [this.vin]) + if (address?.scripts.size) { + const script = address?.scripts.values().next().value; + if (script.template?.label) { + this.label = script.template.label; + } } } handleVout() { - } - - getMatches(str: string, regex: RegExp, index: number) { - if (!index) { - index = 1; - } - const matches = []; - let match; - while (match = regex.exec(str)) { - matches.push(match[index]); + const address = new AddressTypeInfo(this.network || 'mainnet', this.vout.scriptpubkey_address, this.vout.scriptpubkey_type as AddressType, undefined, this.vout); + if (address?.scripts.size) { + const script = address?.scripts.values().next().value; + if (script.template?.label) { + this.label = script.template.label; + } } - return matches; } - } diff --git a/frontend/src/app/components/address-transactions-widget/address-transactions-widget.component.html b/frontend/src/app/components/address-transactions-widget/address-transactions-widget.component.html new file mode 100644 index 0000000000..c1c999d6fd --- /dev/null +++ b/frontend/src/app/components/address-transactions-widget/address-transactions-widget.component.html @@ -0,0 +1,32 @@ + + + + + + + + + + + + + + + +
 
+
TXIDAmount{{ currency }}Date
+ + + +
+ + + + +
+
+
+
+ + +
\ No newline at end of file diff --git a/frontend/src/app/components/address-transactions-widget/address-transactions-widget.component.scss b/frontend/src/app/components/address-transactions-widget/address-transactions-widget.component.scss new file mode 100644 index 0000000000..851da59961 --- /dev/null +++ b/frontend/src/app/components/address-transactions-widget/address-transactions-widget.component.scss @@ -0,0 +1,50 @@ +.latest-transactions { + width: 100%; + text-align: left; + table-layout:fixed; + tr, td, th { + border: 0px; + padding-top: 0.71rem !important; + padding-bottom: 0.75rem !important; + } + td { + overflow:hidden; + width: 25%; + } + .table-cell-satoshis { + display: none; + text-align: right; + @media (min-width: 576px) { + display: table-cell; + } + @media (min-width: 768px) { + display: none; + } + @media (min-width: 1100px) { + display: table-cell; + } + } + .table-cell-fiat { + display: none; + text-align: right; + @media (min-width: 485px) { + display: table-cell; + } + @media (min-width: 768px) { + display: none; + } + @media (min-width: 992px) { + display: table-cell; + } + } + .table-cell-date { + text-align: right; + } +} +.skeleton-loader-transactions { + max-width: 250px; + position: relative; + top: 2px; + margin-bottom: -3px; + height: 18px; +} \ No newline at end of file diff --git a/frontend/src/app/components/address-transactions-widget/address-transactions-widget.component.ts b/frontend/src/app/components/address-transactions-widget/address-transactions-widget.component.ts new file mode 100644 index 0000000000..998d269ba3 --- /dev/null +++ b/frontend/src/app/components/address-transactions-widget/address-transactions-widget.component.ts @@ -0,0 +1,76 @@ +import { Component, Input, OnChanges, OnDestroy, OnInit, SimpleChanges } from '@angular/core'; +import { StateService } from '../../services/state.service'; +import { Address, AddressTxSummary } from '../../interfaces/electrs.interface'; +import { ElectrsApiService } from '../../services/electrs-api.service'; +import { Observable, Subscription, catchError, map, of, switchMap, zip } from 'rxjs'; +import { PriceService } from '../../services/price.service'; + +@Component({ + selector: 'app-address-transactions-widget', + templateUrl: './address-transactions-widget.component.html', + styleUrls: ['./address-transactions-widget.component.scss'], +}) +export class AddressTransactionsWidgetComponent implements OnInit, OnChanges, OnDestroy { + @Input() address: string; + @Input() addressInfo: Address; + @Input() addressSummary$: Observable | null; + @Input() isPubkey: boolean = false; + + currencySubscription: Subscription; + currency: string; + + transactions$: Observable; + + isLoading: boolean = true; + error: any; + + constructor( + public stateService: StateService, + private electrsApiService: ElectrsApiService, + private priceService: PriceService, + ) { } + + ngOnInit(): void { + this.currencySubscription = this.stateService.fiatCurrency$.subscribe((fiat) => { + this.currency = fiat; + }); + this.startAddressSubscription(); + } + + ngOnChanges(changes: SimpleChanges): void { + this.startAddressSubscription(); + } + + startAddressSubscription(): void { + this.isLoading = true; + if (!this.address || !this.addressInfo) { + return; + } + this.transactions$ = (this.addressSummary$ || (this.isPubkey + ? this.electrsApiService.getScriptHashSummary$((this.address.length === 66 ? '21' : '41') + this.address + 'ac') + : this.electrsApiService.getAddressSummary$(this.address)).pipe( + catchError(e => { + this.error = `Failed to fetch address history: ${e?.status || ''} ${e?.statusText || 'unknown error'}`; + return of(null); + }) + )).pipe( + map(summary => { + return summary?.slice(0, 6); + }), + switchMap(txs => { + return (zip(txs.map(tx => this.priceService.getBlockPrice$(tx.time, txs.length < 3, this.currency).pipe( + map(price => { + return { + ...tx, + price, + }; + }) + )))); + }) + ); + } + + ngOnDestroy(): void { + this.currencySubscription.unsubscribe(); + } +} diff --git a/frontend/src/app/components/address/address-preview.component.html b/frontend/src/app/components/address/address-preview.component.html new file mode 100644 index 0000000000..392cc971eb --- /dev/null +++ b/frontend/src/app/components/address/address-preview.component.html @@ -0,0 +1,56 @@ +
+ + Address + +
+
+
+
+

+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Unconfidential + +
Total received
Total sent
Balance
Transactions{{ txCount | number }}
Unspent TXOs{{ totalUnspent | number }}
+
+
+
+
+ +
+
+
+
+ + + Confidential + diff --git a/frontend/src/app/components/address/address-preview.component.scss b/frontend/src/app/components/address/address-preview.component.scss new file mode 100644 index 0000000000..f03e135415 --- /dev/null +++ b/frontend/src/app/components/address/address-preview.component.scss @@ -0,0 +1,35 @@ +.title-wrapper { + padding: 0 15px; +} + +.qr-wrapper { + background-color: #fff; + padding: 10px; + padding-bottom: 5px; + display: inline-block; +} + +.qrcode-col { + width: 468px; + min-width: 468px; + flex-grow: 0; + flex-shrink: 0; + text-align: center; + padding: 0; + margin-left: 2px; + margin-right: 15px; +} + +.table-col { + max-width: calc(100% - 470px); + overflow: hidden; +} + +.table { + font-size: 32px; + margin-top: 48px; + + ::ng-deep .symbol { + font-size: 24px; + } +} \ No newline at end of file diff --git a/frontend/src/app/components/address/address-preview.component.ts b/frontend/src/app/components/address/address-preview.component.ts new file mode 100644 index 0000000000..9bc6e967f7 --- /dev/null +++ b/frontend/src/app/components/address/address-preview.component.ts @@ -0,0 +1,124 @@ +import { Component, OnInit, OnDestroy } from '@angular/core'; +import { ActivatedRoute, ParamMap } from '@angular/router'; +import { ElectrsApiService } from '../../services/electrs-api.service'; +import { switchMap, filter, catchError, map, tap } from 'rxjs/operators'; +import { Address, Transaction } from '../../interfaces/electrs.interface'; +import { StateService } from '../../services/state.service'; +import { OpenGraphService } from '../../services/opengraph.service'; +import { AudioService } from '../../services/audio.service'; +import { ApiService } from '../../services/api.service'; +import { of, merge, Subscription, Observable } from 'rxjs'; +import { SeoService } from '../../services/seo.service'; +import { seoDescriptionNetwork } from '../../shared/common.utils'; +import { AddressInformation } from '../../interfaces/node-api.interface'; + +@Component({ + selector: 'app-address-preview', + templateUrl: './address-preview.component.html', + styleUrls: ['./address-preview.component.scss'] +}) +export class AddressPreviewComponent implements OnInit, OnDestroy { + network = ''; + + rawAddress: string; + address: Address; + addressString: string; + isLoadingAddress = true; + error: any; + mainSubscription: Subscription; + addressLoadingStatus$: Observable; + addressInfo: null | AddressInformation = null; + + totalConfirmedTxCount = 0; + loadedConfirmedTxCount = 0; + txCount = 0; + received = 0; + sent = 0; + totalUnspent = 0; + + constructor( + private route: ActivatedRoute, + private electrsApiService: ElectrsApiService, + private stateService: StateService, + private apiService: ApiService, + private seoService: SeoService, + private openGraphService: OpenGraphService, + ) { } + + ngOnInit() { + this.stateService.networkChanged$.subscribe((network) => this.network = network); + + this.addressLoadingStatus$ = this.route.paramMap + .pipe( + switchMap(() => this.stateService.loadingIndicators$), + map((indicators) => indicators['address-' + this.addressString] !== undefined ? indicators['address-' + this.addressString] : 0) + ); + + this.mainSubscription = this.route.paramMap + .pipe( + switchMap((params: ParamMap) => { + this.rawAddress = params.get('id') || ''; + this.openGraphService.waitFor('address-data-' + this.rawAddress); + this.error = undefined; + this.isLoadingAddress = true; + this.loadedConfirmedTxCount = 0; + this.address = null; + this.addressInfo = null; + this.addressString = params.get('id') || ''; + if (/^[A-Z]{2,5}1[AC-HJ-NP-Z02-9]{8,100}|04[a-fA-F0-9]{128}|(02|03)[a-fA-F0-9]{64}$/.test(this.addressString)) { + this.addressString = this.addressString.toLowerCase(); + } + this.seoService.setTitle($localize`:@@address.component.browser-title:Address: ${this.addressString}:INTERPOLATION:`); + this.seoService.setDescription($localize`:@@meta.description.bitcoin.address:See mempool transactions, confirmed transactions, balance, and more for ${this.stateService.network==='liquid'||this.stateService.network==='liquidtestnet'?'Liquid':'Bitcoin'}${seoDescriptionNetwork(this.stateService.network)} address ${this.addressString}:INTERPOLATION:.`); + + return (this.addressString.match(/04[a-fA-F0-9]{128}|(02|03)[a-fA-F0-9]{64}/) + ? this.electrsApiService.getPubKeyAddress$(this.addressString) + : this.electrsApiService.getAddress$(this.addressString) + ).pipe( + catchError((err) => { + this.isLoadingAddress = false; + this.error = err; + console.log(err); + this.openGraphService.fail('address-data-' + this.rawAddress); + return of(null); + }) + ); + }) + ) + .pipe( + filter((address) => !!address), + tap((address: Address) => { + if ((this.stateService.network === 'liquid' || this.stateService.network === 'liquidtestnet') && /^([m-zA-HJ-NP-Z1-9]{26,35}|[a-z]{2,5}1[ac-hj-np-z02-9]{8,100}|[a-km-zA-HJ-NP-Z1-9]{80})$/.test(address.address)) { + this.apiService.validateAddress$(address.address) + .subscribe((addressInfo) => { + this.addressInfo = addressInfo; + }); + } + this.address = address; + this.updateChainStats(); + this.isLoadingAddress = false; + this.openGraphService.waitOver('address-data-' + this.rawAddress); + }) + ) + .subscribe(() => {}, + (error) => { + console.log(error); + this.error = error; + this.isLoadingAddress = false; + this.openGraphService.fail('address-data-' + this.rawAddress); + } + ); + } + + updateChainStats() { + this.received = this.address.chain_stats.funded_txo_sum + this.address.mempool_stats.funded_txo_sum; + this.sent = this.address.chain_stats.spent_txo_sum + this.address.mempool_stats.spent_txo_sum; + this.txCount = this.address.chain_stats.tx_count + this.address.mempool_stats.tx_count; + this.totalConfirmedTxCount = this.address.chain_stats.tx_count; + this.totalUnspent = this.address.chain_stats.funded_txo_count - this.address.chain_stats.spent_txo_count; + } + + ngOnDestroy() { + this.mainSubscription.unsubscribe(); + } +} diff --git a/frontend/src/app/components/address/address.component.html b/frontend/src/app/components/address/address.component.html index 95f3daa7e5..76c64948bf 100644 --- a/frontend/src/app/components/address/address.component.html +++ b/frontend/src/app/components/address/address.component.html @@ -1,11 +1,18 @@ -
-

Address

- - {{ addressString | shortenString : 24 }} - {{ addressString }} - - -
+
+
+

Address

+ +
@@ -13,59 +20,101 @@

Address

-
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Total received{{ receieved / 100000000 | number: '1.8-8' }} L-BTC
Total sent{{ sent / 100000000 | number: '1.8-8' }} L-BTC
Balance{{ (receieved - sent) / 100000000 | number: '1.8-8' }} L-BTC ()
Total receivedConfidential
Total sentConfidential
BalanceConfidential
+ @if (isMobile) { +
+ + + + + @if (!address.electrum) { + + + } + @if (network === 'liquid' || network === 'liquidtestnet') { + + } @else if (!address.electrum) { + + } + + +
+
+ } @else { +
+ + + + + + + + @if (!address.electrum) { + + + + + + } + + @if (network === 'liquid' || network === 'liquidtestnet') { + + } @else if (!address.electrum) { + + } @else { + + } + + + + +
+
+ } +
+
+ + +
+
+

Balance History

+
+
+
+ all + | + recent
-
-
-
- +
+
+
- -
+
+
+

+   + {{ (transactions?.length | number) || '?' }} of {{ mempoolStats.tx_count + chainStats.tx_count | number }} transaction + {{ (transactions?.length | number) || '?' }} of {{ mempoolStats.tx_count + chainStats.tx_count | number }} transactions +

+
-

{{ (transactions?.length | number) || '?' }} of {{ txCount | number }} transactions

- - +
-
- -
+ + +
+
+
+
+
+
@@ -77,6 +126,12 @@

{{ (transactions?.length | number

+ + + + +
+
@@ -86,38 +141,150 @@

{{ (transactions?.length | number
-
- - - - - - - - - - - - -
-
-
-
- -
+ @if (isMobile) { +
+ + + + + + + + + + + + + + + + + + + + + +
+
+ } @else { +
+ + + + + + + + + + + + + + + + + + +
+
+ }
-
- Error loading address data. -
- {{ error.error }} -
+
+ +
+ Error loading address data. +
+ + There are too many transactions on this address, more than your backend can handle. See more on setting up a stronger backend. +

+ Consider viewing this address on the official Mempool website instead: +
+
+ https://mempool.space/address/{{ addressString }} +
+ http://mempoolhqx4isw62xs7abwphsq7ldayuidyx2v2oethdhhj6mlo2r6ad.onion/address/{{ addressString }} +

+ ({{ error | httpErrorMsg }}) +
+
+ + + Error loading address data. + +

-
\ No newline at end of file +
+ + + Confidential + + + +
+ +
+
+ + + + + + + + + + + + Confirmed balance + + + + + Unconfirmed balance + + + + + Confirmed UTXOs + {{ chainStats.utxos }} + + + + Unconfirmed UTXOs + {{ mempoolStats.utxos > 0 ? '+' : ''}}{{ mempoolStats.utxos }} + + + + Total received + + + + + Type + + + + + + + + + + + Unconfidential + + + + + + + \ No newline at end of file diff --git a/frontend/src/app/components/address/address.component.scss b/frontend/src/app/components/address/address.component.scss index c5961e4282..be562337a2 100644 --- a/frontend/src/app/components/address/address.component.scss +++ b/frontend/src/app/components/address/address.component.scss @@ -1,23 +1,124 @@ .qr-wrapper { - background-color: #FFF; + position: absolute; + top: 30px; + right: 0px; + border: solid 10px var(--active-bg); + border-radius: 5px; + background-color: #fff; padding: 10px; padding-bottom: 5px; - display: inline-block; - margin-right: 25px; + display: block; + z-index: 99; } -@media (min-width: 576px) { - .qrcode-col { - text-align: right; +.qrSpan { + position: relative; + cursor: pointer; + padding-left: 0.4rem; +} + +.fiat { + display: block; + @media (min-width: 992px){ + display: inline-block; + margin-left: 10px; + } +} + +.table { + tr td { + &:last-child { + text-align: right; + @media (min-width: 768px) { + text-align: left; + } + } + + &.wrap-cell { + white-space: normal; + } + } +} + +h1 { + margin: 0px; + padding: 0px; + margin-right: 10px; + font-size: 1.9rem; + @media (min-width: 576px) { + font-size: 2rem; + float: left; + } + @media (min-width: 768px) { + font-size: 2.5rem; + } +} + +.address-link { + line-height: 56px; + margin-left: 0px; + top: -2px; + position: relative; + @media (min-width: 768px) { + line-height: 69px; + } +} + +.row{ + flex-direction: column; + @media (min-width: 576px) { + flex-direction: row; + } +} + +@media (max-width: 767.98px) { + .mobile-bottomcol { + margin-top: 15px; + } + .details-table td:first-child { + white-space: pre-wrap; + } +} + +.tx-link { + display: block; + height: 100%; + top: 9px; + position: relative; + @media (min-width: 576px) { + max-width: calc(100% - 180px); + top: 11px; + } + @media (min-width: 768px) { + top: 17px; } } -@media (max-width: 575.98px) { - .qrcode-col { - text-align: center; + +.title-tx { + h2 { + line-height: 1; + margin-bottom: 10px; } +} - .qrcode-col > div { - margin-top: 20px; - margin-right: 0px; +.liquid-address { + .address-table { + table-layout: fixed; } +} + +.widget-toggler { + font-size: 12px; + position: absolute; + top: -20px; + right: 3px; + text-align: right; +} + +.toggler-option { + text-decoration: none; +} + +.inactive { + color: var(--transparent-fg); } \ No newline at end of file diff --git a/frontend/src/app/components/address/address.component.ts b/frontend/src/app/components/address/address.component.ts index 197a4fadf1..105863a4e9 100644 --- a/frontend/src/app/components/address/address.component.ts +++ b/frontend/src/app/components/address/address.component.ts @@ -1,14 +1,93 @@ -import { Component, OnInit, OnDestroy } from '@angular/core'; +import { Component, OnInit, OnDestroy, HostListener } from '@angular/core'; import { ActivatedRoute, ParamMap } from '@angular/router'; import { ElectrsApiService } from '../../services/electrs-api.service'; -import { switchMap, filter, catchError } from 'rxjs/operators'; -import { Address, Transaction } from '../../interfaces/electrs.interface'; -import { WebsocketService } from 'src/app/services/websocket.service'; -import { StateService } from 'src/app/services/state.service'; -import { AudioService } from 'src/app/services/audio.service'; -import { ApiService } from 'src/app/services/api.service'; -import { of, merge, Subscription } from 'rxjs'; -import { SeoService } from 'src/app/services/seo.service'; +import { switchMap, filter, catchError, map, tap } from 'rxjs/operators'; +import { Address, ChainStats, Transaction, Vin } from '../../interfaces/electrs.interface'; +import { WebsocketService } from '../../services/websocket.service'; +import { StateService } from '../../services/state.service'; +import { AudioService } from '../../services/audio.service'; +import { ApiService } from '../../services/api.service'; +import { of, merge, Subscription, Observable } from 'rxjs'; +import { SeoService } from '../../services/seo.service'; +import { seoDescriptionNetwork } from '../../shared/common.utils'; +import { AddressInformation } from '../../interfaces/node-api.interface'; +import { AddressTypeInfo } from '../../shared/address-utils'; + +class AddressStats implements ChainStats { + address: string; + scriptpubkey?: string; + funded_txo_count: number; + funded_txo_sum: number; + spent_txo_count: number; + spent_txo_sum: number; + tx_count: number; + + constructor (stats: ChainStats, address: string, scriptpubkey?: string) { + Object.assign(this, stats); + this.address = address; + this.scriptpubkey = scriptpubkey; + } + + public addTx(tx: Transaction): void { + for (const vin of tx.vin) { + if (vin.prevout?.scriptpubkey_address === this.address || (this.scriptpubkey === vin.prevout?.scriptpubkey)) { + this.spendTxo(vin.prevout.value); + } + } + for (const vout of tx.vout) { + if (vout.scriptpubkey_address === this.address || (this.scriptpubkey === vout.scriptpubkey)) { + this.fundTxo(vout.value); + } + } + this.tx_count++; + } + + public removeTx(tx: Transaction): void { + for (const vin of tx.vin) { + if (vin.prevout?.scriptpubkey_address === this.address || (this.scriptpubkey === vin.prevout?.scriptpubkey)) { + this.unspendTxo(vin.prevout.value); + } + } + for (const vout of tx.vout) { + if (vout.scriptpubkey_address === this.address || (this.scriptpubkey === vout.scriptpubkey)) { + this.unfundTxo(vout.value); + } + } + this.tx_count--; + } + + private fundTxo(value: number): void { + this.funded_txo_sum += value; + this.funded_txo_count++; + } + + private unfundTxo(value: number): void { + this.funded_txo_sum -= value; + this.funded_txo_count--; + } + + private spendTxo(value: number): void { + this.spent_txo_sum += value; + this.spent_txo_count++; + } + + private unspendTxo(value: number): void { + this.spent_txo_sum -= value; + this.spent_txo_count--; + } + + get balance(): number { + return this.funded_txo_sum - this.spent_txo_sum; + } + + get totalReceived(): number { + return this.funded_txo_sum; + } + + get utxos(): number { + return this.funded_txo_count - this.spent_txo_count; + } +} @Component({ selector: 'app-address', @@ -18,19 +97,32 @@ import { SeoService } from 'src/app/services/seo.service'; export class AddressComponent implements OnInit, OnDestroy { network = ''; + isMobile: boolean; + showQR: boolean = false; + address: Address; addressString: string; isLoadingAddress = true; transactions: Transaction[]; isLoadingTransactions = true; + retryLoadMore = false; error: any; mainSubscription: Subscription; + mempoolTxSubscription: Subscription; + mempoolRemovedTxSubscription: Subscription; + blockTxSubscription: Subscription; + addressLoadingStatus$: Observable; + addressInfo: null | AddressInformation = null; + addressTypeInfo: null | AddressTypeInfo; + + fullyLoaded = false; + chainStats: AddressStats; + mempoolStats: AddressStats; - totalConfirmedTxCount = 0; - loadedConfirmedTxCount = 0; - txCount = 0; - receieved = 0; - sent = 0; + exampleChannel?: any; + + now = Date.now() / 1000; + balancePeriod: 'all' | '1m' = 'all'; private tempTransactions: Transaction[]; private timeTxIndexes: number[]; @@ -40,28 +132,44 @@ export class AddressComponent implements OnInit, OnDestroy { private route: ActivatedRoute, private electrsApiService: ElectrsApiService, private websocketService: WebsocketService, - private stateService: StateService, + public stateService: StateService, private audioService: AudioService, private apiService: ApiService, private seoService: SeoService, ) { } - ngOnInit() { + ngOnInit(): void { this.stateService.networkChanged$.subscribe((network) => this.network = network); - this.websocketService.want(['blocks', 'stats', 'mempool-blocks']); + this.websocketService.want(['blocks']); + + this.onResize(); + + this.addressLoadingStatus$ = this.route.paramMap + .pipe( + switchMap(() => this.stateService.loadingIndicators$), + map((indicators) => indicators['address-' + this.addressString] !== undefined ? indicators['address-' + this.addressString] : 0) + ); this.mainSubscription = this.route.paramMap .pipe( switchMap((params: ParamMap) => { this.error = undefined; this.isLoadingAddress = true; - this.loadedConfirmedTxCount = 0; + this.fullyLoaded = false; this.address = null; this.isLoadingTransactions = true; this.transactions = null; + this.addressInfo = null; + this.exampleChannel = null; document.body.scrollTo(0, 0); this.addressString = params.get('id') || ''; - this.seoService.setTitle('Address: ' + this.addressString, true); + if (/^[A-Z]{2,5}1[AC-HJ-NP-Z02-9]{8,100}|04[a-fA-F0-9]{128}|(02|03)[a-fA-F0-9]{64}$/.test(this.addressString)) { + this.addressString = this.addressString.toLowerCase(); + } + this.seoService.setTitle($localize`:@@address.component.browser-title:Address: ${this.addressString}:INTERPOLATION:`); + this.seoService.setDescription($localize`:@@meta.description.bitcoin.address:See mempool transactions, confirmed transactions, balance, and more for ${this.stateService.network==='liquid'||this.stateService.network==='liquidtestnet'?'Liquid':'Bitcoin'}${seoDescriptionNetwork(this.stateService.network)} address ${this.addressString}:INTERPOLATION:.`); + + this.addressTypeInfo = new AddressTypeInfo(this.stateService.network || 'mainnet', this.addressString); return merge( of(true), @@ -69,11 +177,15 @@ export class AddressComponent implements OnInit, OnDestroy { .pipe(filter((state) => state === 2 && this.transactions && this.transactions.length > 0)) ) .pipe( - switchMap(() => this.electrsApiService.getAddress$(this.addressString) - .pipe( + switchMap(() => ( + this.addressString.match(/04[a-fA-F0-9]{128}|(02|03)[a-fA-F0-9]{64}/) + ? this.electrsApiService.getPubKeyAddress$(this.addressString) + : this.electrsApiService.getAddress$(this.addressString) + ).pipe( catchError((err) => { this.isLoadingAddress = false; this.error = err; + this.seoService.logSoft404(); console.log(err); return of(null); }) @@ -84,19 +196,30 @@ export class AddressComponent implements OnInit, OnDestroy { ) .pipe( filter((address) => !!address), + tap((address: Address) => { + if ((this.stateService.network === 'liquid' || this.stateService.network === 'liquidtestnet') && /^([a-zA-HJ-NP-Z1-9]{26,35}|[a-z]{2,5}1[ac-hj-np-z02-9]{8,100}|[a-km-zA-HJ-NP-Z1-9]{80})$/.test(address.address)) { + this.apiService.validateAddress$(address.address) + .subscribe((addressInfo) => { + this.addressInfo = addressInfo; + this.websocketService.startTrackAddress(addressInfo.unconfidential); + }); + } else { + this.websocketService.startTrackAddress(address.address); + } + }), switchMap((address) => { this.address = address; this.updateChainStats(); - this.websocketService.startTrackAddress(address.address); this.isLoadingAddress = false; this.isLoadingTransactions = true; - return this.electrsApiService.getAddressTransactions$(address.address); + return address.is_pubkey + ? this.electrsApiService.getScriptHashTransactions$((address.address.length === 66 ? '21' : '41') + address.address + 'ac') + : this.electrsApiService.getAddressTransactions$(address.address); }), switchMap((transactions) => { this.tempTransactions = transactions; if (transactions.length) { this.lastTransactionTxId = transactions[transactions.length - 1].txid; - this.loadedConfirmedTxCount += transactions.filter((tx) => tx.status.confirmed).length; } const fetchTxs: string[] = []; @@ -110,90 +233,177 @@ export class AddressComponent implements OnInit, OnDestroy { if (!fetchTxs.length) { return of([]); } - return this.apiService.getTransactionTimes$(fetchTxs); + return this.apiService.getTransactionTimes$(fetchTxs).pipe( + catchError((err) => { + this.isLoadingAddress = false; + this.isLoadingTransactions = false; + this.error = err; + this.seoService.logSoft404(); + console.log(err); + return of([]); + }) + ); }) ) - .subscribe((times: number[]) => { + .subscribe((times: number[] | null) => { + if (!times) { + return; + } times.forEach((time, index) => { this.tempTransactions[this.timeTxIndexes[index]].firstSeen = time; }); this.tempTransactions.sort((a, b) => { - return b.status.block_time - a.status.block_time || b.firstSeen - a.firstSeen; + if (b.status.confirmed) { + if (b.status.block_height === a.status.block_height) { + return b.status.block_time - a.status.block_time; + } + return b.status.block_height - a.status.block_height; + } + return b.firstSeen - a.firstSeen; }); this.transactions = this.tempTransactions; + if (this.transactions.length === (this.mempoolStats.tx_count + this.chainStats.tx_count)) { + this.fullyLoaded = true; + } this.isLoadingTransactions = false; + + let addressVin: Vin[] = []; + for (const tx of this.transactions) { + addressVin = addressVin.concat(tx.vin.filter(v => v.prevout?.scriptpubkey_address === this.address.address)); + } + this.addressTypeInfo.processInputs(addressVin); + // hack to trigger change detection + this.addressTypeInfo = this.addressTypeInfo.clone(); + + if (!this.showBalancePeriod()) { + this.setBalancePeriod('all'); + } else { + this.setBalancePeriod('1m'); + } }, (error) => { console.log(error); this.error = error; + this.seoService.logSoft404(); this.isLoadingAddress = false; }); - this.stateService.mempoolTransactions$ - .subscribe((transaction) => { - if (this.transactions.some((t) => t.txid === transaction.txid)) { - return; - } - - this.transactions.unshift(transaction); - this.transactions = this.transactions.slice(); - this.txCount++; - - if (transaction.vout.some((vout) => vout.scriptpubkey_address === this.address.address)) { - this.audioService.playSound('cha-ching'); - } else { - this.audioService.playSound('chime'); - } + this.mempoolTxSubscription = this.stateService.mempoolTransactions$ + .subscribe(tx => { + this.addTransaction(tx); + this.mempoolStats.addTx(tx); + }); - transaction.vin.forEach((vin) => { - if (vin.prevout.scriptpubkey_address === this.address.address) { - this.sent += vin.prevout.value; - } - }); - transaction.vout.forEach((vout) => { - if (vout.scriptpubkey_address === this.address.address) { - this.receieved += vout.value; - } - }); + this.mempoolRemovedTxSubscription = this.stateService.mempoolRemovedTransactions$ + .subscribe(tx => { + this.removeTransaction(tx); + this.mempoolStats.removeTx(tx); }); - this.stateService.blockTransactions$ + this.blockTxSubscription = this.stateService.blockTransactions$ .subscribe((transaction) => { const tx = this.transactions.find((t) => t.txid === transaction.txid); if (tx) { tx.status = transaction.status; this.transactions = this.transactions.slice(); + this.mempoolStats.removeTx(transaction); this.audioService.playSound('magic'); + } else { + if (this.addTransaction(transaction, false)) { + this.audioService.playSound('magic'); + } } - this.totalConfirmedTxCount++; - this.loadedConfirmedTxCount++; + this.chainStats.addTx(transaction); }); } - loadMore() { - if (this.isLoadingTransactions || !this.totalConfirmedTxCount || this.loadedConfirmedTxCount >= this.totalConfirmedTxCount) { + addTransaction(transaction: Transaction, playSound: boolean = true): boolean { + if (this.transactions.some((t) => t.txid === transaction.txid)) { + return false; + } + + this.transactions.unshift(transaction); + this.transactions = this.transactions.slice(); + + if (playSound) { + if (transaction.vout.some((vout) => vout?.scriptpubkey_address === this.address.address)) { + this.audioService.playSound('cha-ching'); + } else { + this.audioService.playSound('chime'); + } + } + + return true; + } + + removeTransaction(transaction: Transaction): boolean { + const index = this.transactions.findIndex(((tx) => tx.txid === transaction.txid)); + if (index === -1) { + return false; + } + + this.transactions.splice(index, 1); + this.transactions = this.transactions.slice(); + + return true; + } + + loadMore(): void { + if (this.isLoadingTransactions || this.fullyLoaded) { return; } this.isLoadingTransactions = true; - this.electrsApiService.getAddressTransactionsFromHash$(this.address.address, this.lastTransactionTxId) + this.retryLoadMore = false; + (this.address.is_pubkey + ? this.electrsApiService.getScriptHashTransactions$((this.address.address.length === 66 ? '21' : '41') + this.address.address + 'ac', this.lastTransactionTxId) + : this.electrsApiService.getAddressTransactions$(this.address.address, this.lastTransactionTxId)) .subscribe((transactions: Transaction[]) => { - this.lastTransactionTxId = transactions[transactions.length - 1].txid; - this.loadedConfirmedTxCount += transactions.length; - this.transactions = this.transactions.concat(transactions); + if (transactions && transactions.length) { + this.lastTransactionTxId = transactions[transactions.length - 1].txid; + this.transactions = this.transactions.concat(transactions); + } else { + this.fullyLoaded = true; + } this.isLoadingTransactions = false; + }, + (error) => { + this.isLoadingTransactions = false; + this.retryLoadMore = true; + // In the unlikely event of the txid wasn't found in the mempool anymore and we must reload the page. + if (error.status === 422) { + window.location.reload(); + } }); } - updateChainStats() { - this.receieved = this.address.chain_stats.funded_txo_sum + this.address.mempool_stats.funded_txo_sum; - this.sent = this.address.chain_stats.spent_txo_sum + this.address.mempool_stats.spent_txo_sum; - this.txCount = this.address.chain_stats.tx_count + this.address.mempool_stats.tx_count; - this.totalConfirmedTxCount = this.address.chain_stats.tx_count; + updateChainStats(): void { + this.chainStats = new AddressStats(this.address.chain_stats, this.address.address); + this.mempoolStats = new AddressStats(this.address.mempool_stats, this.address.address); + } + + setBalancePeriod(period: 'all' | '1m'): boolean { + this.balancePeriod = period; + return false; + } + + showBalancePeriod(): boolean { + return this.transactions?.length && ( + !this.transactions[0].status?.confirmed + || this.transactions[0].status.block_time > (this.now - (60 * 60 * 24 * 30)) + ); + } + + @HostListener('window:resize', ['$event']) + onResize(): void { + this.isMobile = window.innerWidth < 768; } - ngOnDestroy() { + ngOnDestroy(): void { this.mainSubscription.unsubscribe(); + this.mempoolTxSubscription.unsubscribe(); + this.mempoolRemovedTxSubscription.unsubscribe(); + this.blockTxSubscription.unsubscribe(); this.websocketService.stopTrackingAddress(); } } diff --git a/frontend/src/app/components/amount/amount.component.html b/frontend/src/app/components/amount/amount.component.html index c4c575267d..b513c89d26 100644 --- a/frontend/src/app/components/amount/amount.component.html +++ b/frontend/src/app/components/amount/amount.component.html @@ -1,13 +1,48 @@ - - {{ conversions.USD * (satoshis / 100000000) | currency:'USD':'symbol':'1.2-2' }} + + + {{ addPlus && satoshis >= 0 ? '+' : '' }}{{ + ( + (blockConversion.price[currency] > -1 ? blockConversion.price[currency] : null) ?? + (blockConversion.price['USD'] > -1 ? blockConversion.price['USD'] * blockConversion.exchangeRates['USD' + currency] : null) ?? 0 + ) * satoshis / 100000000 | fiatCurrency : digitsInfo : currency + }} + + + {{ addPlus && satoshis >= 0 ? '+' : '' }}{{ (conversions[currency] > -1 ? conversions[currency] : 0) * satoshis / 100000000 | fiatCurrency : digitsInfo : currency }} + + + + {{ 0 | fiatCurrency : digitsInfo : currency }} + - - - Confidential + + + + Confidential - {{ satoshis / 100000000 | number : digitsInfo }} - L- - tBTC + @if ((viewAmountMode$ | async) === 'btc' || (viewAmountMode$ | async) === 'fiat' || ignoreViewMode === true) { + ‎{{ addPlus && satoshis >= 0 ? '+' : '' }}{{ satoshis / 100000000 | number : digitsInfo }} + + BTC + + } @else { + @if (digitsInfo === '1.8-8') { + ‎{{ addPlus && satoshis >= 0 ? '+' : '' }}{{ satoshis | number }} + } @else { + ‎{{ addPlus && satoshis >= 0 ? '+' : '' }}{{ satoshis | amountShortener : satoshis < 1000 && satoshis > -1000 ? 0 : 1 }} + } + + sats + + } + + + L- + tL- + t + t + s + diff --git a/frontend/src/app/components/amount/amount.component.scss b/frontend/src/app/components/amount/amount.component.scss index 843bd58b6c..87f2fe6cd6 100644 --- a/frontend/src/app/components/amount/amount.component.scss +++ b/frontend/src/app/components/amount/amount.component.scss @@ -1,3 +1,3 @@ .green-color { - color: #3bcc49; -} + color: var(--green); +} \ No newline at end of file diff --git a/frontend/src/app/components/amount/amount.component.spec.ts b/frontend/src/app/components/amount/amount.component.spec.ts deleted file mode 100644 index 963bdbb500..0000000000 --- a/frontend/src/app/components/amount/amount.component.spec.ts +++ /dev/null @@ -1,25 +0,0 @@ -import { async, ComponentFixture, TestBed } from '@angular/core/testing'; - -import { AmountComponent } from './amount.component'; - -describe('AmountComponent', () => { - let component: AmountComponent; - let fixture: ComponentFixture; - - beforeEach(async(() => { - TestBed.configureTestingModule({ - declarations: [ AmountComponent ] - }) - .compileComponents(); - })); - - beforeEach(() => { - fixture = TestBed.createComponent(AmountComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); - - it('should create', () => { - expect(component).toBeTruthy(); - }); -}); diff --git a/frontend/src/app/components/amount/amount.component.ts b/frontend/src/app/components/amount/amount.component.ts index 7958e8a0b0..93715f3c0f 100644 --- a/frontend/src/app/components/amount/amount.component.ts +++ b/frontend/src/app/components/amount/amount.component.ts @@ -1,6 +1,7 @@ -import { Component, OnInit, Input, ChangeDetectionStrategy } from '@angular/core'; +import { Component, OnInit, OnDestroy, Input, ChangeDetectionStrategy, ChangeDetectorRef } from '@angular/core'; import { StateService } from '../../services/state.service'; -import { Observable } from 'rxjs'; +import { Observable, Subscription } from 'rxjs'; +import { Price } from '../../services/price.service'; @Component({ selector: 'app-amount', @@ -8,23 +9,45 @@ import { Observable } from 'rxjs'; styleUrls: ['./amount.component.scss'], changeDetection: ChangeDetectionStrategy.OnPush, }) -export class AmountComponent implements OnInit { +export class AmountComponent implements OnInit, OnDestroy { conversions$: Observable; - viewFiat$: Observable; + currency: string; + viewAmountMode$: Observable<'btc' | 'sats' | 'fiat'>; network = ''; + stateSubscription: Subscription; + currencySubscription: Subscription; + @Input() satoshis: number; @Input() digitsInfo = '1.8-8'; @Input() noFiat = false; + @Input() addPlus = false; + @Input() blockConversion: Price; + @Input() forceBtc: boolean = false; + @Input() ignoreViewMode: boolean = false; + @Input() forceBlockConversion: boolean = false; // true = displays fiat price as 0 if blockConversion is undefined instead of falling back to conversions constructor( private stateService: StateService, - ) { } + private cd: ChangeDetectorRef, + ) { + this.currencySubscription = this.stateService.fiatCurrency$.subscribe((fiat) => { + this.currency = fiat; + this.cd.markForCheck(); + }); + } ngOnInit() { - this.viewFiat$ = this.stateService.viewFiat$.asObservable(); + this.viewAmountMode$ = this.stateService.viewAmountMode$.asObservable(); this.conversions$ = this.stateService.conversions$.asObservable(); - this.stateService.networkChanged$.subscribe((network) => this.network = network); + this.stateSubscription = this.stateService.networkChanged$.subscribe((network) => this.network = network); + } + + ngOnDestroy() { + if (this.stateSubscription) { + this.stateSubscription.unsubscribe(); + } + this.currencySubscription.unsubscribe(); } } diff --git a/frontend/src/app/components/app/app.component.spec.ts b/frontend/src/app/components/app/app.component.spec.ts deleted file mode 100644 index edc031e564..0000000000 --- a/frontend/src/app/components/app/app.component.spec.ts +++ /dev/null @@ -1,35 +0,0 @@ -import { TestBed, async } from '@angular/core/testing'; -import { RouterTestingModule } from '@angular/router/testing'; -import { AppComponent } from './app.component'; - -describe('AppComponent', () => { - beforeEach(async(() => { - TestBed.configureTestingModule({ - imports: [ - RouterTestingModule - ], - declarations: [ - AppComponent - ], - }).compileComponents(); - })); - - it('should create the app', () => { - const fixture = TestBed.createComponent(AppComponent); - const app = fixture.debugElement.componentInstance; - expect(app).toBeTruthy(); - }); - - it(`should have as title 'mempool'`, () => { - const fixture = TestBed.createComponent(AppComponent); - const app = fixture.debugElement.componentInstance; - expect(app.title).toEqual('mempool'); - }); - - it('should render title in a h1 tag', () => { - const fixture = TestBed.createComponent(AppComponent); - fixture.detectChanges(); - const compiled = fixture.debugElement.nativeElement; - expect(compiled.querySelector('h1').textContent).toContain('Welcome to mempool!'); - }); -}); diff --git a/frontend/src/app/components/app/app.component.ts b/frontend/src/app/components/app/app.component.ts index 6a961710ad..4532769660 100644 --- a/frontend/src/app/components/app/app.component.ts +++ b/frontend/src/app/components/app/app.component.ts @@ -1,34 +1,60 @@ -import { Component, HostListener, OnInit } from '@angular/core'; +import { Location } from '@angular/common'; +import { Component, HostListener, OnInit, Inject, LOCALE_ID, HostBinding } from '@angular/core'; import { Router, NavigationEnd } from '@angular/router'; -import { WebsocketService } from '../../services/websocket.service'; -import { StateService } from 'src/app/services/state.service'; +import { StateService } from '../../services/state.service'; +import { OpenGraphService } from '../../services/opengraph.service'; +import { NgbTooltipConfig } from '@ng-bootstrap/ng-bootstrap'; +import { ThemeService } from '../../services/theme.service'; +import { SeoService } from '../../services/seo.service'; @Component({ selector: 'app-root', templateUrl: './app.component.html', - styleUrls: ['./app.component.scss'] + styleUrls: ['./app.component.scss'], + providers: [NgbTooltipConfig] }) export class AppComponent implements OnInit { - link: HTMLElement = document.getElementById('canonical'); - constructor( public router: Router, - private websocketService: WebsocketService, private stateService: StateService, - ) { } + private openGraphService: OpenGraphService, + private seoService: SeoService, + private themeService: ThemeService, + private location: Location, + tooltipConfig: NgbTooltipConfig, + @Inject(LOCALE_ID) private locale: string, + ) { + if (this.locale.startsWith('ar') || this.locale.startsWith('fa') || this.locale.startsWith('he')) { + this.dir = 'rtl'; + this.class = 'rtl-layout'; + } else { + this.class = 'ltr-layout'; + } + + tooltipConfig.animation = false; + tooltipConfig.container = 'body'; + tooltipConfig.triggers = 'hover'; + } + + @HostBinding('attr.dir') dir = 'ltr'; + @HostBinding('class') class; @HostListener('document:keydown', ['$event']) handleKeyboardEvents(event: KeyboardEvent) { if (event.target instanceof HTMLInputElement) { return; } + // prevent arrow key horizontal scrolling + if(["ArrowLeft","ArrowRight"].indexOf(event.code) > -1) { + event.preventDefault(); + } this.stateService.keyNavigation$.next(event); } ngOnInit() { this.router.events.subscribe((val) => { if (val instanceof NavigationEnd) { - this.link.setAttribute('href', 'https://mempool.space' + (location.pathname === '/' ? '' : location.pathname)); + this.seoService.updateCanonical(this.location.path()); } }); } diff --git a/frontend/src/app/components/asset-circulation/asset-circulation.component.html b/frontend/src/app/components/asset-circulation/asset-circulation.component.html new file mode 100644 index 0000000000..98d672c55a --- /dev/null +++ b/frontend/src/app/components/asset-circulation/asset-circulation.component.html @@ -0,0 +1,6 @@ + + Confidential + + {{ circulating.amount | amountShortener }} + {{ circulating.amount | number: '1.2-2' }} {{ circulating.ticker }} + \ No newline at end of file diff --git a/frontend/src/app/components/asset-circulation/asset-circulation.component.scss b/frontend/src/app/components/asset-circulation/asset-circulation.component.scss new file mode 100644 index 0000000000..5e43c829c5 --- /dev/null +++ b/frontend/src/app/components/asset-circulation/asset-circulation.component.scss @@ -0,0 +1,3 @@ +.ticker { + color: grey; +} diff --git a/frontend/src/app/components/asset-circulation/asset-circulation.component.ts b/frontend/src/app/components/asset-circulation/asset-circulation.component.ts new file mode 100644 index 0000000000..cc09c48099 --- /dev/null +++ b/frontend/src/app/components/asset-circulation/asset-circulation.component.ts @@ -0,0 +1,59 @@ +import { ChangeDetectionStrategy, Component, Inject, Input, LOCALE_ID, OnInit } from '@angular/core'; +import { combineLatest, Observable } from 'rxjs'; +import { map } from 'rxjs/operators'; +import { moveDec } from '../../bitcoin.utils'; +import { AssetsService } from '../../services/assets.service'; +import { ElectrsApiService } from '../../services/electrs-api.service'; +import { environment } from '../../../environments/environment'; + +@Component({ + selector: 'app-asset-circulation', + templateUrl: './asset-circulation.component.html', + styleUrls: ['./asset-circulation.component.scss'], + changeDetection: ChangeDetectionStrategy.OnPush, +}) +export class AssetCirculationComponent implements OnInit { + @Input() assetId: string; + + circulatingAmount$: Observable<{ amount: number, ticker: string}>; + + constructor( + private electrsApiService: ElectrsApiService, + private assetsService: AssetsService, + @Inject(LOCALE_ID) private locale: string, + ) { } + + ngOnInit(): void { + this.circulatingAmount$ = combineLatest([ + this.electrsApiService.getAsset$(this.assetId), + this.assetsService.getAssetsMinimalJson$] + ) + .pipe( + map(([asset, assetsMinimal]) => { + const assetData = assetsMinimal[asset.asset_id]; + if (!asset.chain_stats.has_blinded_issuances) { + if (asset.asset_id === environment.nativeAssetId) { + return { + amount: this.formatAmount(asset.chain_stats.peg_in_amount - asset.chain_stats.burned_amount - asset.chain_stats.peg_out_amount, assetData[3]), + ticker: assetData[1] + }; + } else { + return { + amount: this.formatAmount(asset.chain_stats.issued_amount - asset.chain_stats.burned_amount, assetData[3]), + ticker: assetData[1] + }; + } + } else { + return { + amount: -1, + ticker: '', + }; + } + }), + ); + } + + formatAmount(value: number, precision = 0): number { + return parseFloat(moveDec(value, -precision)); + } +} diff --git a/frontend/src/app/components/asset/asset.component.html b/frontend/src/app/components/asset/asset.component.html index 58038bf1d0..a7f4d31188 100644 --- a/frontend/src/app/components/asset/asset.component.html +++ b/frontend/src/app/components/asset/asset.component.html @@ -1,11 +1,12 @@
-

Asset

- - {{ assetString | shortenString : 24 }} - {{ assetString }} - - -
+
+

Asset

+ +
@@ -17,62 +18,68 @@

Asset

- - + + - + - - + + - - + + - -
Name{{ assetContract[2] }} ({{ assetContract[1] }})Name{{ assetContract[2] }} ({{ assetContract[1] }})
PrecisionPrecision {{ assetContract[3] }}
Issuer
Issuer {{ assetContract[0] }}
Issuance tx
Issuance TX {{ asset.issuance_txin.txid | shortenString : 13 }}
-
-
-
- - - - - + + + - - - + + + - - - + + + - - + + - - - + + + - - - + + +
Pegged in{{ asset.chain_stats.peg_in_amount / 100000000 | number: '1.0-' + assetContract[3] }} {{ assetContract[1] }}
Pegged in{{ formatAmount(asset.chain_stats.peg_in_amount, assetContract[3]) | number: '1.0-' + assetContract[3] }} {{ assetContract[1] }}
Pegged out{{ asset.chain_stats.peg_out_amount / 100000000 | number: '1.0-' + assetContract[3] }} {{ assetContract[1] }}
Pegged out{{ formatAmount(asset.chain_stats.peg_out_amount, assetContract[3]) | number: '1.0-' + assetContract[3] }} {{ assetContract[1] }}
Issued amount{{ asset.chain_stats.issued_amount / 100000000 | number: '1.0-' + assetContract[3] }} {{ assetContract[1] }}
Issued amount{{ formatAmount(asset.chain_stats.issued_amount, assetContract[3]) | number: '1.0-' + assetContract[3] }} {{ assetContract[1] }}
Burned amount{{ asset.chain_stats.burned_amount / 100000000 | number: '1.0-' + assetContract[3] }} {{ assetContract[1] }}Burned amount{{ formatAmount(asset.chain_stats.burned_amount, assetContract[3]) | number: '1.0-' + assetContract[3] }} {{ assetContract[1] }}
Circulating amount{{ (asset.chain_stats.issued_amount - asset.chain_stats.burned_amount) / 100000000 | number: '1.0-' + assetContract[3] }} {{ assetContract[1] }}
Circulating amount{{ formatAmount(asset.chain_stats.issued_amount - asset.chain_stats.burned_amount, assetContract[3]) | number: '1.0-' + assetContract[3] }} {{ assetContract[1] }}
Circulating amount{{ (asset.chain_stats.peg_in_amount - asset.chain_stats.burned_amount - asset.chain_stats.peg_out_amount) / 100000000 | number: '1.0-' + assetContract[3] }} {{ assetContract[1] }}
Circulating amount{{ formatAmount(asset.chain_stats.peg_in_amount - asset.chain_stats.burned_amount - asset.chain_stats.peg_out_amount, assetContract[3]) | number: '1.0-' + assetContract[3] }} {{ assetContract[1] }}
+
+
+ + + + +

-

{{ (transactions?.length | number) || '?' }} of {{ txCount | number }} Peg In/Out and Burn TransactionsIn/Out and Burn Transactions

+
+

+ {{ (transactions?.length | number) || '?' }} of {{ txCount | number }}  + Peg In/Out and Burn Transactions + Issuance and Burn Transactions +

+
@@ -100,41 +107,53 @@

{{ (transactions?.length | number - -
- - - - - - - - - - - - -
-
-
-
- - +
+ + + + + + + + + + + + + + + + + + + + + + + + +
+
+
+
+ +
-
- Error loading asset data. -
- {{ error.error }} -
+ + Error loading asset data. +
-

-
\ No newline at end of file +
+ + + Confidential + diff --git a/frontend/src/app/components/asset/asset.component.scss b/frontend/src/app/components/asset/asset.component.scss index c5961e4282..56b1d6258c 100644 --- a/frontend/src/app/components/asset/asset.component.scss +++ b/frontend/src/app/components/asset/asset.component.scss @@ -1,5 +1,5 @@ .qr-wrapper { - background-color: #FFF; + background-color: #fff; padding: 10px; padding-bottom: 5px; display: inline-block; @@ -20,4 +20,61 @@ margin-top: 20px; margin-right: 0px; } -} \ No newline at end of file +} + +h1 { + margin: 0px; + padding: 0px; + margin-right: 15px; + @media (min-width: 576px) { + float: left; + } +} + +.tx-link { + display: block; + height: 100%; + top: 9px; + position: relative; + @media (min-width: 576px) { + top: 11px; + } + @media (min-width: 768px) { + top: 17px; + } +} +.title-tx { + h2 { + line-height: 1; + margin-bottom: 10px; + } +} + +.assetIcon { + height: 150px; + margin: 25px; + @media (min-width: 768px) { + height: 250px; + margin: 0; + } +} + +.icon-holder { + display: flex; + justify-content: center; + align-items: center; +} + +.defaultIcon { + margin: 25px; + height: 150px; +} + +.defaultIcon.skeleton { + opacity: 0.5; +} + +.assetName { + word-break: break-word; + white-space: normal; +} diff --git a/frontend/src/app/components/asset/asset.component.ts b/frontend/src/app/components/asset/asset.component.ts index 4cd84540b2..dd09468cc2 100644 --- a/frontend/src/app/components/asset/asset.component.ts +++ b/frontend/src/app/components/asset/asset.component.ts @@ -3,14 +3,15 @@ import { ActivatedRoute, ParamMap } from '@angular/router'; import { ElectrsApiService } from '../../services/electrs-api.service'; import { switchMap, filter, catchError, take } from 'rxjs/operators'; import { Asset, Transaction } from '../../interfaces/electrs.interface'; -import { WebsocketService } from 'src/app/services/websocket.service'; -import { StateService } from 'src/app/services/state.service'; -import { AudioService } from 'src/app/services/audio.service'; -import { ApiService } from 'src/app/services/api.service'; +import { WebsocketService } from '../../services/websocket.service'; +import { StateService } from '../../services/state.service'; +import { AudioService } from '../../services/audio.service'; +import { ApiService } from '../../services/api.service'; import { of, merge, Subscription, combineLatest } from 'rxjs'; -import { SeoService } from 'src/app/services/seo.service'; -import { environment } from 'src/environments/environment'; -import { AssetsService } from 'src/app/services/assets.service'; +import { SeoService } from '../../services/seo.service'; +import { environment } from '../../../environments/environment'; +import { AssetsService } from '../../services/assets.service'; +import { moveDec } from '../../bitcoin.utils'; @Component({ selector: 'app-asset', @@ -19,9 +20,10 @@ import { AssetsService } from 'src/app/services/assets.service'; }) export class AssetComponent implements OnInit, OnDestroy { network = ''; - nativeAssetId = environment.nativeAssetId; + nativeAssetId = this.stateService.network === 'liquidtestnet' ? environment.nativeTestAssetId : environment.nativeAssetId; asset: Asset; + blindedIssuance: boolean; assetContract: any; assetString: string; isLoadingAsset = true; @@ -30,6 +32,7 @@ export class AssetComponent implements OnInit, OnDestroy { isNativeAsset = false; error: any; mainSubscription: Subscription; + imageError = false; totalConfirmedTxCount = 0; loadedConfirmedTxCount = 0; @@ -53,13 +56,14 @@ export class AssetComponent implements OnInit, OnDestroy { ) { } ngOnInit() { - this.websocketService.want(['blocks', 'stats', 'mempool-blocks']); + this.websocketService.want(['blocks', 'mempool-blocks']); this.stateService.networkChanged$.subscribe((network) => this.network = network); this.mainSubscription = this.route.paramMap .pipe( switchMap((params: ParamMap) => { this.error = undefined; + this.imageError = false; this.isLoadingAsset = true; this.loadedConfirmedTxCount = 0; this.asset = null; @@ -68,7 +72,7 @@ export class AssetComponent implements OnInit, OnDestroy { this.transactions = null; document.body.scrollTo(0, 0); this.assetString = params.get('id') || ''; - this.seoService.setTitle('Asset: ' + this.assetString, true); + this.seoService.setTitle($localize`:@@asset.component.asset-browser-title:Asset: ${this.assetString}:INTERPOLATION:`); return merge( of(true), @@ -82,6 +86,7 @@ export class AssetComponent implements OnInit, OnDestroy { catchError((err) => { this.isLoadingAsset = false; this.error = err; + this.seoService.logSoft404(); console.log(err); return of(null); }) @@ -97,6 +102,11 @@ export class AssetComponent implements OnInit, OnDestroy { switchMap(([asset, assetsData]) => { this.asset = asset; this.assetContract = assetsData[this.asset.asset_id]; + if (!this.assetContract) { + this.assetContract = [null, '?', 'Unknown', 0]; + } + this.seoService.setDescription($localize`:@@meta.description.liquid.asset:Browse an overview of the Liquid asset ${this.assetContract[2]}:INTERPOLATION: (${this.assetContract[1]}:INTERPOLATION:): see issued amount, burned amount, circulating amount, related transactions, and more.`); + this.blindedIssuance = this.asset.chain_stats.has_blinded_issuances || this.asset.mempool_stats.has_blinded_issuances; this.isNativeAsset = asset.asset_id === this.nativeAssetId; this.updateChainStats(); this.websocketService.startTrackAsset(asset.asset_id); @@ -130,7 +140,13 @@ export class AssetComponent implements OnInit, OnDestroy { this.tempTransactions[this.timeTxIndexes[index]].firstSeen = time; }); this.tempTransactions.sort((a, b) => { - return b.status.block_time - a.status.block_time || b.firstSeen - a.firstSeen; + if (b.status.confirmed) { + if (b.status.block_height === a.status.block_height) { + return b.status.block_time - a.status.block_time; + } + return b.status.block_height - a.status.block_height; + } + return b.firstSeen - a.firstSeen; }); this.transactions = this.tempTransactions; @@ -139,6 +155,7 @@ export class AssetComponent implements OnInit, OnDestroy { (error) => { console.log(error); this.error = error; + this.seoService.logSoft404(); this.isLoadingAsset = false; }); @@ -189,6 +206,10 @@ export class AssetComponent implements OnInit, OnDestroy { this.totalConfirmedTxCount = this.asset.chain_stats.tx_count; } + formatAmount(value: number, precision = 0): number | string { + return moveDec(value, -precision); + } + ngOnDestroy() { this.mainSubscription.unsubscribe(); this.websocketService.stopTrackingAsset(); diff --git a/frontend/src/app/components/assets/asset-group/asset-group.component.html b/frontend/src/app/components/assets/asset-group/asset-group.component.html new file mode 100644 index 0000000000..600a8a9bd0 --- /dev/null +++ b/frontend/src/app/components/assets/asset-group/asset-group.component.html @@ -0,0 +1,37 @@ +
+ + + + +
+

{{ group['group'].name }}

+
Group of {{ group.assets.length | number }} assets
+
+
+ +
+ +
+ +
+
+
+ + + + +
{{ asset.ticker }}
+
+
+
+ +
+ + +
+
+
+
+
\ No newline at end of file diff --git a/frontend/src/app/components/assets/asset-group/asset-group.component.scss b/frontend/src/app/components/assets/asset-group/asset-group.component.scss new file mode 100644 index 0000000000..d434c16ef3 --- /dev/null +++ b/frontend/src/app/components/assets/asset-group/asset-group.component.scss @@ -0,0 +1,60 @@ +.image { + width: 150px; + float: left; +} + +.main-title { + float: left +} + +.sub-title { + color: grey; +} + +.featuredBox { + display: flex; + flex-flow: row wrap; + justify-content: center; + gap: 27px; +} + +.card { + background-color: var(--bg); + width: 200px; + height: 200px; + align-items: center; + justify-content: center; + flex-wrap: wrap; + @media (max-width: 767.98px) { + width: 150px; + height: 150px; + } +} + +.title { + font-size: 14px; + font-weight: bold; + margin-top: 10px; + text-align: center; +} + +.sub-title { + color: grey; +} + +.assetIcon { + width: 100px; + height: 100px; + @media (max-width: 767.98px) { + width: 50px; + height: 50px; + } +} + +.view-link { + margin-top: 30px; +} + +.ticker { + color: grey; +} diff --git a/frontend/src/app/components/assets/asset-group/asset-group.component.ts b/frontend/src/app/components/assets/asset-group/asset-group.component.ts new file mode 100644 index 0000000000..27e048558e --- /dev/null +++ b/frontend/src/app/components/assets/asset-group/asset-group.component.ts @@ -0,0 +1,44 @@ +import { Component, OnInit } from '@angular/core'; +import { ActivatedRoute, ParamMap } from '@angular/router'; +import { combineLatest, Observable } from 'rxjs'; +import { map, switchMap } from 'rxjs/operators'; +import { ApiService } from '../../../services/api.service'; +import { AssetsService } from '../../../services/assets.service'; + +@Component({ + selector: 'app-asset-group', + templateUrl: './asset-group.component.html', + styleUrls: ['./asset-group.component.scss'] +}) +export class AssetGroupComponent implements OnInit { + group$: Observable; + + constructor( + private route: ActivatedRoute, + private apiService: ApiService, + private assetsService: AssetsService, + ) { } + + ngOnInit(): void { + this.group$ = this.route.paramMap + .pipe( + switchMap((params: ParamMap) => { + return combineLatest([ + this.assetsService.getAssetsJson$, + this.apiService.getAssetGroup$(params.get('id')), + ]); + }), + map(([assets, group]) => { + const items = []; + // @ts-ignore + for (const item of group.assets) { + items.push(assets.objects[item]); + } + return { + group: group, + assets: items + }; + }) + ); + } +} diff --git a/frontend/src/app/components/assets/assets-featured/assets-featured.component.html b/frontend/src/app/components/assets/assets-featured/assets-featured.component.html new file mode 100644 index 0000000000..52573c437d --- /dev/null +++ b/frontend/src/app/components/assets/assets-featured/assets-featured.component.html @@ -0,0 +1,31 @@ +
+
+
No featured assets
+
+
+ + + + + +
Group of {{ group.assets.length | number }} assets
+
+ + + + + +
{{ group.ticker }}
+
+
+ +
+ + +
+
+
+
+
\ No newline at end of file diff --git a/frontend/src/app/components/assets/assets-featured/assets-featured.component.scss b/frontend/src/app/components/assets/assets-featured/assets-featured.component.scss new file mode 100644 index 0000000000..c80c3689d8 --- /dev/null +++ b/frontend/src/app/components/assets/assets-featured/assets-featured.component.scss @@ -0,0 +1,55 @@ + +.featuredBox { + display: flex; + flex-flow: row wrap; + justify-content: center; + gap: 27px; +} + +.card { + background-color: var(--bg); + width: 200px; + height: 200px; + align-items: center; + justify-content: center; + flex-wrap: wrap; + @media (max-width: 767.98px) { + width: 150px; + height: 150px; + } +} + +.title { + font-size: 14px; + font-weight: bold; + margin-top: 10px; + text-align: center; +} + +.sub-title { + color: grey; + font-size: 12px; +} + +.assetIcon { + width: 100px; + height: 100px; + @media (max-width: 767.98px) { + width: 50px; + height: 50px; + } +} + +.view-link { + margin-top: 30px; +} + +.ticker { + color: grey; +} + +.symbol { + color: grey; + font-size: 1.5rem; + font-style: italic; +} \ No newline at end of file diff --git a/frontend/src/app/components/assets/assets-featured/assets-featured.component.ts b/frontend/src/app/components/assets/assets-featured/assets-featured.component.ts new file mode 100644 index 0000000000..a9bf305f68 --- /dev/null +++ b/frontend/src/app/components/assets/assets-featured/assets-featured.component.ts @@ -0,0 +1,23 @@ +import { Component, OnInit } from '@angular/core'; +import { Observable } from 'rxjs'; +import { ApiService } from '../../../services/api.service'; +import { StateService } from '../../../services/state.service'; + +@Component({ + selector: 'app-assets-featured', + templateUrl: './assets-featured.component.html', + styleUrls: ['./assets-featured.component.scss'] +}) +export class AssetsFeaturedComponent implements OnInit { + featuredAssets$: Observable; + + constructor( + private apiService: ApiService, + private stateService: StateService, + ) { } + + ngOnInit(): void { + this.featuredAssets$ = this.apiService.listFeaturedAssets$(this.stateService.network); + } + +} diff --git a/frontend/src/app/components/assets/assets-nav/assets-nav.component.html b/frontend/src/app/components/assets/assets-nav/assets-nav.component.html new file mode 100644 index 0000000000..420fff818b --- /dev/null +++ b/frontend/src/app/components/assets/assets-nav/assets-nav.component.html @@ -0,0 +1,33 @@ +
+
+

Assets

+
+ + + +
+ + + +
+ +
diff --git a/frontend/src/app/components/assets/assets-nav/assets-nav.component.scss b/frontend/src/app/components/assets/assets-nav/assets-nav.component.scss new file mode 100644 index 0000000000..21ab756d9a --- /dev/null +++ b/frontend/src/app/components/assets/assets-nav/assets-nav.component.scss @@ -0,0 +1,24 @@ +ul { + margin-bottom: 20px; + float: left; + +} + +form { + float: right; + width: 300px; + @media (max-width: 767.98px) { + width: 90%; + margin-bottom: 15px; + } +} + +@media (max-width: 767.98px) { + .nav-container { + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + margin: auto; + } +} \ No newline at end of file diff --git a/frontend/src/app/components/assets/assets-nav/assets-nav.component.ts b/frontend/src/app/components/assets/assets-nav/assets-nav.component.ts new file mode 100644 index 0000000000..c9b044b344 --- /dev/null +++ b/frontend/src/app/components/assets/assets-nav/assets-nav.component.ts @@ -0,0 +1,96 @@ +import { Component, OnInit, ViewChild } from '@angular/core'; +import { UntypedFormBuilder, UntypedFormGroup, Validators } from '@angular/forms'; +import { Router } from '@angular/router'; +import { NgbTypeahead } from '@ng-bootstrap/ng-bootstrap'; +import { merge, Observable, of, Subject } from 'rxjs'; +import { distinctUntilChanged, filter, map, switchMap } from 'rxjs/operators'; +import { AssetExtended } from '../../../interfaces/electrs.interface'; +import { AssetsService } from '../../../services/assets.service'; +import { SeoService } from '../../../services/seo.service'; +import { StateService } from '../../../services/state.service'; +import { RelativeUrlPipe } from '../../../shared/pipes/relative-url/relative-url.pipe'; +import { environment } from '../../../../environments/environment'; + +@Component({ + selector: 'app-assets-nav', + templateUrl: './assets-nav.component.html', + styleUrls: ['./assets-nav.component.scss'] +}) +export class AssetsNavComponent implements OnInit { + @ViewChild('instance', {static: true}) instance: NgbTypeahead; + nativeAssetId = this.stateService.network === 'liquidtestnet' ? environment.nativeTestAssetId : environment.nativeAssetId; + searchForm: UntypedFormGroup; + assetsCache: AssetExtended[]; + + typeaheadSearchFn: ((text: Observable) => Observable); + formatterFn = (asset: AssetExtended) => asset.name + ' (' + asset.ticker + ')'; + focus$ = new Subject(); + click$ = new Subject(); + + itemsPerPage = 15; + + constructor( + private formBuilder: UntypedFormBuilder, + private seoService: SeoService, + private router: Router, + private assetsService: AssetsService, + private stateService: StateService, + private relativeUrlPipe: RelativeUrlPipe, + ) { } + + ngOnInit(): void { + this.seoService.setTitle($localize`:@@ee8f8008bae6ce3a49840c4e1d39b4af23d4c263:Assets`); + this.seoService.setDescription($localize`:@@meta.description.liquid.assets:Explore all the assets issued on the Liquid network like L-BTC, L-CAD, USDT, and more.`); + this.typeaheadSearchFn = this.typeaheadSearch; + + this.searchForm = this.formBuilder.group({ + searchText: [{ value: '', disabled: false }, Validators.required] + }); + } + + typeaheadSearch = (text$: Observable) => { + const debouncedText$ = text$.pipe( + distinctUntilChanged() + ); + const clicksWithClosedPopup$ = this.click$.pipe(filter(() => !this.instance.isPopupOpen())); + const inputFocus$ = this.focus$; + + return merge(debouncedText$, inputFocus$, clicksWithClosedPopup$) + .pipe( + switchMap((searchText) => { + if (!searchText.length) { + return of([]); + } + return this.assetsService.getAssetsJson$.pipe( + map((assets) => { + if (searchText.length ) { + const filteredAssets = assets.array.filter((asset) => asset.name.toLowerCase().indexOf(searchText.toLowerCase()) > -1 + || (asset.ticker || '').toLowerCase().indexOf(searchText.toLowerCase()) > -1 + || (asset.entity && asset.entity.domain || '').toLowerCase().indexOf(searchText.toLowerCase()) > -1); + return filteredAssets.slice(0, this.itemsPerPage); + } else { + return assets.array.slice(0, this.itemsPerPage); + } + }) + ) + }), + ); + } + + itemSelected() { + setTimeout(() => this.search()); + } + + search() { + const searchText = this.searchForm.value.searchText; + this.navigate('/assets/asset/', searchText.asset_id); + } + + navigate(url: string, searchText: string, extras?: any) { + this.router.navigate([this.relativeUrlPipe.transform(url), searchText], extras); + this.searchForm.setValue({ + searchText: '', + }); + } + +} diff --git a/frontend/src/app/components/assets/assets.component.html b/frontend/src/app/components/assets/assets.component.html new file mode 100644 index 0000000000..30c6b72559 --- /dev/null +++ b/frontend/src/app/components/assets/assets.component.html @@ -0,0 +1,52 @@ + + + + + + + + + + + + + + + + +
NameTickerIssuer domainAsset ID
{{ asset.name }}{{ asset.ticker }}{{ asset.entity && asset.entity.domain }}{{ asset.asset_id | shortenString : 13 }}
+ +
+ + + +
+
+
+ + + + + + + + + + + + + + + + + + +
NameTickerIssuer domainAsset ID
+ +
+ + + + Error loading assets data. + + diff --git a/frontend/src/app/assets/assets.component.scss b/frontend/src/app/components/assets/assets.component.scss similarity index 52% rename from frontend/src/app/assets/assets.component.scss rename to frontend/src/app/components/assets/assets.component.scss index 2cfc390fb6..9c337d2918 100644 --- a/frontend/src/app/assets/assets.component.scss +++ b/frontend/src/app/components/assets/assets.component.scss @@ -3,4 +3,11 @@ overflow: hidden; text-overflow: ellipsis; white-space: nowrap; -} \ No newline at end of file +} +.title-asset { + h1 { + line-height: 1; + margin: 0px; + padding-bottom: 10px; + } +} diff --git a/frontend/src/app/components/assets/assets.component.ts b/frontend/src/app/components/assets/assets.component.ts new file mode 100644 index 0000000000..85d236bca0 --- /dev/null +++ b/frontend/src/app/components/assets/assets.component.ts @@ -0,0 +1,99 @@ +import { Component, OnInit, ChangeDetectionStrategy } from '@angular/core'; +import { AssetsService } from '../../services/assets.service'; +import { environment } from '../../../environments/environment'; +import { UntypedFormGroup } from '@angular/forms'; +import { filter, map, switchMap, take } from 'rxjs/operators'; +import { ActivatedRoute, Router } from '@angular/router'; +import { combineLatest, Observable } from 'rxjs'; +import { AssetExtended } from '../../interfaces/electrs.interface'; +import { SeoService } from '../../services/seo.service'; +import { StateService } from '../../services/state.service'; + +@Component({ + selector: 'app-assets', + templateUrl: './assets.component.html', + styleUrls: ['./assets.component.scss'], + changeDetection: ChangeDetectionStrategy.OnPush +}) +export class AssetsComponent implements OnInit { + nativeAssetId = this.stateService.network === 'liquidtestnet' ? environment.nativeTestAssetId : environment.nativeAssetId; + paginationMaxSize = window.matchMedia('(max-width: 670px)').matches ? 4 : 6; + ellipses = window.matchMedia('(max-width: 670px)').matches ? false : true; + + assets: AssetExtended[]; + assetsCache: AssetExtended[]; + searchForm: UntypedFormGroup; + assets$: Observable; + + page = 1; + error: any; + + itemsPerPage: number; + contentSpace = window.innerHeight - (250 + 200); + fiveItemsPxSize = 250; + + constructor( + private assetsService: AssetsService, + private route: ActivatedRoute, + private router: Router, + private seoService: SeoService, + private stateService: StateService, + ) { } + + ngOnInit() { + this.seoService.setTitle($localize`:@@ee8f8008bae6ce3a49840c4e1d39b4af23d4c263:Assets`); + this.itemsPerPage = Math.max(Math.round(this.contentSpace / this.fiveItemsPxSize) * 5, 10); + + this.assets$ = combineLatest([ + this.assetsService.getAssetsJson$, + this.route.queryParams, + ]) + .pipe( + take(1), + switchMap(([assets, qp]) => { + this.assets = assets.array; + + return this.route.queryParams + .pipe( + filter((queryParams) => { + const newPage = parseInt(queryParams.page, 10); + if (newPage !== this.page) { + return true; + } + return false; + }), + map((queryParams) => { + if (queryParams.page) { + const newPage = parseInt(queryParams.page, 10); + this.page = newPage; + } else { + this.page = 1; + } + return ''; + }) + ); + }), + map(() => { + const start = (this.page - 1) * this.itemsPerPage; + return this.assets.slice(start, this.itemsPerPage + start); + }) + ); + } + + pageChange(page: number) { + const queryParams = { page: page }; + if (queryParams.page === 1) { + queryParams.page = null; + } + this.page = -1; + this.router.navigate([], { + relativeTo: this.route, + queryParams: queryParams, + queryParamsHandling: 'merge', + }); + } + + trackByAsset(index: number, asset: any) { + return asset.asset_id; + } +} diff --git a/frontend/src/app/components/balance-widget/balance-widget.component.html b/frontend/src/app/components/balance-widget/balance-widget.component.html new file mode 100644 index 0000000000..4923a2c061 --- /dev/null +++ b/frontend/src/app/components/balance-widget/balance-widget.component.html @@ -0,0 +1,59 @@ +
+
+
+
+
BTC Holdings
+
+ {{ ((addressInfo.chain_stats.funded_txo_sum - addressInfo.chain_stats.spent_txo_sum) / 100_000_000) | number: '1.2-2' }} BTC +
+
+ +
+
+
+
Change (7d)
+
+ {{ delta7d > 0 ? '+' : ''}}{{ ((delta7d) / 100_000_000) | number: '1.2-2' }} BTC +
+
+ +
+
+
+
Change (30d)
+
+ {{ delta30d > 0 ? '+' : ''}}{{ ((delta30d) / 100_000_000) | number: '1.2-2' }} BTC +
+
+ +
+
+
+
+
+ + +
+
+
BTC Holdings
+
+
+
+
+
+
+
Change (7d)
+
+
+
+
+
+
+
Change (30d)
+
+
+
+
+
+
+
diff --git a/frontend/src/app/components/balance-widget/balance-widget.component.scss b/frontend/src/app/components/balance-widget/balance-widget.component.scss new file mode 100644 index 0000000000..a2f803c79e --- /dev/null +++ b/frontend/src/app/components/balance-widget/balance-widget.component.scss @@ -0,0 +1,160 @@ +.balance-container { + display: flex; + flex-direction: row; + justify-content: space-around; + height: 76px; + .shared-block { + color: var(--transparent-fg); + font-size: 12px; + } + .item { + padding: 0 5px; + width: 100%; + max-width: 150px; + &:last-child { + display: none; + @media (min-width: 485px) { + display: table-cell; + } + @media (min-width: 768px) { + display: none; + } + @media (min-width: 992px) { + display: table-cell; + } + } + } + .card-text { + font-size: 22px; + margin-top: -9px; + position: relative; + } +} + + +.balance-skeleton { + display: flex; + justify-content: space-between; + @media (min-width: 376px) { + flex-direction: row; + } + .item { + min-width: 120px; + max-width: 150px; + margin: 0; + width: -webkit-fill-available; + @media (min-width: 376px) { + margin: 0 auto 0px; + } + &:last-child{ + display: none; + @media (min-width: 485px) { + display: block; + } + @media (min-width: 768px) { + display: none; + } + @media (min-width: 992px) { + display: block; + } + } + &:last-child { + margin-bottom: 0; + } + } + .card-text { + .skeleton-loader { + width: 100%; + display: block; + &:first-child { + margin: 14px auto 0; + max-width: 80px; + } + &:last-child { + margin: 10px auto 0; + max-width: 120px; + } + } + } +} + +.card { + background-color: var(--bg); + height: 126px; +} + +.card-title { + color: var(--title-fg); + font-size: 1rem; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; +} + +.progress { + display: inline-flex; + width: 100%; + background-color: var(--secondary); + height: 1.1rem; + max-width: 180px; +} + +.skeleton-loader { + max-width: 100%; +} + +.more-padding { + padding: 24px 20px; +} + +.small-bar { + height: 8px; + top: -4px; + max-width: 120px; +} + +.loading-container { + min-height: 76px; +} + +.main-title { + position: relative; + color: #ffffff91; + margin-top: -13px; + font-size: 10px; + text-transform: uppercase; + font-weight: 500; + text-align: center; + padding-bottom: 3px; +} + +.card-wrapper { + .card { + height: auto !important; + } + .card-body { + display: flex; + flex: inherit; + text-align: center; + flex-direction: column; + justify-content: space-around; + padding: 24px 20px; + } +} + +.retarget-sign { + margin-right: -3px; + font-size: 14px; + top: -2px; + position: relative; +} + +.previous-retarget-sign { + margin-right: -2px; + font-size: 10px; +} + +.symbol { + font-size: 13px; + white-space: nowrap; +} \ No newline at end of file diff --git a/frontend/src/app/components/balance-widget/balance-widget.component.ts b/frontend/src/app/components/balance-widget/balance-widget.component.ts new file mode 100644 index 0000000000..8e1d3f4421 --- /dev/null +++ b/frontend/src/app/components/balance-widget/balance-widget.component.ts @@ -0,0 +1,72 @@ +import { ChangeDetectionStrategy, ChangeDetectorRef, Component, Input, OnChanges, OnInit, SimpleChanges } from '@angular/core'; +import { StateService } from '../../services/state.service'; +import { Address, AddressTxSummary } from '../../interfaces/electrs.interface'; +import { ElectrsApiService } from '../../services/electrs-api.service'; +import { Observable, catchError, of } from 'rxjs'; + +@Component({ + selector: 'app-balance-widget', + templateUrl: './balance-widget.component.html', + styleUrls: ['./balance-widget.component.scss'], + changeDetection: ChangeDetectionStrategy.OnPush, +}) +export class BalanceWidgetComponent implements OnInit, OnChanges { + @Input() address: string; + @Input() addressInfo: Address; + @Input() addressSummary$: Observable | null; + @Input() isPubkey: boolean = false; + + isLoading: boolean = true; + error: any; + + delta7d: number = 0; + delta30d: number = 0; + + constructor( + public stateService: StateService, + private electrsApiService: ElectrsApiService, + private cd: ChangeDetectorRef, + ) { } + + ngOnInit(): void { + + } + + ngOnChanges(changes: SimpleChanges): void { + this.isLoading = true; + if (!this.address || !this.addressInfo) { + return; + } + (this.addressSummary$ || (this.isPubkey + ? this.electrsApiService.getScriptHashSummary$((this.address.length === 66 ? '21' : '41') + this.address + 'ac') + : this.electrsApiService.getAddressSummary$(this.address)).pipe( + catchError(e => { + this.error = `Failed to fetch address balance history: ${e?.status || ''} ${e?.statusText || 'unknown error'}`; + return of(null); + }), + )).subscribe(addressSummary => { + if (addressSummary) { + this.error = null; + this.calculateStats(addressSummary); + } + this.isLoading = false; + this.cd.markForCheck(); + }); + } + + calculateStats(summary: AddressTxSummary[]): void { + let weekTotal = 0; + let monthTotal = 0; + + const weekAgo = (new Date(new Date().setHours(0, 0, 0, 0) - (7 * 24 * 60 * 60 * 1000)).getTime()) / 1000; + const monthAgo = (new Date(new Date().setHours(0, 0, 0, 0) - (30 * 24 * 60 * 60 * 1000)).getTime()) / 1000; + for (let i = 0; i < summary.length && summary[i].time >= monthAgo; i++) { + monthTotal += summary[i].value; + if (summary[i].time >= weekAgo) { + weekTotal += summary[i].value; + } + } + this.delta7d = weekTotal; + this.delta30d = monthTotal; + } +} diff --git a/frontend/src/app/components/bitcoin-invoice/bitcoin-invoice.component.html b/frontend/src/app/components/bitcoin-invoice/bitcoin-invoice.component.html new file mode 100644 index 0000000000..790f046f78 --- /dev/null +++ b/frontend/src/app/components/bitcoin-invoice/bitcoin-invoice.component.html @@ -0,0 +1,99 @@ +
+ + @if (!minimal) { + + Payment successful. You can close this page. + + + + A transaction has been detected in the mempool fully paying for this invoice. Waiting for on-chain confirmation. + + } + +
+ +
+ +
+
+ + + +
+
+ +
+ + + +
+ + + +
+ +
+ +
+ +
+
+ @if (!minimal) { +

{{ invoice.btcDue | number: '1.0-8' }} BTC

+ } + +
+ + + +
+ + + +
+ +
+ +
+ +
+
+ + @if (!minimal) { +

{{ invoice.btcDue * 100_000_000 | number: '1.0-0' }} sats

+ } + +
+ + + +
+ + + +
+
+
+ +
+ +
+
+ @if (!minimal) { +

{{ invoice.btcDue | number: '1.0-8' }} BTC

+ } + +
+ + @if (!minimal) { +

Waiting for transaction...

+
+ } +
+
\ No newline at end of file diff --git a/frontend/src/app/components/bitcoin-invoice/bitcoin-invoice.component.scss b/frontend/src/app/components/bitcoin-invoice/bitcoin-invoice.component.scss new file mode 100644 index 0000000000..b88a2ef740 --- /dev/null +++ b/frontend/src/app/components/bitcoin-invoice/bitcoin-invoice.component.scss @@ -0,0 +1,150 @@ +.form-panel { + background-color: #292b45; + padding: 20px; +} + + +.sponsor-page { + text-align: center; +} + +.qr-wrapper { + background-color: #FFF; + padding: 10px; + display: inline-block; + padding-bottom: 5px; + margin: 20px auto 0px; +} + +.info-group { + max-width: 400px; +} + +.card { + width: 240px; + height: 220px; + background-color: var(--bg); + border: 2px solid var(--bg); + cursor: pointer; + position: relative; + transition: 100ms all; + margin: 30px 30px 20px 30px; + @media(min-width: 476px) { + margin: 30px 100px 20px 100px; + } + @media(min-width: 851px) { + margin: 60px 20px 40px 20px; + } + + .card-title { + font-weight: bold; + span { + font-weight: 100; + } + } + + &.bigger { + height: 220px; + width: 240px; + margin-top: 40px; + } + + &:hover { + background-color: #5058926b; + border: 2px solid #505892; + transform: scale(1.1) translateY(-10px); + margin-top: 70px; + + .card-header { + background-color: #505892; + } + } +} + +.donation-form { + max-width: 280px; + margin: auto; + button { + width: 100%; + } +} + +.card-header { + background-color: #171929; +} + +.flex-container { + display: flex; + flex-direction: row; + flex-wrap: wrap; + justify-content: center; +} + +.middle-card { + width: 280px; + height: 260px; + margin-top: 40px; + &:hover { + margin-top: 50px; + } +} + +.shiny-border { + background-color: #5058926b; + border: 2px solid #505892; + transform: scale(1.1) translateY(-10px); + margin-top: 70px; + box-shadow: 0px 0px 100px #9858ff52; + .card-header { + background-color: #505892; + } + + &.middle-card { + margin-top: 50px; + } +} + +.input-group { + margin: 20px auto; +} + +.donation-confirmed { + h2 { + margin-top: 50px; + span { + display: block; + &:last-child { + color: #9858ff; + font-weight: bold; + font-size: 2rem; + } + } + } + + .order-details { + margin-top: 50px; + span { + color: #d81b60; + margin-left: 10px; + } + } +} + +.card-body { + align-items: center; + display: flex; + justify-content: center; + flex-direction: column; + height: 100%; +} + +.wrapper { + text-align: center; + width: 100%; +} + +.input-dark { + background-color: var(--bg); + border-color: var(--active-bg); + color: white; +} diff --git a/frontend/src/app/components/bitcoin-invoice/bitcoin-invoice.component.ts b/frontend/src/app/components/bitcoin-invoice/bitcoin-invoice.component.ts new file mode 100644 index 0000000000..79584b3d83 --- /dev/null +++ b/frontend/src/app/components/bitcoin-invoice/bitcoin-invoice.component.ts @@ -0,0 +1,93 @@ +import { Component, EventEmitter, Input, OnChanges, OnDestroy, OnInit, Output, SimpleChanges } from '@angular/core'; +import { FormBuilder, FormGroup } from '@angular/forms'; +import { DomSanitizer, SafeUrl } from '@angular/platform-browser'; +import { ActivatedRoute } from '@angular/router'; +import { Subscription, of, timer } from 'rxjs'; +import { retry, switchMap, tap } from 'rxjs/operators'; +import { ServicesApiServices } from '../../services/services-api.service'; + +@Component({ + selector: 'app-bitcoin-invoice', + templateUrl: './bitcoin-invoice.component.html', + styleUrls: ['./bitcoin-invoice.component.scss'] +}) +export class BitcoinInvoiceComponent implements OnInit, OnChanges, OnDestroy { + @Input() invoice; + @Input() redirect = true; + @Input() minimal = false; + @Output() completed = new EventEmitter(); + + paymentForm: FormGroup; + requestSubscription: Subscription | undefined; + paymentStatusSubscription: Subscription | undefined; + paymentStatus = 1; // 1 - Waiting for invoice | 2 - Pending payment | 3 - Payment completed + paramMapSubscription: Subscription | undefined; + invoiceSubscription: Subscription | undefined; + invoiceTimeout; // Wait for angular to load all the things before making a request + + constructor( + private formBuilder: FormBuilder, + private apiService: ServicesApiServices, + private sanitizer: DomSanitizer, + private activatedRoute: ActivatedRoute + ) { } + + ngOnDestroy() { + if (this.requestSubscription) { + this.requestSubscription.unsubscribe(); + } + if (this.paramMapSubscription) { + this.paramMapSubscription.unsubscribe(); + } + if (this.invoiceSubscription) { + this.invoiceSubscription.unsubscribe(); + } + if (this.paymentStatusSubscription) { + this.paymentStatusSubscription.unsubscribe(); + } + } + + ngOnInit(): void { + this.paymentForm = this.formBuilder.group({ + 'method': 'lightning' + }); + } + + ngOnChanges(changes: SimpleChanges): void { + if (changes.invoice) { + this.watchInvoice(); + } + } + + watchInvoice(): void { + if (this.paymentStatusSubscription) { + this.paymentStatusSubscription.unsubscribe(); + } + if (!this.invoice) { + this.paymentStatus = 1; + return; + } + if (this.invoice.btcDue > 0) { + this.paymentStatus = 2; + } else { + this.paymentStatus = 4; + } + this.paymentStatusSubscription = this.apiService.getPaymentStatus$(this.invoice.btcpayInvoiceId).pipe( + retry({ delay: () => timer(2000)}) + ).subscribe((response) => { + if (response.status === 204 || response.status === 404) { + return; + } + this.paymentStatus = 3; + this.completed.emit(); + }); + } + + get availableMethods(): string[] { + return Object.keys(this.invoice?.addresses || {}).filter(k => k === 'BTC_LightningLike'); + } + + bypassSecurityTrustUrl(text: string): SafeUrl { + return this.sanitizer.bypassSecurityTrustUrl(text); + } +} diff --git a/frontend/src/app/components/block-fee-rates-graph/block-fee-rates-graph.component.html b/frontend/src/app/components/block-fee-rates-graph/block-fee-rates-graph.component.html new file mode 100644 index 0000000000..e9de40559f --- /dev/null +++ b/frontend/src/app/components/block-fee-rates-graph/block-fee-rates-graph.component.html @@ -0,0 +1,89 @@ + + +
+
+
+ Block Fee Rates + +
+ +
+
+ + + + + + + + + + +
+
+
+ +
+
+
+
Avg Block Fee (24h)
+

+ +

+
+
+
Avg Block Fee (1m)
+

+ +

+
+
+
+ +
+
+
+
+
+ +
+ + +
+
Avg Block Fee (24h)
+

+ +

+
+
+ +
+
Avg Block Fee (1m)
+

+ +

+
+
\ No newline at end of file diff --git a/frontend/src/app/components/block-fee-rates-graph/block-fee-rates-graph.component.scss b/frontend/src/app/components/block-fee-rates-graph/block-fee-rates-graph.component.scss new file mode 100644 index 0000000000..e2883e8b38 --- /dev/null +++ b/frontend/src/app/components/block-fee-rates-graph/block-fee-rates-graph.component.scss @@ -0,0 +1,141 @@ +.card-header { + border-bottom: 0; + font-size: 18px; + @media (min-width: 465px) { + font-size: 20px; + } + @media (min-width: 992px) { + height: 40px; + } +} + +.main-title { + position: relative; + color: var(--fg); + opacity: var(--opacity); + margin-top: -13px; + font-size: 10px; + text-transform: uppercase; + font-weight: 500; + text-align: center; + padding-bottom: 3px; +} + +.full-container { + display: flex; + flex-direction: column; + padding: 0px 15px; + width: 100%; + height: calc(100vh - 225px); + min-height: 400px; + @media (min-width: 992px) { + height: calc(100vh - 150px); + } +} + +.chart { + display: flex; + flex: 1; + height: 100%; + padding-bottom: 20px; + padding-right: 10px; + @media (max-width: 992px) { + padding-bottom: 25px; + } + @media (max-width: 829px) { + padding-bottom: 50px; + } + @media (max-width: 767px) { + padding-bottom: 25px; + } + @media (max-width: 629px) { + padding-bottom: 55px; + } + @media (max-width: 567px) { + padding-bottom: 55px; + } +} +.chart-widget { + width: 100%; + height: 100%; + max-height: 238px; +} + +.block-fee-rates { + min-height: 56px; + display: block; + @media (min-width: 485px) { + display: flex; + flex-direction: row; + } + h5 { + margin-bottom: 10px; + } + .item { + width: 50%; + display: inline-block; + margin: 0px auto 20px; + &:nth-child(2) { + order: 2; + @media (min-width: 485px) { + order: 3; + } + } + &:nth-child(3) { + order: 3; + @media (min-width: 485px) { + order: 2; + display: block; + } + @media (min-width: 768px) { + display: none; + } + @media (min-width: 992px) { + display: block; + } + } + .card-title { + font-size: 1rem; + color: var(--title-fg); + } + .card-text { + font-size: 18px; + span { + color: var(--transparent-fg); + font-size: 12px; + } + } + } +} + +.formRadioGroup { + margin-top: 6px; + display: flex; + flex-direction: column; + @media (min-width: 991px) { + position: relative; + top: -100px; + } + @media (min-width: 830px) and (max-width: 991px) { + position: relative; + top: 0px; + } + @media (min-width: 830px) { + flex-direction: row; + float: right; + margin-top: 0px; + } + .btn-sm { + font-size: 9px; + @media (min-width: 830px) { + font-size: 14px; + } + } +} + +.skeleton-loader { + width: 100%; + display: block; + max-width: 80px; + margin: 15px auto 3px; +} diff --git a/frontend/src/app/components/block-fee-rates-graph/block-fee-rates-graph.component.ts b/frontend/src/app/components/block-fee-rates-graph/block-fee-rates-graph.component.ts new file mode 100644 index 0000000000..ba3489e173 --- /dev/null +++ b/frontend/src/app/components/block-fee-rates-graph/block-fee-rates-graph.component.ts @@ -0,0 +1,390 @@ +import { ChangeDetectionStrategy, ChangeDetectorRef, Component, Inject, Input, LOCALE_ID, NgZone, OnInit } from '@angular/core'; +import { echarts, EChartsOption } from '../../graphs/echarts'; +import { Observable, combineLatest, of } from 'rxjs'; +import { map, share, startWith, switchMap, tap } from 'rxjs/operators'; +import { ApiService } from '../../services/api.service'; +import { SeoService } from '../../services/seo.service'; +import { formatNumber } from '@angular/common'; +import { UntypedFormBuilder, UntypedFormGroup } from '@angular/forms'; +import { download, formatterXAxis, formatterXAxisLabel, formatterXAxisTimeCategory } from '../../shared/graphs.utils'; +import { StorageService } from '../../services/storage.service'; +import { MiningService } from '../../services/mining.service'; +import { selectPowerOfTen } from '../../bitcoin.utils'; +import { RelativeUrlPipe } from '../../shared/pipes/relative-url/relative-url.pipe'; +import { StateService } from '../../services/state.service'; +import { ActivatedRoute, Router } from '@angular/router'; + +@Component({ + selector: 'app-block-fee-rates-graph', + templateUrl: './block-fee-rates-graph.component.html', + styleUrls: ['./block-fee-rates-graph.component.scss'], + styles: [` + .loadingGraphs { + position: absolute; + top: 50%; + left: calc(50% - 15px); + z-index: 100; + } + `], + changeDetection: ChangeDetectionStrategy.OnPush, +}) +export class BlockFeeRatesGraphComponent implements OnInit { + @Input() widget = false; + @Input() right: number | string = 45; + @Input() left: number | string = 75; + + miningWindowPreference: string; + radioGroupForm: UntypedFormGroup; + + chartOptions: EChartsOption = {}; + chartInitOptions = { + renderer: 'svg', + }; + + hrStatsObservable$: Observable; + statsObservable$: Observable; + isLoading = true; + formatNumber = formatNumber; + timespan = ''; + chartInstance: any = undefined; + + constructor( + @Inject(LOCALE_ID) public locale: string, + private seoService: SeoService, + private apiService: ApiService, + private formBuilder: UntypedFormBuilder, + private storageService: StorageService, + private miningService: MiningService, + public stateService: StateService, + private router: Router, + private zone: NgZone, + private route: ActivatedRoute, + private cd: ChangeDetectorRef, + ) { + this.radioGroupForm = this.formBuilder.group({ dateSpan: '1y' }); + this.radioGroupForm.controls.dateSpan.setValue('1y'); + } + + ngOnInit(): void { + if (this.widget) { + this.miningWindowPreference = '1m'; + } else { + this.seoService.setTitle($localize`:@@ed8e33059967f554ff06b4f5b6049c465b92d9b3:Block Fee Rates`); + this.seoService.setDescription($localize`:@@meta.description.bitcoin.graphs.block-fee-rates:See Bitcoin feerates visualized over time, including minimum and maximum feerates per block along with feerates at various percentiles.`); + this.miningWindowPreference = this.miningService.getDefaultTimespan('24h'); + } + this.radioGroupForm = this.formBuilder.group({ dateSpan: this.miningWindowPreference }); + this.radioGroupForm.controls.dateSpan.setValue(this.miningWindowPreference); + + if (!this.widget) { + this.route + .fragment + .subscribe((fragment) => { + if (['24h', '3d', '1w', '1m', '3m', '6m', '1y', '2y', '3y', 'all'].indexOf(fragment) > -1) { + this.radioGroupForm.controls.dateSpan.setValue(fragment, { emitEvent: false }); + } + }); + } + + this.hrStatsObservable$ = combineLatest([ + this.apiService.getHistoricalBlockFeeRates$('24h'), + this.stateService.rateUnits$ + ]).pipe( + map(([response, rateUnits]) => { + return { + blockCount: parseInt(response.headers.get('x-total-count'), 10), + avgMedianRate: response.body.length ? response.body.reduce((acc, rate) => acc + rate.avgFee_50, 0) / response.body.length : 0, + }; + }), + share(), + ); + + this.statsObservable$ = combineLatest([ + this.widget ? of(this.miningWindowPreference) : this.radioGroupForm.get('dateSpan').valueChanges.pipe(startWith(this.radioGroupForm.controls.dateSpan.value)), + this.stateService.rateUnits$ + ]).pipe( + switchMap(([timespan, rateUnits]) => { + if (!this.widget) { + this.storageService.setValue('miningWindowPreference', timespan); + } + this.timespan = timespan; + this.isLoading = true; + return this.apiService.getHistoricalBlockFeeRates$(timespan) + .pipe( + tap((response) => { + // Group by percentile + const seriesData = this.widget ? { 'Median': [] } : { + 'Min': [], + '10th': [], + '25th': [], + 'Median': [], + '75th': [], + '90th': [], + 'Max': [] + }; + for (const rate of response.body) { + const timestamp = rate.timestamp * 1000; + if (this.widget) { + seriesData['Median'].push([timestamp, rate.avgFee_50, rate.avgHeight]); + } else { + seriesData['Min'].push([timestamp, rate.avgFee_0, rate.avgHeight]); + seriesData['10th'].push([timestamp, rate.avgFee_10, rate.avgHeight]); + seriesData['25th'].push([timestamp, rate.avgFee_25, rate.avgHeight]); + seriesData['Median'].push([timestamp, rate.avgFee_50, rate.avgHeight]); + seriesData['75th'].push([timestamp, rate.avgFee_75, rate.avgHeight]); + seriesData['90th'].push([timestamp, rate.avgFee_90, rate.avgHeight]); + seriesData['Max'].push([timestamp, rate.avgFee_100, rate.avgHeight]); + } + } + + // Prepare chart + const series = []; + const legends = []; + for (const percentile in seriesData) { + series.push({ + zlevel: 0, + stack: 'Total', + name: percentile, + data: seriesData[percentile], + type: 'bar', + barWidth: '100%', + large: true, + }); + + legends.push({ + name: percentile, + inactiveColor: 'rgb(110, 112, 121)', + textStyle: { + color: 'white', + }, + icon: 'roundRect', + enabled: false, + selected: false, + }); + } + + if (this.widget) { + let maResolution = 30; + const medianMa = []; + for (let i = maResolution - 1; i < seriesData['Median'].length; ++i) { + let avg = 0; + for (let y = maResolution - 1; y >= 0; --y) { + avg += seriesData['Median'][i - y][1]; + } + avg /= maResolution; + medianMa.push([seriesData['Median'][i][0], avg, seriesData['Median'][i][2]]); + } + series.push({ + zlevel: 1, + name: 'Moving average', + data: medianMa, + type: 'line', + showSymbol: false, + symbol: 'none', + lineStyle: { + width: 3, + } + }); + } + + this.prepareChartOptions({ + legends: legends, + series: series + }, rateUnits === 'wu'); + + this.isLoading = false; + this.cd.markForCheck(); + }), + map((response) => { + return { + blockCount: parseInt(response.headers.get('x-total-count'), 10), + avgMedianRate: response.body.length ? response.body.reduce((acc, rate) => acc + rate.avgFee_50, 0) / response.body.length : 0, + }; + }), + ); + }), + share() + ); + } + + prepareChartOptions(data, weightMode) { + this.chartOptions = { + color: this.widget ? ['#6b6b6b', new echarts.graphic.LinearGradient(0, 0, 0, 0.65, [ + { offset: 0, color: '#F4511E' }, + { offset: 0.25, color: '#FB8C00' }, + { offset: 0.5, color: '#FFB300' }, + { offset: 0.75, color: '#FDD835' }, + { offset: 1, color: '#7CB342' } + ])] : ['#D81B60', '#8E24AA', '#1E88E5', '#7CB342', '#FDD835', '#6D4C41', '#546E7A'], + animation: false, + grid: { + right: this.right, + left: this.left, + bottom: this.widget ? 30 : 80, + top: this.widget ? 20 : (this.isMobile() ? 10 : 50), + }, + tooltip: { + show: !this.isMobile(), + trigger: 'axis', + axisPointer: { + type: 'line' + }, + backgroundColor: 'rgba(17, 19, 31, 1)', + borderRadius: 4, + shadowColor: 'rgba(0, 0, 0, 0.5)', + textStyle: { + color: 'var(--tooltip-grey)', + align: 'left', + }, + borderColor: '#000', + formatter: function(data) { + if (data.length <= 0) { + return ''; + } + let tooltip = `${formatterXAxis(this.locale, this.timespan, parseInt(data[0].axisValue, 10))}
`; + + for (const rate of data.reverse()) { + if (weightMode) { + tooltip += `${rate.marker} ${rate.seriesName}: ${(rate.data[1] / 4).toFixed(2)} sats/WU
`; + } else { + tooltip += `${rate.marker} ${rate.seriesName}: ${rate.data[1].toFixed(2)} sats/vByte
`; + } + } + + if (['24h', '3d'].includes(this.timespan)) { + tooltip += `` + $localize`At block: ${data[0].data[2]}` + ``; + } else { + tooltip += `` + $localize`Around block: ${data[0].data[2]}` + ``; + } + + return tooltip; + }.bind(this) + }, + xAxis: data.series.length === 0 ? undefined : + { + name: this.widget ? undefined : formatterXAxisLabel(this.locale, this.timespan), + nameLocation: 'middle', + nameTextStyle: { + padding: [10, 0, 0, 0], + }, + type: 'category', + boundaryGap: false, + axisLine: { onZero: true }, + axisLabel: { + formatter: val => formatterXAxisTimeCategory(this.locale, this.timespan, parseInt(val, 10)), + align: 'center', + fontSize: 11, + lineHeight: 12, + hideOverlap: true, + padding: [0, 5], + }, + }, + legend: (this.widget || data.series.length === 0) ? undefined : { + padding: [10, 75], + data: data.legends, + selected: JSON.parse(this.storageService.getValue('fee_rates_legend') || 'null') ?? { + 'Min': true, + '10th': true, + '25th': true, + 'Median': true, + '75th': true, + '90th': true, + 'Max': false, + }, + id: 4242, + }, + yAxis: data.series.length === 0 ? undefined : { + position: 'left', + axisLabel: { + color: 'rgb(110, 112, 121)', + formatter: (val) => { + if (weightMode) { + val /= 4; + } + const selectedPowerOfTen: any = selectPowerOfTen(val); + const newVal = Math.round(val / selectedPowerOfTen.divider); + return `${newVal}${selectedPowerOfTen.unit} s/${weightMode ? 'WU': 'vB'}`; + }, + }, + splitLine: { + lineStyle: { + type: 'dotted', + color: 'var(--transparent-fg)', + opacity: 0.25, + } + }, + type: 'value', + max: (val) => this.timespan === 'all' ? Math.min(val.max, 5000) : undefined, + }, + series: data.series, + dataZoom: this.widget ? null : [{ + type: 'inside', + realtime: true, + zoomLock: true, + maxSpan: 100, + minSpan: 5, + moveOnMouseMove: false, + }, { + showDetail: false, + show: true, + type: 'slider', + brushSelect: false, + realtime: true, + left: 20, + right: 15, + selectedDataBackground: { + lineStyle: { + color: '#fff', + opacity: 0.45, + }, + areaStyle: { + opacity: 0, + } + }, + }], + }; + } + + onChartInit(ec) { + if (this.chartInstance !== undefined) { + return; + } + + this.chartInstance = ec; + + this.chartInstance.on('click', (e) => { + this.zone.run(() => { + if (['24h', '3d'].includes(this.timespan)) { + const url = new RelativeUrlPipe(this.stateService).transform(`/block/${e.data[2]}`); + this.router.navigate([url]); + } + }); + }); + + this.chartInstance.on('legendselectchanged', (e) => { + this.storageService.setValue('fee_rates_legend', JSON.stringify(e.selected)); + }); + } + + isMobile() { + return (window.innerWidth <= 767.98); + } + + onSaveChart() { + // @ts-ignore + const prevBottom = this.chartOptions.grid.bottom; + const now = new Date(); + // @ts-ignore + this.chartOptions.grid.bottom = 40; + this.chartOptions.backgroundColor = 'var(--active-bg)'; + this.chartInstance.setOption(this.chartOptions); + download(this.chartInstance.getDataURL({ + pixelRatio: 2, + excludeComponents: ['dataZoom'], + }), `block-fee-rates-${this.timespan}-${Math.round(now.getTime() / 1000)}.svg`); + // @ts-ignore + this.chartOptions.grid.bottom = prevBottom; + this.chartOptions.backgroundColor = 'none'; + this.chartInstance.setOption(this.chartOptions); + } +} diff --git a/frontend/src/app/components/block-fees-graph/block-fees-graph.component.html b/frontend/src/app/components/block-fees-graph/block-fees-graph.component.html new file mode 100644 index 0000000000..0328e7eb12 --- /dev/null +++ b/frontend/src/app/components/block-fees-graph/block-fees-graph.component.html @@ -0,0 +1,46 @@ + + +
+
+
+ Block Fees + +
+ +
+
+ + + + + + + +
+
+
+ +
+
+
+
+
+ +
diff --git a/frontend/src/app/components/block-fees-graph/block-fees-graph.component.scss b/frontend/src/app/components/block-fees-graph/block-fees-graph.component.scss new file mode 100644 index 0000000000..b095994255 --- /dev/null +++ b/frontend/src/app/components/block-fees-graph/block-fees-graph.component.scss @@ -0,0 +1,62 @@ +.card-header { + border-bottom: 0; + font-size: 18px; + @media (min-width: 465px) { + font-size: 20px; + } + @media (min-width: 992px) { + height: 40px; + } +} + +.main-title { + position: relative; + color: var(--fg); + opacity: var(--opacity); + margin-top: -13px; + font-size: 10px; + text-transform: uppercase; + font-weight: 500; + text-align: center; + padding-bottom: 3px; +} + +.full-container { + display: flex; + flex-direction: column; + padding: 0px 15px; + width: 100%; + height: calc(100vh - 225px); + min-height: 400px; + @media (min-width: 992px) { + height: calc(100vh - 150px); + } +} + +.chart { + display: flex; + flex: 1; + width: 100%; + padding-bottom: 20px; + padding-right: 10px; + @media (max-width: 992px) { + padding-bottom: 25px; + } + @media (max-width: 829px) { + padding-bottom: 50px; + } + @media (max-width: 767px) { + padding-bottom: 25px; + } + @media (max-width: 629px) { + padding-bottom: 55px; + } + @media (max-width: 567px) { + padding-bottom: 55px; + } +} +.chart-widget { + width: 100%; + height: 100%; + max-height: 270px; +} diff --git a/frontend/src/app/components/block-fees-graph/block-fees-graph.component.ts b/frontend/src/app/components/block-fees-graph/block-fees-graph.component.ts new file mode 100644 index 0000000000..eb567c2a65 --- /dev/null +++ b/frontend/src/app/components/block-fees-graph/block-fees-graph.component.ts @@ -0,0 +1,319 @@ +import { ChangeDetectionStrategy, Component, Inject, Input, LOCALE_ID, OnInit } from '@angular/core'; +import { echarts, EChartsOption } from '../../graphs/echarts'; +import { Observable } from 'rxjs'; +import { map, share, startWith, switchMap, tap } from 'rxjs/operators'; +import { ApiService } from '../../services/api.service'; +import { SeoService } from '../../services/seo.service'; +import { formatNumber } from '@angular/common'; +import { UntypedFormBuilder, UntypedFormGroup } from '@angular/forms'; +import { download, formatterXAxis } from '../../shared/graphs.utils'; +import { StorageService } from '../../services/storage.service'; +import { MiningService } from '../../services/mining.service'; +import { ActivatedRoute } from '@angular/router'; +import { FiatShortenerPipe } from '../../shared/pipes/fiat-shortener.pipe'; +import { FiatCurrencyPipe } from '../../shared/pipes/fiat-currency.pipe'; +import { StateService } from '../../services/state.service'; + +@Component({ + selector: 'app-block-fees-graph', + templateUrl: './block-fees-graph.component.html', + styleUrls: ['./block-fees-graph.component.scss'], + styles: [` + .loadingGraphs { + position: absolute; + top: 50%; + left: calc(50% - 15px); + z-index: 100; + } + `], + changeDetection: ChangeDetectionStrategy.OnPush, +}) +export class BlockFeesGraphComponent implements OnInit { + @Input() right: number | string = 45; + @Input() left: number | string = 75; + + miningWindowPreference: string; + radioGroupForm: UntypedFormGroup; + + chartOptions: EChartsOption = {}; + chartInitOptions = { + renderer: 'svg', + }; + + statsObservable$: Observable; + isLoading = true; + formatNumber = formatNumber; + timespan = ''; + chartInstance: any = undefined; + + currency: string; + + constructor( + @Inject(LOCALE_ID) public locale: string, + private seoService: SeoService, + private apiService: ApiService, + private formBuilder: UntypedFormBuilder, + private storageService: StorageService, + private miningService: MiningService, + public stateService: StateService, + private route: ActivatedRoute, + private fiatShortenerPipe: FiatShortenerPipe, + private fiatCurrencyPipe: FiatCurrencyPipe, + ) { + this.radioGroupForm = this.formBuilder.group({ dateSpan: '1y' }); + this.radioGroupForm.controls.dateSpan.setValue('1y'); + this.currency = 'USD'; + } + + ngOnInit(): void { + this.seoService.setTitle($localize`:@@6c453b11fd7bd159ae30bc381f367bc736d86909:Block Fees`); + this.seoService.setDescription($localize`:@@meta.description.bitcoin.graphs.block-fees:See the average mining fees earned per Bitcoin block visualized in BTC and USD over time.`); + this.miningWindowPreference = this.miningService.getDefaultTimespan('1m'); + this.radioGroupForm = this.formBuilder.group({ dateSpan: this.miningWindowPreference }); + this.radioGroupForm.controls.dateSpan.setValue(this.miningWindowPreference); + + this.route + .fragment + .subscribe((fragment) => { + if (['1m', '3m', '6m', '1y', '2y', '3y', 'all'].indexOf(fragment) > -1) { + this.radioGroupForm.controls.dateSpan.setValue(fragment, { emitEvent: false }); + } + }); + + this.statsObservable$ = this.radioGroupForm.get('dateSpan').valueChanges + .pipe( + startWith(this.radioGroupForm.controls.dateSpan.value), + switchMap((timespan) => { + this.isLoading = true; + this.storageService.setValue('miningWindowPreference', timespan); + this.timespan = timespan; + this.isLoading = true; + return this.apiService.getHistoricalBlockFees$(timespan) + .pipe( + tap((response) => { + this.prepareChartOptions({ + blockFees: response.body.map(val => [val.timestamp * 1000, val.avgFees / 100000000, val.avgHeight]), + blockFeesFiat: response.body.filter(val => val[this.currency] > 0).map(val => [val.timestamp * 1000, val.avgFees / 100000000 * val[this.currency], val.avgHeight]), + }); + this.isLoading = false; + }), + map((response) => { + return { + blockCount: parseInt(response.headers.get('x-total-count'), 10), + }; + }), + ); + }), + share() + ); + } + + prepareChartOptions(data) { + let title: object; + if (data.blockFees.length === 0) { + title = { + textStyle: { + color: 'grey', + fontSize: 15 + }, + text: $localize`:@@23555386d8af1ff73f297e89dd4af3f4689fb9dd:Indexing blocks`, + left: 'center', + top: 'center' + }; + } + + this.chartOptions = { + title: title, + color: [ + new echarts.graphic.LinearGradient(0, 0, 0, 1, [ + { offset: 0, color: '#FDD835' }, + { offset: 1, color: '#FB8C00' }, + ]), + new echarts.graphic.LinearGradient(0, 0, 0, 1, [ + { offset: 0, color: '#C0CA33' }, + { offset: 1, color: '#1B5E20' }, + ]), + ], + animation: false, + grid: { + top: 30, + bottom: 80, + right: this.right, + left: this.left, + }, + tooltip: { + show: !this.isMobile(), + trigger: 'axis', + axisPointer: { + type: 'line' + }, + backgroundColor: 'rgba(17, 19, 31, 1)', + borderRadius: 4, + shadowColor: 'rgba(0, 0, 0, 0.5)', + textStyle: { + color: 'var(--tooltip-grey)', + align: 'left', + }, + borderColor: '#000', + formatter: function (data) { + if (data.length <= 0) { + return ''; + } + let tooltip = ` + ${formatterXAxis(this.locale, this.timespan, parseInt(data[0].axisValue, 10))}
`; + + for (const tick of data) { + if (tick.seriesIndex === 0) { + tooltip += `${tick.marker} ${tick.seriesName}: ${formatNumber(tick.data[1], this.locale, '1.3-3')} BTC
`; + } else if (tick.seriesIndex === 1) { + tooltip += `${tick.marker} ${tick.seriesName}: ${this.fiatCurrencyPipe.transform(tick.data[1], null, this.currency) }
`; + } + } + + tooltip += `* On average around block ${data[0].data[2]}`; + return tooltip; + }.bind(this) + }, + xAxis: data.blockFees.length === 0 ? undefined : + { + type: 'time', + splitNumber: this.isMobile() ? 5 : 10, + axisLabel: { + hideOverlap: true, + } + }, + legend: data.blockFees.length === 0 ? undefined : { + data: [ + { + name: 'Fees BTC', + inactiveColor: 'rgb(110, 112, 121)', + textStyle: { + color: 'white', + }, + icon: 'roundRect', + }, + { + name: 'Fees ' + this.currency, + inactiveColor: 'rgb(110, 112, 121)', + textStyle: { + color: 'white', + }, + icon: 'roundRect', + }, + ], + }, + yAxis: data.blockFees.length === 0 ? undefined : [ + { + type: 'value', + axisLabel: { + color: 'rgb(110, 112, 121)', + formatter: (val) => { + return `${val} BTC`; + } + }, + splitLine: { + lineStyle: { + type: 'dotted', + color: 'var(--transparent-fg)', + opacity: 0.25, + } + }, + }, + { + type: 'value', + position: 'right', + axisLabel: { + color: 'rgb(110, 112, 121)', + formatter: function(val) { + return this.fiatShortenerPipe.transform(val, null, this.currency); + }.bind(this) + }, + splitLine: { + show: false, + }, + }, + ], + series: data.blockFees.length === 0 ? undefined : [ + { + legendHoverLink: false, + zlevel: 0, + yAxisIndex: 0, + name: 'Fees BTC', + data: data.blockFees, + type: 'line', + smooth: 0.25, + symbol: 'none', + lineStyle: { + width: 1, + opacity: 1, + } + }, + { + legendHoverLink: false, + zlevel: 1, + yAxisIndex: 1, + name: 'Fees ' + this.currency, + data: data.blockFeesFiat, + type: 'line', + smooth: 0.25, + symbol: 'none', + lineStyle: { + width: 2, + opacity: 1, + } + }, + ], + dataZoom: data.blockFees.length === 0 ? undefined : [{ + type: 'inside', + realtime: true, + zoomLock: true, + maxSpan: 100, + minSpan: 5, + moveOnMouseMove: false, + }, { + showDetail: false, + show: true, + type: 'slider', + brushSelect: false, + realtime: true, + left: 20, + right: 15, + selectedDataBackground: { + lineStyle: { + color: '#fff', + opacity: 0.45, + }, + areaStyle: { + opacity: 0, + } + }, + }], + }; + } + + onChartInit(ec) { + this.chartInstance = ec; + } + + isMobile() { + return (window.innerWidth <= 767.98); + } + + onSaveChart() { + // @ts-ignore + const prevBottom = this.chartOptions.grid.bottom; + const now = new Date(); + // @ts-ignore + this.chartOptions.grid.bottom = 40; + this.chartOptions.backgroundColor = 'var(--active-bg)'; + this.chartInstance.setOption(this.chartOptions); + download(this.chartInstance.getDataURL({ + pixelRatio: 2, + excludeComponents: ['dataZoom'], + }), `block-fees-${this.timespan}-${Math.round(now.getTime() / 1000)}.svg`); + // @ts-ignore + this.chartOptions.grid.bottom = prevBottom; + this.chartOptions.backgroundColor = 'none'; + this.chartInstance.setOption(this.chartOptions); + } +} diff --git a/frontend/src/app/components/block-fees-subsidy-graph/block-fees-subsidy-graph.component.html b/frontend/src/app/components/block-fees-subsidy-graph/block-fees-subsidy-graph.component.html new file mode 100644 index 0000000000..341b166409 --- /dev/null +++ b/frontend/src/app/components/block-fees-subsidy-graph/block-fees-subsidy-graph.component.html @@ -0,0 +1,55 @@ + + +
+
+
+ Block Fees Vs Subsidy + +
+ +
+
+ + + + + + + + + + +
+
+
+ +
+
+
+
+
+ +
diff --git a/frontend/src/app/components/block-fees-subsidy-graph/block-fees-subsidy-graph.component.scss b/frontend/src/app/components/block-fees-subsidy-graph/block-fees-subsidy-graph.component.scss new file mode 100644 index 0000000000..f0a89b37bf --- /dev/null +++ b/frontend/src/app/components/block-fees-subsidy-graph/block-fees-subsidy-graph.component.scss @@ -0,0 +1,61 @@ +.card-header { + border-bottom: 0; + font-size: 18px; + @media (min-width: 465px) { + font-size: 20px; + } + @media (min-width: 992px) { + height: 40px; + } +} + +.main-title { + position: relative; + color: #ffffff91; + margin-top: -13px; + font-size: 10px; + text-transform: uppercase; + font-weight: 500; + text-align: center; + padding-bottom: 3px; +} + +.full-container { + display: flex; + flex-direction: column; + padding: 0px 15px; + width: 100%; + height: calc(100vh - 225px); + min-height: 400px; + @media (min-width: 992px) { + height: calc(100vh - 150px); + } +} + +.chart { + display: flex; + flex: 1; + width: 100%; + padding-bottom: 20px; + padding-right: 10px; + @media (max-width: 992px) { + padding-bottom: 25px; + } + @media (max-width: 829px) { + padding-bottom: 50px; + } + @media (max-width: 767px) { + padding-bottom: 25px; + } + @media (max-width: 629px) { + padding-bottom: 55px; + } + @media (max-width: 567px) { + padding-bottom: 55px; + } +} +.chart-widget { + width: 100%; + height: 100%; + max-height: 270px; +} diff --git a/frontend/src/app/components/block-fees-subsidy-graph/block-fees-subsidy-graph.component.ts b/frontend/src/app/components/block-fees-subsidy-graph/block-fees-subsidy-graph.component.ts new file mode 100644 index 0000000000..18e57ada82 --- /dev/null +++ b/frontend/src/app/components/block-fees-subsidy-graph/block-fees-subsidy-graph.component.ts @@ -0,0 +1,573 @@ +import { ChangeDetectionStrategy, ChangeDetectorRef, Component, HostListener, Inject, Input, LOCALE_ID, NgZone, OnInit } from '@angular/core'; +import { EChartsOption } from '../../graphs/echarts'; +import { Observable } from 'rxjs'; +import { catchError, map, share, startWith, switchMap, tap } from 'rxjs/operators'; +import { ApiService } from '../../services/api.service'; +import { SeoService } from '../../services/seo.service'; +import { formatNumber } from '@angular/common'; +import { UntypedFormBuilder, UntypedFormGroup } from '@angular/forms'; +import { download, formatterXAxis } from '../../shared/graphs.utils'; +import { ActivatedRoute, Router } from '@angular/router'; +import { FiatShortenerPipe } from '../../shared/pipes/fiat-shortener.pipe'; +import { FiatCurrencyPipe } from '../../shared/pipes/fiat-currency.pipe'; +import { StateService } from '../../services/state.service'; +import { MiningService } from '../../services/mining.service'; +import { StorageService } from '../../services/storage.service'; +import { RelativeUrlPipe } from '../../shared/pipes/relative-url/relative-url.pipe'; + +@Component({ + selector: 'app-block-fees-subsidy-graph', + templateUrl: './block-fees-subsidy-graph.component.html', + styleUrls: ['./block-fees-subsidy-graph.component.scss'], + styles: [` + .loadingGraphs { + position: absolute; + top: 50%; + left: calc(50% - 15px); + z-index: 100; + } + `], + changeDetection: ChangeDetectionStrategy.OnPush, +}) +export class BlockFeesSubsidyGraphComponent implements OnInit { + @Input() right: number | string = 45; + @Input() left: number | string = 75; + + miningWindowPreference: string; + radioGroupForm: UntypedFormGroup; + + chartOptions: EChartsOption = {}; + chartInitOptions = { + renderer: 'svg', + }; + + statsObservable$: Observable; + data: any; + subsidies: { [key: number]: number } = {}; + isLoading = true; + formatNumber = formatNumber; + timespan = ''; + chartInstance: any = undefined; + displayMode: 'normal' | 'fiat' | 'percentage' = 'normal'; + updateZoom = false; + zoomSpan = 100; + zoomTimeSpan = ''; + + constructor( + @Inject(LOCALE_ID) public locale: string, + private seoService: SeoService, + private apiService: ApiService, + private formBuilder: UntypedFormBuilder, + public stateService: StateService, + private storageService: StorageService, + private miningService: MiningService, + private route: ActivatedRoute, + private router: Router, + private zone: NgZone, + private fiatShortenerPipe: FiatShortenerPipe, + private fiatCurrencyPipe: FiatCurrencyPipe, + private cd: ChangeDetectorRef, + ) { + this.radioGroupForm = this.formBuilder.group({ dateSpan: '1y' }); + this.radioGroupForm.controls.dateSpan.setValue('1y'); + + this.subsidies = this.initSubsidies(); + } + + ngOnInit(): void { + this.seoService.setTitle($localize`:@@41545303ec98792b738d6237adbd1f3b54a22196:Block Fees Vs Subsidy`); + this.seoService.setDescription($localize`:@@meta.description.bitcoin.graphs.block-fees-subsidy:See the mining fees earned per Bitcoin block compared to the Bitcoin block subsidy, visualized in BTC and USD over time.`); + + this.miningWindowPreference = this.miningService.getDefaultTimespan('24h'); + this.radioGroupForm = this.formBuilder.group({ dateSpan: this.miningWindowPreference }); + this.radioGroupForm.controls.dateSpan.setValue(this.miningWindowPreference); + + this.route + .fragment + .subscribe((fragment) => { + if (['24h', '3d', '1w', '1m', '3m', '6m', '1y', '2y', '3y', 'all'].indexOf(fragment) > -1) { + this.radioGroupForm.controls.dateSpan.setValue(fragment, { emitEvent: false }); + } + }); + + this.statsObservable$ = this.radioGroupForm.get('dateSpan').valueChanges + .pipe( + startWith(this.radioGroupForm.controls.dateSpan.value), + switchMap((timespan) => { + this.isLoading = true; + this.storageService.setValue('miningWindowPreference', timespan); + this.timespan = timespan; + this.zoomTimeSpan = timespan; + return this.apiService.getHistoricalBlockFees$(timespan) + .pipe( + tap((response) => { + this.data = { + timestamp: response.body.map(val => val.timestamp * 1000), + blockHeight: response.body.map(val => val.avgHeight), + blockFees: response.body.map(val => val.avgFees / 100_000_000), + blockFeesFiat: response.body.filter(val => val['USD'] > 0).map(val => val.avgFees / 100_000_000 * val['USD']), + blockFeesPercent: response.body.map(val => val.avgFees / (val.avgFees + this.subsidyAt(val.avgHeight)) * 100), + blockSubsidy: response.body.map(val => this.subsidyAt(val.avgHeight) / 100_000_000), + blockSubsidyFiat: response.body.filter(val => val['USD'] > 0).map(val => this.subsidyAt(val.avgHeight) / 100_000_000 * val['USD']), + blockSubsidyPercent: response.body.map(val => this.subsidyAt(val.avgHeight) / (val.avgFees + this.subsidyAt(val.avgHeight)) * 100), + }; + + this.prepareChartOptions(); + this.isLoading = false; + }), + map((response) => { + return { + blockCount: parseInt(response.headers.get('x-total-count'), 10), + }; + }), + ); + }), + share() + ); + } + + prepareChartOptions() { + let title: object; + if (this.data.blockFees.length === 0) { + title = { + textStyle: { + color: 'grey', + fontSize: 15 + }, + text: $localize`:@@23555386d8af1ff73f297e89dd4af3f4689fb9dd:Indexing blocks`, + left: 'center', + top: 'center' + }; + } + + this.chartOptions = { + title: title, + color: [ + '#ff9f00', + '#0aab2f', + ], + animation: false, + grid: { + top: 80, + bottom: 80, + right: this.right, + left: this.left, + }, + tooltip: { + show: !this.isMobile(), + trigger: 'axis', + axisPointer: { + type: 'line' + }, + backgroundColor: 'rgba(17, 19, 31, 1)', + borderRadius: 4, + shadowColor: 'rgba(0, 0, 0, 0.5)', + textStyle: { + color: 'var(--tooltip-grey)', + align: 'left', + }, + borderColor: 'var(--active-bg)', + formatter: function (data) { + if (data.length <= 0) { + return ''; + } + let tooltip = `${formatterXAxis(this.locale, this.zoomTimeSpan, parseInt(this.data.timestamp[data[0].dataIndex], 10))}
`; + for (let i = data.length - 1; i >= 0; i--) { + const tick = data[i]; + tooltip += `${tick.marker} ${tick.seriesName.split(' ')[0]}: `; + if (this.displayMode === 'normal') tooltip += `${formatNumber(tick.data, this.locale, '1.0-3')} BTC
`; + else if (this.displayMode === 'fiat') tooltip += `${this.fiatCurrencyPipe.transform(tick.data, null, 'USD') }
`; + else tooltip += `${formatNumber(tick.data, this.locale, '1.0-2')}%
`; + } + if (this.displayMode === 'normal') tooltip += `
${formatNumber(data.reduce((acc, val) => acc + val.data, 0), this.locale, '1.0-3')} BTC
`; + else if (this.displayMode === 'fiat') tooltip += `
${this.fiatCurrencyPipe.transform(data.reduce((acc, val) => acc + val.data, 0), null, 'USD')}
`; + if (['24h', '3d'].includes(this.zoomTimeSpan)) { + tooltip += `` + $localize`At block ${'' + data[0].axisValue}` + ``; + } else { + tooltip += `` + $localize`Around block ${'' + data[0].axisValue}` + ``; + } + return tooltip; + }.bind(this) + }, + xAxis: this.data.blockFees.length === 0 ? undefined : [ + { + type: 'category', + data: this.data.blockHeight, + show: false, + axisLabel: { + hideOverlap: true, + } + }, + { + type: 'category', + data: this.data.timestamp, + show: true, + position: 'bottom', + axisLabel: { + color: 'var(--grey)', + formatter: (val) => { + return formatterXAxis(this.locale, this.timespan, parseInt(val, 10)); + } + }, + axisTick: { + show: false, + }, + axisLine: { + show: false, + }, + splitLine: { + show: false, + }, + } + ], + legend: this.data.blockFees.length === 0 ? undefined : { + data: [ + { + name: 'Subsidy', + inactiveColor: 'var(--grey)', + textStyle: { + color: 'white', + }, + icon: 'roundRect', + }, + { + name: 'Fees', + inactiveColor: 'var(--grey)', + textStyle: { + color: 'white', + }, + icon: 'roundRect', + }, + { + name: 'Subsidy (USD)', + inactiveColor: 'var(--grey)', + textStyle: { + color: 'white', + }, + icon: 'roundRect', + }, + { + name: 'Fees (USD)', + inactiveColor: 'var(--grey)', + textStyle: { + color: 'white', + }, + icon: 'roundRect', + }, + { + name: 'Subsidy (%)', + inactiveColor: 'var(--grey)', + textStyle: { + color: 'white', + }, + icon: 'roundRect', + }, + { + name: 'Fees (%)', + inactiveColor: 'var(--grey)', + textStyle: { + color: 'white', + }, + icon: 'roundRect', + }, + ], + selected: { + 'Subsidy (USD)': this.displayMode === 'fiat', + 'Fees (USD)': this.displayMode === 'fiat', + 'Subsidy': this.displayMode === 'normal', + 'Fees': this.displayMode === 'normal', + 'Subsidy (%)': this.displayMode === 'percentage', + 'Fees (%)': this.displayMode === 'percentage', + }, + }, + yAxis: this.data.blockFees.length === 0 ? undefined : [ + { + type: 'value', + axisLabel: { + color: 'var(--grey)', + formatter: (val) => { + return `${val}${this.displayMode === 'percentage' ? '%' : ' BTC'}`; + } + }, + min: 0, + max: (value) => { + if (this.displayMode === 'percentage') { + return 100; + } + }, + splitLine: { + lineStyle: { + type: 'dotted', + color: 'var(--transparent-fg)', + opacity: 0.25, + } + }, + }, + { + type: 'value', + position: 'right', + axisLabel: { + color: 'var(--grey)', + formatter: function(val) { + return this.fiatShortenerPipe.transform(val, null, 'USD'); + }.bind(this) + }, + splitLine: { + show: false, + }, + }, + ], + series: this.data.blockFees.length === 0 ? undefined : [ + { + name: 'Subsidy', + yAxisIndex: 0, + type: 'bar', + barWidth: '90%', + stack: 'total', + data: this.data.blockSubsidy, + }, + { + name: 'Fees', + yAxisIndex: 0, + type: 'bar', + barWidth: '90%', + stack: 'total', + data: this.data.blockFees, + }, + { + name: 'Subsidy (USD)', + yAxisIndex: 1, + type: 'bar', + barWidth: '90%', + stack: 'total', + data: this.data.blockSubsidyFiat, + }, + { + name: 'Fees (USD)', + yAxisIndex: 1, + type: 'bar', + barWidth: '90%', + stack: 'total', + data: this.data.blockFeesFiat, + }, + { + name: 'Subsidy (%)', + yAxisIndex: 0, + type: 'bar', + barWidth: '90%', + stack: 'total', + data: this.data.blockSubsidyPercent, + }, + { + name: 'Fees (%)', + yAxisIndex: 0, + type: 'bar', + barWidth: '90%', + stack: 'total', + data: this.data.blockFeesPercent, + }, + ], + dataZoom: this.data.blockFees.length === 0 ? undefined : [{ + type: 'inside', + realtime: true, + zoomLock: true, + maxSpan: 100, + minSpan: 1, + moveOnMouseMove: false, + }, { + showDetail: false, + show: true, + type: 'slider', + brushSelect: false, + realtime: true, + left: 20, + right: 15, + selectedDataBackground: { + lineStyle: { + color: '#fff', + opacity: 0.45, + }, + }, + }], + }; + } + + onChartInit(ec) { + this.chartInstance = ec; + + this.chartInstance.on('legendselectchanged', (params) => { + if (this.isLoading) { + return; + } + + let mode: 'normal' | 'fiat' | 'percentage'; + if (params.name.includes('USD')) { + mode = 'fiat'; + } else if (params.name.includes('%')) { + mode = 'percentage'; + } else { + mode = 'normal'; + } + + if (this.displayMode === mode) return; + + const isActivation = params.selected[params.name]; + + if (isActivation) { + this.displayMode = mode; + this.chartInstance.dispatchAction({ type: this.displayMode === 'normal' ? 'legendSelect' : 'legendUnSelect', name: 'Subsidy' }); + this.chartInstance.dispatchAction({ type: this.displayMode === 'normal' ? 'legendSelect' : 'legendUnSelect', name: 'Fees' }); + this.chartInstance.dispatchAction({ type: this.displayMode === 'fiat' ? 'legendSelect' : 'legendUnSelect', name: 'Subsidy (USD)' }); + this.chartInstance.dispatchAction({ type: this.displayMode === 'fiat' ? 'legendSelect' : 'legendUnSelect', name: 'Fees (USD)' }); + this.chartInstance.dispatchAction({ type: this.displayMode === 'percentage' ? 'legendSelect' : 'legendUnSelect', name: 'Subsidy (%)' }); + this.chartInstance.dispatchAction({ type: this.displayMode === 'percentage' ? 'legendSelect' : 'legendUnSelect', name: 'Fees (%)' }); + } + }); + + this.chartInstance.on('datazoom', (params) => { + if (params.silent || this.isLoading || ['24h', '3d'].includes(this.timespan)) { + return; + } + this.updateZoom = true; + }); + + this.chartInstance.on('click', (e) => { + this.zone.run(() => { + if (['24h', '3d'].includes(this.zoomTimeSpan)) { + const url = new RelativeUrlPipe(this.stateService).transform(`/block/${e.name}`); + if (e.event.event.shiftKey || e.event.event.ctrlKey || e.event.event.metaKey) { + window.open(url); + } else { + this.router.navigate([url]); + } + } + }); + }); + } + + @HostListener('document:pointerup', ['$event']) + onPointerUp(event: PointerEvent) { + if (this.updateZoom) { + this.onZoom(); + this.updateZoom = false; + } + } + + isMobile() { + return (window.innerWidth <= 767.98); + } + + initSubsidies(): { [key: number]: number } { + let blockReward = 50 * 100_000_000; + const subsidies = {}; + for (let i = 0; i <= 33; i++) { + subsidies[i] = blockReward; + blockReward = Math.floor(blockReward / 2); + } + return subsidies; + } + + subsidyAt(height: number): number { + return this.subsidies[Math.floor(Math.min(height / 210000, 33))]; + } + + onZoom() { + const option = this.chartInstance.getOption(); + const timestamps = option.xAxis[1].data; + const startTimestamp = timestamps[option.dataZoom[0].startValue]; + const endTimestamp = timestamps[option.dataZoom[0].endValue]; + + this.isLoading = true; + this.cd.detectChanges(); + + const subscription = this.apiService.getBlockFeesFromTimespan$(Math.floor(startTimestamp / 1000), Math.floor(endTimestamp / 1000)) + .pipe( + tap((response) => { + const startIndex = option.dataZoom[0].startValue; + const endIndex = option.dataZoom[0].endValue; + + // Update series with more granular data + const lengthBefore = this.data.timestamp.length; + this.data.timestamp.splice(startIndex, endIndex - startIndex, ...response.body.map(val => val.timestamp * 1000)); + this.data.blockHeight.splice(startIndex, endIndex - startIndex, ...response.body.map(val => val.avgHeight)); + this.data.blockFees.splice(startIndex, endIndex - startIndex, ...response.body.map(val => val.avgFees / 100_000_000)); + this.data.blockFeesFiat.splice(startIndex, endIndex - startIndex, ...response.body.filter(val => val['USD'] > 0).map(val => val.avgFees / 100_000_000 * val['USD'])); + this.data.blockFeesPercent.splice(startIndex, endIndex - startIndex, ...response.body.map(val => val.avgFees / (val.avgFees + this.subsidyAt(val.avgHeight)) * 100)); + this.data.blockSubsidy.splice(startIndex, endIndex - startIndex, ...response.body.map(val => this.subsidyAt(val.avgHeight) / 100_000_000)); + this.data.blockSubsidyFiat.splice(startIndex, endIndex - startIndex, ...response.body.filter(val => val['USD'] > 0).map(val => this.subsidyAt(val.avgHeight) / 100_000_000 * val['USD'])); + this.data.blockSubsidyPercent.splice(startIndex, endIndex - startIndex, ...response.body.map(val => this.subsidyAt(val.avgHeight) / (val.avgFees + this.subsidyAt(val.avgHeight)) * 100)); + option.series[0].data = this.data.blockSubsidy; + option.series[1].data = this.data.blockFees; + option.series[2].data = this.data.blockSubsidyFiat; + option.series[3].data = this.data.blockFeesFiat; + option.series[4].data = this.data.blockSubsidyPercent; + option.series[5].data = this.data.blockFeesPercent; + option.xAxis[0].data = this.data.blockHeight; + option.xAxis[1].data = this.data.timestamp; + this.chartInstance.setOption(option, true); + const lengthAfter = this.data.timestamp.length; + + // Update the zoom to keep the same range after the update + this.chartInstance.dispatchAction({ + type: 'dataZoom', + startValue: startIndex, + endValue: endIndex + lengthAfter - lengthBefore, + silent: true, + }); + + // Update the chart + const newOption = this.chartInstance.getOption(); + this.zoomSpan = newOption.dataZoom[0].end - newOption.dataZoom[0].start; + this.zoomTimeSpan = this.getTimeRangeFromTimespan(Math.floor(this.data.timestamp[newOption.dataZoom[0].startValue] / 1000), Math.floor(this.data.timestamp[newOption.dataZoom[0].endValue] / 1000)); + this.isLoading = false; + }), + catchError(() => { + const newOption = this.chartInstance.getOption(); + this.zoomSpan = newOption.dataZoom[0].end - newOption.dataZoom[0].start; + this.zoomTimeSpan = this.getTimeRangeFromTimespan(Math.floor(this.data.timestamp[newOption.dataZoom[0].startValue] / 1000), Math.floor(this.data.timestamp[newOption.dataZoom[0].endValue] / 1000)); + this.isLoading = false; + this.cd.detectChanges(); + return []; + }) + ).subscribe(() => { + subscription.unsubscribe(); + this.cd.detectChanges(); + }); + } + + getTimeRangeFromTimespan(from: number, to: number): string { + const timespan = to - from; + switch (true) { + case timespan >= 3600 * 24 * 365 * 4: return 'all'; + case timespan >= 3600 * 24 * 365 * 3: return '4y'; + case timespan >= 3600 * 24 * 365 * 2: return '3y'; + case timespan >= 3600 * 24 * 365: return '2y'; + case timespan >= 3600 * 24 * 30 * 6: return '1y'; + case timespan >= 3600 * 24 * 30 * 3: return '6m'; + case timespan >= 3600 * 24 * 30: return '3m'; + case timespan >= 3600 * 24 * 7: return '1m'; + case timespan >= 3600 * 24 * 3: return '1w'; + case timespan >= 3600 * 24: return '3d'; + default: return '24h'; + } + } + + onSaveChart() { + // @ts-ignore + const prevBottom = this.chartOptions.grid.bottom; + const now = new Date(); + // @ts-ignore + this.chartOptions.grid.bottom = 40; + this.chartOptions.backgroundColor = 'var(--active-bg)'; + this.chartInstance.setOption(this.chartOptions); + download(this.chartInstance.getDataURL({ + pixelRatio: 2, + excludeComponents: ['dataZoom'], + }), `block-fees-subsidy-${this.timespan}-${Math.round(now.getTime() / 1000)}.svg`); + // @ts-ignore + this.chartOptions.grid.bottom = prevBottom; + this.chartOptions.backgroundColor = 'none'; + this.chartInstance.setOption(this.chartOptions); + } + +} diff --git a/frontend/src/app/components/block-filters/block-filters.component.html b/frontend/src/app/components/block-filters/block-filters.component.html new file mode 100644 index 0000000000..2a22681d6e --- /dev/null +++ b/frontend/src/app/components/block-filters/block-filters.component.html @@ -0,0 +1,57 @@ +
+ + beta + + +
+ +
+ + + +
+
+
+
+
+
Match
+
+ + +
+
+
+
Tint
+
+ + +
+
+
+ +
{{ group.label }}
+
+ + + +
+
+
+
+ + + + + +
+
\ No newline at end of file diff --git a/frontend/src/app/components/block-filters/block-filters.component.scss b/frontend/src/app/components/block-filters/block-filters.component.scss new file mode 100644 index 0000000000..7cbc738b7c --- /dev/null +++ b/frontend/src/app/components/block-filters/block-filters.component.scss @@ -0,0 +1,205 @@ +.block-filters { + position: absolute; + left: 0; + top: 0; + width: 100%; + height: 100%; + padding: 1em; + z-index: 10; + pointer-events: none; + + .filter-bar, .active-tags { + display: flex; + flex-direction: row; + align-items: center; + } + + .active-tags { + flex-wrap: wrap; + row-gap: 0.25em; + margin-left: 0.5em; + } + + .info-badges { + display: flex; + flex-direction: row; + align-items: center; + float: right; + + &:hover, &:active { + text-decoration: none; + } + } + + .menu-toggle { + width: 3em; + min-width: 3em; + height: 1.8em; + padding: 0px 1px; + opacity: 0; + cursor: pointer; + color: white; + background: none; + border: none; + border-radius: 0.35em; + pointer-events: all; + align-self: normal; + } + + .filter-menu { + .filter-row { + display: flex; + flex-direction: row; + justify-content: start; + align-items: baseline; + } + + h5 { + font-size: 0.8rem; + color: white; + margin: 0; + margin-top: 0.5em; + } + } + + .filter-group { + display: flex; + flex-direction: row; + flex-wrap: wrap; + row-gap: 0.25em; + margin-bottom: 0.5em; + } + + .filter-tag { + font-size: 0.9em; + background: #181b2daf; + border: solid 1px var(--primary); + color: white; + border-radius: 0.2rem; + padding: 0.2em 0.5em; + transition: background-color 300ms; + margin-right: 0.25em; + pointer-events: all; + + &.selected { + background-color: var(--primary); + } + } + + &.any-mode { + .filter-tag { + border: solid 1px var(--success); + &.selected { + background-color: var(--success); + } + } + } + + .btn-group { + font-size: 0.9em; + margin-right: 0.25em; + } + + .mode-toggle { + padding: 0.2em 0.5em; + pointer-events: all; + line-height: 1.5; + background: #181b2daf; + + &:first-child { + border-top-left-radius: 0.2rem; + border-bottom-left-radius: 0.2rem; + } + &:last-child { + border-top-right-radius: 0.2rem; + border-bottom-right-radius: 0.2rem; + } + + &.blue { + border: solid 1px var(--primary); + &.active { + background: var(--primary); + } + } + &.green { + border: solid 1px var(--success); + &.active { + background: var(--success); + } + } + &.yellow { + border: solid 1px #bf7815; + &.active { + background: #bf7815; + } + } + } + + :host-context(.block-overview-graph:hover) &, &:hover, &:active { + .menu-toggle { + opacity: 0.5; + background: var(--stat-box-bg); + + &:hover { + opacity: 1; + background: #181b2d7f; + } + } + + &.menu-open, &.filters-active { + .menu-toggle { + opacity: 1; + background: none; + + &:hover { + background: #181b2d7f; + } + } + } + } + + &.menu-open, &.filters-active { + .menu-toggle { + opacity: 1; + background: none; + + &:hover { + background: #181b2d7f; + } + } + } + + &.menu-open { + pointer-events: all; + background: #181b2d7f; + } + + &.small { + .filter-tag { + font-size: 0.8em; + } + } + + &.vsmall { + .filter-menu { + margin-top: 0.25em; + h5 { + display: none; + } + } + .filter-tag { + font-size: 0.7em; + } + .mode-toggle { + font-size: 0.7em; + margin-bottom: 5px; + margin-top: 2px; + } + } + + &.tiny { + .filter-tag { + font-size: 0.5em; + } + } +} \ No newline at end of file diff --git a/frontend/src/app/components/block-filters/block-filters.component.ts b/frontend/src/app/components/block-filters/block-filters.component.ts new file mode 100644 index 0000000000..7f997617c0 --- /dev/null +++ b/frontend/src/app/components/block-filters/block-filters.component.ts @@ -0,0 +1,118 @@ +import { Component, EventEmitter, Output, HostListener, Input, ChangeDetectorRef, OnChanges, SimpleChanges, OnInit, OnDestroy } from '@angular/core'; +import { ActiveFilter, FilterGroups, FilterMode, GradientMode, TransactionFilters } from '../../shared/filters.utils'; +import { StateService } from '../../services/state.service'; +import { Subscription } from 'rxjs'; + + +@Component({ + selector: 'app-block-filters', + templateUrl: './block-filters.component.html', + styleUrls: ['./block-filters.component.scss'], +}) +export class BlockFiltersComponent implements OnInit, OnChanges, OnDestroy { + @Input() cssWidth: number = 800; + @Input() excludeFilters: string[] = []; + @Output() onFilterChanged: EventEmitter = new EventEmitter(); + + filterSubscription: Subscription; + + filters = TransactionFilters; + filterGroups = FilterGroups; + disabledFilters: { [key: string]: boolean } = {}; + activeFilters: string[] = []; + filterFlags: { [key: string]: boolean } = {}; + filterMode: FilterMode = 'and'; + gradientMode: GradientMode = 'fee'; + menuOpen: boolean = false; + + constructor( + private stateService: StateService, + private cd: ChangeDetectorRef, + ) {} + + ngOnInit(): void { + this.filterSubscription = this.stateService.activeGoggles$.subscribe((active: ActiveFilter) => { + this.filterMode = active.mode; + this.gradientMode = active.gradient; + for (const key of Object.keys(this.filterFlags)) { + this.filterFlags[key] = false; + } + for (const key of active.filters) { + this.filterFlags[key] = !this.disabledFilters[key]; + } + this.activeFilters = [...active.filters.filter(key => !this.disabledFilters[key])]; + this.onFilterChanged.emit({ mode: active.mode, filters: this.activeFilters, gradient: this.gradientMode }); + }); + } + + ngOnChanges(changes: SimpleChanges): void { + if (changes.cssWidth) { + this.cd.markForCheck(); + } + if (changes.excludeFilters) { + this.disabledFilters = {}; + this.excludeFilters.forEach(filter => { + this.disabledFilters[filter] = true; + }); + } + } + + setFilterMode(mode): void { + this.filterMode = mode; + this.onFilterChanged.emit({ mode: this.filterMode, filters: this.activeFilters, gradient: this.gradientMode }); + this.stateService.activeGoggles$.next({ mode: this.filterMode, filters: [...this.activeFilters], gradient: this.gradientMode }); + } + + setGradientMode(mode): void { + this.gradientMode = mode; + this.onFilterChanged.emit({ mode: this.filterMode, filters: this.activeFilters, gradient: this.gradientMode }); + this.stateService.activeGoggles$.next({ mode: this.filterMode, filters: [...this.activeFilters], gradient: this.gradientMode }); + } + + toggleFilter(key): void { + const filter = this.filters[key]; + this.filterFlags[key] = !this.filterFlags[key]; + if (this.filterFlags[key]) { + // remove any other flags in the same toggle group + if (filter.toggle) { + this.activeFilters.forEach(f => { + if (this.filters[f].toggle === filter.toggle) { + this.filterFlags[f] = false; + } + }); + this.activeFilters = this.activeFilters.filter(f => this.filters[f].toggle !== filter.toggle); + } + // add new active filter + this.activeFilters.push(key); + } else { + // remove active filter + this.activeFilters = this.activeFilters.filter(f => f != key); + } + const booleanFlags = this.getBooleanFlags(); + this.onFilterChanged.emit({ mode: this.filterMode, filters: this.activeFilters, gradient: this.gradientMode }); + this.stateService.activeGoggles$.next({ mode: this.filterMode, filters: [...this.activeFilters], gradient: this.gradientMode }); + } + + getBooleanFlags(): bigint | null { + let flags = 0n; + for (const key of Object.keys(this.filterFlags)) { + if (this.filterFlags[key]) { + flags |= this.filters[key].flag; + } + } + return flags || null; + } + + @HostListener('document:click', ['$event']) + onClick(event): boolean { + // click away from menu + if (!event.target.closest('button') && !event.target.closest('label')) { + this.menuOpen = false; + } + return true; + } + + ngOnDestroy(): void { + this.filterSubscription.unsubscribe(); + } +} \ No newline at end of file diff --git a/frontend/src/app/components/block-health-graph/block-health-graph.component.html b/frontend/src/app/components/block-health-graph/block-health-graph.component.html new file mode 100644 index 0000000000..86eb918622 --- /dev/null +++ b/frontend/src/app/components/block-health-graph/block-health-graph.component.html @@ -0,0 +1,55 @@ + + +
+
+
+ Block Health + +
+ +
+
+ + + + + + + + + + +
+
+
+ +
+
+
+
+
+ +
diff --git a/frontend/src/app/components/block-health-graph/block-health-graph.component.scss b/frontend/src/app/components/block-health-graph/block-health-graph.component.scss new file mode 100644 index 0000000000..98f6892029 --- /dev/null +++ b/frontend/src/app/components/block-health-graph/block-health-graph.component.scss @@ -0,0 +1,62 @@ +.card-header { + border-bottom: 0; + font-size: 18px; + @media (min-width: 465px) { + font-size: 20px; + } + @media (min-width: 992px) { + height: 40px; + } +} + +.main-title { + position: relative; + color: var(--fg); + opacity: var(--opacity); + margin-top: -13px; + font-size: 10px; + text-transform: uppercase; + font-weight: 500; + text-align: center; + padding-bottom: 3px; +} + +.full-container { + display: flex; + flex-direction: column; + padding: 0px 15px; + width: 100%; + height: calc(100vh - 225px); + min-height: 400px; + @media (min-width: 992px) { + height: calc(100vh - 150px); + } +} + +.chart { + display: flex; + flex: 1; + height: 100%; + padding-bottom: 20px; + padding-right: 10px; + @media (max-width: 992px) { + padding-bottom: 25px; + } + @media (max-width: 829px) { + padding-bottom: 50px; + } + @media (max-width: 767px) { + padding-bottom: 25px; + } + @media (max-width: 629px) { + padding-bottom: 55px; + } + @media (max-width: 567px) { + padding-bottom: 55px; + } +} +.chart-widget { + width: 100%; + height: 100%; + max-height: 270px; +} diff --git a/frontend/src/app/components/block-health-graph/block-health-graph.component.ts b/frontend/src/app/components/block-health-graph/block-health-graph.component.ts new file mode 100644 index 0000000000..59f34cd456 --- /dev/null +++ b/frontend/src/app/components/block-health-graph/block-health-graph.component.ts @@ -0,0 +1,304 @@ +import { ChangeDetectionStrategy, Component, Inject, Input, LOCALE_ID, NgZone, OnInit } from '@angular/core'; +import { EChartsOption } from '../../graphs/echarts'; +import { Observable } from 'rxjs'; +import { map, share, startWith, switchMap, tap } from 'rxjs/operators'; +import { ApiService } from '../../services/api.service'; +import { SeoService } from '../../services/seo.service'; +import { formatNumber } from '@angular/common'; +import { UntypedFormBuilder, UntypedFormGroup } from '@angular/forms'; +import { download, formatterXAxis, formatterXAxisLabel, formatterXAxisTimeCategory } from '../../shared/graphs.utils'; +import { StorageService } from '../../services/storage.service'; +import { ActivatedRoute, Router } from '@angular/router'; +import { RelativeUrlPipe } from '../../shared/pipes/relative-url/relative-url.pipe'; +import { StateService } from '../../services/state.service'; + +@Component({ + selector: 'app-block-health-graph', + templateUrl: './block-health-graph.component.html', + styleUrls: ['./block-health-graph.component.scss'], + styles: [` + .loadingGraphs { + position: absolute; + top: 50%; + left: calc(50% - 15px); + z-index: 100; + } + `], + changeDetection: ChangeDetectionStrategy.OnPush, +}) +export class BlockHealthGraphComponent implements OnInit { + @Input() right: number | string = 45; + @Input() left: number | string = 75; + + miningWindowPreference: string; + radioGroupForm: UntypedFormGroup; + + chartOptions: EChartsOption = {}; + chartInitOptions = { + renderer: 'svg', + }; + + statsObservable$: Observable; + isLoading = true; + formatNumber = formatNumber; + timespan = ''; + chartInstance: any = undefined; + + constructor( + @Inject(LOCALE_ID) public locale: string, + private seoService: SeoService, + private apiService: ApiService, + private formBuilder: UntypedFormBuilder, + private storageService: StorageService, + private zone: NgZone, + private route: ActivatedRoute, + public stateService: StateService, + private router: Router, + ) { + this.radioGroupForm = this.formBuilder.group({ dateSpan: '1y' }); + this.radioGroupForm.controls.dateSpan.setValue('1y'); + } + + ngOnInit(): void { + this.seoService.setTitle($localize`:@@b1fa5b210c9670d49a6506f046d4a0c2797fd402:Block Health`); + this.seoService.setDescription($localize`:@@meta.description.bitcoin.graphs.block-health:See Bitcoin block health visualized over time. Block health is a measure of how many expected transactions were included in an actual mined block. Expected transactions are determined using Mempool's re-implementation of Bitcoin Core's transaction selection algorithm.`); + this.miningWindowPreference = '24h';//this.miningService.getDefaultTimespan('24h'); + this.radioGroupForm = this.formBuilder.group({ dateSpan: this.miningWindowPreference }); + this.radioGroupForm.controls.dateSpan.setValue(this.miningWindowPreference); + + this.route + .fragment + .subscribe((fragment) => { + if (['24h', '3d', '1w', '1m', '3m', '6m', '1y', '2y', '3y', 'all'].indexOf(fragment) > -1) { + this.radioGroupForm.controls.dateSpan.setValue(fragment, { emitEvent: false }); + } + }); + + this.statsObservable$ = this.radioGroupForm.get('dateSpan').valueChanges + .pipe( + startWith(this.radioGroupForm.controls.dateSpan.value), + switchMap((timespan) => { + this.storageService.setValue('miningWindowPreference', timespan); + this.timespan = timespan; + this.isLoading = true; + return this.apiService.getHistoricalBlocksHealth$(timespan) + .pipe( + tap((response) => { + this.prepareChartOptions(response.body); + this.isLoading = false; + }), + map((response) => { + return { + blockCount: parseInt(response.headers.get('x-total-count'), 10), + }; + }), + ); + }), + share() + ); + } + + prepareChartOptions(data) { + let title: object; + if (data.length === 0) { + title = { + textStyle: { + color: 'grey', + fontSize: 15 + }, + text: $localize`No data to display yet. Try again later.`, + left: 'center', + top: 'center' + }; + } + + this.chartOptions = { + title: data.length === 0 ? title : undefined, + animation: false, + grid: { + top: 30, + bottom: 80, + right: this.right, + left: this.left, + }, + tooltip: { + show: !this.isMobile(), + trigger: 'axis', + axisPointer: { + type: 'line' + }, + backgroundColor: 'rgba(17, 19, 31, 1)', + borderRadius: 4, + shadowColor: 'rgba(0, 0, 0, 0.5)', + textStyle: { + color: 'var(--tooltip-grey)', + align: 'left', + }, + borderColor: '#000', + formatter: (ticks) => { + let tooltip = `${formatterXAxis(this.locale, this.timespan, parseInt(ticks[0].axisValue, 10) * 1000)}
`; + tooltip += `${ticks[0].marker} ${ticks[0].seriesName}: ${formatNumber(ticks[0].data.value, this.locale, '1.2-2')}%
`; + + if (['24h', '3d'].includes(this.timespan)) { + tooltip += `` + $localize`At block: ${ticks[0].data.block}` + ``; + } else { + tooltip += `` + $localize`Around block: ${ticks[0].data.block}` + ``; + } + + return tooltip; + } + }, + xAxis: data.length === 0 ? undefined : { + name: formatterXAxisLabel(this.locale, this.timespan), + nameLocation: 'middle', + nameTextStyle: { + padding: [10, 0, 0, 0], + }, + type: 'category', + axisLine: { onZero: true }, + axisLabel: { + formatter: val => formatterXAxisTimeCategory(this.locale, this.timespan, parseInt(val, 10) * 1000), + align: 'center', + fontSize: 11, + lineHeight: 12, + hideOverlap: true, + padding: [0, 5], + }, + data: data.map(health => health[0]) + }, + yAxis: data.length === 0 ? undefined : [ + { + type: 'value', + axisLabel: { + color: 'rgb(110, 112, 121)', + formatter: (val) => { + return `${val}%`; + } + }, + splitLine: { + lineStyle: { + type: 'dotted', + color: 'var(--transparent-fg)', + opacity: 0.25, + } + }, + }, + ], + series: data.length === 0 ? undefined : [ + { + zlevel: 0, + name: $localize`:@@d2bcd3296d2850de762fb943060b7e086a893181:Health`, + data: data.map(health => ({ + value: health[2], + block: health[1], + itemStyle: { + color: this.getHealthColor(health[2]) + } + })), + type: 'bar', + barWidth: '90%', + barMaxWidth: 50, + }, + ], + dataZoom: data.length === 0 ? undefined : [{ + type: 'inside', + realtime: true, + zoomLock: true, + maxSpan: 100, + minSpan: 5, + moveOnMouseMove: false, + }, { + showDetail: false, + show: true, + type: 'slider', + brushSelect: false, + realtime: true, + left: 20, + right: 15, + selectedDataBackground: { + lineStyle: { + color: '#fff', + opacity: 0.45, + }, + areaStyle: { + opacity: 0, + } + }, + }], + }; + } + + colorGradient(fadeFraction, rgbColor1, rgbColor2, rgbColor3) { + let color1 = rgbColor1; + let color2 = rgbColor2; + let fade = fadeFraction; + + // Do we have 3 colors for the gradient? Need to adjust the params. + if (rgbColor3) { + fade = fade * 2; + + // Find which interval to use and adjust the fade percentage + if (fade >= 1) { + fade -= 1; + color1 = rgbColor2; + color2 = rgbColor3; + } + } + + const diffRed = color2.red - color1.red; + const diffGreen = color2.green - color1.green; + const diffBlue = color2.blue - color1.blue; + + const gradient = { + red: Math.floor(color1.red + (diffRed * fade)), + green: Math.floor(color1.green + (diffGreen * fade)), + blue: Math.floor(color1.blue + (diffBlue * fade)), + }; + + return 'rgb(' + gradient.red + ',' + gradient.green + ',' + gradient.blue + ')'; + } + + getHealthColor(matchRate) { + return this.colorGradient( + Math.pow((100 - matchRate) / 100, 0.5), + {red: 67, green: 171, blue: 71}, + {red: 253, green: 216, blue: 53}, + {red: 244, green: 0, blue: 0}, + ); + } + + onChartInit(ec) { + this.chartInstance = ec; + + this.chartInstance.on('click', (e) => { + this.zone.run(() => { + if (['24h', '3d'].includes(this.timespan)) { + const url = new RelativeUrlPipe(this.stateService).transform(`/block/${e.data.block}`); + this.router.navigate([url]); + } + }); + }); + } + + isMobile() { + return (window.innerWidth <= 767.98); + } + + onSaveChart() { + // @ts-ignore + const prevBottom = this.chartOptions.grid.bottom; + const now = new Date(); + // @ts-ignore + this.chartOptions.grid.bottom = 40; + this.chartOptions.backgroundColor = 'var(--active-bg)'; + this.chartInstance.setOption(this.chartOptions); + download(this.chartInstance.getDataURL({ + pixelRatio: 2, + excludeComponents: ['dataZoom'], + }), `block-health-${this.timespan}-${Math.round(now.getTime() / 1000)}.svg`); + // @ts-ignore + this.chartOptions.grid.bottom = prevBottom; + this.chartOptions.backgroundColor = 'none'; + this.chartInstance.setOption(this.chartOptions); + } +} diff --git a/frontend/src/app/components/block-overview-graph/block-overview-graph.component.html b/frontend/src/app/components/block-overview-graph/block-overview-graph.component.html new file mode 100644 index 0000000000..2ef07d12c4 --- /dev/null +++ b/frontend/src/app/components/block-overview-graph/block-overview-graph.component.html @@ -0,0 +1,24 @@ + +
+
+ +
+
+
not available
+
+ + +
+ Your browser does not support this feature. +
+
+
diff --git a/frontend/src/app/components/block-overview-graph/block-overview-graph.component.scss b/frontend/src/app/components/block-overview-graph/block-overview-graph.component.scss new file mode 100644 index 0000000000..af5135db79 --- /dev/null +++ b/frontend/src/app/components/block-overview-graph/block-overview-graph.component.scss @@ -0,0 +1,67 @@ +.block-overview-graph { + position: relative; + width: 100%; + padding-bottom: 100%; + background: var(--stat-box-bg); + display: flex; + justify-content: center; + align-items: center; + grid-column: 1/-1; + + .placeholder { + display: flex; + position: absolute; + left: 0; + right: 0; + top: 0; + bottom: 0; + height: 100%; + width: 100%; + align-items: center; + justify-content: center; + } +} + +.graph-alignment { + position: relative; + width: 100%; +} + +.grid-align { + display: grid; + grid-template-columns: repeat(auto-fit, 75px); + justify-content: center; +} + +.block-overview-canvas { + position: absolute; + left: 0; + right: 0; + top: 0; + bottom: 0; + width: 100%; + height: 100%; + overflow: hidden; + + &.clickable { + cursor: pointer; + } +} + +.loader-wrapper { + position: absolute; + background: #181b2d7f; + left: 0; + right: 0; + top: 0; + bottom: 0; + display: flex; + justify-content: center; + align-items: center; + transition: opacity 500ms 500ms; + pointer-events: none; + + &.hidden { + opacity: 0; + } +} diff --git a/frontend/src/app/components/block-overview-graph/block-overview-graph.component.ts b/frontend/src/app/components/block-overview-graph/block-overview-graph.component.ts new file mode 100644 index 0000000000..6231ba70d1 --- /dev/null +++ b/frontend/src/app/components/block-overview-graph/block-overview-graph.component.ts @@ -0,0 +1,759 @@ +import { Component, ElementRef, ViewChild, HostListener, Input, Output, EventEmitter, NgZone, AfterViewInit, OnDestroy, OnChanges } from '@angular/core'; +import { TransactionStripped } from '../../interfaces/node-api.interface'; +import { FastVertexArray } from './fast-vertex-array'; +import BlockScene from './block-scene'; +import TxSprite from './tx-sprite'; +import TxView from './tx-view'; +import { Color, Position } from './sprite-types'; +import { Price } from '../../services/price.service'; +import { StateService } from '../../services/state.service'; +import { ThemeService } from '../../services/theme.service'; +import { Subscription } from 'rxjs'; +import { defaultColorFunction, setOpacity, defaultAuditColors, defaultColors, ageColorFunction, contrastColorFunction, contrastAuditColors, contrastColors } from './utils'; +import { ActiveFilter, FilterMode, toFlags } from '../../shared/filters.utils'; +import { detectWebGL } from '../../shared/graphs.utils'; + +const unmatchedOpacity = 0.2; +const unmatchedAuditColors = { + censored: setOpacity(defaultAuditColors.censored, unmatchedOpacity), + missing: setOpacity(defaultAuditColors.missing, unmatchedOpacity), + added: setOpacity(defaultAuditColors.added, unmatchedOpacity), + prioritized: setOpacity(defaultAuditColors.prioritized, unmatchedOpacity), + accelerated: setOpacity(defaultAuditColors.accelerated, unmatchedOpacity), +}; +const unmatchedContrastAuditColors = { + censored: setOpacity(contrastAuditColors.censored, unmatchedOpacity), + missing: setOpacity(contrastAuditColors.missing, unmatchedOpacity), + added: setOpacity(contrastAuditColors.added, unmatchedOpacity), + prioritized: setOpacity(contrastAuditColors.prioritized, unmatchedOpacity), + accelerated: setOpacity(contrastAuditColors.accelerated, unmatchedOpacity), +}; + +@Component({ + selector: 'app-block-overview-graph', + templateUrl: './block-overview-graph.component.html', + styleUrls: ['./block-overview-graph.component.scss'], +}) +export class BlockOverviewGraphComponent implements AfterViewInit, OnDestroy, OnChanges { + @Input() isLoading: boolean; + @Input() resolution: number; + @Input() autofit: boolean = false; + @Input() blockLimit: number; + @Input() orientation = 'left'; + @Input() flip = true; + @Input() animationDuration: number = 1000; + @Input() animationOffset: number | null = null; + @Input() disableSpinner = false; + @Input() mirrorTxid: string | void; + @Input() unavailable: boolean = false; + @Input() auditHighlighting: boolean = false; + @Input() showFilters: boolean = false; + @Input() excludeFilters: string[] = []; + @Input() filterFlags: bigint | null = null; + @Input() filterMode: FilterMode = 'and'; + @Input() gradientMode: 'fee' | 'age' = 'fee'; + @Input() relativeTime: number | null; + @Input() blockConversion: Price; + @Input() overrideColors: ((tx: TxView) => Color) | null = null; + @Output() txClickEvent = new EventEmitter<{ tx: TransactionStripped, keyModifier: boolean}>(); + @Output() txHoverEvent = new EventEmitter(); + @Output() readyEvent = new EventEmitter(); + + @ViewChild('blockCanvas') + canvas: ElementRef; + themeChangedSubscription: Subscription; + + gl: WebGLRenderingContext; + animationFrameRequest: number; + animationHeartBeat: number; + displayWidth: number; + displayHeight: number; + cssWidth: number; + cssHeight: number; + shaderProgram: WebGLProgram; + vertexArray: FastVertexArray; + running: boolean; + scene: BlockScene; + hoverTx: TxView | void; + selectedTx: TxView | void; + highlightTx: TxView | void; + mirrorTx: TxView | void; + tooltipPosition: Position; + + readyNextFrame = false; + lastUpdate: number = 0; + pendingUpdate: { + count: number, + add: { [txid: string]: TransactionStripped }, + remove: { [txid: string]: string }, + change: { [txid: string]: { txid: string, rate: number | undefined, acc: boolean | undefined } }, + direction?: string, + } = { + count: 0, + add: {}, + remove: {}, + change: {}, + direction: 'left', + }; + + searchText: string; + searchSubscription: Subscription; + filtersAvailable: boolean = true; + activeFilterFlags: bigint | null = null; + + webGlEnabled = true; + + constructor( + readonly ngZone: NgZone, + readonly elRef: ElementRef, + public stateService: StateService, + private themeService: ThemeService, + ) { + this.webGlEnabled = this.stateService.isBrowser && detectWebGL(); + this.vertexArray = new FastVertexArray(512, TxSprite.dataSize); + this.searchSubscription = this.stateService.searchText$.subscribe((text) => { + this.searchText = text; + this.updateSearchHighlight(); + }); + } + + ngAfterViewInit(): void { + if (this.canvas) { + this.canvas.nativeElement.addEventListener('webglcontextlost', this.handleContextLost, false); + this.canvas.nativeElement.addEventListener('webglcontextrestored', this.handleContextRestored, false); + this.gl = this.canvas.nativeElement.getContext('webgl'); + + if (this.gl) { + this.initCanvas(); + this.resizeCanvas(); + this.themeChangedSubscription = this.themeService.themeChanged$.subscribe(() => { + this.scene.setColorFunction(this.getColorFunction()); + }); + } + } + } + + ngOnChanges(changes): void { + if (changes.orientation || changes.flip) { + if (this.scene) { + this.scene.setOrientation(this.orientation, this.flip); + } + } + if (changes.mirrorTxid) { + this.setMirror(this.mirrorTxid); + } + if (changes.auditHighlighting) { + this.setHighlightingEnabled(this.auditHighlighting); + } + if (changes.overrideColor && this.scene) { + this.scene.setColorFunction(this.getFilterColorFunction(0n, this.gradientMode)); + } + if ((changes.filterFlags || changes.showFilters || changes.filterMode || changes.gradientMode)) { + this.setFilterFlags(); + } + } + + setFilterFlags(goggle?: ActiveFilter): void { + this.filterMode = goggle?.mode || this.filterMode; + this.gradientMode = goggle?.gradient || this.gradientMode; + this.activeFilterFlags = goggle?.filters ? toFlags(goggle.filters) : this.filterFlags; + if (this.scene) { + if (this.activeFilterFlags != null && this.filtersAvailable) { + this.scene.setColorFunction(this.getFilterColorFunction(this.activeFilterFlags, this.gradientMode)); + } else { + this.scene.setColorFunction(this.getFilterColorFunction(0n, this.gradientMode)); + } + } + this.start(); + } + + ngOnDestroy(): void { + if (this.animationFrameRequest) { + cancelAnimationFrame(this.animationFrameRequest); + clearTimeout(this.animationHeartBeat); + } + if (this.canvas) { + this.canvas.nativeElement.removeEventListener('webglcontextlost', this.handleContextLost); + this.canvas.nativeElement.removeEventListener('webglcontextrestored', this.handleContextRestored); + this.themeChangedSubscription?.unsubscribe(); + } + } + + clear(direction): void { + this.exit(direction); + this.hoverTx = null; + this.selectedTx = null; + this.onTxHover(null); + this.start(); + } + + destroy(): void { + if (this.scene) { + this.scene.destroy(); + this.clearUpdateQueue(); + this.start(); + } + } + + // initialize the scene without any entry transition + setup(transactions: TransactionStripped[]): void { + const filtersAvailable = transactions.reduce((flagSet, tx) => flagSet || tx.flags > 0, false); + if (filtersAvailable !== this.filtersAvailable) { + this.setFilterFlags(); + } + this.filtersAvailable = filtersAvailable; + if (this.scene) { + this.clearUpdateQueue(); + this.scene.setup(transactions); + this.readyNextFrame = true; + this.start(); + this.updateSearchHighlight(); + } + } + + enter(transactions: TransactionStripped[], direction: string): void { + if (this.scene) { + this.clearUpdateQueue(); + this.scene.enter(transactions, direction); + this.start(); + this.updateSearchHighlight(); + } + } + + exit(direction: string): void { + if (this.scene) { + this.clearUpdateQueue(); + this.scene.exit(direction); + this.start(); + this.updateSearchHighlight(); + } + } + + replace(transactions: TransactionStripped[], direction: string, sort: boolean = true, startTime?: number): void { + if (this.scene) { + this.clearUpdateQueue(); + this.scene.replace(transactions || [], direction, sort, startTime); + this.start(); + this.updateSearchHighlight(); + } + } + + // collates deferred updates into a set of consistent pending changes + queueUpdate(add: TransactionStripped[], remove: string[], change: { txid: string, rate: number | undefined, acc: boolean | undefined }[], direction: string = 'left'): void { + for (const tx of add) { + this.pendingUpdate.add[tx.txid] = tx; + delete this.pendingUpdate.remove[tx.txid]; + delete this.pendingUpdate.change[tx.txid]; + } + for (const txid of remove) { + delete this.pendingUpdate.add[txid]; + this.pendingUpdate.remove[txid] = txid; + delete this.pendingUpdate.change[txid]; + } + for (const tx of change) { + if (this.pendingUpdate.add[tx.txid]) { + this.pendingUpdate.add[tx.txid].rate = tx.rate; + this.pendingUpdate.add[tx.txid].acc = tx.acc; + } else { + this.pendingUpdate.change[tx.txid] = tx; + } + } + this.pendingUpdate.direction = direction; + this.pendingUpdate.count++; + } + + deferredUpdate(add: TransactionStripped[], remove: string[], change: { txid: string, rate: number | undefined, acc: boolean | undefined }[], direction: string = 'left'): void { + this.queueUpdate(add, remove, change, direction); + this.applyQueuedUpdates(); + } + + applyQueuedUpdates(): void { + if (this.pendingUpdate.count && performance.now() > (this.lastUpdate + this.animationDuration)) { + this.applyUpdate(Object.values(this.pendingUpdate.add), Object.values(this.pendingUpdate.remove), Object.values(this.pendingUpdate.change), this.pendingUpdate.direction); + this.clearUpdateQueue(); + } + } + + clearUpdateQueue(): void { + this.pendingUpdate = { + count: 0, + add: {}, + remove: {}, + change: {}, + }; + this.lastUpdate = performance.now(); + } + + update(add: TransactionStripped[], remove: string[], change: { txid: string, rate: number | undefined, acc: boolean | undefined }[], direction: string = 'left', resetLayout: boolean = false): void { + // merge any pending changes into this update + this.queueUpdate(add, remove, change); + this.applyUpdate(Object.values(this.pendingUpdate.add), Object.values(this.pendingUpdate.remove), Object.values(this.pendingUpdate.change), direction, resetLayout); + this.clearUpdateQueue(); + } + + applyUpdate(add: TransactionStripped[], remove: string[], change: { txid: string, rate: number | undefined, acc: boolean | undefined }[], direction: string = 'left', resetLayout: boolean = false): void { + if (this.scene) { + add = add.filter(tx => !this.scene.txs[tx.txid]); + remove = remove.filter(txid => this.scene.txs[txid]); + change = change.filter(tx => this.scene.txs[tx.txid]); + + if (this.gradientMode === 'age') { + this.scene.updateAllColors(); + } + this.scene.update(add, remove, change, direction, resetLayout); + this.start(); + this.lastUpdate = performance.now(); + this.updateSearchHighlight(); + } + } + + initCanvas(): void { + if (!this.canvas || !this.gl) { + return; + } + + this.gl.clearColor(0.0, 0.0, 0.0, 0.0); + this.gl.clear(this.gl.COLOR_BUFFER_BIT); + + const shaderSet = [ + { + type: this.gl.VERTEX_SHADER, + src: vertShaderSrc + }, + { + type: this.gl.FRAGMENT_SHADER, + src: fragShaderSrc + } + ]; + + this.shaderProgram = this.buildShaderProgram(shaderSet); + + this.gl.useProgram(this.shaderProgram); + + // Set up alpha blending + this.gl.enable(this.gl.BLEND); + this.gl.blendFunc(this.gl.ONE, this.gl.ONE_MINUS_SRC_ALPHA); + + const glBuffer = this.gl.createBuffer(); + this.gl.bindBuffer(this.gl.ARRAY_BUFFER, glBuffer); + + /* SET UP SHADER ATTRIBUTES */ + Object.keys(attribs).forEach((key, i) => { + attribs[key].pointer = this.gl.getAttribLocation(this.shaderProgram, key); + this.gl.enableVertexAttribArray(attribs[key].pointer); + }); + + this.start(); + } + + handleContextLost(event): void { + event.preventDefault(); + cancelAnimationFrame(this.animationFrameRequest); + this.animationFrameRequest = null; + this.running = false; + this.gl = null; + } + + handleContextRestored(event): void { + if (this.canvas?.nativeElement) { + this.gl = this.canvas.nativeElement.getContext('webgl'); + if (this.gl) { + this.initCanvas(); + } + } + } + + @HostListener('window:resize', ['$event']) + resizeCanvas(): void { + if (this.canvas) { + this.cssWidth = this.canvas.nativeElement.offsetParent.clientWidth; + this.cssHeight = this.canvas.nativeElement.offsetParent.clientHeight; + this.displayWidth = window.devicePixelRatio * this.cssWidth; + this.displayHeight = window.devicePixelRatio * this.cssHeight; + this.canvas.nativeElement.width = this.displayWidth; + this.canvas.nativeElement.height = this.displayHeight; + if (this.gl) { + this.gl.viewport(0, 0, this.displayWidth, this.displayHeight); + } + if (this.scene) { + this.scene.resize({ width: this.displayWidth, height: this.displayHeight, animate: false }); + this.start(); + } else { + this.scene = new BlockScene({ width: this.displayWidth, height: this.displayHeight, resolution: this.resolution, + blockLimit: this.blockLimit, orientation: this.orientation, flip: this.flip, vertexArray: this.vertexArray, theme: this.themeService, + highlighting: this.auditHighlighting, animationDuration: this.animationDuration, animationOffset: this.animationOffset, + colorFunction: this.getColorFunction() }); + this.start(); + } + } + } + + compileShader(src, type): WebGLShader { + if (!this.gl) { + return; + } + const shader = this.gl.createShader(type); + + this.gl.shaderSource(shader, src); + this.gl.compileShader(shader); + + if (!this.gl.getShaderParameter(shader, this.gl.COMPILE_STATUS)) { + console.log(`Error compiling ${type === this.gl.VERTEX_SHADER ? 'vertex' : 'fragment'} shader:`); + console.log(this.gl.getShaderInfoLog(shader)); + } + return shader; + } + + buildShaderProgram(shaderInfo): WebGLProgram { + if (!this.gl) { + return; + } + const program = this.gl.createProgram(); + + shaderInfo.forEach((desc) => { + const shader = this.compileShader(desc.src, desc.type); + if (shader) { + this.gl.attachShader(program, shader); + } + }); + + this.gl.linkProgram(program); + + if (!this.gl.getProgramParameter(program, this.gl.LINK_STATUS)) { + console.log('Error linking shader program:'); + console.log(this.gl.getProgramInfoLog(program)); + } + + return program; + } + + start(): void { + this.running = true; + this.ngZone.runOutsideAngular(() => this.doRun()); + } + + doRun(): void { + if (this.animationFrameRequest) { + cancelAnimationFrame(this.animationFrameRequest); + } + this.animationFrameRequest = requestAnimationFrame(() => this.run()); + } + + run(now?: DOMHighResTimeStamp): void { + if (!now) { + now = performance.now(); + } + this.applyQueuedUpdates(); + // skip re-render if there's no change to the scene + if (this.scene && this.gl) { + /* SET UP SHADER UNIFORMS */ + // screen dimensions + this.gl.uniform2f(this.gl.getUniformLocation(this.shaderProgram, 'screenSize'), this.displayWidth, this.displayHeight); + // frame timestamp + this.gl.uniform1f(this.gl.getUniformLocation(this.shaderProgram, 'now'), now); + + if (this.vertexArray.dirty) { + /* SET UP SHADER ATTRIBUTES */ + Object.keys(attribs).forEach((key, i) => { + this.gl.vertexAttribPointer(attribs[key].pointer, + attribs[key].count, // number of primitives in this attribute + this.gl[attribs[key].type], // type of primitive in this attribute (e.g. gl.FLOAT) + false, // never normalised + stride, // distance between values of the same attribute + attribs[key].offset); // offset of the first value + }); + + const pointArray = this.vertexArray.getVertexData(); + + if (pointArray.length) { + this.gl.bufferData(this.gl.ARRAY_BUFFER, pointArray, this.gl.DYNAMIC_DRAW); + this.gl.drawArrays(this.gl.TRIANGLES, 0, pointArray.length / TxSprite.vertexSize); + } + this.vertexArray.dirty = false; + } else { + const pointArray = this.vertexArray.getVertexData(); + if (pointArray.length) { + this.gl.drawArrays(this.gl.TRIANGLES, 0, pointArray.length / TxSprite.vertexSize); + } + } + + if (this.readyNextFrame) { + this.readyNextFrame = false; + this.readyEvent.emit(); + } + } + + /* LOOP */ + if (this.running && this.scene && now <= (this.scene.animateUntil + 500)) { + this.doRun(); + } else { + if (this.animationHeartBeat) { + clearTimeout(this.animationHeartBeat); + } + this.animationHeartBeat = window.setTimeout(() => { + this.start(); + }, 1000); + } + } + + @HostListener('document:click', ['$event']) + clickAway(event) { + if (!this.elRef.nativeElement.contains(event.target)) { + const currentPreview = this.selectedTx || this.hoverTx; + if (currentPreview && this.scene) { + this.scene.setHover(currentPreview, false); + this.start(); + } + this.hoverTx = null; + this.selectedTx = null; + this.onTxHover(null); + } + } + + @HostListener('pointerup', ['$event']) + onClick(event) { + if (!this.canvas) { + return; + } + if (event.target === this.canvas.nativeElement && event.pointerType === 'touch') { + this.setPreviewTx(event.offsetX, event.offsetY, true); + } else if (event.target === this.canvas.nativeElement) { + const keyMod = event.shiftKey || event.ctrlKey || event.metaKey; + const middleClick = event.which === 2 || event.button === 1; + this.onTxClick(event.offsetX, event.offsetY, keyMod || middleClick); + } + } + + @HostListener('pointermove', ['$event']) + onPointerMove(event) { + if (!this.canvas) { + return; + } + if (event.target === this.canvas.nativeElement) { + this.setPreviewTx(event.offsetX, event.offsetY, false); + } else { + this.onPointerLeave(event); + } + } + + @HostListener('pointerleave', ['$event']) + onPointerLeave(event) { + if (event.pointerType !== 'touch') { + this.setPreviewTx(-1, -1, true); + } + } + + setPreviewTx(cssX: number, cssY: number, clicked: boolean = false) { + const x = cssX * window.devicePixelRatio; + const y = cssY * window.devicePixelRatio; + if (this.scene && (!this.selectedTx || clicked)) { + this.tooltipPosition = { + x: cssX, + y: cssY + }; + const selected = this.scene.getTxAt({ x, y }); + const currentPreview = this.selectedTx || this.hoverTx; + + if (selected !== currentPreview) { + if (currentPreview && this.scene) { + this.scene.setHover(currentPreview, false); + this.start(); + } + if (selected) { + if (selected && this.scene) { + this.scene.setHover(selected, true); + this.start(); + } + if (clicked) { + this.selectedTx = selected; + } else { + this.hoverTx = selected; + this.onTxHover(this.hoverTx ? this.hoverTx.txid : null); + } + } else { + if (clicked) { + this.selectedTx = null; + } + this.hoverTx = null; + this.onTxHover(null); + } + } else if (clicked) { + if (selected === this.selectedTx) { + this.hoverTx = this.selectedTx; + this.selectedTx = null; + this.onTxHover(this.hoverTx ? this.hoverTx.txid : null); + } else { + this.selectedTx = selected; + } + } + } + } + + setMirror(txid: string | void) { + if (this.mirrorTx) { + this.scene.setHover(this.mirrorTx, false); + this.start(); + } + if (txid && this.scene.txs[txid]) { + this.mirrorTx = this.scene.txs[txid]; + this.scene.setHover(this.mirrorTx, true); + this.start(); + } + } + + updateSearchHighlight(): void { + if (this.highlightTx && this.highlightTx.txid !== this.searchText && this.scene) { + this.scene.setHighlight(this.highlightTx, false); + this.start(); + } else if (this.scene?.txs && this.searchText && this.searchText.length === 64) { + this.highlightTx = this.scene.txs[this.searchText]; + if (this.highlightTx) { + this.scene.setHighlight(this.highlightTx, true); + this.start(); + } + } + } + + setHighlightingEnabled(enabled: boolean): void { + if (this.scene) { + this.scene.setHighlighting(enabled); + this.start(); + } + } + + onTxClick(cssX: number, cssY: number, keyModifier: boolean = false) { + if (this.scene) { + const x = cssX * window.devicePixelRatio; + const y = cssY * window.devicePixelRatio; + const selected = this.scene.getTxAt({ x, y }); + if (selected && selected.txid) { + this.txClickEvent.emit({ tx: selected, keyModifier }); + } + } + } + + onTxHover(hoverId: string) { + this.txHoverEvent.emit(hoverId); + } + + getColorFunction(): ((tx: TxView) => Color) { + if (this.overrideColors) { + return this.overrideColors; + } else if (this.filterFlags) { + return this.getFilterColorFunction(this.filterFlags, this.gradientMode); + } else if (this.activeFilterFlags) { + return this.getFilterColorFunction(this.activeFilterFlags, this.gradientMode); + } else { + return this.getFilterColorFunction(0n, this.gradientMode); + } + } + + getFilterColorFunction(flags: bigint, gradient: 'fee' | 'age'): ((tx: TxView) => Color) { + return (tx: TxView) => { + if ((this.filterMode === 'and' && (tx.bigintFlags & flags) === flags) || (this.filterMode === 'or' && (flags === 0n || (tx.bigintFlags & flags) > 0n))) { + if (this.themeService.theme !== 'contrast' && this.themeService.theme !== 'bukele') { + return (gradient === 'age') ? ageColorFunction(tx, defaultColors.fee, defaultAuditColors, this.relativeTime || (Date.now() / 1000)) : defaultColorFunction(tx, defaultColors.fee, defaultAuditColors, this.relativeTime || (Date.now() / 1000)); + } else { + return (gradient === 'age') ? ageColorFunction(tx, contrastColors.fee, contrastAuditColors, this.relativeTime || (Date.now() / 1000)) : contrastColorFunction(tx, contrastColors.fee, contrastAuditColors, this.relativeTime || (Date.now() / 1000)); + } + } else { + if (this.themeService.theme !== 'contrast' && this.themeService.theme !== 'bukele') { + return (gradient === 'age') ? { r: 1, g: 1, b: 1, a: 0.05 } : defaultColorFunction( + tx, + defaultColors.unmatchedfee, + unmatchedAuditColors, + this.relativeTime || (Date.now() / 1000) + ); + } else { + return (gradient === 'age') ? { r: 1, g: 1, b: 1, a: 0.05 } : contrastColorFunction( + tx, + contrastColors.unmatchedfee, + unmatchedContrastAuditColors, + this.relativeTime || (Date.now() / 1000) + ); + } + } + }; + } +} + +// WebGL shader attributes +const attribs = { + offset: { type: 'FLOAT', count: 2, pointer: null, offset: 0 }, + posX: { type: 'FLOAT', count: 4, pointer: null, offset: 0 }, + posY: { type: 'FLOAT', count: 4, pointer: null, offset: 0 }, + posR: { type: 'FLOAT', count: 4, pointer: null, offset: 0 }, + colR: { type: 'FLOAT', count: 4, pointer: null, offset: 0 }, + colG: { type: 'FLOAT', count: 4, pointer: null, offset: 0 }, + colB: { type: 'FLOAT', count: 4, pointer: null, offset: 0 }, + colA: { type: 'FLOAT', count: 4, pointer: null, offset: 0 } +}; +// Calculate the number of bytes per vertex based on specified attributes +const stride = Object.values(attribs).reduce((total, attrib) => { + return total + (attrib.count * 4); +}, 0); +// Calculate vertex attribute offsets +for (let i = 0, offset = 0; i < Object.keys(attribs).length; i++) { + const attrib = Object.values(attribs)[i]; + attrib.offset = offset; + offset += (attrib.count * 4); +} + +const vertShaderSrc = ` +varying lowp vec4 vColor; + +// each attribute contains [x: startValue, y: endValue, z: startTime, w: rate] +// shader interpolates between start and end values at the given rate, from the given time + +attribute vec2 offset; +attribute vec4 posX; +attribute vec4 posY; +attribute vec4 posR; +attribute vec4 colR; +attribute vec4 colG; +attribute vec4 colB; +attribute vec4 colA; + +uniform vec2 screenSize; +uniform float now; + +float smootherstep(float x) { + x = clamp(x, 0.0, 1.0); + float ix = 1.0 - x; + x = x * x; + return x / (x + ix * ix); +} + +float interpolateAttribute(vec4 attr) { + float d = (now - attr.z) * attr.w; + float delta = smootherstep(d); + return mix(attr.x, attr.y, delta); +} + +void main() { + vec4 screenTransform = vec4(2.0 / screenSize.x, 2.0 / screenSize.y, -1.0, -1.0); + // vec4 screenTransform = vec4(1.0 / screenSize.x, 1.0 / screenSize.y, -0.5, -0.5); + + float radius = interpolateAttribute(posR); + vec2 position = vec2(interpolateAttribute(posX), interpolateAttribute(posY)) + (radius * offset); + + gl_Position = vec4(position * screenTransform.xy + screenTransform.zw, 1.0, 1.0); + + float red = interpolateAttribute(colR); + float green = interpolateAttribute(colG); + float blue = interpolateAttribute(colB); + float alpha = interpolateAttribute(colA); + + vColor = vec4(red, green, blue, alpha); +} +`; + +const fragShaderSrc = ` +varying lowp vec4 vColor; + +void main() { + gl_FragColor = vColor; + // premultiply alpha + gl_FragColor.rgb *= gl_FragColor.a; +} +`; diff --git a/frontend/src/app/components/block-overview-graph/block-scene.ts b/frontend/src/app/components/block-overview-graph/block-scene.ts new file mode 100644 index 0000000000..c59fcb7d4c --- /dev/null +++ b/frontend/src/app/components/block-overview-graph/block-scene.ts @@ -0,0 +1,917 @@ +import { FastVertexArray } from './fast-vertex-array'; +import TxView from './tx-view'; +import { TransactionStripped } from '../../interfaces/node-api.interface'; +import { Color, Position, Square, ViewUpdateParams } from './sprite-types'; +import { defaultColorFunction, contrastColorFunction } from './utils'; +import { ThemeService } from '../../services/theme.service'; + +export default class BlockScene { + scene: { count: number, offset: { x: number, y: number}}; + vertexArray: FastVertexArray; + txs: { [key: string]: TxView }; + getColor: ((tx: TxView) => Color) = defaultColorFunction; + theme: ThemeService; + orientation: string; + flip: boolean; + animationDuration: number = 1000; + configAnimationOffset: number | null; + animationOffset: number; + highlightingEnabled: boolean; + filterFlags: bigint | null = 0b00000100_00000000_00000000_00000000n; + width: number; + height: number; + gridWidth: number; + gridHeight: number; + gridSize: number; + vbytesPerUnit: number; + unitPadding: number; + unitWidth: number; + initialised: boolean; + layout: BlockLayout; + animateUntil = 0; + dirty: boolean; + + constructor({ width, height, resolution, blockLimit, animationDuration, animationOffset, orientation, flip, vertexArray, theme, highlighting, colorFunction }: + { width: number, height: number, resolution: number, blockLimit: number, animationDuration: number, animationOffset: number, + orientation: string, flip: boolean, vertexArray: FastVertexArray, theme: ThemeService, highlighting: boolean, colorFunction: ((tx: TxView) => Color) | null } + ) { + this.init({ width, height, resolution, blockLimit, animationDuration, animationOffset, orientation, flip, vertexArray, theme, highlighting, colorFunction }); + } + + resize({ width = this.width, height = this.height, animate = true }: { width?: number, height?: number, animate: boolean }): void { + this.width = width; + this.height = height; + this.gridSize = this.width / this.gridWidth; + this.unitPadding = Math.max(1, Math.floor(this.gridSize / 5)); + this.unitWidth = this.gridSize - (this.unitPadding * 2); + this.animationOffset = this.configAnimationOffset == null ? (this.width * 1.4) : this.configAnimationOffset; + + this.dirty = true; + if (this.initialised && this.scene) { + this.updateAll(performance.now(), 50, 'left', animate); + } + } + + setOrientation(orientation: string, flip: boolean): void { + this.orientation = orientation; + this.flip = flip; + this.dirty = true; + if (this.initialised && this.scene) { + this.updateAll(performance.now(), 50); + } + } + + setHighlighting(enabled: boolean): void { + this.highlightingEnabled = enabled; + if (this.initialised && this.scene) { + this.updateAll(performance.now(), 50); + } + } + + setColorFunction(colorFunction: ((tx: TxView) => Color) | null): void { + this.theme.theme === 'contrast' || this.theme.theme === 'bukele' ? this.getColor = colorFunction || contrastColorFunction : this.getColor = colorFunction || defaultColorFunction; + this.updateAllColors(); + } + + updateAllColors(): void { + this.dirty = true; + if (this.initialised && this.scene) { + this.updateColors(performance.now(), 50); + } + } + + // Destroy the current layout and clean up graphics sprites without any exit animation + destroy(): void { + Object.values(this.txs).forEach(tx => tx.destroy()); + this.txs = {}; + this.layout = null; + } + + // set up the scene with an initial set of transactions, without any transition animation + setup(txs: TransactionStripped[]) { + // clean up any old transactions + Object.values(this.txs).forEach(tx => { + tx.destroy(); + delete this.txs[tx.txid]; + }); + this.layout = new BlockLayout({ width: this.gridWidth, height: this.gridHeight }); + txs.forEach(tx => { + const txView = new TxView(tx, this); + this.txs[tx.txid] = txView; + this.place(txView); + this.saveGridToScreenPosition(txView); + this.applyTxUpdate(txView, { + display: { + position: txView.screenPosition, + color: this.getColor(txView) + }, + duration: 0 + }); + }); + } + + // Animate new block entering scene + enter(txs: TransactionStripped[], direction, startTime?: number) { + this.replace(txs, direction, false, startTime); + } + + // Animate block leaving scene + exit(direction: string): void { + const startTime = performance.now(); + const removed = this.removeBatch(Object.keys(this.txs), startTime, direction); + + // clean up sprites + setTimeout(() => { + removed.forEach(tx => { + tx.destroy(); + }); + }, 2000); + } + + // Reset layout and replace with new set of transactions + replace(txs: TransactionStripped[], direction: string = 'left', sort: boolean = true, startTime: number = performance.now()): void { + const nextIds = {}; + const remove = []; + txs.forEach(tx => { + nextIds[tx.txid] = true; + }); + Object.keys(this.txs).forEach(txid => { + if (!nextIds[txid]) { + remove.push(txid); + } + }); + txs.forEach(tx => { + if (!this.txs[tx.txid]) { + this.txs[tx.txid] = new TxView(tx, this); + } + }); + + const removed = this.removeBatch(remove, startTime, direction); + + // clean up sprites + setTimeout(() => { + removed.forEach(tx => { + tx.destroy(); + }); + }, (startTime - performance.now()) + this.animationDuration + 1000); + + this.layout = new BlockLayout({ width: this.gridWidth, height: this.gridHeight }); + + if (sort) { + Object.values(this.txs).sort(feeRateDescending).forEach(tx => { + this.place(tx); + }); + } else { + txs.forEach(tx => { + this.place(this.txs[tx.txid]); + }); + } + + this.updateAll(startTime, 50, direction); + } + + update(add: TransactionStripped[], remove: string[], change: { txid: string, rate: number | undefined, acc: boolean | undefined }[], direction: string = 'left', resetLayout: boolean = false): void { + const startTime = performance.now(); + const removed = this.removeBatch(remove, startTime, direction); + + // clean up sprites + setTimeout(() => { + removed.forEach(tx => { + tx.destroy(); + }); + }, (startTime - performance.now()) + this.animationDuration + 1000); + + if (resetLayout) { + add.forEach(tx => { + if (!this.txs[tx.txid]) { + this.txs[tx.txid] = new TxView(tx, this); + } + }); + this.layout = new BlockLayout({ width: this.gridWidth, height: this.gridHeight }); + Object.values(this.txs).sort(feeRateDescending).forEach(tx => { + this.place(tx); + }); + } else { + // update effective rates + change.forEach(tx => { + if (this.txs[tx.txid]) { + this.txs[tx.txid].acc = tx.acc; + this.txs[tx.txid].feerate = tx.rate || (this.txs[tx.txid].fee / this.txs[tx.txid].vsize); + this.txs[tx.txid].rate = tx.rate; + this.txs[tx.txid].dirty = true; + this.updateColor(this.txs[tx.txid], startTime, 50, true); + } + }); + + // try to insert new txs directly + const remaining = []; + add.map(tx => new TxView(tx, this)).sort(feeRateDescending).forEach(tx => { + if (!this.tryInsertByFee(tx)) { + remaining.push(tx); + } + }); + this.placeBatch(remaining); + this.layout.applyGravity(); + } + + this.updateAll(startTime, 100, direction); + } + + // return the tx at this screen position, if any + getTxAt(position: Position): TxView | void { + if (this.layout) { + const gridPosition = this.screenToGrid(position); + return this.layout.getTx(gridPosition); + } else { + return null; + } + } + + setHover(tx: TxView, value: boolean): void { + this.animateUntil = Math.max(this.animateUntil, tx.setHover(value)); + } + + setHighlight(tx: TxView, value: boolean): void { + this.animateUntil = Math.max(this.animateUntil, tx.setHighlight(value)); + } + + private init({ width, height, resolution, blockLimit, animationDuration, animationOffset, orientation, flip, vertexArray, theme, highlighting, colorFunction }: + { width: number, height: number, resolution: number, blockLimit: number, animationDuration: number, animationOffset: number, + orientation: string, flip: boolean, vertexArray: FastVertexArray, theme: ThemeService, highlighting: boolean, colorFunction: ((tx: TxView) => Color) | null } + ): void { + this.animationDuration = animationDuration || this.animationDuration || 1000; + this.configAnimationOffset = animationOffset; + this.animationOffset = this.configAnimationOffset == null ? (this.width * 1.4) : this.configAnimationOffset; + this.orientation = orientation; + this.flip = flip; + this.vertexArray = vertexArray; + this.highlightingEnabled = highlighting; + theme.theme === 'contrast' || theme.theme === 'bukele' ? this.getColor = colorFunction || contrastColorFunction : this.getColor = colorFunction || defaultColorFunction; + this.theme = theme; + + this.scene = { + count: 0, + offset: { + x: 0, + y: 0 + } + }; + + // Set the scale of the visualization (with a 5% margin) + this.vbytesPerUnit = blockLimit / Math.pow(resolution / 1.02, 2); + this.gridWidth = resolution; + this.gridHeight = resolution; + this.resize({ width, height, animate: true }); + this.layout = new BlockLayout({ width: this.gridWidth, height: this.gridHeight }); + + this.txs = {}; + + this.initialised = true; + this.dirty = true; + } + + private applyTxUpdate(tx: TxView, update: ViewUpdateParams): void { + this.animateUntil = Math.max(this.animateUntil, tx.update(update)); + } + + private updateTxColor(tx: TxView, startTime: number, delay: number, animate: boolean = true, duration?: number): void { + if (tx.dirty || this.dirty) { + const txColor = this.getColor(tx); + this.applyTxUpdate(tx, { + display: { + color: txColor + }, + duration: animate ? (duration || this.animationDuration) : 1, + start: startTime, + delay: animate ? delay : 0, + }); + } + } + + private updateTx(tx: TxView, startTime: number, delay: number, direction: string = 'left', animate: boolean = true): void { + if (tx.dirty || this.dirty) { + this.saveGridToScreenPosition(tx); + this.setTxOnScreen(tx, startTime, delay, direction, animate); + } + } + + private updateColor(tx: TxView, startTime: number, delay: number, animate: boolean = true, duration: number = 500): void { + if (tx.dirty || this.dirty) { + const txColor = this.getColor(tx); + this.applyTxUpdate(tx, { + display: { + color: txColor, + }, + start: startTime, + delay, + duration: animate ? duration : 0, + }); + } + } + + private setTxOnScreen(tx: TxView, startTime: number, delay: number = 50, direction: string = 'left', animate: boolean = true): void { + if (!tx.initialised) { + const txColor = this.getColor(tx); + this.applyTxUpdate(tx, { + display: { + position: { + x: tx.screenPosition.x + (direction === 'right' ? -this.width - this.animationOffset : (direction === 'left' ? this.width + this.animationOffset : 0)), + y: tx.screenPosition.y + (direction === 'up' ? -this.height - this.animationOffset : (direction === 'down' ? this.height + this.animationOffset : 0)), + s: tx.screenPosition.s + }, + color: txColor, + }, + start: startTime, + delay: 0, + }); + this.applyTxUpdate(tx, { + display: { + position: tx.screenPosition, + color: txColor + }, + duration: animate ? this.animationDuration : 1, + start: startTime, + delay: animate ? delay : 0, + }); + } else { + this.applyTxUpdate(tx, { + display: { + position: tx.screenPosition, + }, + duration: animate ? this.animationDuration : 0, + minDuration: animate ? (this.animationDuration / 2) : 0, + start: startTime, + delay: animate ? delay : 0, + adjust: animate + }); + if (!animate) { + this.applyTxUpdate(tx, { + display: { + position: tx.screenPosition + }, + duration: 0, + minDuration: 0, + start: startTime, + delay: 0, + adjust: false + }); + } + } + } + + private updateAll(startTime: number, delay: number = 50, direction: string = 'left', animate: boolean = true): void { + this.scene.count = 0; + const ids = this.getTxList(); + startTime = startTime || performance.now(); + for (const id of ids) { + this.updateTx(this.txs[id], startTime, delay, direction, animate); + } + this.dirty = false; + } + + private updateColors(startTime: number, delay: number = 50, animate: boolean = true, duration: number = 500): void { + const ids = this.getTxList(); + startTime = startTime || performance.now(); + for (const id of ids) { + this.updateColor(this.txs[id], startTime, delay, animate, duration); + } + this.dirty = false; + } + + private remove(id: string, startTime: number, direction: string = 'left'): TxView | void { + const tx = this.txs[id]; + if (tx) { + this.layout.remove(tx); + this.applyTxUpdate(tx, { + display: { + position: { + x: tx.screenPosition.x + (direction === 'right' ? this.width + this.animationOffset : (direction === 'left' ? -this.width - this.animationOffset : 0)), + y: tx.screenPosition.y + (direction === 'up' ? this.height + this.animationOffset : (direction === 'down' ? -this.height - this.animationOffset : 0)), + } + }, + duration: this.animationDuration, + start: startTime, + delay: 50 + }); + } + delete this.txs[id]; + return tx; + } + + private getTxList(): string[] { + return Object.keys(this.txs); + } + + private saveGridToScreenPosition(tx: TxView): void { + tx.screenPosition = this.gridToScreen(tx.gridPosition); + } + + // convert grid coordinates to screen coordinates + private gridToScreen(position: Square | void): Square { + if (position) { + const slotSize = (position.s * this.gridSize); + const squareSize = slotSize - (this.unitPadding * 2); + + // The grid is laid out notionally left-to-right, bottom-to-top, + // so we rotate and/or flip the y axis to match the target configuration. + // + // e.g. for flip = true, orientation = 'left': + // + // grid screen + // ________ ________ ________ + // | | | | | a| + // | | flip | | rotate | c | + // | c | --> | c | --> | | + // |a______b| |b______a| |_______b| + + let x = (this.gridSize * position.x) + (slotSize / 2); + let y = (this.gridSize * position.y) + (slotSize / 2); + let t; + if (this.flip) { + x = this.width - x; + } + switch (this.orientation) { + case 'left': + t = x; + x = this.width - y; + y = t; + break; + case 'right': + t = x; + x = y; + y = t; + break; + case 'bottom': + y = this.height - y; + break; + } + return { + x: x + this.unitPadding - (slotSize / 2), + y: y + this.unitPadding - (slotSize / 2), + s: squareSize + }; + } else { + return { x: 0, y: 0, s: 0 }; + } + } + + private screenToGrid(position: Position): Position { + let x = position.x; + let y = this.height - position.y; + let t; + + switch (this.orientation) { + case 'left': + t = x; + x = y; + y = this.width - t; + break; + case 'right': + t = x; + x = y; + y = t; + break; + case 'bottom': + y = this.height - y; + break; + } + if (this.flip) { + x = this.width - x; + } + return { + x: Math.floor(x / this.gridSize), + y: Math.floor(y / this.gridSize) + }; + } + + // calculates and returns the size of the tx in multiples of the grid size + private txSize(tx: TxView): number { + const scale = Math.max(1, Math.round(Math.sqrt(1.1 * tx.vsize / this.vbytesPerUnit))); + return Math.min(this.gridWidth, Math.max(1, scale)); // bound between 1 and the max displayable size (just in case!) + } + + private place(tx: TxView): void { + const size = this.txSize(tx); + this.layout.insert(tx, size); + } + + private tryInsertByFee(tx: TxView): boolean { + const size = this.txSize(tx); + const position = this.layout.tryInsertByFee(tx, size); + if (position) { + this.txs[tx.txid] = tx; + return true; + } else { + return false; + } + } + + // Add a list of transactions to the layout, + // keeping everything approximately sorted by feerate. + private placeBatch(txs: TxView[]): void { + if (txs.length) { + // grab the new tx with the highest fee rate + txs = txs.sort(feeRateDescending); + const maxSize = 2 * txs.reduce((max, tx) => { + return Math.max(this.txSize(tx), max); + }, 1); + + // find a reasonable place for it in the layout + const root = this.layout.getReplacementRoot(txs[0].feerate, maxSize); + + // extract a sub tree of transactions from the layout, rooted at that point + const popped = this.layout.popTree(root.x, root.y, maxSize); + // combine those with the new transactions and sort + txs = txs.concat(popped); + txs = txs.sort(feeRateDescending); + + // insert everything back into the layout + txs.forEach(tx => { + this.txs[tx.txid] = tx; + this.place(tx); + }); + } + } + + private removeBatch(ids: string[], startTime: number, direction: string = 'left'): TxView[] { + if (!startTime) { + startTime = performance.now(); + } + return ids.map(id => { + return this.remove(id, startTime, direction); + }).filter(tx => tx != null) as TxView[]; + } +} + + +class Slot { + l: number; + r: number; + w: number; + + constructor(l: number, r: number) { + this.l = l; + this.r = r; + this.w = r - l; + } + + intersects(slot: Slot): boolean { + return !((slot.r <= this.l) || (slot.l >= this.r)); + } + + subtract(slot: Slot): Slot[] | void { + if (this.intersects(slot)) { + // from middle + if (slot.l > this.l && slot.r < this.r) { + return [ + new Slot(this.l, slot.l), + new Slot(slot.r, this.r) + ]; + } // totally covered + else if (slot.l <= this.l && slot.r >= this.r) { + return []; + } // from left side + else if (slot.l <= this.l) { + if (slot.r === this.r) { + return []; + } else { + return [new Slot(slot.r, this.r)]; + } + } // from right side + else if (slot.r >= this.r) { + if (slot.l === this.l) { + return []; + } else { + return [new Slot(this.l, slot.l)]; + } + } + } else { + return [this]; + } + } +} + +class TxSlot extends Slot { + tx: TxView; + + constructor(l: number, r: number, tx: TxView) { + super(l, r); + this.tx = tx; + } +} + +class Row { + y: number; + w: number; + filled: TxSlot[]; + slots: Slot[]; + + + constructor(y: number, width: number) { + this.y = y; + this.w = width; + this.filled = []; + this.slots = [new Slot(0, this.w)]; + } + + // insert a transaction w/ given width into row starting at position x + insert(x: number, w: number, tx: TxView): void { + const newSlot = new TxSlot(x, x + w, tx); + // insert into filled list + let index = this.filled.findIndex((slot) => (slot.l >= newSlot.r)); + if (index < 0) { + index = this.filled.length; + } + this.filled.splice(index || 0, 0, newSlot); + // subtract from overlapping slots + for (let i = 0; i < this.slots.length; i++) { + if (newSlot.intersects(this.slots[i])) { + const diff = this.slots[i].subtract(newSlot); + if (diff) { + this.slots.splice(i, 1, ...diff); + i += diff.length - 1; + } + } + } + } + + remove(x: number, w: number): void { + const txIndex = this.filled.findIndex((slot) => (slot.l === x) ); + this.filled.splice(txIndex, 1); + + const newSlot = new Slot(x, x + w); + let slotIndex = this.slots.findIndex((slot) => (slot.l >= newSlot.r) ); + if (slotIndex < 0) { + slotIndex = this.slots.length; + } + this.slots.splice(slotIndex || 0, 0, newSlot); + this.normalize(); + } + + // merge any contiguous empty slots + private normalize(): void { + for (let i = 0; i < this.slots.length - 1; i++) { + if (this.slots[i].r === this.slots[i + 1].l) { + this.slots[i].r = this.slots[i + 1].r; + this.slots[i].w += this.slots[i + 1].w; + this.slots.splice(i + 1, 1); + i--; + } + } + } + + txAt(x: number): TxView | void { + let i = 0; + while (i < this.filled.length && this.filled[i].l <= x) { + if (this.filled[i].l <= x && this.filled[i].r > x) { + return this.filled[i].tx; + } + i++; + } + } + + getSlotsBetween(left: number, right: number): TxSlot[] { + const range = new Slot(left, right); + return this.filled.filter(slot => { + return slot.intersects(range); + }); + } + + slotAt(x: number): Slot | void { + let i = 0; + while (i < this.slots.length && this.slots[i].l <= x) { + if (this.slots[i].l <= x && this.slots[i].r > x) { + return this.slots[i]; + } + i++; + } + } + + getAvgFeerate(): number { + let count = 0; + let total = 0; + this.filled.forEach(slot => { + if (slot.tx) { + count += slot.w; + total += (slot.tx.feerate * slot.w); + } + }); + return total / count; + } +} + +class BlockLayout { + width: number; + height: number; + rows: Row[]; + txPositions: { [key: string]: Square }; + txs: { [key: string]: TxView }; + + constructor({ width, height }: { width: number, height: number }) { + this.width = width; + this.height = height; + this.rows = [new Row(0, this.width)]; + this.txPositions = {}; + this.txs = {}; + } + + getRow(position: Square): Row { + return this.rows[position.y]; + } + + getTx(position: Square): TxView | void { + if (this.getRow(position)) { + return this.getRow(position).txAt(position.x); + } + } + + addRow(): void { + this.rows.push(new Row(this.rows.length, this.width)); + } + + remove(tx: TxView) { + const position = this.txPositions[tx.txid]; + if (position) { + for (let y = position.y; y < position.y + position.s && y < this.rows.length; y++) { + this.rows[y].remove(position.x, position.s); + } + } + delete this.txPositions[tx.txid]; + delete this.txs[tx.txid]; + } + + insert(tx: TxView, width: number): Square { + const fit = this.fit(tx, width); + + // insert the tx into rows at that position + for (let y = fit.y; y < fit.y + width; y++) { + if (y >= this.rows.length) { + this.addRow(); + } + this.rows[y].insert(fit.x, width, tx); + } + const position = { x: fit.x, y: fit.y, s: width }; + this.txPositions[tx.txid] = position; + this.txs[tx.txid] = tx; + tx.applyGridPosition(position); + return position; + } + + // Find the first slot large enough to hold a transaction of this size + fit(tx: TxView, width: number): Square { + let fit; + for (let y = 0; y < this.rows.length && !fit; y++) { + fit = this.findFit(0, this.width, y, y, width); + } + // fall back to placing tx in a new row at the top of the layout + if (!fit) { + fit = { x: 0, y: this.rows.length }; + } + return fit; + } + + // recursively check rows to see if there's space for a tx (depth-first) + // left/right: initial column boundaries to check + // row: current row to check + // start: starting row + // size: size of space needed + findFit(left: number, right: number, row: number, start: number, size: number): Square { + if ((row - start) >= size || row >= this.rows.length) { + return { x: left, y: start }; + } + for (const slot of this.rows[row].slots) { + const l = Math.max(left, slot.l); + const r = Math.min(right, slot.r); + if (r - l >= size) { + const fit = this.findFit(l, r, row + 1, start, size); + if (fit) { + return fit; + } + } + } + } + + // insert only if the tx fits into a fee-appropriate position + tryInsertByFee(tx: TxView, size: number): Square | void { + const fit = this.fit(tx, size); + + if (this.checkRowFees(fit.y, tx.feerate)) { + // insert the tx into rows at that position + for (let y = fit.y; y < fit.y + size; y++) { + if (y >= this.rows.length) { + this.addRow(); + } + this.rows[y].insert(fit.x, size, tx); + } + const position = { x: fit.x, y: fit.y, s: size }; + this.txPositions[tx.txid] = position; + this.txs[tx.txid] = tx; + tx.applyGridPosition(position); + return position; + } + } + + // Return the first slot with a lower feerate + getReplacementRoot(feerate: number, width: number): Square { + let slot; + for (let row = 0; row <= this.rows.length; row++) { + if (this.rows[row].slots.length > 0) { + return { x: this.rows[row].slots[0].l, y: row }; + } else { + slot = this.rows[row].filled.find(x => { + return x.tx.feerate < feerate; + }); + if (slot) { + return { x: Math.min(slot.l, this.width - width), y: row }; + } + } + } + return { x: 0, y: this.rows.length }; + } + + // remove and return all transactions in a subtree of the layout + popTree(x: number, y: number, width: number) { + const selected: { [key: string]: TxView } = {}; + let left = x; + let right = x + width; + let prevWidth = right - left; + let prevFee = Infinity; + // scan rows upwards within a channel bounded by 'left' and 'right' + for (let row = y; row < this.rows.length; row++) { + let rowMax = 0; + const slots = this.rows[row].getSlotsBetween(left, right); + // check each slot in this row overlapping the search channel + slots.forEach(slot => { + // select the associated transaction + selected[slot.tx.txid] = slot.tx; + rowMax = Math.max(rowMax, slot.tx.feerate); + // widen the search channel to accommodate this slot if necessary + if (slot.w > prevWidth) { + left = slot.l; + right = slot.r; + // if this slot's tx has a higher feerate than the max in the previous row + // (i.e. it's out of position) + // select all txs overlapping the slot's full width in some rows *below* + // to free up space for this tx to sink down to its proper position + if (slot.tx.feerate > prevFee) { + let count = 0; + // keep scanning back down until we find a full row of higher-feerate txs + for (let echo = row - 1; echo >= 0 && count < slot.w; echo--) { + const echoSlots = this.rows[echo].getSlotsBetween(slot.l, slot.r); + count = 0; + echoSlots.forEach(echoSlot => { + selected[echoSlot.tx.txid] = echoSlot.tx; + if (echoSlot.tx.feerate >= slot.tx.feerate) { + count += echoSlot.w; + } + }); + } + } + } + }); + prevWidth = right - left; + prevFee = rowMax; + } + + const txList = Object.values(selected); + + txList.forEach(tx => { + this.remove(tx); + }); + return txList; + } + + // Check if this row has high enough avg fees + // for a tx with this feerate to make sense here + checkRowFees(row: number, targetFee: number): boolean { + // first row is always fine + if (row === 0 || !this.rows[row]) { + return true; + } + return (this.rows[row].getAvgFeerate() > (targetFee * 0.9)); + } + + // drop any free-floating transactions down into empty spaces + applyGravity(): void { + Object.entries(this.txPositions).sort(([keyA, posA], [keyB, posB]) => { + return posA.y - posB.y || posA.x - posB.x; + }).forEach(([txid, position]) => { + // see how far this transaction can fall + let dropTo = position.y; + while (dropTo > 0 && !this.rows[dropTo - 1].getSlotsBetween(position.x, position.x + position.s).length) { + dropTo--; + } + // if it can fall at all + if (dropTo < position.y) { + // remove and reinsert in the row we found + const tx = this.txs[txid]; + this.remove(tx); + this.insert(tx, position.s); + } + }); + } +} + +function feeRateDescending(a: TxView, b: TxView) { + return b.feerate - a.feerate; +} \ No newline at end of file diff --git a/frontend/src/app/components/block-overview-graph/fast-vertex-array.ts b/frontend/src/app/components/block-overview-graph/fast-vertex-array.ts new file mode 100644 index 0000000000..bc09002385 --- /dev/null +++ b/frontend/src/app/components/block-overview-graph/fast-vertex-array.ts @@ -0,0 +1,113 @@ +/* + Utility class for access and management of low-level sprite data + + Maintains a single Float32Array of sprite data, keeping track of empty slots + to allow constant-time insertion and deletion + + Automatically resizes by copying to a new, larger Float32Array when necessary, + or compacting into a smaller Float32Array when there's space to do so. +*/ + +import TxSprite from './tx-sprite'; + +export class FastVertexArray { + length: number; + count: number; + stride: number; + sprites: TxSprite[]; + data: Float32Array; + freeSlots: number[]; + lastSlot: number; + dirty = false; + + constructor(length, stride) { + this.length = length; + this.count = 0; + this.stride = stride; + this.sprites = []; + this.data = new Float32Array(this.length * this.stride); + this.freeSlots = []; + this.lastSlot = 0; + this.dirty = true; + } + + insert(sprite: TxSprite): number { + this.count++; + + let position; + if (this.freeSlots.length) { + position = this.freeSlots.shift(); + } else { + position = this.lastSlot; + this.lastSlot++; + if (this.lastSlot > this.length) { + this.expand(); + } + } + this.sprites[position] = sprite; + return position; + this.dirty = true; + } + + remove(index: number): void { + this.count--; + this.clearData(index); + this.freeSlots.push(index); + this.sprites[index] = null; + if (this.length > 2048 && this.count < (this.length * 0.4)) { + this.compact(); + } + this.dirty = true; + } + + setData(index: number, dataChunk: number[]): void { + this.data.set(dataChunk, (index * this.stride)); + this.dirty = true; + } + + clearData(index: number): void { + this.data.fill(0, (index * this.stride), ((index + 1) * this.stride)); + this.dirty = true; + } + + getData(index: number): Float32Array { + return this.data.subarray(index, this.stride); + } + + expand(): void { + this.length *= 2; + const newData = new Float32Array(this.length * this.stride); + newData.set(this.data); + this.data = newData; + this.dirty = true; + } + + compact(): void { + // New array length is the smallest power of 2 larger than the sprite count (but no smaller than 512) + const newLength = Math.max(512, Math.pow(2, Math.ceil(Math.log2(this.count)))); + if (newLength !== this.length) { + this.length = newLength; + this.data = new Float32Array(this.length * this.stride); + let sprite; + const newSprites = []; + let i = 0; + for (const index in this.sprites) { + sprite = this.sprites[index]; + if (sprite) { + newSprites.push(sprite); + sprite.moveVertexPointer(i); + sprite.compile(); + i++; + } + } + this.sprites = newSprites; + this.freeSlots = []; + this.lastSlot = i; + } + this.dirty = true; + } + + getVertexData(): Float32Array { + return this.data; + } +} diff --git a/frontend/src/app/components/block-overview-graph/sprite-types.ts b/frontend/src/app/components/block-overview-graph/sprite-types.ts new file mode 100644 index 0000000000..45bf86e3c7 --- /dev/null +++ b/frontend/src/app/components/block-overview-graph/sprite-types.ts @@ -0,0 +1,74 @@ +export type Position = { + x: number, + y: number, +}; + +export type Square = Position & { + s?: number +}; + +export type Color = { + r: number, + g: number, + b: number, + a: number, +}; + +export type InterpolatedAttribute = { + a: number, + b: number, + t: number, + v: number, + d: number +}; + +export type Update = Position & { s: number } & Color; + +export type Attributes = { + x: InterpolatedAttribute, + y: InterpolatedAttribute, + s: InterpolatedAttribute, + r: InterpolatedAttribute, + g: InterpolatedAttribute, + b: InterpolatedAttribute, + a: InterpolatedAttribute +}; + +export type OptionalAttributes = { + x?: InterpolatedAttribute, + y?: InterpolatedAttribute, + s?: InterpolatedAttribute, + r?: InterpolatedAttribute, + g?: InterpolatedAttribute, + b?: InterpolatedAttribute, + a?: InterpolatedAttribute +}; + +export type SpriteUpdateParams = { + x?: number, + y?: number, + s?: number, + r?: number, + g?: number, + b?: number, + a?: number + start?: DOMHighResTimeStamp, + duration?: number, + minDuration?: number, + adjust?: boolean, + temp?: boolean +}; + +export type ViewUpdateParams = { + display: { + position?: Square, + color?: Color, + }, + start?: number, + duration?: number, + minDuration?: number, + delay?: number, + jitter?: number, + state?: string, + adjust?: boolean +}; diff --git a/frontend/src/app/components/block-overview-graph/tx-sprite.ts b/frontend/src/app/components/block-overview-graph/tx-sprite.ts new file mode 100644 index 0000000000..75c1577fc6 --- /dev/null +++ b/frontend/src/app/components/block-overview-graph/tx-sprite.ts @@ -0,0 +1,215 @@ +import { FastVertexArray } from './fast-vertex-array'; +import { InterpolatedAttribute, Attributes, OptionalAttributes, SpriteUpdateParams, Update } from './sprite-types'; + +const attribKeys = ['a', 'b', 't', 'v']; +const updateKeys = ['x', 'y', 's', 'r', 'g', 'b', 'a']; + +export default class TxSprite { + static vertexSize = 30; + static vertexCount = 6; + static dataSize: number = (30 * 6); + + vertexArray: FastVertexArray; + vertexPointer: number; + vertexData: number[]; + updateMap: Update; + attributes: Attributes; + tempAttributes: OptionalAttributes; + + + constructor(params: SpriteUpdateParams, vertexArray: FastVertexArray) { + const offsetTime = params.start; + this.vertexArray = vertexArray; + this.vertexData = Array(VI.length).fill(0); + this.updateMap = { + x: 0, y: 0, s: 0, r: 0, g: 0, b: 0, a: 0 + }; + + this.attributes = { + x: { a: params.x, b: params.x, t: offsetTime, v: 0, d: 0 }, + y: { a: params.y, b: params.y, t: offsetTime, v: 0, d: 0 }, + s: { a: params.s, b: params.s, t: offsetTime, v: 0, d: 0 }, + r: { a: params.r, b: params.r, t: offsetTime, v: 0, d: 0 }, + g: { a: params.g, b: params.g, t: offsetTime, v: 0, d: 0 }, + b: { a: params.b, b: params.b, t: offsetTime, v: 0, d: 0 }, + a: { a: params.a, b: params.a, t: offsetTime, v: 0, d: 0 }, + }; + + // Used to temporarily modify the sprite, so that the base view can be resumed later + this.tempAttributes = null; + + this.vertexPointer = this.vertexArray.insert(this); + + this.compile(); + } + + private interpolateAttributes(updateMap: Update, attributes: OptionalAttributes, offsetTime: DOMHighResTimeStamp, v: number, + duration: number, minDuration: number, adjust: boolean): void { + for (const key of Object.keys(updateMap)) { + // for each non-null attribute: + if (updateMap[key] != null) { + // calculate current interpolated value, and set as 'from' + interpolateAttributeStart(attributes[key], offsetTime); + // update start time + attributes[key].t = offsetTime; + + if (!adjust || (duration && attributes[key].d === 0)) { + attributes[key].v = v; + attributes[key].d = duration; + } else if (minDuration > attributes[key].d) { + // enforce minimum transition duration + attributes[key].v = 1 / minDuration; + attributes[key].d = minDuration; + } + // set 'to' to target value + attributes[key].b = updateMap[key]; + } + } + } + + /* + params: + x, y, s: position & size of the sprite + r, g, b, a: color & opacity + start: performance.now() timestamp, when to start the transition + duration: of the tweening animation + adjust: if true, alter the target value of any conflicting transitions without changing the duration + minDuration: minimum remaining transition duration when adjust = true + temp: if true, this update is only temporary (can be reversed with 'resume') + */ + update(params: SpriteUpdateParams): void { + const offsetTime = params.start || performance.now(); + const v = params.duration > 0 ? (1 / params.duration) : 0; + + updateKeys.forEach(key => { + this.updateMap[key] = params[key]; + }); + + const isModified = !!this.tempAttributes; + if (!params.temp) { + this.interpolateAttributes(this.updateMap, this.attributes, offsetTime, v, params.duration, params.minDuration, params.adjust); + } else { + if (!isModified) { // set up tempAttributes + this.tempAttributes = {}; + for (const key of Object.keys(this.updateMap)) { + if (this.updateMap[key] != null) { + this.tempAttributes[key] = { ...this.attributes[key] }; + } + } + } + this.interpolateAttributes(this.updateMap, this.tempAttributes, offsetTime, v, params.duration, params.minDuration, params.adjust); + } + + this.compile(); + } + + // Transition back from modified state back to base attributes + resume(duration: number, start: DOMHighResTimeStamp = performance.now()): void { + // If not in modified state, there's nothing to do + if (!this.tempAttributes) { + return; + } + + const offsetTime = start; + const v = duration > 0 ? (1 / duration) : 0; + + for (const key of Object.keys(this.tempAttributes)) { + // If this base attribute is static (fixed or post-transition), transition smoothly back + if (this.attributes[key].v === 0 || (this.attributes[key].t + this.attributes[key].d) <= start) { + // calculate current interpolated value, and set as 'from' + interpolateAttributeStart(this.tempAttributes[key], offsetTime); + this.attributes[key].a = this.tempAttributes[key].a; + this.attributes[key].t = offsetTime; + this.attributes[key].v = v; + this.attributes[key].d = duration; + } + } + + this.tempAttributes = null; + + this.compile(); + } + + // Write current state into the graphics vertex array for rendering + compile(): void { + let attributes = this.attributes; + if (this.tempAttributes) { + attributes = { + ...this.attributes, + ...this.tempAttributes + }; + } + const size = attributes.s; + + // update vertex data in place + // ugly, but avoids overhead of allocating large temporary arrays + const vertexStride = VI.length + 2; + for (let vertex = 0; vertex < 6; vertex++) { + this.vertexData[vertex * vertexStride] = vertexOffsetFactors[vertex][0]; + this.vertexData[(vertex * vertexStride) + 1] = vertexOffsetFactors[vertex][1]; + for (let step = 0; step < VI.length; step++) { + // components of each field in the vertex array are defined by an entry in VI: + // VI[i].a is the attribute, VI[i].f is the inner field, VI[i].offA and VI[i].offB are offset factors + this.vertexData[(vertex * vertexStride) + step + 2] = attributes[VI[step].a][VI[step].f]; + } + } + + this.vertexArray.setData(this.vertexPointer, this.vertexData); + } + + moveVertexPointer(index: number): void { + this.vertexPointer = index; + } + + destroy(): void { + this.vertexArray.remove(this.vertexPointer); + this.vertexPointer = null; + } +} + +// expects 0 <= x <= 1 +function smootherstep(x: number): number { + const ix = 1 - x; + x = x * x; + return x / (x + ix * ix); +} + +function interpolateAttributeStart(attribute: InterpolatedAttribute, start: DOMHighResTimeStamp): void { + if (attribute.v === 0 || (attribute.t + attribute.d) <= start) { + // transition finished, next transition starts from current end state + // (clamp to 1) + attribute.a = attribute.b; + attribute.v = 0; + attribute.d = 0; + } else if (attribute.t > start) { + // transition not started + // (clamp to 0) + } else { + // transition in progress + // (interpolate) + const progress = (start - attribute.t); + const delta = smootherstep(progress / attribute.d); + attribute.a = attribute.a + (delta * (attribute.b - attribute.a)); + attribute.d = attribute.d - progress; + attribute.v = 1 / attribute.d; + } +} + +const vertexOffsetFactors = [ + [0, 0], + [1, 1], + [1, 0], + [0, 0], + [1, 1], + [0, 1] +]; + +const VI = []; +updateKeys.forEach((attribute, aIndex) => { + attribKeys.forEach(field => { + VI.push({ + a: attribute, + f: field + }); + }); +}); diff --git a/frontend/src/app/components/block-overview-graph/tx-view.ts b/frontend/src/app/components/block-overview-graph/tx-view.ts new file mode 100644 index 0000000000..742c305f5f --- /dev/null +++ b/frontend/src/app/components/block-overview-graph/tx-view.ts @@ -0,0 +1,194 @@ +import TxSprite from './tx-sprite'; +import { FastVertexArray } from './fast-vertex-array'; +import { SpriteUpdateParams, Square, Color, ViewUpdateParams } from './sprite-types'; +import { hexToColor } from './utils'; +import BlockScene from './block-scene'; +import { TransactionStripped } from '../../interfaces/node-api.interface'; +import { TransactionFlags } from '../../shared/filters.utils'; + +const hoverTransitionTime = 300; +const defaultHoverColor = hexToColor('1bd8f4'); +const defaultHighlightColor = hexToColor('800080'); + +// convert from this class's update format to TxSprite's update format +function toSpriteUpdate(params: ViewUpdateParams): SpriteUpdateParams { + return { + start: (params.start || performance.now()) + (params.delay || 0), + duration: params.duration, + minDuration: params.minDuration, + ...params.display.position, + ...params.display.color, + adjust: params.adjust + }; +} + +export default class TxView implements TransactionStripped { + txid: string; + fee: number; + vsize: number; + value: number; + feerate: number; + acc?: boolean; + rate?: number; + flags: number; + bigintFlags?: bigint | null = 0b00000100_00000000_00000000_00000000n; + time?: number; + status?: 'found' | 'missing' | 'sigop' | 'fresh' | 'freshcpfp' | 'added' | 'prioritized' | 'censored' | 'selected' | 'rbf' | 'accelerated'; + context?: 'projected' | 'actual'; + scene?: BlockScene; + + initialised: boolean; + vertexArray: FastVertexArray; + hover: boolean; + highlight: boolean; + sprite: TxSprite; + hoverColor: Color | void; + highlightColor: Color | void; + + screenPosition: Square; + gridPosition: Square | void; + + dirty: boolean; + + constructor(tx: TransactionStripped, scene: BlockScene) { + this.scene = scene; + this.context = tx.context; + this.txid = tx.txid; + this.time = tx.time || 0; + this.fee = tx.fee; + this.vsize = tx.vsize; + this.value = tx.value; + this.feerate = tx.rate || (tx.fee / tx.vsize); // sort by effective fee rate where available + this.acc = tx.acc; + this.rate = tx.rate; + this.status = tx.status; + this.flags = tx.flags || 0; + this.bigintFlags = tx.flags ? (BigInt(tx.flags) | (this.acc ? TransactionFlags.acceleration : 0n)): 0n; + this.initialised = false; + this.vertexArray = scene.vertexArray; + + this.hover = false; + + this.screenPosition = { x: 0, y: 0, s: 0 }; + + this.dirty = true; + } + + destroy(): void { + if (this.sprite) { + this.sprite.destroy(); + this.sprite = null; + this.initialised = false; + } + } + + applyGridPosition(position: Square): void { + if (!this.gridPosition) { + this.gridPosition = { x: 0, y: 0, s: 0 }; + } + if (this.gridPosition.x !== position.x || this.gridPosition.y !== position.y || this.gridPosition.s !== position.s) { + this.gridPosition.x = position.x; + this.gridPosition.y = position.y; + this.gridPosition.s = position.s; + this.dirty = true; + } + } + + /* + display: defines the final appearance of the sprite + position: { x, y, s } (coordinates & size) + color: { r, g, b, a} (color channels & alpha) + duration: of the tweening animation from the previous display state + start: performance.now() timestamp, when to start the transition + delay: additional milliseconds to wait before starting + jitter: if set, adds a random amount to the delay, + adjust: if true, modify an in-progress transition instead of replacing it + + returns minimum transition end time + */ + update(params: ViewUpdateParams): number { + if (params.jitter) { + params.delay += (Math.random() * params.jitter); + } + + if (!this.initialised || !this.sprite) { + this.initialised = true; + this.sprite = new TxSprite( + toSpriteUpdate(params), + this.vertexArray + ); + // apply any pending hover event + if (this.hover) { + params.duration = Math.max(params.duration, hoverTransitionTime); + this.sprite.update({ + ...this.hoverColor, + duration: hoverTransitionTime, + adjust: false, + temp: true + }); + } + } else { + this.sprite.update( + toSpriteUpdate(params) + ); + } + this.dirty = false; + return (params.start || performance.now()) + (params.delay || 0) + (params.duration || 0); + } + + // Temporarily override the tx color + // returns minimum transition end time + setHover(hoverOn: boolean, color: Color | void = defaultHoverColor): number { + if (hoverOn) { + this.hover = true; + this.hoverColor = color; + + this.sprite.update({ + ...this.hoverColor, + duration: hoverTransitionTime, + adjust: false, + temp: true + }); + } else { + this.hover = false; + this.hoverColor = null; + if (this.highlight) { + this.setHighlight(true, this.highlightColor); + } else { + if (this.sprite) { + this.sprite.resume(hoverTransitionTime); + } + } + } + this.dirty = false; + return performance.now() + hoverTransitionTime; + } + + // Temporarily override the tx color + // returns minimum transition end time + setHighlight(highlightOn: boolean, color: Color | void = defaultHighlightColor): number { + if (highlightOn) { + this.highlight = true; + this.highlightColor = color; + + this.sprite.update({ + ...this.highlightColor, + duration: hoverTransitionTime, + adjust: false, + temp: true + }); + } else { + this.highlight = false; + this.highlightColor = null; + if (this.hover) { + this.setHover(true, this.hoverColor); + } else { + if (this.sprite) { + this.sprite.resume(hoverTransitionTime); + } + } + } + this.dirty = false; + return performance.now() + hoverTransitionTime; + } +} diff --git a/frontend/src/app/components/block-overview-graph/utils.ts b/frontend/src/app/components/block-overview-graph/utils.ts new file mode 100644 index 0000000000..9a6d9da43c --- /dev/null +++ b/frontend/src/app/components/block-overview-graph/utils.ts @@ -0,0 +1,189 @@ +import { feeLevels, defaultMempoolFeeColors, contrastMempoolFeeColors } from '../../app.constants'; +import { Color } from './sprite-types'; +import TxView from './tx-view'; + +export function hexToColor(hex: string): Color { + return { + r: parseInt(hex.slice(0, 2), 16) / 255, + g: parseInt(hex.slice(2, 4), 16) / 255, + b: parseInt(hex.slice(4, 6), 16) / 255, + a: hex.length > 6 ? parseInt(hex.slice(6, 8), 16) / 255 : 1 + }; +} + +export function desaturate(color: Color, amount: number): Color { + const gray = (color.r + color.g + color.b) / 6; + return { + r: color.r + ((gray - color.r) * amount), + g: color.g + ((gray - color.g) * amount), + b: color.b + ((gray - color.b) * amount), + a: color.a, + }; +} + +export function darken(color: Color, amount: number): Color { + return { + r: color.r * amount, + g: color.g * amount, + b: color.b * amount, + a: color.a, + }; +} + +export function setOpacity(color: Color, opacity: number): Color { + return { + ...color, + a: opacity + }; +} + +interface ColorPalette { + base: Color[], + audit: Color[], + marginal: Color[], + baseLevel: (tx: TxView, rate: number, time: number) => number, +} + +// precomputed colors +const defaultColors: { [key: string]: ColorPalette } = { + fee: { + base: defaultMempoolFeeColors.map(hexToColor), + audit: [], + marginal: [], + baseLevel: (tx: TxView, rate: number) => feeLevels.findIndex((feeLvl) => Math.max(1, rate) < feeLvl) - 1 + }, +} +for (const key in defaultColors) { + const base = defaultColors[key].base; + defaultColors[key].audit = base.map((color) => darken(desaturate(color, 0.3), 0.9)); + defaultColors[key].marginal = base.map((color) => darken(desaturate(color, 0.8), 1.1)); + defaultColors['unmatched' + key] = { + base: defaultColors[key].base.map(c => setOpacity(c, 0.2)), + audit: defaultColors[key].audit.map(c => setOpacity(c, 0.2)), + marginal: defaultColors[key].marginal.map(c => setOpacity(c, 0.2)), + baseLevel: defaultColors[key].baseLevel, + }; +} + +export { defaultColors as defaultColors }; + +export const defaultAuditColors = { + censored: hexToColor('f344df'), + missing: darken(desaturate(hexToColor('f344df'), 0.3), 0.7), + added: hexToColor('0099ff'), + prioritized: darken(desaturate(hexToColor('0099ff'), 0.3), 0.7), + accelerated: hexToColor('8f5ff6'), +}; + +const contrastColors: { [key: string]: ColorPalette } = { + fee: { + base: contrastMempoolFeeColors.map(hexToColor), + audit: [], + marginal: [], + baseLevel: (tx: TxView, rate: number) => feeLevels.findIndex((feeLvl) => Math.max(1, rate) < feeLvl) - 1 + }, +} +for (const key in contrastColors) { + const base = contrastColors[key].base; + contrastColors[key].audit = base.map((color) => darken(desaturate(color, 0.3), 0.9)); + contrastColors[key].marginal = base.map((color) => darken(desaturate(color, 0.8), 1.1)); + contrastColors['unmatched' + key] = { + base: contrastColors[key].base.map(c => setOpacity(c, 0.2)), + audit: contrastColors[key].audit.map(c => setOpacity(c, 0.2)), + marginal: contrastColors[key].marginal.map(c => setOpacity(c, 0.2)), + baseLevel: contrastColors[key].baseLevel, + }; +} + +export { contrastColors as contrastColors }; + +export const contrastAuditColors = { + censored: hexToColor('ffa8ff'), + missing: darken(desaturate(hexToColor('ffa8ff'), 0.3), 0.7), + added: hexToColor('00bb98'), + prioritized: darken(desaturate(hexToColor('00bb98'), 0.3), 0.7), + accelerated: hexToColor('8f5ff6'), +}; + +export function defaultColorFunction( + tx: TxView, + colors: { base: Color[], audit: Color[], marginal: Color[], baseLevel: (tx: TxView, rate: number, time: number) => number } = defaultColors.fee, + auditColors: { [status: string]: Color } = defaultAuditColors, + relativeTime?: number, +): Color { + const rate = tx.fee / tx.vsize; // color by simple single-tx fee rate + const levelIndex = colors.baseLevel(tx, rate, relativeTime || (Date.now() / 1000)); + const levelColor = colors.base[levelIndex] || colors.base[defaultMempoolFeeColors.length - 1]; + // Normal mode + if (!tx.scene?.highlightingEnabled) { + if (tx.acc) { + return auditColors.accelerated; + } else { + return levelColor; + } + return levelColor; + } + // Block audit + switch(tx.status) { + case 'censored': + return auditColors.censored; + case 'missing': + case 'sigop': + case 'rbf': + return colors.marginal[levelIndex] || colors.marginal[defaultMempoolFeeColors.length - 1]; + case 'fresh': + case 'freshcpfp': + return auditColors.missing; + case 'added': + return auditColors.added; + case 'prioritized': + return auditColors.prioritized; + case 'selected': + return colors.marginal[levelIndex] || colors.marginal[defaultMempoolFeeColors.length - 1]; + case 'accelerated': + return auditColors.accelerated; + case 'found': + if (tx.context === 'projected') { + return colors.audit[levelIndex] || colors.audit[defaultMempoolFeeColors.length - 1]; + } else { + return levelColor; + } + default: + if (tx.acc) { + return auditColors.accelerated; + } else { + return levelColor; + } + } +} + +export function contrastColorFunction( + tx: TxView, + colors: { base: Color[], audit: Color[], marginal: Color[], baseLevel: (tx: TxView, rate: number, time: number) => number } = contrastColors.fee, + auditColors: { [status: string]: Color } = contrastAuditColors, + relativeTime?: number, +): Color { + return defaultColorFunction(tx, colors, auditColors, relativeTime); +} + +export function ageColorFunction( + tx: TxView, + colors: { base: Color[], audit: Color[], marginal: Color[], baseLevel: (tx: TxView, rate: number, time: number) => number } = defaultColors.fee, + auditColors: { [status: string]: Color } = defaultAuditColors, + relativeTime?: number, + theme?: string, +): Color { + if (tx.acc || tx.status === 'accelerated') { + return auditColors.accelerated; + } + + const color = theme !== 'contrast' && theme !== 'bukele' ? defaultColorFunction(tx, colors, auditColors, relativeTime) : contrastColorFunction(tx, colors, auditColors, relativeTime); + + const ageLevel = (!tx.time ? 0 : (0.8 * Math.tanh((1 / 15) * Math.log2((Math.max(1, 0.6 * ((relativeTime - tx.time) - 60))))))); + return { + r: color.r, + g: color.g, + b: color.b, + a: color.a * (1 - ageLevel) + }; +} diff --git a/frontend/src/app/components/block-overview-tooltip/block-overview-tooltip.component.html b/frontend/src/app/components/block-overview-tooltip/block-overview-tooltip.component.html new file mode 100644 index 0000000000..bfb4cd206f --- /dev/null +++ b/frontend/src/app/components/block-overview-tooltip/block-overview-tooltip.component.html @@ -0,0 +1,97 @@ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + {{ activeFilters.rbf }} + + + + +
Transaction + {{ txid | shortenString : 16}} +
First seenFirst seenFirst seenConfirmed
Amount
Fee{{ fee | number }} sat   +
Fee rate + +
Effective fee rateAccelerated fee rate + +
Virtual size
Weight
Audit status + + Match + Removed + Marginal fee rate + High sigop count + Recently broadcasted + Recently CPFP'd + Added + Prioritized + Marginal fee rate + Conflict + Accelerated + +
+
+ Accelerated + + {{ filter.label }} + +
+
+
diff --git a/frontend/src/app/components/block-overview-tooltip/block-overview-tooltip.component.scss b/frontend/src/app/components/block-overview-tooltip/block-overview-tooltip.component.scss new file mode 100644 index 0000000000..28708506bc --- /dev/null +++ b/frontend/src/app/components/block-overview-tooltip/block-overview-tooltip.component.scss @@ -0,0 +1,77 @@ +.block-overview-tooltip { + position: absolute; + background: color-mix(in srgb, var(--active-bg) 95%, transparent); + border-radius: 4px; + box-shadow: 1px 1px 10px rgba(0,0,0,0.5); + color: var(--tooltip-grey); + display: flex; + flex-direction: column; + justify-content: space-between; + padding: 10px 15px; + text-align: left; + min-width: 340px; + max-width: 400px; + pointer-events: none; + z-index: 11; + + &.clickable { + pointer-events: all; + } +} + +th, td { + &.label { + width: 30%; + } + &.value { + width: 70%; + text-align: end; + } +} + +.badge.badge-accelerated { + background-color: #653b9c; + box-shadow: #ad7de57f 0px 0px 12px -2px; + color: white; + animation: acceleratePulse 1s infinite; +} + +.tags { + display: flex; + flex-wrap: wrap; + row-gap: 0.25em; + margin-top: 0.2em; + max-width: 310px; + + .badge { + border-radius: 0.2rem; + padding: 0.2em 0.5em; + margin-right: 0.25em; + } + + .filter-tag { + background: #181b2daf; + border: solid 1px var(--primary); + color: white; + transition: background-color 300ms; + + &.matching { + background-color: var(--primary); + } + } + + &.any-mode { + .filter-tag { + border: solid 1px var(--success); + &.matching { + background-color: var(--success); + } + } + } +} + +@keyframes acceleratePulse { + 0% { background-color: #653b9c; box-shadow: #ad7de57f 0px 0px 12px -2px; } + 50% { background-color: #8457bb; box-shadow: #ad7de5 0px 0px 18px -2px;} + 100% { background-color: #653b9c; box-shadow: #ad7de57f 0px 0px 12px -2px; } +} \ No newline at end of file diff --git a/frontend/src/app/components/block-overview-tooltip/block-overview-tooltip.component.ts b/frontend/src/app/components/block-overview-tooltip/block-overview-tooltip.component.ts new file mode 100644 index 0000000000..0a606983e7 --- /dev/null +++ b/frontend/src/app/components/block-overview-tooltip/block-overview-tooltip.component.ts @@ -0,0 +1,103 @@ +import { Component, ElementRef, ViewChild, Input, OnChanges, ChangeDetectionStrategy, ChangeDetectorRef } from '@angular/core'; +import { Position } from '../../components/block-overview-graph/sprite-types.js'; +import { Price } from '../../services/price.service'; +import { TransactionStripped } from '../../interfaces/node-api.interface.js'; +import { Filter, FilterMode, TransactionFlags, toFilters } from '../../shared/filters.utils'; +import { Block } from '../../interfaces/electrs.interface.js'; + +@Component({ + selector: 'app-block-overview-tooltip', + templateUrl: './block-overview-tooltip.component.html', + styleUrls: ['./block-overview-tooltip.component.scss'], +}) +export class BlockOverviewTooltipComponent implements OnChanges { + @Input() tx: TransactionStripped | void; + @Input() relativeTime?: number; + @Input() cursorPosition: Position; + @Input() clickable: boolean; + @Input() auditEnabled: boolean = false; + @Input() blockConversion: Price; + @Input() filterFlags: bigint | null = null; + @Input() filterMode: FilterMode = 'and'; + + txid = ''; + time: number = 0; + fee = 0; + value = 0; + vsize = 1; + feeRate = 0; + effectiveRate; + acceleration; + hasEffectiveRate: boolean = false; + timeMode: 'mempool' | 'mined' | 'missed' | 'after' = 'mempool'; + filters: Filter[] = []; + activeFilters: { [key: string]: boolean } = {}; + + tooltipPosition: Position = { x: 0, y: 0 }; + + @ViewChild('tooltip') tooltipElement: ElementRef; + + constructor( + private cd: ChangeDetectorRef, + ) {} + + ngOnChanges(changes): void { + if (changes.cursorPosition && changes.cursorPosition.currentValue) { + let x = changes.cursorPosition.currentValue.x + 10; + let y = changes.cursorPosition.currentValue.y + 10; + if (this.tooltipElement) { + const elementBounds = this.tooltipElement.nativeElement.getBoundingClientRect(); + const parentBounds = this.tooltipElement.nativeElement.offsetParent.getBoundingClientRect(); + if ((parentBounds.left + x + elementBounds.width) > parentBounds.right) { + x = Math.max(0, parentBounds.width - elementBounds.width - 10); + } + if (y + elementBounds.height > parentBounds.height) { + y = y - elementBounds.height - 20; + } + } + this.tooltipPosition = { x, y }; + } + + if (this.tx && (changes.tx || changes.filterFlags || changes.filterMode)) { + this.txid = this.tx.txid || ''; + this.time = this.tx.time || 0; + this.fee = this.tx.fee || 0; + this.value = this.tx.value || 0; + this.vsize = this.tx.vsize || 1; + this.feeRate = this.fee / this.vsize; + this.effectiveRate = this.tx.rate; + const txFlags = BigInt(this.tx.flags) || 0n; + this.acceleration = this.tx.acc || (txFlags & TransactionFlags.acceleration); + this.hasEffectiveRate = this.tx.acc || !(Math.abs((this.fee / this.vsize) - this.effectiveRate) <= 0.1 && Math.abs((this.fee / Math.ceil(this.vsize)) - this.effectiveRate) <= 0.1) + || (txFlags && (txFlags & (TransactionFlags.cpfp_child | TransactionFlags.cpfp_parent)) > 0n); + this.filters = this.tx.flags ? toFilters(txFlags).filter(f => f.tooltip) : []; + this.activeFilters = {} + for (const filter of this.filters) { + if (this.filterFlags && (this.filterFlags & BigInt(filter.flag))) { + this.activeFilters[filter.key] = true; + } + } + + if (!this.relativeTime) { + this.timeMode = 'mempool'; + } else { + if (this.tx?.context === 'actual' || this.tx?.status === 'found') { + this.timeMode = 'mined'; + } else { + const time = this.relativeTime || Date.now(); + if (this.time <= time) { + this.timeMode = 'missed'; + } else { + this.timeMode = 'after'; + } + } + } + + this.cd.markForCheck(); + } + } + + getTooltipLeftPosition(): string { + return window.innerWidth < 392 ? '-50px' : this.tooltipPosition.x + 'px'; + } +} diff --git a/frontend/src/app/components/block-rewards-graph/block-rewards-graph.component.html b/frontend/src/app/components/block-rewards-graph/block-rewards-graph.component.html new file mode 100644 index 0000000000..b239a0982a --- /dev/null +++ b/frontend/src/app/components/block-rewards-graph/block-rewards-graph.component.html @@ -0,0 +1,47 @@ + + +
+ +
+
+ Block Rewards + +
+ +
+
+ + + + + + + +
+
+
+ +
+
+
+
+
+ +
\ No newline at end of file diff --git a/frontend/src/app/components/block-rewards-graph/block-rewards-graph.component.scss b/frontend/src/app/components/block-rewards-graph/block-rewards-graph.component.scss new file mode 100644 index 0000000000..98f6892029 --- /dev/null +++ b/frontend/src/app/components/block-rewards-graph/block-rewards-graph.component.scss @@ -0,0 +1,62 @@ +.card-header { + border-bottom: 0; + font-size: 18px; + @media (min-width: 465px) { + font-size: 20px; + } + @media (min-width: 992px) { + height: 40px; + } +} + +.main-title { + position: relative; + color: var(--fg); + opacity: var(--opacity); + margin-top: -13px; + font-size: 10px; + text-transform: uppercase; + font-weight: 500; + text-align: center; + padding-bottom: 3px; +} + +.full-container { + display: flex; + flex-direction: column; + padding: 0px 15px; + width: 100%; + height: calc(100vh - 225px); + min-height: 400px; + @media (min-width: 992px) { + height: calc(100vh - 150px); + } +} + +.chart { + display: flex; + flex: 1; + height: 100%; + padding-bottom: 20px; + padding-right: 10px; + @media (max-width: 992px) { + padding-bottom: 25px; + } + @media (max-width: 829px) { + padding-bottom: 50px; + } + @media (max-width: 767px) { + padding-bottom: 25px; + } + @media (max-width: 629px) { + padding-bottom: 55px; + } + @media (max-width: 567px) { + padding-bottom: 55px; + } +} +.chart-widget { + width: 100%; + height: 100%; + max-height: 270px; +} diff --git a/frontend/src/app/components/block-rewards-graph/block-rewards-graph.component.ts b/frontend/src/app/components/block-rewards-graph/block-rewards-graph.component.ts new file mode 100644 index 0000000000..d0c1544206 --- /dev/null +++ b/frontend/src/app/components/block-rewards-graph/block-rewards-graph.component.ts @@ -0,0 +1,329 @@ +import { ChangeDetectionStrategy, Component, Inject, Input, LOCALE_ID, OnInit } from '@angular/core'; +import { echarts, EChartsOption } from '../../graphs/echarts'; +import { Observable } from 'rxjs'; +import { map, share, startWith, switchMap, tap } from 'rxjs/operators'; +import { ApiService } from '../../services/api.service'; +import { SeoService } from '../../services/seo.service'; +import { formatNumber } from '@angular/common'; +import { UntypedFormBuilder, UntypedFormGroup } from '@angular/forms'; +import { download, formatterXAxis } from '../../shared/graphs.utils'; +import { MiningService } from '../../services/mining.service'; +import { StorageService } from '../../services/storage.service'; +import { ActivatedRoute } from '@angular/router'; +import { FiatShortenerPipe } from '../../shared/pipes/fiat-shortener.pipe'; +import { FiatCurrencyPipe } from '../../shared/pipes/fiat-currency.pipe'; +import { StateService } from '../../services/state.service'; + +@Component({ + selector: 'app-block-rewards-graph', + templateUrl: './block-rewards-graph.component.html', + styleUrls: ['./block-rewards-graph.component.scss'], + styles: [` + .loadingGraphs { + position: absolute; + top: 50%; + left: calc(50% - 15px); + z-index: 100; + } + `], + changeDetection: ChangeDetectionStrategy.OnPush, +}) +export class BlockRewardsGraphComponent implements OnInit { + @Input() right: number | string = 45; + @Input() left: number | string = 75; + + miningWindowPreference: string; + radioGroupForm: UntypedFormGroup; + + chartOptions: EChartsOption = {}; + chartInitOptions = { + renderer: 'svg', + }; + + statsObservable$: Observable; + isLoading = true; + formatNumber = formatNumber; + timespan = ''; + chartInstance: any = undefined; + + currency: string; + + constructor( + @Inject(LOCALE_ID) public locale: string, + private seoService: SeoService, + private apiService: ApiService, + private formBuilder: UntypedFormBuilder, + private miningService: MiningService, + private storageService: StorageService, + public stateService: StateService, + private route: ActivatedRoute, + private fiatShortenerPipe: FiatShortenerPipe, + private fiatCurrencyPipe: FiatCurrencyPipe, + ) { + this.currency = 'USD'; + } + + ngOnInit(): void { + this.seoService.setTitle($localize`:@@8ba8fe810458280a83df7fdf4c614dfc1a826445:Block Rewards`); + this.seoService.setDescription($localize`:@@meta.description.bitcoin.graphs.block-rewards:See Bitcoin block rewards in BTC and USD visualized over time. Block rewards are the total funds miners earn from the block subsidy and fees.`); + this.miningWindowPreference = this.miningService.getDefaultTimespan('3m'); + this.radioGroupForm = this.formBuilder.group({ dateSpan: this.miningWindowPreference }); + this.radioGroupForm.controls.dateSpan.setValue(this.miningWindowPreference); + + this.route + .fragment + .subscribe((fragment) => { + if (['1m', '3m', '6m', '1y', '2y', '3y', 'all'].indexOf(fragment) > -1) { + this.radioGroupForm.controls.dateSpan.setValue(fragment, { emitEvent: false }); + } + }); + + this.statsObservable$ = this.radioGroupForm.get('dateSpan').valueChanges + .pipe( + startWith(this.radioGroupForm.controls.dateSpan.value), + switchMap((timespan) => { + this.storageService.setValue('miningWindowPreference', timespan); + this.timespan = timespan; + this.isLoading = true; + return this.apiService.getHistoricalBlockRewards$(timespan) + .pipe( + tap((response) => { + this.prepareChartOptions({ + blockRewards: response.body.map(val => [val.timestamp * 1000, val.avgRewards / 100000000, val.avgHeight]), + blockRewardsFiat: response.body.filter(val => val[this.currency] > 0).map(val => [val.timestamp * 1000, val.avgRewards / 100000000 * val[this.currency], val.avgHeight]), + }); + this.isLoading = false; + }), + map((response) => { + return { + blockCount: parseInt(response.headers.get('x-total-count'), 10), + }; + }), + ); + }), + share() + ); + } + + prepareChartOptions(data) { + let title: object; + if (data.blockRewards.length === 0) { + title = { + textStyle: { + color: 'grey', + fontSize: 15 + }, + text: $localize`:@@23555386d8af1ff73f297e89dd4af3f4689fb9dd:Indexing blocks`, + left: 'center', + top: 'center' + }; + } + + const scaleFactor = 0.1; + + this.chartOptions = { + title: title, + animation: false, + color: [ + new echarts.graphic.LinearGradient(0, 0, 0, 1, [ + { offset: 0, color: '#FDD835' }, + { offset: 1, color: '#FB8C00' }, + ]), + new echarts.graphic.LinearGradient(0, 0, 0, 1, [ + { offset: 0, color: '#C0CA33' }, + { offset: 1, color: '#1B5E20' }, + ]), + ], + grid: { + top: 20, + bottom: 80, + right: this.right, + left: this.left, + }, + tooltip: { + show: !this.isMobile(), + trigger: 'axis', + axisPointer: { + type: 'line' + }, + backgroundColor: 'rgba(17, 19, 31, 1)', + borderRadius: 4, + shadowColor: 'rgba(0, 0, 0, 0.5)', + textStyle: { + color: 'var(--tooltip-grey)', + align: 'left', + }, + borderColor: '#000', + formatter: function (data) { + if (data.length <= 0) { + return ''; + } + let tooltip = ` + ${formatterXAxis(this.locale, this.timespan, parseInt(data[0].axisValue, 10))}
`; + + for (const tick of data) { + if (tick.seriesIndex === 0) { + tooltip += `${tick.marker} ${tick.seriesName}: ${formatNumber(tick.data[1], this.locale, '1.3-3')} BTC
`; + } else if (tick.seriesIndex === 1) { + tooltip += `${tick.marker} ${tick.seriesName}: ${this.fiatCurrencyPipe.transform(tick.data[1], null, this.currency)}
`; + } + } + + tooltip += `* On average around block ${data[0].data[2]}`; + return tooltip; + }.bind(this) + }, + xAxis: data.blockRewards.length === 0 ? undefined : + { + type: 'time', + splitNumber: this.isMobile() ? 5 : 10, + axisLabel: { + hideOverlap: true, + } + }, + legend: data.blockRewards.length === 0 ? undefined : { + data: [ + { + name: 'Rewards BTC', + inactiveColor: 'rgb(110, 112, 121)', + textStyle: { + color: 'white', + }, + icon: 'roundRect', + }, + { + name: 'Rewards ' + this.currency, + inactiveColor: 'rgb(110, 112, 121)', + textStyle: { + color: 'white', + }, + icon: 'roundRect', + }, + ], + }, + yAxis: data.blockRewards.length === 0 ? undefined : [ + { + type: 'value', + axisLabel: { + color: 'rgb(110, 112, 121)', + formatter: (val) => { + return `${val} BTC`; + } + }, + min: (value) => { + return Math.round(value.min * (1.0 - scaleFactor) * 10) / 10; + }, + max: (value) => { + return Math.round(value.max * (1.0 + scaleFactor) * 10) / 10; + }, + splitLine: { + lineStyle: { + type: 'dotted', + color: 'var(--transparent-fg)', + opacity: 0.25, + } + }, + }, + { + min: (value) => { + return Math.round(value.min * (1.0 - scaleFactor) * 10) / 10; + }, + max: (value) => { + return Math.round(value.max * (1.0 + scaleFactor) * 10) / 10; + }, + type: 'value', + position: 'right', + axisLabel: { + color: 'rgb(110, 112, 121)', + formatter: function(val) { + return this.fiatShortenerPipe.transform(val, null, this.currency); + }.bind(this) + }, + splitLine: { + show: false, + }, + }, + ], + series: data.blockRewards.length === 0 ? undefined : [ + { + legendHoverLink: false, + zlevel: 0, + yAxisIndex: 0, + name: 'Rewards BTC', + data: data.blockRewards, + type: 'line', + smooth: 0.25, + symbol: 'none', + }, + { + legendHoverLink: false, + zlevel: 1, + yAxisIndex: 1, + name: 'Rewards ' + this.currency, + data: data.blockRewardsFiat, + type: 'line', + smooth: 0.25, + symbol: 'none', + lineStyle: { + width: 2, + opacity: 0.75, + }, + areaStyle: { + opacity: 0.05, + } + }, + ], + dataZoom: data.blockRewards.length === 0 ? undefined : [{ + type: 'inside', + realtime: true, + zoomLock: true, + maxSpan: 100, + minSpan: 5, + moveOnMouseMove: false, + }, { + showDetail: false, + show: true, + type: 'slider', + brushSelect: false, + realtime: true, + left: 20, + right: 15, + selectedDataBackground: { + lineStyle: { + color: '#fff', + opacity: 0.45, + }, + areaStyle: { + opacity: 0, + } + }, + }], + }; + } + + onChartInit(ec) { + this.chartInstance = ec; + } + + isMobile() { + return (window.innerWidth <= 767.98); + } + + onSaveChart() { + // @ts-ignore + const prevBottom = this.chartOptions.grid.bottom; + const now = new Date(); + // @ts-ignore + this.chartOptions.grid.bottom = 40; + this.chartOptions.backgroundColor = 'var(--active-bg)'; + this.chartInstance.setOption(this.chartOptions); + download(this.chartInstance.getDataURL({ + pixelRatio: 2, + excludeComponents: ['dataZoom'], + }), `block-rewards-${this.timespan}-${Math.round(now.getTime() / 1000)}.svg`); + // @ts-ignore + this.chartOptions.grid.bottom = prevBottom; + this.chartOptions.backgroundColor = 'none'; + this.chartInstance.setOption(this.chartOptions); + } +} diff --git a/frontend/src/app/components/block-sizes-weights-graph/block-sizes-weights-graph.component.html b/frontend/src/app/components/block-sizes-weights-graph/block-sizes-weights-graph.component.html new file mode 100644 index 0000000000..521357c4b0 --- /dev/null +++ b/frontend/src/app/components/block-sizes-weights-graph/block-sizes-weights-graph.component.html @@ -0,0 +1,54 @@ +
+ +
+
+ Block Sizes and Weights + +
+ +
+
+ + + + + + + + + + +
+
+
+ +
+
+
+
+
+ +
diff --git a/frontend/src/app/components/block-sizes-weights-graph/block-sizes-weights-graph.component.scss b/frontend/src/app/components/block-sizes-weights-graph/block-sizes-weights-graph.component.scss new file mode 100644 index 0000000000..98f6892029 --- /dev/null +++ b/frontend/src/app/components/block-sizes-weights-graph/block-sizes-weights-graph.component.scss @@ -0,0 +1,62 @@ +.card-header { + border-bottom: 0; + font-size: 18px; + @media (min-width: 465px) { + font-size: 20px; + } + @media (min-width: 992px) { + height: 40px; + } +} + +.main-title { + position: relative; + color: var(--fg); + opacity: var(--opacity); + margin-top: -13px; + font-size: 10px; + text-transform: uppercase; + font-weight: 500; + text-align: center; + padding-bottom: 3px; +} + +.full-container { + display: flex; + flex-direction: column; + padding: 0px 15px; + width: 100%; + height: calc(100vh - 225px); + min-height: 400px; + @media (min-width: 992px) { + height: calc(100vh - 150px); + } +} + +.chart { + display: flex; + flex: 1; + height: 100%; + padding-bottom: 20px; + padding-right: 10px; + @media (max-width: 992px) { + padding-bottom: 25px; + } + @media (max-width: 829px) { + padding-bottom: 50px; + } + @media (max-width: 767px) { + padding-bottom: 25px; + } + @media (max-width: 629px) { + padding-bottom: 55px; + } + @media (max-width: 567px) { + padding-bottom: 55px; + } +} +.chart-widget { + width: 100%; + height: 100%; + max-height: 270px; +} diff --git a/frontend/src/app/components/block-sizes-weights-graph/block-sizes-weights-graph.component.ts b/frontend/src/app/components/block-sizes-weights-graph/block-sizes-weights-graph.component.ts new file mode 100644 index 0000000000..bf591ad70e --- /dev/null +++ b/frontend/src/app/components/block-sizes-weights-graph/block-sizes-weights-graph.component.ts @@ -0,0 +1,356 @@ +import { ChangeDetectionStrategy, Component, Inject, Input, LOCALE_ID, OnInit, HostBinding } from '@angular/core'; +import { EChartsOption} from '../../graphs/echarts'; +import { Observable } from 'rxjs'; +import { map, share, startWith, switchMap, tap } from 'rxjs/operators'; +import { ApiService } from '../../services/api.service'; +import { SeoService } from '../../services/seo.service'; +import { formatNumber } from '@angular/common'; +import { UntypedFormBuilder, UntypedFormGroup } from '@angular/forms'; +import { StorageService } from '../../services/storage.service'; +import { MiningService } from '../../services/mining.service'; +import { ActivatedRoute } from '@angular/router'; +import { download, formatterXAxis } from '../../shared/graphs.utils'; +import { StateService } from '../../services/state.service'; + +@Component({ + selector: 'app-block-sizes-weights-graph', + templateUrl: './block-sizes-weights-graph.component.html', + styleUrls: ['./block-sizes-weights-graph.component.scss'], + styles: [` + .loadingGraphs { + position: absolute; + top: 50%; + left: calc(50% - 15px); + z-index: 100; + } + `], + changeDetection: ChangeDetectionStrategy.OnPush, +}) +export class BlockSizesWeightsGraphComponent implements OnInit { + @Input() right: number | string = 45; + @Input() left: number | string = 75; + + miningWindowPreference: string; + radioGroupForm: UntypedFormGroup; + + chartOptions: EChartsOption = {}; + chartInitOptions = { + renderer: 'svg', + }; + + @HostBinding('attr.dir') dir = 'ltr'; + + blockSizesWeightsObservable$: Observable; + isLoading = true; + formatNumber = formatNumber; + timespan = ''; + chartInstance: any = undefined; + + constructor( + @Inject(LOCALE_ID) public locale: string, + private seoService: SeoService, + private apiService: ApiService, + private formBuilder: UntypedFormBuilder, + private storageService: StorageService, + private miningService: MiningService, + public stateService: StateService, + private route: ActivatedRoute, + ) { + } + + ngOnInit(): void { + let firstRun = true; + + this.seoService.setTitle($localize`:@@56fa1cd221491b6478998679cba2dc8d55ba330d:Block Sizes and Weights`); + this.seoService.setDescription($localize`:@@meta.description.bitcoin.graphs.block-sizes:See Bitcoin block sizes (MB) and block weights (weight units) visualized over time.`); + this.miningWindowPreference = this.miningService.getDefaultTimespan('24h'); + this.radioGroupForm = this.formBuilder.group({ dateSpan: this.miningWindowPreference }); + this.radioGroupForm.controls.dateSpan.setValue(this.miningWindowPreference); + + this.route + .fragment + .subscribe((fragment) => { + if (['24h', '3d', '1w', '1m', '3m', '6m', '1y', '2y', '3y', 'all'].indexOf(fragment) > -1) { + this.radioGroupForm.controls.dateSpan.setValue(fragment, { emitEvent: false }); + } + }); + + this.blockSizesWeightsObservable$ = this.radioGroupForm.get('dateSpan').valueChanges + .pipe( + startWith(this.radioGroupForm.controls.dateSpan.value), + switchMap((timespan) => { + this.timespan = timespan; + if (!firstRun) { + this.storageService.setValue('miningWindowPreference', timespan); + } + firstRun = false; + this.miningWindowPreference = timespan; + this.isLoading = true; + return this.apiService.getHistoricalBlockSizesAndWeights$(timespan) + .pipe( + tap((response) => { + const data = response.body; + this.prepareChartOptions({ + sizes: data.sizes.map(val => [val.timestamp * 1000, val.avgSize / 1000000, val.avgHeight]), + weights: data.weights.map(val => [val.timestamp * 1000, val.avgWeight / 1000000, val.avgHeight]), + sizePerWeight: data.weights.map((val, i) => [val.timestamp * 1000, data.sizes[i].avgSize / (val.avgWeight / 4), val.avgHeight]), + }); + this.isLoading = false; + }), + map((response) => { + return { + blockCount: parseInt(response.headers.get('x-total-count'), 10), + }; + }), + ); + }), + share() + ); + } + + prepareChartOptions(data) { + let title: object; + if (data.sizes.length === 0) { + title = { + textStyle: { + color: 'grey', + fontSize: 15 + }, + text: $localize`:@@23555386d8af1ff73f297e89dd4af3f4689fb9dd:Indexing blocks`, + left: 'center', + top: 'center' + }; + } + + this.chartOptions = { + title: title, + animation: false, + color: [ + '#FDD835', + '#D81B60', + '#039BE5', + ], + grid: { + top: 30, + bottom: 70, + right: this.right, + left: this.left, + }, + tooltip: { + show: !this.isMobile(), + trigger: 'axis', + axisPointer: { + type: 'line' + }, + backgroundColor: 'rgba(17, 19, 31, 1)', + borderRadius: 4, + shadowColor: 'rgba(0, 0, 0, 0.5)', + textStyle: { + color: 'var(--tooltip-grey)', + align: 'left', + }, + borderColor: '#000', + formatter: (ticks) => { + let tooltip = `${formatterXAxis(this.locale, this.timespan, parseInt(ticks[0].axisValue, 10))}
`; + + for (const tick of ticks) { + if (tick.seriesIndex === 0) { // Size + tooltip += `${tick.marker} ${tick.seriesName}: ${formatNumber(tick.data[1], this.locale, '1.2-2')} MB`; + } else if (tick.seriesIndex === 1) { // Weight + tooltip += `${tick.marker} ${tick.seriesName}: ${formatNumber(tick.data[1], this.locale, '1.2-2')} MWU`; + } else if (tick.seriesIndex === 2) { // Size per weight + tooltip += `${tick.marker} ${tick.seriesName}: ${formatNumber(tick.data[1], this.locale, '1.2-2')} B/vB`; + } + tooltip += `
`; + } + + if (['24h', '3d'].includes(this.timespan)) { + tooltip += `` + $localize`At block: ${ticks[0].data[2]}` + ``; + } else { + tooltip += `` + $localize`Around block: ${ticks[0].data[2]}` + ``; + } + + return tooltip; + } + }, + xAxis: data.sizes.length === 0 ? undefined : { + type: 'time', + splitNumber: this.isMobile() ? 5 : 10, + axisLabel: { + hideOverlap: true, + } + }, + legend: data.sizes.length === 0 ? undefined : { + padding: 10, + data: [ + { + name: $localize`:@@7faaaa08f56427999f3be41df1093ce4089bbd75:Size`, + inactiveColor: 'rgb(110, 112, 121)', + textStyle: { + color: 'white', + }, + icon: 'roundRect', + }, + { + name: $localize`:@@919f2fd60a898850c24b1584362bbf18a4628bcb:Weight`, + inactiveColor: 'rgb(110, 112, 121)', + textStyle: { + color: 'white', + }, + icon: 'roundRect', + }, + { + name: $localize`Size per weight`, + inactiveColor: 'rgb(110, 112, 121)', + textStyle: { + color: 'white', + }, + icon: 'roundRect', + }, + ], + selected: JSON.parse(this.storageService.getValue('sizes_weights_legend')) ?? { + 'Size': true, + 'Weight': true, + 'Size per weight': true, + } + }, + yAxis: data.sizes.length === 0 ? undefined : [ + { + type: 'value', + position: 'left', + min: (value) => { + return value.min * 0.9; + }, + axisLabel: { + color: 'rgb(110, 112, 121)', + formatter: (val) => { + return `${Math.round(val * 100) / 100} MWU`; + } + }, + splitLine: { + lineStyle: { + type: 'dotted', + color: 'var(--transparent-fg)', + opacity: 0.25, + } + }, + } + ], + series: data.sizes.length === 0 ? [] : [ + { + zlevel: 1, + name: $localize`:@@7faaaa08f56427999f3be41df1093ce4089bbd75:Size`, + showSymbol: false, + symbol: 'none', + data: data.sizes, + type: 'line', + lineStyle: { + width: 2, + }, + markLine: { + silent: true, + symbol: 'none', + lineStyle: { + type: 'solid', + color: 'var(--transparent-fg)', + opacity: 1, + width: 1, + }, + data: [{ + yAxis: 1, + label: { + position: 'end', + show: true, + color: '#ffffff', + formatter: `1 MB` + } + }], + } + }, + { + zlevel: 1, + yAxisIndex: 0, + name: $localize`:@@919f2fd60a898850c24b1584362bbf18a4628bcb:Weight`, + showSymbol: false, + symbol: 'none', + data: data.weights, + type: 'line', + lineStyle: { + width: 2, + } + }, + { + zlevel: 1, + yAxisIndex: 0, + name: $localize`Size per weight`, + showSymbol: false, + symbol: 'none', + data: data.sizePerWeight, + type: 'line', + lineStyle: { + width: 2, + } + } + ], + dataZoom: [{ + type: 'inside', + realtime: true, + zoomLock: true, + maxSpan: 100, + minSpan: 5, + moveOnMouseMove: false, + }, { + showDetail: false, + show: true, + type: 'slider', + brushSelect: false, + realtime: true, + left: 20, + right: 15, + selectedDataBackground: { + lineStyle: { + color: '#fff', + opacity: 0.45, + }, + areaStyle: { + opacity: 0, + } + }, + }], + }; + } + + onChartInit(ec) { + if (this.chartInstance !== undefined) { + return; + } + + this.chartInstance = ec; + + this.chartInstance.on('legendselectchanged', (e) => { + this.storageService.setValue('sizes_weights_legend', JSON.stringify(e.selected)); + }); + } + + isMobile() { + return (window.innerWidth <= 767.98); + } + + onSaveChart() { + // @ts-ignore + const prevBottom = this.chartOptions.grid.bottom; + const now = new Date(); + // @ts-ignore + this.chartOptions.grid.bottom = 40; + this.chartOptions.backgroundColor = 'var(--active-bg)'; + this.chartInstance.setOption(this.chartOptions); + download(this.chartInstance.getDataURL({ + pixelRatio: 2, + excludeComponents: ['dataZoom'], + }), `block-sizes-weights-${this.timespan}-${Math.round(now.getTime() / 1000)}.svg`); + // @ts-ignore + this.chartOptions.grid.bottom = prevBottom; + this.chartOptions.backgroundColor = 'none'; + this.chartInstance.setOption(this.chartOptions); + } +} diff --git a/frontend/src/app/components/block-view/block-view.component.html b/frontend/src/app/components/block-view/block-view.component.html new file mode 100644 index 0000000000..f0dc94e2c3 --- /dev/null +++ b/frontend/src/app/components/block-view/block-view.component.html @@ -0,0 +1,15 @@ +
+
+ +
+
diff --git a/frontend/src/app/components/block-view/block-view.component.scss b/frontend/src/app/components/block-view/block-view.component.scss new file mode 100644 index 0000000000..746ac654d3 --- /dev/null +++ b/frontend/src/app/components/block-view/block-view.component.scss @@ -0,0 +1,22 @@ +.block-wrapper { + width: 100vw; + height: 100vh; + background: var(--stat-box-bg); +} + +.block-container { + flex-grow: 0; + flex-shrink: 0; + width: 100vw; + max-width: 100vh; + height: 100vh; + padding: 0; + margin: auto; + display: flex; + justify-content: center; + align-items: center; + + * { + flex-grow: 1; + } +} \ No newline at end of file diff --git a/frontend/src/app/components/block-view/block-view.component.ts b/frontend/src/app/components/block-view/block-view.component.ts new file mode 100644 index 0000000000..5c3b7719c1 --- /dev/null +++ b/frontend/src/app/components/block-view/block-view.component.ts @@ -0,0 +1,180 @@ +import { Component, OnInit, OnDestroy, ViewChild, HostListener } from '@angular/core'; +import { ActivatedRoute, ParamMap, Router } from '@angular/router'; +import { ElectrsApiService } from '../../services/electrs-api.service'; +import { switchMap, tap, catchError, shareReplay, filter } from 'rxjs/operators'; +import { of, Subscription } from 'rxjs'; +import { StateService } from '../../services/state.service'; +import { SeoService } from '../../services/seo.service'; +import { BlockExtended, TransactionStripped } from '../../interfaces/node-api.interface'; +import { ApiService } from '../../services/api.service'; +import { seoDescriptionNetwork } from '../../shared/common.utils'; +import { BlockOverviewGraphComponent } from '../block-overview-graph/block-overview-graph.component'; +import { RelativeUrlPipe } from '../../shared/pipes/relative-url/relative-url.pipe'; + +function bestFitResolution(min, max, n): number { + const target = (min + max) / 2; + let bestScore = Infinity; + let best = null; + for (let i = min; i <= max; i++) { + const remainder = (n % i); + if (remainder < bestScore || (remainder === bestScore && (Math.abs(i - target) < Math.abs(best - target)))) { + bestScore = remainder; + best = i; + } + } + return best; +} + +@Component({ + selector: 'app-block-view', + templateUrl: './block-view.component.html', + styleUrls: ['./block-view.component.scss'] +}) +export class BlockViewComponent implements OnInit, OnDestroy { + network = ''; + block: BlockExtended; + blockHeight: number; + blockHash: string; + rawId: string; + isLoadingBlock = true; + strippedTransactions: TransactionStripped[]; + isLoadingOverview = true; + autofit: boolean = false; + resolution: number = 80; + + overviewSubscription: Subscription; + networkChangedSubscription: Subscription; + queryParamsSubscription: Subscription; + + @ViewChild('blockGraph') blockGraph: BlockOverviewGraphComponent; + + constructor( + private route: ActivatedRoute, + private router: Router, + private electrsApiService: ElectrsApiService, + public stateService: StateService, + private seoService: SeoService, + private apiService: ApiService + ) { } + + ngOnInit(): void { + this.network = this.stateService.network; + + this.queryParamsSubscription = this.route.queryParams.subscribe((params) => { + this.autofit = params.autofit === 'true'; + if (this.autofit) { + this.onResize(); + } + }); + + const block$ = this.route.paramMap.pipe( + switchMap((params: ParamMap) => { + this.rawId = params.get('id') || ''; + + const blockHash: string = params.get('id') || ''; + this.block = undefined; + + let isBlockHeight = false; + if (/^[0-9]+$/.test(blockHash)) { + isBlockHeight = true; + } else { + this.blockHash = blockHash; + } + + this.isLoadingBlock = true; + this.isLoadingOverview = true; + + if (isBlockHeight) { + return this.electrsApiService.getBlockHashFromHeight$(parseInt(blockHash, 10)) + .pipe( + switchMap((hash) => { + if (hash) { + this.blockHash = hash; + return this.apiService.getBlock$(hash); + } else { + return null; + } + }), + catchError(() => { + return of(null); + }), + ); + } + return this.apiService.getBlock$(blockHash); + }), + filter((block: BlockExtended | void) => block != null), + tap((block: BlockExtended) => { + this.block = block; + this.blockHeight = block.height; + + this.seoService.setTitle($localize`:@@block.component.browser-title:Block ${block.height}:BLOCK_HEIGHT:: ${block.id}:BLOCK_ID:`); + if( this.stateService.network === 'liquid' || this.stateService.network === 'liquidtestnet' ) { + this.seoService.setDescription($localize`:@@meta.description.liquid.block:See size, weight, fee range, included transactions, and more for Liquid${seoDescriptionNetwork(this.stateService.network)} block ${block.height}:BLOCK_HEIGHT: (${block.id}:BLOCK_ID:).`); + } else { + this.seoService.setDescription($localize`:@@meta.description.bitcoin.block:See size, weight, fee range, included transactions, audit (expected v actual), and more for Bitcoin${seoDescriptionNetwork(this.stateService.network)} block ${block.height}:BLOCK_HEIGHT: (${block.id}:BLOCK_ID:).`); + } + this.isLoadingBlock = false; + this.isLoadingOverview = true; + }), + shareReplay(1) + ); + + this.overviewSubscription = block$.pipe( + switchMap((block) => this.apiService.getStrippedBlockTransactions$(block.id) + .pipe( + catchError(() => { + return of([]); + }), + switchMap((transactions) => { + return of(transactions); + }) + ) + ), + ) + .subscribe((transactions: TransactionStripped[]) => { + this.strippedTransactions = transactions; + this.isLoadingOverview = false; + if (this.blockGraph) { + this.blockGraph.destroy(); + this.blockGraph.setup(this.strippedTransactions); + } + }, + () => { + this.isLoadingOverview = false; + if (this.blockGraph) { + this.blockGraph.destroy(); + } + }); + + this.networkChangedSubscription = this.stateService.networkChanged$ + .subscribe((network) => this.network = network); + } + + onTxClick(event: { tx: TransactionStripped, keyModifier: boolean }): void { + const url = new RelativeUrlPipe(this.stateService).transform(`/tx/${event.tx.txid}`); + if (!event.keyModifier) { + this.router.navigate([url]); + } else { + window.open(url, '_blank'); + } + } + + @HostListener('window:resize', ['$event']) + onResize(): void { + if (this.autofit) { + this.resolution = bestFitResolution(64, 96, Math.min(window.innerWidth, window.innerHeight)); + } + } + + ngOnDestroy(): void { + if (this.overviewSubscription) { + this.overviewSubscription.unsubscribe(); + } + if (this.networkChangedSubscription) { + this.networkChangedSubscription.unsubscribe(); + } + if (this.queryParamsSubscription) { + this.queryParamsSubscription.unsubscribe(); + } + } +} diff --git a/frontend/src/app/components/block/block-preview.component.html b/frontend/src/app/components/block/block-preview.component.html new file mode 100644 index 0000000000..56fa8886ed --- /dev/null +++ b/frontend/src/app/components/block/block-preview.component.html @@ -0,0 +1,84 @@ +
+ + Block + +
+
+
+
+

+ Genesis + {{ blockHeight }} +

+
+

{{ blockHash.slice(0,32) }}

+

{{ blockHash.slice(32) }}

+
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
Timestamp + {{ block?.timestamp * 1000 | date:'yyyy-MM-dd HH:mm' }} +
Weight
Median fee~
Total fees + + + +
Miner + + + {{ block.extras.pool.name }} + + + + {{ block?.extras.pool.name }} + +
+
+
+ +
+
+
diff --git a/frontend/src/app/components/block/block-preview.component.scss b/frontend/src/app/components/block/block-preview.component.scss new file mode 100644 index 0000000000..cc1546ede6 --- /dev/null +++ b/frontend/src/app/components/block/block-preview.component.scss @@ -0,0 +1,75 @@ +.table { + font-size: 32px; + margin-top: 36px; +} + +.block-titles { + margin: 0; + padding-left: 15px; + padding-right: 15px; + display: flex; + flex-direction: row; + flex-wrap: nowrap; + align-items: center; + justify-content: space-between; + width: 100%; + flex-grow: 1; + + .title { + flex-shrink: 0; + flex-grow: 0; + margin-right: 30px; + font-size: 64px; + } + + .blockhash { + width: 0; + flex-grow: 1; + flex-shrink: 1; + font-family: Consolas,Liberation Mono,Courier New,monospace; + font-size: 32px; + text-align: right; + + .truncate { + max-width: 100%; + overflow: hidden; + white-space: nowrap; + text-overflow: ellipsis; + margin: 0; + + &.left { + direction: rtl; + } + } + } +} + +.table-col { + max-width: calc(100% - 470px); + overflow: hidden; +} + +.chart-container { + flex-grow: 0; + flex-shrink: 0; + width: 480px; + min-width: 480px; + padding: 0; + margin-right: 15px; +} + +::ng-deep .symbol { + font-size: 24px; +} + +.badge { + transition: none; +} + +.pool-logo { + width: 25px; + height: 25px; + position: relative; + top: -1px; + margin-right: 2px; +} diff --git a/frontend/src/app/components/block/block-preview.component.ts b/frontend/src/app/components/block/block-preview.component.ts new file mode 100644 index 0000000000..72da968180 --- /dev/null +++ b/frontend/src/app/components/block/block-preview.component.ts @@ -0,0 +1,201 @@ +import { Component, OnInit, OnDestroy, ViewChild, ElementRef } from '@angular/core'; +import { ActivatedRoute, ParamMap } from '@angular/router'; +import { ElectrsApiService } from '../../services/electrs-api.service'; +import { switchMap, tap, throttleTime, catchError, shareReplay, startWith, pairwise, filter } from 'rxjs/operators'; +import { of, Subscription, asyncScheduler, forkJoin } from 'rxjs'; +import { StateService } from '../../services/state.service'; +import { SeoService } from '../../services/seo.service'; +import { OpenGraphService } from '../../services/opengraph.service'; +import { BlockExtended, TransactionStripped } from '../../interfaces/node-api.interface'; +import { ApiService } from '../../services/api.service'; +import { seoDescriptionNetwork } from '../../shared/common.utils'; +import { BlockOverviewGraphComponent } from '../../components/block-overview-graph/block-overview-graph.component'; +import { ServicesApiServices } from '../../services/services-api.service'; + +@Component({ + selector: 'app-block-preview', + templateUrl: './block-preview.component.html', + styleUrls: ['./block-preview.component.scss'] +}) +export class BlockPreviewComponent implements OnInit, OnDestroy { + network = ''; + block: BlockExtended; + blockHeight: number; + blockHash: string; + rawId: string; + isLoadingBlock = true; + strippedTransactions: TransactionStripped[]; + overviewTransitionDirection: string; + isLoadingOverview = true; + error: any; + blockSubsidy: number; + fees: number; + overviewError: any = null; + + overviewSubscription: Subscription; + networkChangedSubscription: Subscription; + + @ViewChild('blockGraph') blockGraph: BlockOverviewGraphComponent; + + constructor( + private route: ActivatedRoute, + private electrsApiService: ElectrsApiService, + public stateService: StateService, + private seoService: SeoService, + private openGraphService: OpenGraphService, + private apiService: ApiService, + private servicesApiService: ServicesApiServices, + ) { } + + ngOnInit() { + this.network = this.stateService.network; + + const block$ = this.route.paramMap.pipe( + switchMap((params: ParamMap) => { + this.rawId = params.get('id') || ''; + this.openGraphService.waitFor('block-viz-' + this.rawId); + this.openGraphService.waitFor('block-data-' + this.rawId); + + const blockHash: string = params.get('id') || ''; + this.block = undefined; + this.error = undefined; + this.overviewError = undefined; + this.fees = undefined; + + let isBlockHeight = false; + if (/^[0-9]+$/.test(blockHash)) { + isBlockHeight = true; + } else { + this.blockHash = blockHash; + } + + this.isLoadingBlock = true; + this.isLoadingOverview = true; + + if (isBlockHeight) { + return this.electrsApiService.getBlockHashFromHeight$(parseInt(blockHash, 10)) + .pipe( + switchMap((hash) => { + if (hash) { + this.blockHash = hash; + return this.apiService.getBlock$(hash); + } else { + return null; + } + }), + catchError((err) => { + this.error = err; + this.seoService.logSoft404(); + this.openGraphService.fail('block-data-' + this.rawId); + this.openGraphService.fail('block-viz-' + this.rawId); + return of(null); + }), + ); + } + return this.apiService.getBlock$(blockHash); + }), + filter((block: BlockExtended | void) => block != null), + tap((block: BlockExtended) => { + this.block = block; + this.blockHeight = block.height; + + this.seoService.setTitle($localize`:@@block.component.browser-title:Block ${block.height}:BLOCK_HEIGHT:: ${block.id}:BLOCK_ID:`); + if( this.stateService.network === 'liquid' || this.stateService.network === 'liquidtestnet' ) { + this.seoService.setDescription($localize`:@@meta.description.liquid.block:See size, weight, fee range, included transactions, and more for Liquid${seoDescriptionNetwork(this.stateService.network)} block ${block.height}:BLOCK_HEIGHT: (${block.id}:BLOCK_ID:).`); + } else { + this.seoService.setDescription($localize`:@@meta.description.bitcoin.block:See size, weight, fee range, included transactions, audit (expected v actual), and more for Bitcoin${seoDescriptionNetwork(this.stateService.network)} block ${block.height}:BLOCK_HEIGHT: (${block.id}:BLOCK_ID:).`); + } + this.isLoadingBlock = false; + this.setBlockSubsidy(); + if (block?.extras?.reward !== undefined) { + this.fees = block.extras.reward / 100000000 - this.blockSubsidy; + } + this.stateService.markBlock$.next({ blockHeight: this.blockHeight }); + this.isLoadingOverview = true; + this.overviewError = null; + + this.openGraphService.waitOver('block-data-' + this.rawId); + }), + throttleTime(50, asyncScheduler, { leading: true, trailing: true }), + shareReplay(1) + ); + + this.overviewSubscription = block$.pipe( + startWith(null), + pairwise(), + switchMap(([prevBlock, block]) => { + return forkJoin([ + this.apiService.getStrippedBlockTransactions$(block.id) + .pipe( + catchError((err) => { + this.overviewError = err; + this.openGraphService.fail('block-viz-' + this.rawId); + return of([]); + }), + switchMap((transactions) => { + return of(transactions); + }) + ), + this.stateService.env.ACCELERATOR === true && block.height > 819500 + ? this.servicesApiService.getAccelerationHistory$({ blockHeight: block.height }) + .pipe(catchError(() => { + return of([]); + })) + : of([]) + ]); + } + ), + ) + .subscribe(([transactions, accelerations]) => { + this.strippedTransactions = transactions; + + const acceleratedInBlock = {}; + for (const acc of accelerations) { + acceleratedInBlock[acc.txid] = acc; + } + for (const tx of transactions) { + if (acceleratedInBlock[tx.txid]) { + tx.acc = true; + } + } + + this.isLoadingOverview = false; + if (this.blockGraph) { + this.blockGraph.destroy(); + this.blockGraph.setup(this.strippedTransactions); + } + }, + (error) => { + this.error = error; + this.isLoadingOverview = false; + this.seoService.logSoft404(); + this.openGraphService.fail('block-viz-' + this.rawId); + this.openGraphService.fail('block-data-' + this.rawId); + if (this.blockGraph) { + this.blockGraph.destroy(); + } + }); + + this.networkChangedSubscription = this.stateService.networkChanged$ + .subscribe((network) => this.network = network); + } + + ngOnDestroy() { + if (this.overviewSubscription) { + this.overviewSubscription.unsubscribe(); + } + if (this.networkChangedSubscription) { + this.networkChangedSubscription.unsubscribe(); + } + } + + // TODO - Refactor this.fees/this.reward for liquid because it is not + // used anymore on Bitcoin networks (we use block.extras directly) + setBlockSubsidy() { + this.blockSubsidy = 0; + } + + onGraphReady(): void { + this.openGraphService.waitOver('block-viz-' + this.rawId); + } +} diff --git a/frontend/src/app/components/block/block-transactions.component.html b/frontend/src/app/components/block/block-transactions.component.html new file mode 100644 index 0000000000..c732ea41ea --- /dev/null +++ b/frontend/src/app/components/block/block-transactions.component.html @@ -0,0 +1,53 @@ +
+

+ + {{ i }} transaction + {{ i }} transactions +

+ +
+
+ + + + +
+ + Error loading data. + +
+
+
+ + +
+ +
+
+
+
+
+
+ +
+
+
+ +
+
+ + + +
+
+
+
+
+ + +
+ +
+
+ + diff --git a/frontend/src/app/components/block/block-transactions.component.scss b/frontend/src/app/components/block/block-transactions.component.scss new file mode 100644 index 0000000000..d1ade512b5 --- /dev/null +++ b/frontend/src/app/components/block/block-transactions.component.scss @@ -0,0 +1,37 @@ +.block-tx-title { + display: flex; + justify-content: space-between; + flex-direction: column; + margin-top: -15px; + position: relative; + @media (min-width: 550px) { + margin-top: 1rem; + flex-direction: row; + } + h2 { + line-height: 1; + margin: 0; + position: relative; + padding-bottom: 10px; + @media (min-width: 550px) { + padding-bottom: 0px; + align-self: end; + } + } +} + +.tx-skeleton { + margin-top: 10px; + margin-bottom: 10px; + .header-bg { + &:first-child { + padding: 10px; + margin-bottom: 10px; + } + &:nth-child(2) { + .row { + height: 107px; + } + } + } +} diff --git a/frontend/src/app/components/block/block-transactions.component.ts b/frontend/src/app/components/block/block-transactions.component.ts new file mode 100644 index 0000000000..c0cda6c4f8 --- /dev/null +++ b/frontend/src/app/components/block/block-transactions.component.ts @@ -0,0 +1,74 @@ +import { ChangeDetectionStrategy, Component, EventEmitter, Input, OnDestroy, OnInit, Output } from '@angular/core'; +import { StateService } from '../../services/state.service'; +import { Transaction, Vout } from '../../interfaces/electrs.interface'; +import { Observable, Subscription, catchError, combineLatest, map, of, startWith, switchMap, tap } from 'rxjs'; +import { ActivatedRoute, Router } from '@angular/router'; +import { ElectrsApiService } from '../../services/electrs-api.service'; +import { PreloadService } from '../../services/preload.service'; + +@Component({ + selector: 'app-block-transactions', + templateUrl: './block-transactions.component.html', + styleUrl: './block-transactions.component.scss', + changeDetection: ChangeDetectionStrategy.OnPush, +}) +export class BlockTransactionsComponent implements OnInit { + @Input() txCount: number; + @Input() timestamp: number; + @Input() blockHash: string; + @Input() previousBlockHash: string; + @Input() block$: Observable; + @Input() paginationMaxSize: number; + @Output() blockReward = new EventEmitter(); + + itemsPerPage = this.stateService.env.ITEMS_PER_PAGE; + page = 1; + + transactions$: Observable; + isLoadingTransactions = true; + transactionsError: any = null; + transactionSubscription: Subscription; + txsLoadingStatus$: Observable; + nextBlockTxListSubscription: Subscription; + + constructor( + private stateService: StateService, + private route: ActivatedRoute, + private router: Router, + private electrsApiService: ElectrsApiService, + ) { } + + ngOnInit(): void { + this.transactions$ = combineLatest([this.block$, this.route.queryParams]).pipe( + tap(([_, queryParams]) => { + this.page = +queryParams['page'] || 1; + }), + switchMap(([block, _]) => this.electrsApiService.getBlockTransactions$(block.id, (this.page - 1) * this.itemsPerPage) + .pipe( + startWith(null), + catchError((err) => { + this.transactionsError = err; + return of([]); + })) + ), + tap((transactions: Transaction[]) => { + // The block API doesn't contain the block rewards on Liquid + if (this.stateService.isLiquid() && transactions && transactions[0] && transactions[0].vin[0].is_coinbase) { + const blockReward = transactions[0].vout.reduce((acc: number, curr: Vout) => acc + curr.value, 0) / 100000000; + this.blockReward.emit(blockReward); + } + }) + ); + + this.txsLoadingStatus$ = this.route.paramMap + .pipe( + switchMap(() => this.stateService.loadingIndicators$), + map((indicators) => indicators['blocktxs-' + this.blockHash] !== undefined ? indicators['blocktxs-' + this.blockHash] : 0) + ); + } + + pageChange(page: number, target: HTMLElement): void { + target.scrollIntoView(); // works for chrome + this.router.navigate([], { queryParams: { page: page }, queryParamsHandling: 'merge' }); + } +} diff --git a/frontend/src/app/components/block/block.component.html b/frontend/src/app/components/block/block.component.html index b1fb3c9c66..1dd9d8a8da 100644 --- a/frontend/src/app/components/block/block.component.html +++ b/frontend/src/app/components/block/block.component.html @@ -1,125 +1,85 @@ -
+
-
-

Block {{ blockHeight }}

- +
+ +

+ Block + Genesis + + + + + + {{ blockHeight }} + + + + + +

+ +
+ + + +
- - -
-
-
- - +
+
+
+
+ + - - + + - + - - + + - - + + - -
Hash{{ block.id | shortenString : 13 }} Hash{{ block.id | shortenString : 13 }}
TimestampTimestamp - {{ block.timestamp * 1000 | date:'yyyy-MM-dd HH:mm' }} -
- ( ago) -
+
Size{{ block.size | bytes: 2 }}Size
Weight{{ block.weight | wuBytes: 2 }}Weight
-
-
- - - - - + + + - - - - - - - - - - - - - - - - - - - - - - - - - -
Median fee~{{ block.medianFee | number:'1.0-0' }} sat/vB ()
Health + {{ blockAudit?.matchRate }}% + + + Unknown + + + + + +
Total fees ()
Subsidy + fees: - () -
Total fees
Subsidy + fees:
Miner
-
-
-
- -
- -

{{ block.tx_count | number }} transactions

- - - -
- - - - -
- -
- -
- -
-
-
- -
-
- - -
-
-
- -
-
- - - -
- - - -
-
-
- - + + @@ -132,40 +92,372 @@

{{ block.tx_count | number }} transactions

- -
-
-
- - - - - - - - - + - - - - -
+ + + + +
+
+ + + + +
+
+ +
+
+ + + + + Fee span + - + + + Median fee + ~ + + + + + + + + Total fees + + + + + + + + +   + + + + + Subsidy + fees + + + + + + + + + + + Total fees + + + + Subsidy + fees + + + + + Miner + + + + {{ block.extras.pool.name }} + + + + + {{ block.extras.pool.name }} + + + + + + + + + + + + + + + + + + + + + - -
- Error loading block data. -

- {{ error.error }} + + +
+
+ + +
+ +
+
+

Expected Block

+
+ + +
+ + + + + +
+
+

Actual Block

+
+ + +
+ + + + + +
+
+
+ + +
+
+ +
+
+
+ + + + + + + + + + + + + + + +
Version{{ block.version | decimal2hex }} Taproot
Bits{{ block.bits | decimal2hex }}
Merkle root

{{ block.merkle_root }}

+
+
+ + + + + + + + + + + + + + + + +
Difficulty{{ block.difficulty }}
Nonce{{ block.nonce | decimal2hex }}
Block Header Hex
+
+
+
+ +
+ + +
+ + @defer (on viewport) { + + } @placeholder { +
+
+

+ + {{ i }} transaction + {{ i }} transactions +

+ +
+
+
+ +
+ +
+
+
+
+ +
+
+ + + +
+
+
+
+
+ } + +
+
+
+ + + Error loading block data. +
+ + + + Why is this block empty? + + + + + + + + + + + + + + + + + + + +
Total fees + +
Weight
Transactions{{ blockAudit.template?.length || 0 }}
+
+ + + + + + + + + + + + + + + + + +
Total fees + + + + + + {{ blockAudit.feeDelta < 0 ? '+' : '' }}{{ (-blockAudit.feeDelta * 100) | amountShortener: 2 }}% + +
Weight + + + {{ blockAudit.weightDelta < 0 ? '+' : '' }}{{ (-blockAudit.weightDelta * 100) | amountShortener: 2 }}% + +
Transactions + {{ block.tx_count }} + + {{ blockAudit.txDelta < 0 ? '+' : '' }}{{ (-blockAudit.txDelta * 100) | amountShortener: 2 }}% + +
+
+ + + + + + + + + + + + + + + + + +
Total fees
Weight
Transactions
+
+

diff --git a/frontend/src/app/components/block/block.component.scss b/frontend/src/app/components/block/block.component.scss index 38ddb2a6a2..fe53183750 100644 --- a/frontend/src/app/components/block/block.component.scss +++ b/frontend/src/app/components/block/block.component.scss @@ -1,16 +1,282 @@ .title-block { - color: #FFF; - padding-top: 20px; - padding-bottom: 3px; - border-top: 3px solid #FFF; + flex-wrap: wrap; + align-items: baseline; + @media (min-width: 650px) { + flex-direction: row; + } + h1 { + margin: 0rem; + margin-right: 15px; + line-height: 1; + } + + .alert-mempool { + flex-direction: row; + flex-wrap: wrap; + } + + .container-button { + align-self: center; + margin-right: 1em; + } +} + +.fiat { + display: block; + font-size: 13px; + @media (min-width: 768px) { + font-size: 14px; + display: inline-block; + margin-left: 10px; + } +} +.table { + tr td { + &:last-child { + text-align: right; + @media (min-width: 768px) { + text-align: left; + } + } + .difference { + margin-left: 0.5em; + + &.positive { + color: rgb(66, 183, 71); + } + &.negative { + color: rgb(183, 66, 66); + } + } + } +} + +.audit-col { + max-width: 50%; + + &.mobile { + max-width: 100%; + } } -.td-width { - width: 175px; +.block-subtitle.actual a { + position: absolute; + top: -3px; } +.block-subtitle.actual fa-icon { + color: rgba(255, 255, 255, 0.4); + font-size: 18px; + margin-left: 8px; +} + +h1 { + margin: 0px; + padding: 0px; + line-height: 1; + a { + &:hover, &:focus{ + text-decoration: none;; + } + } +} + +.row { + flex-direction: column; + @media (min-width: 768px) { + flex-direction: row; + } +} @media (max-width: 767.98px) { - .td-width { - width: 140px; + .mobile-bottomcol { + margin-top: 15px; + } + .details-table td:first-child { + white-space: pre-wrap; } } + +.toggle-btns { + position: relative; + z-index: 2; + top: 7px; + @media (min-width: 550px) { + top: 0px; + } +} + +.btn-audit { + margin-right: .5em; +} + +.grow { + flex-grow: 1; +} + +.next-previous-blocks { + font-size: 28px; + display: inline-flex; + flex-direction: row; + @media (min-width: 768px) { + font-size: 36px; + } + + a { + &:hover, &:focus { + display: inline-block; + } + } +} + +.time-ltr .next-previous-blocks { + .nav-arrow { + transform: scaleX(-1); + } + .nav-arrow.next { + order: 2; + } + .block-link { + order: 1; + } + .nav-arrow.prev { + order: 0; + } +} + +.disable { + font-size: 28px; + color: #393e5c73; + @media (min-width: 768px) { + font-size: 36px; + } +} + +.chart-container{ + margin: 20px auto; + @media (min-width: 768px) { + margin: auto; + } +} + +.menu-button { + @media (min-width: 768px) { + max-width: 150px; + } +} + +.block-subtitle { + text-align: center; +} + +.nav-tabs { + border-color: white; + border-width: 1px; + margin-bottom: 1em; +} + +.nav-tabs .nav-link { + background: inherit; + border-width: 1px; + border-bottom: none; + border-color: transparent; + margin-bottom: -1px; + cursor: pointer; + + &.active { + background: var(--box-bg); + } + + &.active, &:hover { + border-color: white; + } +} + +.block-graph-wrapper { + position: relative; +} + +.info-bubble-link { + position: absolute; + display: block; + top: 2em; + left: 50%; + margin: auto; + text-align: center; + padding: 0.5em 1em; + font-size: 80%; + transform: translateX(-50%); + + .ng-fa-icon { + margin-right: 1em; + } +} + +.beta { + font-size: 10px; + margin: 5p; + padding: 5p; + position: absolute; + top: 11px; + margin-left: 10px; +} + +.audit-details-table { + margin-top: 1.25rem; + @media (max-width: 767.98px) { + margin-top: 0.75rem; + } + + .oobFees { + color: #905cf4; + } +} + +.graph-col { + flex-grow: 1.11; +} + +.block-tx-title { + display: flex; + justify-content: space-between; + flex-direction: column; + margin-top: -15px; + position: relative; + @media (min-width: 550px) { + margin-top: 1rem; + flex-direction: row; + } + h2 { + line-height: 1; + margin: 0; + position: relative; + padding-bottom: 10px; + @media (min-width: 550px) { + padding-bottom: 0px; + align-self: end; + } + } +} + +.tx-skeleton { + margin-top: 10px; + margin-bottom: 10px; + .header-bg { + &:first-child { + padding: 10px; + margin-bottom: 10px; + } + &:nth-child(2) { + .row { + height: 107px; + } + } + } +} + +.pool-logo { + width: 15px; + height: 15px; + position: relative; + top: -1px; + margin-right: 2px; +} diff --git a/frontend/src/app/components/block/block.component.ts b/frontend/src/app/components/block/block.component.ts index f05b8a5c85..01702487fe 100644 --- a/frontend/src/app/components/block/block.component.ts +++ b/frontend/src/app/components/block/block.component.ts @@ -1,68 +1,178 @@ -import { Component, OnInit, OnDestroy } from '@angular/core'; +import { Component, OnInit, OnDestroy, ViewChildren, QueryList, ChangeDetectorRef } from '@angular/core'; import { Location } from '@angular/common'; import { ActivatedRoute, ParamMap, Router } from '@angular/router'; import { ElectrsApiService } from '../../services/electrs-api.service'; -import { switchMap, tap, debounceTime, catchError } from 'rxjs/operators'; -import { Block, Transaction, Vout } from '../../interfaces/electrs.interface'; -import { of, Subscription } from 'rxjs'; +import { switchMap, tap, throttleTime, catchError, map, shareReplay, startWith, filter } from 'rxjs/operators'; +import { Observable, of, Subscription, asyncScheduler, EMPTY, combineLatest, forkJoin } from 'rxjs'; import { StateService } from '../../services/state.service'; -import { SeoService } from 'src/app/services/seo.service'; -import { env } from 'src/app/app.constants'; +import { SeoService } from '../../services/seo.service'; +import { WebsocketService } from '../../services/websocket.service'; +import { RelativeUrlPipe } from '../../shared/pipes/relative-url/relative-url.pipe'; +import { Acceleration, BlockAudit, BlockExtended, TransactionStripped } from '../../interfaces/node-api.interface'; +import { ApiService } from '../../services/api.service'; +import { BlockOverviewGraphComponent } from '../../components/block-overview-graph/block-overview-graph.component'; +import { detectWebGL } from '../../shared/graphs.utils'; +import { seoDescriptionNetwork } from '../../shared/common.utils'; +import { PriceService, Price } from '../../services/price.service'; +import { CacheService } from '../../services/cache.service'; +import { ServicesApiServices } from '../../services/services-api.service'; +import { PreloadService } from '../../services/preload.service'; @Component({ selector: 'app-block', templateUrl: './block.component.html', - styleUrls: ['./block.component.scss'] + styleUrls: ['./block.component.scss'], + styles: [` + .loadingGraphs { + position: absolute; + top: 50%; + left: calc(50% - 15px); + z-index: 100; + } + `], }) export class BlockComponent implements OnInit, OnDestroy { network = ''; - block: Block; + block: BlockExtended; + blockAudit: BlockAudit = undefined; blockHeight: number; + lastBlockHeight: number; + nextBlockHeight: number; blockHash: string; isLoadingBlock = true; - latestBlock: Block; - transactions: Transaction[]; - isLoadingTransactions = true; + latestBlock: BlockExtended; + latestBlocks: BlockExtended[] = []; + oobFees: number = 0; + strippedTransactions: TransactionStripped[]; + accelerations: Acceleration[]; + overviewTransitionDirection: string; + isLoadingOverview = true; error: any; blockSubsidy: number; - subscription: Subscription; fees: number; - paginationMaxSize: number; - coinbaseTx: Transaction; - page = 1; - itemsPerPage = env.ELCTRS_ITEMS_PER_PAGE; + block$: Observable; + showDetails = false; + showPreviousBlocklink = true; + showNextBlocklink = true; + overviewError: any = null; + webGlEnabled = true; + auditParamEnabled: boolean = false; + auditSupported: boolean = this.stateService.env.AUDIT && this.stateService.env.BASE_MODULE === 'mempool' && this.stateService.env.MINING_DASHBOARD === true; + auditModeEnabled: boolean = !this.stateService.hideAudit.value; + auditAvailable = true; + showAudit: boolean; + isMobile = window.innerWidth <= 767.98; + hoverTx: string; + numMissing: number = 0; + paginationMaxSize = window.matchMedia('(max-width: 670px)').matches ? 3 : 5; + numUnexpected: number = 0; + mode: 'projected' | 'actual' = 'projected'; + + overviewSubscription: Subscription; + accelerationsSubscription: Subscription; + keyNavigationSubscription: Subscription; + blocksSubscription: Subscription; + cacheBlocksSubscription: Subscription; + networkChangedSubscription: Subscription; + queryParamsSubscription: Subscription; + timeLtrSubscription: Subscription; + timeLtr: boolean; + childChangeSubscription: Subscription; + auditPrefSubscription: Subscription; + oobSubscription: Subscription; + + priceSubscription: Subscription; + blockConversion: Price; + + @ViewChildren('blockGraphProjected') blockGraphProjected: QueryList; + @ViewChildren('blockGraphActual') blockGraphActual: QueryList; constructor( private route: ActivatedRoute, private location: Location, private router: Router, private electrsApiService: ElectrsApiService, - private stateService: StateService, + public stateService: StateService, private seoService: SeoService, - ) { } + private websocketService: WebsocketService, + private relativeUrlPipe: RelativeUrlPipe, + private apiService: ApiService, + private priceService: PriceService, + private cacheService: CacheService, + private servicesApiService: ServicesApiServices, + private cd: ChangeDetectorRef, + private preloadService: PreloadService, + ) { + this.webGlEnabled = this.stateService.isBrowser && detectWebGL(); + } - ngOnInit() { - this.paginationMaxSize = window.matchMedia('(max-width: 700px)').matches ? 3 : 5; + ngOnInit(): void { + this.websocketService.want(['blocks', 'mempool-blocks']); this.network = this.stateService.network; - this.subscription = this.route.paramMap - .pipe( + this.timeLtrSubscription = this.stateService.timeLtr.subscribe((ltr) => { + this.timeLtr = !!ltr; + }); + + this.setAuditAvailable(this.auditSupported); + + if (this.auditSupported) { + this.isAuditEnabledFromParam().subscribe(auditParam => { + if (this.auditParamEnabled) { + this.auditModeEnabled = auditParam; + } else { + this.auditPrefSubscription = this.stateService.hideAudit.subscribe(hide => { + this.auditModeEnabled = !hide; + this.showAudit = this.auditAvailable && this.auditModeEnabled; + }); + } + }); + } + + this.cacheBlocksSubscription = this.cacheService.loadedBlocks$.subscribe((block) => { + this.loadedCacheBlock(block); + }); + + this.blocksSubscription = this.stateService.blocks$ + .subscribe((blocks) => { + this.latestBlock = blocks[0]; + this.latestBlocks = blocks; + this.setNextAndPreviousBlockLink(); + + for (const block of blocks) { + if (block.id === this.blockHash) { + this.block = block; + if (block.extras) { + block.extras.minFee = this.getMinBlockFee(block); + block.extras.maxFee = this.getMaxBlockFee(block); + if (block?.extras?.reward != undefined) { + this.fees = block.extras.reward / 100000000 - this.blockSubsidy; + } + } + } else if (block.height === this.block?.height) { + this.block.stale = true; + this.block.canonical = block.id; + } + } + }); + + this.block$ = this.route.paramMap.pipe( switchMap((params: ParamMap) => { const blockHash: string = params.get('id') || ''; this.block = undefined; - this.page = 1; - this.coinbaseTx = undefined; this.error = undefined; this.fees = undefined; - this.stateService.markBlock$.next({}); + this.oobFees = 0; if (history.state.data && history.state.data.blockHeight) { this.blockHeight = history.state.data.blockHeight; + this.updateAuditAvailableFromBlockHeight(this.blockHeight); } let isBlockHeight = false; if (/^[0-9]+$/.test(blockHash)) { isBlockHeight = true; + this.stateService.markBlock$.next({ blockHeight: parseInt(blockHash, 10)}); } else { this.blockHash = blockHash; } @@ -70,11 +180,21 @@ export class BlockComponent implements OnInit, OnDestroy { if (history.state.data && history.state.data.block) { this.blockHeight = history.state.data.block.height; + this.updateAuditAvailableFromBlockHeight(this.blockHeight); return of(history.state.data.block); } else { this.isLoadingBlock = true; + this.isLoadingOverview = true; + this.strippedTransactions = undefined; + this.blockAudit = undefined; + this.accelerations = undefined; + let blockInCache: BlockExtended; if (isBlockHeight) { + blockInCache = this.latestBlocks.find((block) => block.height === parseInt(blockHash, 10)); + if (blockInCache) { + return of(blockInCache); + } return this.electrsApiService.getBlockHashFromHeight$(parseInt(blockHash, 10)) .pipe( switchMap((hash) => { @@ -82,87 +202,587 @@ export class BlockComponent implements OnInit, OnDestroy { this.location.replaceState( this.router.createUrlTree([(this.network ? '/' + this.network : '') + '/block/', hash]).toString() ); - return this.electrsApiService.getBlock$(hash); - }) + this.seoService.updateCanonical(this.location.path()); + return this.apiService.getBlock$(hash).pipe( + catchError((err) => { + this.error = err; + this.isLoadingBlock = false; + this.isLoadingOverview = false; + this.seoService.logSoft404(); + return EMPTY; + }) + ); + }), + catchError((err) => { + this.error = err; + this.isLoadingBlock = false; + this.isLoadingOverview = false; + this.seoService.logSoft404(); + return EMPTY; + }), ); } - return this.electrsApiService.getBlock$(blockHash); + + blockInCache = this.latestBlocks.find((block) => block.id === this.blockHash); + if (blockInCache) { + return of(blockInCache); + } + + return this.apiService.getBlock$(blockHash).pipe( + catchError((err) => { + this.error = err; + this.isLoadingBlock = false; + this.isLoadingOverview = false; + this.seoService.logSoft404(); + return EMPTY; + }) + ); } }), - tap((block: Block) => { + tap((block: BlockExtended) => { + if (block.previousblockhash) { + this.preloadService.block$.next(block.previousblockhash); + if (this.auditSupported) { + this.preloadService.blockAudit$.next(block.previousblockhash); + } + } + this.updateAuditAvailableFromBlockHeight(block.height); this.block = block; + if (block.extras) { + block.extras.minFee = this.getMinBlockFee(block); + block.extras.maxFee = this.getMaxBlockFee(block); + } this.blockHeight = block.height; - this.seoService.setTitle('Block: #' + block.height + ': ' + block.id, true); - this.isLoadingBlock = false; - if (block.coinbaseTx) { - this.coinbaseTx = block.coinbaseTx; + this.lastBlockHeight = this.blockHeight; + this.nextBlockHeight = block.height + 1; + this.setNextAndPreviousBlockLink(); + + this.seoService.setTitle($localize`:@@block.component.browser-title:Block ${block.height}:BLOCK_HEIGHT:: ${block.id}:BLOCK_ID:`); + if( this.stateService.network === 'liquid' || this.stateService.network === 'liquidtestnet' ) { + this.seoService.setDescription($localize`:@@meta.description.liquid.block:See size, weight, fee range, included transactions, and more for Liquid${seoDescriptionNetwork(this.stateService.network)} block ${block.height}:BLOCK_HEIGHT: (${block.id}:BLOCK_ID:).`); + } else { + this.seoService.setDescription($localize`:@@meta.description.bitcoin.block:See size, weight, fee range, included transactions, audit (expected v actual), and more for Bitcoin${seoDescriptionNetwork(this.stateService.network)} block ${block.height}:BLOCK_HEIGHT: (${block.id}:BLOCK_ID:).`); } + this.isLoadingBlock = false; this.setBlockSubsidy(); - if (block.reward) { - this.fees = block.reward / 100000000 - this.blockSubsidy; + if (block?.extras?.reward !== undefined) { + this.fees = block.extras.reward / 100000000 - this.blockSubsidy; } this.stateService.markBlock$.next({ blockHeight: this.blockHeight }); - this.isLoadingTransactions = true; - this.transactions = null; + this.isLoadingOverview = true; + this.overviewError = null; + + const cachedBlock = this.cacheService.getCachedBlock(block.height); + if (!cachedBlock) { + this.cacheService.loadBlock(block.height); + } else { + this.loadedCacheBlock(cachedBlock); + } }), - debounceTime(300), - switchMap((block) => this.electrsApiService.getBlockTransactions$(block.id) + throttleTime(300, asyncScheduler, { leading: true, trailing: true }), + shareReplay(1) + ); + + this.overviewSubscription = this.block$.pipe( + switchMap((block) => { + return forkJoin([ + this.apiService.getStrippedBlockTransactions$(block.id) + .pipe( + catchError((err) => { + this.overviewError = err; + return of(null); + }) + ), + !this.isAuditAvailableFromBlockHeight(block.height) ? of(null) : this.apiService.getBlockAudit$(block.id) + .pipe( + catchError((err) => { + this.overviewError = err; + return of(null); + }) + ) + ]); + }) + ) + .subscribe(([transactions, blockAudit]) => { + if (transactions) { + this.strippedTransactions = transactions; + } else { + this.strippedTransactions = []; + } + this.blockAudit = blockAudit; + + this.setupBlockAudit(); + this.isLoadingOverview = false; + }); + + this.accelerationsSubscription = this.block$.pipe( + switchMap((block) => { + return this.stateService.env.ACCELERATOR === true && block.height > 819500 + ? this.servicesApiService.getAccelerationHistory$({ blockHeight: block.height }) + .pipe(catchError(() => { + return of([]); + })) + : of([]); + }) + ).subscribe((accelerations) => { + this.accelerations = accelerations; + if (accelerations.length) { + this.setupBlockAudit(); + } + }); + + this.oobSubscription = this.block$.pipe( + filter(() => this.stateService.env.PUBLIC_ACCELERATIONS === true && this.stateService.network === ''), + switchMap((block) => this.apiService.getAccelerationsByHeight$(block.height) .pipe( - catchError((err) => { - console.log(err); - return of([]); + map(accelerations => { + return { block, accelerations }; + }), + catchError(() => { + return of({ block, accelerations: [] }); })) ), - ) - .subscribe((transactions: Transaction[]) => { - if (this.fees === undefined && transactions[0]) { - this.fees = transactions[0].vout.reduce((acc: number, curr: Vout) => acc + curr.value, 0) / 100000000 - this.blockSubsidy; + ).subscribe(({ block, accelerations}) => { + let totalFees = 0; + for (const acc of accelerations) { + totalFees += acc.boost_cost; } - if (!this.coinbaseTx && transactions[0]) { - this.coinbaseTx = transactions[0]; + this.oobFees = totalFees; + if (block && this.block && this.blockAudit && block?.height === this.block?.height) { + this.blockAudit.feeDelta = this.blockAudit.expectedFees > 0 ? (this.blockAudit.expectedFees - (this.block.extras.totalFees + this.oobFees)) / this.blockAudit.expectedFees : 0; } - this.transactions = transactions; - this.isLoadingTransactions = false; }, (error) => { this.error = error; this.isLoadingBlock = false; + this.isLoadingOverview = false; }); - this.stateService.blocks$ - .subscribe(([block]) => this.latestBlock = block); - - this.stateService.networkChanged$ + this.networkChangedSubscription = this.stateService.networkChanged$ .subscribe((network) => this.network = network); + + this.queryParamsSubscription = this.route.queryParams.subscribe((params) => { + if (params.showDetails === 'true') { + this.showDetails = true; + } else { + this.showDetails = false; + } + if (params.view === 'projected') { + this.mode = 'projected'; + } else { + this.mode = 'actual'; + } + this.setupBlockGraphs(); + }); + + this.keyNavigationSubscription = this.stateService.keyNavigation$.subscribe((event) => { + const prevKey = this.timeLtr ? 'ArrowLeft' : 'ArrowRight'; + const nextKey = this.timeLtr ? 'ArrowRight' : 'ArrowLeft'; + if (this.showPreviousBlocklink && event.key === prevKey && this.nextBlockHeight - 2 >= 0) { + this.navigateToPreviousBlock(); + } + if (event.key === nextKey) { + if (this.showNextBlocklink) { + this.navigateToNextBlock(); + } else { + this.router.navigate([this.relativeUrlPipe.transform('/mempool-block'), '0']); + } + } + }); + + if (this.priceSubscription) { + this.priceSubscription.unsubscribe(); + } + this.priceSubscription = combineLatest([this.stateService.fiatCurrency$, this.block$]).pipe( + switchMap(([currency, block]) => { + return this.priceService.getBlockPrice$(block.timestamp, true, currency).pipe( + tap((price) => { + this.blockConversion = price; + }) + ); + }) + ).subscribe(); } - ngOnDestroy() { + ngAfterViewInit(): void { + this.childChangeSubscription = combineLatest([this.blockGraphProjected.changes.pipe(startWith(null)), this.blockGraphActual.changes.pipe(startWith(null))]).subscribe(() => { + this.setupBlockGraphs(); + }); + } + + ngOnDestroy(): void { this.stateService.markBlock$.next({}); - this.subscription.unsubscribe(); + this.overviewSubscription?.unsubscribe(); + this.keyNavigationSubscription?.unsubscribe(); + this.blocksSubscription?.unsubscribe(); + this.cacheBlocksSubscription?.unsubscribe(); + this.networkChangedSubscription?.unsubscribe(); + this.queryParamsSubscription?.unsubscribe(); + this.timeLtrSubscription?.unsubscribe(); + this.childChangeSubscription?.unsubscribe(); + this.priceSubscription?.unsubscribe(); + this.oobSubscription?.unsubscribe(); + } + + // TODO - Refactor this.fees/this.reward for liquid because it is not + // used anymore on Bitcoin networks (we use block.extras directly) + setBlockSubsidy(): void { + this.blockSubsidy = 0; + } + + toggleShowDetails(): void { + if (this.showDetails) { + this.showDetails = false; + this.router.navigate([], { + relativeTo: this.route, + queryParams: { showDetails: false, view: this.mode }, + queryParamsHandling: 'merge', + fragment: 'block' + }); + } else { + this.showDetails = true; + this.router.navigate([], { + relativeTo: this.route, + queryParams: { showDetails: true, view: this.mode }, + queryParamsHandling: 'merge', + fragment: 'details' + }); + } + } + + hasTaproot(version: number): boolean { + const versionBit = 2; // Taproot + return (Number(version) & (1 << versionBit)) === (1 << versionBit); + } + + displayTaprootStatus(): boolean { + if (this.stateService.network !== '') { + return false; + } + return this.block && this.block.height > 681393 && (new Date().getTime() / 1000) < 1628640000; } - setBlockSubsidy() { - if (this.network === 'liquid') { - this.blockSubsidy = 0; + navigateToPreviousBlock(): void { + if (!this.block) { return; } - this.blockSubsidy = 50; - let halvenings = Math.floor(this.block.height / 210000); - while (halvenings > 0) { - this.blockSubsidy = this.blockSubsidy / 2; - halvenings--; + const block = this.latestBlocks.find((b) => b.height === this.nextBlockHeight - 2); + this.router.navigate([this.relativeUrlPipe.transform('/block/'), + block ? block.id : this.block.previousblockhash], { state: { data: { block, blockHeight: this.nextBlockHeight - 2 } } }); + } + + navigateToNextBlock(): void { + const block = this.latestBlocks.find((b) => b.height === this.nextBlockHeight); + this.router.navigate([this.relativeUrlPipe.transform('/block/'), + block ? block.id : this.nextBlockHeight], { state: { data: { block, blockHeight: this.nextBlockHeight } } }); + } + + setNextAndPreviousBlockLink(): void { + if (this.latestBlock) { + if (!this.blockHeight){ + this.showPreviousBlocklink = false; + } else { + this.showPreviousBlocklink = true; + } + if (this.latestBlock.height && this.latestBlock.height === this.blockHeight) { + this.showNextBlocklink = false; + } else { + this.showNextBlocklink = true; + } } } - pageChange(page: number) { - const start = (page - 1) * this.itemsPerPage; - this.isLoadingTransactions = true; - this.transactions = null; + setupBlockAudit(): void { + const transactions = this.strippedTransactions || []; + const blockAudit = this.blockAudit; + const accelerations = this.accelerations || []; + + const acceleratedInBlock = {}; + for (const acc of accelerations) { + if (acc.pools?.some(pool => pool === this.block?.extras?.pool.id)) { + acceleratedInBlock[acc.txid] = acc; + } + } + + for (const tx of transactions) { + if (acceleratedInBlock[tx.txid]) { + tx.acc = true; + const acceleration = acceleratedInBlock[tx.txid]; + const boostCost = acceleration.boostCost || acceleration.bidBoost; + const acceleratedFeeRate = Math.max(acceleration.effectiveFee, acceleration.effectiveFee + boostCost) / acceleration.effectiveVsize; + if (acceleratedFeeRate > tx.rate) { + tx.rate = acceleratedFeeRate; + } + } else { + tx.acc = false; + } + } + + if (transactions && blockAudit) { + const inTemplate = {}; + const inBlock = {}; + const isAdded = {}; + const isPrioritized = {}; + const isCensored = {}; + const isMissing = {}; + const isSelected = {}; + const isFresh = {}; + const isSigop = {}; + const isRbf = {}; + const isAccelerated = {}; + this.numMissing = 0; + this.numUnexpected = 0; + + if (blockAudit?.template) { + for (const tx of blockAudit.template) { + inTemplate[tx.txid] = true; + if (tx.acc) { + isAccelerated[tx.txid] = true; + } + } + for (const tx of transactions) { + inBlock[tx.txid] = true; + } + for (const txid of blockAudit.addedTxs) { + isAdded[txid] = true; + } + for (const txid of blockAudit.prioritizedTxs || []) { + isPrioritized[txid] = true; + } + for (const txid of blockAudit.missingTxs) { + isCensored[txid] = true; + } + for (const txid of blockAudit.freshTxs || []) { + isFresh[txid] = true; + } + for (const txid of blockAudit.sigopTxs || []) { + isSigop[txid] = true; + } + for (const txid of blockAudit.fullrbfTxs || []) { + isRbf[txid] = true; + } + for (const txid of blockAudit.acceleratedTxs || []) { + isAccelerated[txid] = true; + } + // set transaction statuses + for (const tx of blockAudit.template) { + tx.context = 'projected'; + if (isCensored[tx.txid]) { + tx.status = 'censored'; + } else if (inBlock[tx.txid]) { + tx.status = 'found'; + } else { + if (isFresh[tx.txid]) { + if (tx.rate - (tx.fee / tx.vsize) >= 0.1) { + tx.status = 'freshcpfp'; + } else { + tx.status = 'fresh'; + } + } else if (isSigop[tx.txid]) { + tx.status = 'sigop'; + } else if (isRbf[tx.txid]) { + tx.status = 'rbf'; + } else { + tx.status = 'missing'; + } + isMissing[tx.txid] = true; + this.numMissing++; + } + if (isAccelerated[tx.txid]) { + tx.status = 'accelerated'; + } + } + for (const [index, tx] of transactions.entries()) { + tx.context = 'actual'; + if (index === 0) { + tx.status = null; + } else if (isAdded[tx.txid]) { + tx.status = 'added'; + } else if (isPrioritized[tx.txid]) { + tx.status = 'prioritized'; + } else if (inTemplate[tx.txid]) { + tx.status = 'found'; + } else if (isRbf[tx.txid]) { + tx.status = 'rbf'; + } else { + tx.status = 'selected'; + isSelected[tx.txid] = true; + this.numUnexpected++; + } + if (isAccelerated[tx.txid]) { + tx.status = 'accelerated'; + } + } + for (const tx of transactions) { + inBlock[tx.txid] = true; + } + + blockAudit.feeDelta = blockAudit.expectedFees > 0 ? (blockAudit.expectedFees - (this.block?.extras.totalFees + this.oobFees)) / blockAudit.expectedFees : 0; + blockAudit.weightDelta = blockAudit.expectedWeight > 0 ? (blockAudit.expectedWeight - this.block?.weight) / blockAudit.expectedWeight : 0; + blockAudit.txDelta = blockAudit.template.length > 0 ? (blockAudit.template.length - this.block?.tx_count) / blockAudit.template.length : 0; + this.blockAudit = blockAudit; + this.setAuditAvailable(true); + } else { + this.setAuditAvailable(false); + } + } else { + this.setAuditAvailable(false); + } + + this.setupBlockGraphs(); + this.cd.markForCheck(); + } - this.electrsApiService.getBlockTransactions$(this.block.id, start) - .subscribe((transactions) => { - this.transactions = transactions; - this.isLoadingTransactions = false; + setupBlockGraphs(): void { + if (this.blockAudit || this.strippedTransactions) { + this.blockGraphProjected.forEach(graph => { + graph.destroy(); + if (this.isMobile && this.mode === 'actual') { + graph.setup(this.blockAudit?.transactions || this.strippedTransactions || []); + } else { + graph.setup(this.blockAudit?.template || []); + } }); + this.blockGraphActual.forEach(graph => { + graph.destroy(); + graph.setup(this.blockAudit?.transactions || this.strippedTransactions || []); + }); + } + } + + onResize(event: Event): void { + const target = event.target as Window; + const isMobile = target.innerWidth <= 767.98; + const changed = isMobile !== this.isMobile; + this.isMobile = isMobile; + this.paginationMaxSize = target.innerWidth < 670 ? 3 : 5; + + if (changed) { + this.changeMode(this.mode); + } + } + + changeMode(mode: 'projected' | 'actual'): void { + this.router.navigate([], { + relativeTo: this.route, + queryParams: { showDetails: this.showDetails, view: mode }, + queryParamsHandling: 'merge', + fragment: 'overview' + }); + } + + onTxClick(event: { tx: TransactionStripped, keyModifier: boolean }): void { + const url = new RelativeUrlPipe(this.stateService).transform(`/tx/${event.tx.txid}`); + if (!event.keyModifier) { + this.router.navigate([url]); + } else { + window.open(url, '_blank'); + } + } + + onTxHover(txid: string): void { + if (txid && txid.length) { + this.hoverTx = txid; + } else { + this.hoverTx = null; + } + } + + setAuditAvailable(available: boolean): void { + this.auditAvailable = available; + this.showAudit = this.auditAvailable && this.auditModeEnabled && this.auditSupported; + } + + toggleAuditMode(): void { + this.stateService.hideAudit.next(this.auditModeEnabled); + + this.route.queryParams.subscribe(params => { + const queryParams = { ...params }; + delete queryParams['audit']; + + let newUrl = this.router.url.split('?')[0]; + const queryString = new URLSearchParams(queryParams).toString(); + if (queryString) { + newUrl += '?' + queryString; + } + + this.location.replaceState(newUrl); + }); + + this.auditPrefSubscription = this.stateService.hideAudit.subscribe((hide) => { + this.auditModeEnabled = !hide; + this.showAudit = this.auditAvailable && this.auditModeEnabled; + }); + } + + updateAuditAvailableFromBlockHeight(blockHeight: number): void { + if (!this.isAuditAvailableFromBlockHeight(blockHeight)) { + this.setAuditAvailable(false); + } + } + + isAuditEnabledFromParam(): Observable { + return this.route.queryParams.pipe( + map(params => { + this.auditParamEnabled = 'audit' in params; + + return this.auditParamEnabled ? !(params['audit'] === 'false') : true; + }) + ); + } + + isAuditAvailableFromBlockHeight(blockHeight: number): boolean { + if (!this.auditSupported) { + return false; + } + switch (this.stateService.network) { + case 'testnet': + if (blockHeight < this.stateService.env.TESTNET_BLOCK_AUDIT_START_HEIGHT) { + return false; + } + break; + case 'signet': + if (blockHeight < this.stateService.env.SIGNET_BLOCK_AUDIT_START_HEIGHT) { + return false; + } + break; + default: + if (blockHeight < this.stateService.env.MAINNET_BLOCK_AUDIT_START_HEIGHT) { + return false; + } + } + return true; + } + + getMinBlockFee(block: BlockExtended): number { + if (block?.extras?.feeRange) { + // heuristic to check if feeRange is adjusted for effective rates + if (block.extras.medianFee === block.extras.feeRange[3]) { + return block.extras.feeRange[1]; + } else { + return block.extras.feeRange[0]; + } + } + return 0; + } + + getMaxBlockFee(block: BlockExtended): number { + if (block?.extras?.feeRange) { + return block.extras.feeRange[block.extras.feeRange.length - 1]; + } + return 0; + } + + loadedCacheBlock(block: BlockExtended): void { + if (this.block && block.height === this.block.height && block.id !== this.block.id) { + this.block.stale = true; + this.block.canonical = block.id; + } + } + + updateBlockReward(blockReward: number): void { + if (this.fees === undefined) { + this.fees = blockReward; + } } -} +} \ No newline at end of file diff --git a/frontend/src/app/components/block/block.module.ts b/frontend/src/app/components/block/block.module.ts new file mode 100644 index 0000000000..661e52dcfe --- /dev/null +++ b/frontend/src/app/components/block/block.module.ts @@ -0,0 +1,45 @@ +import { NgModule } from '@angular/core'; +import { CommonModule } from '@angular/common'; +import { Routes, RouterModule } from '@angular/router'; +import { BlockComponent } from './block.component'; +import { BlockTransactionsComponent } from './block-transactions.component'; +import { SharedModule } from '../../shared/shared.module'; + +const routes: Routes = [ + { + path: ':id', + component: BlockComponent, + data: { + ogImage: true + } + } +]; + +@NgModule({ + imports: [ + RouterModule.forChild(routes) + ], + exports: [ + RouterModule + ] +}) +export class BlockRoutingModule { } + +@NgModule({ + imports: [ + CommonModule, + BlockRoutingModule, + SharedModule, + ], + declarations: [ + BlockComponent, + BlockTransactionsComponent, + ] +}) +export class BlockModule { } + + + + + + diff --git a/frontend/src/app/components/blockchain-blocks/blockchain-blocks.component.html b/frontend/src/app/components/blockchain-blocks/blockchain-blocks.component.html index 7fe8666405..a60e1db0ae 100644 --- a/frontend/src/app/components/blockchain-blocks/blockchain-blocks.component.html +++ b/frontend/src/app/components/blockchain-blocks/blockchain-blocks.component.html @@ -1,22 +1,101 @@ -
-
-
-   -
- {{ block.height }} +
+
+ +
+
+   + +
+ +
+ ~ +
+ +
+ +
+
+
+ + - + +
+ +
+ +
+
+
+ +
+ +
+
+
+ + {{ i }} transaction + {{ i }} transactions +
+
+
+
+
+
-
-
- ~{{ block.medianFee | number:'1.0-0' }} sat/vB + + + +
+
-
- {{ block.feeRange[0] | number:'1.0-0' }} - {{ block.feeRange[block.feeRange.length - 1] | number:'1.0-0' }} sat/vB + + + + +
+
-
{{ block.size | bytes: 2 }}
-
{{ block.tx_count | number }} transactions
-
ago
+
+
+
+
+
+ + +
+
+
+
-
-
+ diff --git a/frontend/src/app/components/blockchain-blocks/blockchain-blocks.component.scss b/frontend/src/app/components/blockchain-blocks/blockchain-blocks.component.scss index 35c0c144df..b8de4f2ca2 100644 --- a/frontend/src/app/components/blockchain-blocks/blockchain-blocks.component.scss +++ b/frontend/src/app/components/blockchain-blocks/blockchain-blocks.component.scss @@ -1,6 +1,6 @@ .bitcoin-block { - width: 125px; - height: 125px; + width: var(--block-size); + height: var(--block-size); } .blockLink { @@ -11,10 +11,26 @@ z-index: 10; } +.blockLink:hover { + text-decoration: none; +} + +.blockLink.disabled { + pointer-events: none; +} + .mined-block { position: absolute; top: 0px; - transition: 2s; + transition: background 2s, left 2s, transform 1s, opacity 1s; +} + +.mined-block.offscreen { + opacity: 0; +} + +.mined-block.placeholder-block { + background: none !important; } .block-size { @@ -23,9 +39,11 @@ } .blocks-container { + --block-size: 125px; + --block-offset: calc(0.32 * var(--block-size)); position: absolute; top: 0px; - left: 40px; + left: var(--block-offset); } .block-body { @@ -44,14 +62,14 @@ .fee-span { font-size: 11px; - margin-bottom: 4px; - color: #fff000; + margin-bottom: 5px; + color: var(--yellow); } .transaction-count { font-size: 10px; - margin-top: 2px; - margin-bottom: 5px; + margin-top: 3px; + margin-bottom: 4px; } .block-height { @@ -65,11 +83,11 @@ .bitcoin-block::after { content: ''; - width: 125px; - height: 24px; + width: var(--block-size); + height: calc(0.192 * var(--block-size)); position:absolute; - top: -24px; - left: -20px; + top: calc(-0.192 * var(--block-size)); + left: calc(-0.16 * var(--block-size)); background-color: #232838; transform:skew(40deg); transform-origin:top; @@ -77,30 +95,98 @@ .bitcoin-block::before { content: ''; - width: 20px; - height: 125px; + width: calc(0.16 * var(--block-size)); + height: var(--block-size); position: absolute; - top: -12px; - left: -20px; + top: calc(-0.096 * var(--block-size)); + left: calc(-0.16 * var(--block-size)); background-color: #191c27; transform: skewY(50deg); transform-origin: top; } +.bitcoin-block.placeholder-block::after { + content: none; + background: 0; +} + +.bitcoin-block.placeholder-block::before { + content: none; + background: 0; +} + .black-background { - background-color: #11131f; + background-color: var(--active-bg); z-index: 100; position: relative; } #arrow-up { position: relative; - left: 30px; - top: 140px; + left: calc(var(--block-size) * 0.6); + top: calc(var(--block-size) * 1.28); width: 0; height: 0; - border-left: 35px solid transparent; - border-right: 35px solid transparent; - border-bottom: 35px solid #FFF; + border-left: calc(var(--block-size) * 0.2) solid transparent; + border-right: calc(var(--block-size) * 0.2) solid transparent; + border-bottom: calc(var(--block-size) * 0.2) solid var(--fg); +} + +.flashing { + /* force compositing */ + will-change: opacity; + transform: translateZ(0); + /* effective max frame rate = (#keyframes - 1) x steps / duration */ + animation: opacityPulse 2s steps(30, end); + animation-iteration-count: infinite; + opacity: 1; +} + +.loading .bitcoin-block.mined-block { + background: var(--secondary); +} + +@keyframes opacityPulse { + 0% {opacity: 0.7;} + 50% {opacity: 1.0;} + 100% {opacity: 0.7;} } + +.badge { + position: relative; + top: 15px; + z-index: 101; + color: #FFF; +} + +.pool-logo { + width: 15px; + height: 15px; + position: relative; + top: -1px; + margin-right: 2px; +} + +.animated { + transition: all 0.15s ease-in-out; + white-space: nowrap; +} + +.time-ltr { + .bitcoin-block { + transform: scaleX(-1); + } +} + +.spotlight-bottom { + position: absolute; + width: calc(0.6 * var(--block-size)); + height: calc(0.25 * var(--block-size)); + border-left: solid calc(0.3 * var(--block-size)) transparent; + border-bottom: solid calc(0.3 * var(--block-size)) white; + border-right: solid calc(0.3 * var(--block-size)) transparent; + transform: translate(calc(0.2 * var(--block-size)), calc(1.1 * var(--block-size))); + border-radius: 2px; + z-index: -1; +} \ No newline at end of file diff --git a/frontend/src/app/components/blockchain-blocks/blockchain-blocks.component.ts b/frontend/src/app/components/blockchain-blocks/blockchain-blocks.component.ts index 7f25d5ff7c..1a75980791 100644 --- a/frontend/src/app/components/blockchain-blocks/blockchain-blocks.component.ts +++ b/frontend/src/app/components/blockchain-blocks/blockchain-blocks.component.ts @@ -1,160 +1,434 @@ -import { Component, OnInit, OnDestroy } from '@angular/core'; -import { Subscription } from 'rxjs'; -import { Block } from 'src/app/interfaces/electrs.interface'; -import { StateService } from 'src/app/services/state.service'; -import { Router } from '@angular/router'; -import { AudioService } from 'src/app/services/audio.service'; +import { Component, OnInit, OnDestroy, ChangeDetectionStrategy, ChangeDetectorRef, Input, OnChanges, SimpleChanges } from '@angular/core'; +import { Observable, Subscription, delay, filter, tap } from 'rxjs'; +import { StateService } from '../../services/state.service'; +import { specialBlocks } from '../../app.constants'; +import { BlockExtended } from '../../interfaces/node-api.interface'; +import { Location } from '@angular/common'; +import { CacheService } from '../../services/cache.service'; + +interface BlockchainBlock extends BlockExtended { + placeholder?: boolean; + loading?: boolean; +} @Component({ selector: 'app-blockchain-blocks', templateUrl: './blockchain-blocks.component.html', - styleUrls: ['./blockchain-blocks.component.scss'] + styleUrls: ['./blockchain-blocks.component.scss'], + changeDetection: ChangeDetectionStrategy.OnPush, }) -export class BlockchainBlocksComponent implements OnInit, OnDestroy { +export class BlockchainBlocksComponent implements OnInit, OnChanges, OnDestroy { + @Input() static: boolean = false; + @Input() offset: number = 0; + @Input() height: number = 0; // max height of blocks in chunk (dynamic blocks only) + @Input() count: number = 8; // number of blocks in this chunk (dynamic blocks only) + @Input() loadingTip: boolean = false; + @Input() connected: boolean = true; + @Input() minimal: boolean = false; + @Input() blockWidth: number = 125; + @Input() spotlight: number = 0; + @Input() showPools: boolean = true; + @Input() getHref?: (index, block) => string = (index, block) => `/block/${block.id}`; + + specialBlocks = specialBlocks; network = ''; - blocks: Block[] = []; + blocks: BlockchainBlock[] = []; + dynamicBlocksAmount: number = 8; + emptyBlocks: BlockExtended[] = this.mountEmptyBlocks(); markHeight: number; + chainTip: number; + pendingMarkBlock: { animate: boolean, newBlockFromLeft: boolean }; blocksSubscription: Subscription; + blockPageSubscription: Subscription; + networkSubscription: Subscription; + tabHiddenSubscription: Subscription; + markBlockSubscription: Subscription; + txConfirmedSubscription: Subscription; + loadingBlocks$: Observable; + showMiningInfoSubscription: Subscription; + blockDisplayModeSubscription: Subscription; + blockDisplayMode: 'size' | 'fees'; + blockTransformation = {}; blockStyles = []; + emptyBlockStyles = []; interval: any; - tabHidden = true; - + tabHidden = false; + feeRounding = '1.0-0'; arrowVisible = false; arrowLeftPx = 30; + blocksFilled = false; + arrowTransition = '1s'; + timeLtrSubscription: Subscription; + timeLtr: boolean; - transition = '1s'; + blockOffset: number = 155; + dividerBlockOffset: number = 205; + blockPadding: number = 30; gradientColors = { - '': ['#9339f4', '#105fb0'], - bisq: ['#9339f4', '#105fb0'], - liquid: ['#116761', '#183550'], - testnet: ['#1d486f', '#183550'], + '': ['var(--mainnet-alt)', 'var(--primary)'], + liquid: ['var(--liquid)', 'var(--testnet-alt)'], + 'liquidtestnet': ['var(--liquidtestnet)', 'var(--liquidtestnet-alt)'], + testnet: ['var(--testnet)', 'var(--testnet-alt)'], + testnet4: ['var(--testnet)', 'var(--testnet-alt)'], + signet: ['var(--signet)', 'var(--signet-alt)'], }; constructor( - private stateService: StateService, - private router: Router, - private audioService: AudioService, - ) { } + public stateService: StateService, + public cacheService: CacheService, + private cd: ChangeDetectorRef, + private location: Location, + ) { + } ngOnInit() { - this.stateService.networkChanged$.subscribe((network) => this.network = network); - this.stateService.isTabHidden$.subscribe((tabHidden) => this.tabHidden = tabHidden); + this.dynamicBlocksAmount = Math.min(8, this.stateService.env.KEEP_BLOCKS_AMOUNT); - this.blocksSubscription = this.stateService.blocks$ - .subscribe(([block, txConfirmed, refilling]) => { - if (this.blocks.some((b) => b.height === block.height)) { - return; - } - this.blocks.unshift(block); - this.blocks = this.blocks.slice(0, 8); + this.blockDisplayMode = this.stateService.blockDisplayMode$.value as 'size' | 'fees'; + this.blockDisplayModeSubscription = this.stateService.blockDisplayMode$ + .pipe( + filter((mode: 'size' | 'fees') => mode !== this.blockDisplayMode), + tap(() => { + this.blockTransformation = this.timeLtr ? { + transform: 'scaleX(-1) rotateX(90deg)', + transition: 'transform 0.375s' + } : { + transform: 'rotateX(90deg)', + transition: 'transform 0.375s' + }; + }), + delay(375), + tap((mode) => { + this.blockDisplayMode = mode; + this.blockTransformation = this.timeLtr ? { + transform: 'scaleX(-1)', + transition: 'transform 0.375s' + } : { + transition: 'transform 0.375s' + }; + this.cd.markForCheck(); + }), + delay(375), + ) + .subscribe(() => { + this.blockTransformation = {}; + }); - if (!refilling && !this.tabHidden) { - // setTimeout(() => this.audioService.playSound('bright-harmony')); - block.stage = block.matchRate >= 66 ? 1 : 2; - } + this.timeLtrSubscription = this.stateService.timeLtr.subscribe((ltr) => { + this.timeLtr = !!ltr; + this.cd.markForCheck(); + }); + + if (this.stateService.network === 'liquid' || this.stateService.network === 'liquidtestnet') { + this.feeRounding = '1.0-1'; + } + this.emptyBlocks.forEach((b) => this.emptyBlockStyles.push(this.getStyleForEmptyBlock(b))); + this.loadingBlocks$ = this.stateService.isLoadingWebSocket$; + this.networkSubscription = this.stateService.networkChanged$.subscribe((network) => this.network = network); + this.tabHiddenSubscription = this.stateService.isTabHidden$.subscribe((tabHidden) => this.tabHidden = tabHidden); + if (!this.static) { + this.blocksSubscription = this.stateService.blocks$ + .subscribe((blocks) => { + if (!blocks?.length) { + return; + } + const latestHeight = blocks[0].height; + const animate = this.chainTip != null && latestHeight > this.chainTip; + + for (const block of blocks) { + if (block?.extras) { + block.extras.minFee = this.getMinBlockFee(block); + block.extras.maxFee = this.getMaxBlockFee(block); + } + } - if (txConfirmed) { + this.blocks = blocks; + + this.blockStyles = []; + if (animate) { + this.blocks.forEach((b, i) => this.blockStyles.push(this.getStyleForBlock(b, i, i ? -this.blockOffset : -this.dividerBlockOffset))); + setTimeout(() => { + this.blockStyles = []; + this.blocks.forEach((b, i) => this.blockStyles.push(this.getStyleForBlock(b, i))); + this.cd.markForCheck(); + }, 50); + } else { + this.blocks.forEach((b, i) => this.blockStyles.push(this.getStyleForBlock(b, i))); + } + + this.chainTip = latestHeight; + + if (this.pendingMarkBlock) { + this.moveArrowToPosition(this.pendingMarkBlock.animate, this.pendingMarkBlock.newBlockFromLeft); + this.pendingMarkBlock = null; + } + this.cd.markForCheck(); + }); + + this.txConfirmedSubscription = this.stateService.txConfirmed$.subscribe(([txid, block]) => { + if (txid) { this.markHeight = block.height; this.moveArrowToPosition(true, true); } else { this.moveArrowToPosition(true, false); } - - this.blockStyles = []; - this.blocks.forEach((b) => this.blockStyles.push(this.getStyleForBlock(b))); - setTimeout(() => { - this.blockStyles = []; - this.blocks.forEach((b) => this.blockStyles.push(this.getStyleForBlock(b))); - }, 50); - + }) + } else { + this.blockPageSubscription = this.cacheService.loadedBlocks$.subscribe((block) => { + if (block.height <= this.height && block.height > this.height - this.count) { + this.onBlockLoaded(block); + } }); + } - this.stateService.markBlock$ + this.markBlockSubscription = this.stateService.markBlock$ .subscribe((state) => { this.markHeight = undefined; - if (state.blockHeight) { + if (state.blockHeight !== undefined) { this.markHeight = state.blockHeight; } this.moveArrowToPosition(false); + this.cd.markForCheck(); }); - this.stateService.keyNavigation$.subscribe((event) => { - if (!this.markHeight) { - return; - } + if (this.static) { + this.updateStaticBlocks(); + } + } - if (event.key === 'ArrowRight') { - const blockindex = this.blocks.findIndex((b) => b.height === this.markHeight); - if (this.blocks[blockindex + 1]) { - this.router.navigate([(this.network ? '/' + this.network : '') + '/block/', - this.blocks[blockindex + 1].id], { state: { data: { block: this.blocks[blockindex + 1] } } }); - } - } else if (event.key === 'ArrowLeft') { - const blockindex = this.blocks.findIndex((b) => b.height === this.markHeight); - if (blockindex === 0) { - this.router.navigate([(this.network ? '/' + this.network : '') + '/mempool-block/', '0']); - } else { - this.router.navigate([(this.network ? '/' + this.network : '') + '/block/', - this.blocks[blockindex - 1].id], { state: { data: { block: this.blocks[blockindex - 1] }}}); - } - } - }); + ngOnChanges(changes: SimpleChanges): void { + if (changes.blockWidth && this.blockWidth) { + this.blockPadding = 0.24 * this.blockWidth; + this.blockOffset = this.blockWidth + this.blockPadding; + this.dividerBlockOffset = this.blockOffset + (0.4 * this.blockWidth); + this.blockStyles = []; + this.blocks.forEach((b, i) => this.blockStyles.push(this.getStyleForBlock(b, i))); + } + if (this.static) { + const animateSlide = changes.height && (changes.height.currentValue === changes.height.previousValue + 1); + this.updateStaticBlocks(animateSlide); + } } ngOnDestroy() { - this.blocksSubscription.unsubscribe(); + if (this.blocksSubscription) { + this.blocksSubscription.unsubscribe(); + } + if (this.blockPageSubscription) { + this.blockPageSubscription.unsubscribe(); + } + if (this.txConfirmedSubscription) { + this.txConfirmedSubscription.unsubscribe(); + } + this.networkSubscription.unsubscribe(); + this.tabHiddenSubscription.unsubscribe(); + this.markBlockSubscription.unsubscribe(); + this.blockDisplayModeSubscription.unsubscribe(); + this.timeLtrSubscription.unsubscribe(); clearInterval(this.interval); } moveArrowToPosition(animate: boolean, newBlockFromLeft = false) { - if (!this.markHeight) { + if (this.markHeight === undefined) { this.arrowVisible = false; return; } + if (this.chainTip == null) { + this.pendingMarkBlock = { animate, newBlockFromLeft }; + } const blockindex = this.blocks.findIndex((b) => b.height === this.markHeight); if (blockindex > -1) { if (!animate) { - this.transition = 'inherit'; + this.arrowTransition = 'inherit'; } this.arrowVisible = true; if (newBlockFromLeft) { - this.arrowLeftPx = blockindex * 155 + 30 - 205; + this.arrowLeftPx = blockindex * this.blockOffset + this.blockPadding - this.dividerBlockOffset; setTimeout(() => { - this.transition = '2s'; - this.arrowLeftPx = blockindex * 155 + 30; + this.arrowTransition = '2s'; + this.arrowLeftPx = blockindex * this.blockOffset + this.blockPadding; + this.cd.markForCheck(); }, 50); } else { - this.arrowLeftPx = blockindex * 155 + 30; + this.arrowLeftPx = blockindex * this.blockOffset + this.blockPadding; if (!animate) { - setTimeout(() => this.transition = '2s'); + setTimeout(() => { + this.arrowTransition = '2s'; + this.cd.markForCheck(); + }, 50); } } + } else { + this.arrowVisible = false; } } - trackByBlocksFn(index: number, item: Block) { + trackByBlocksFn(index: number, item: BlockchainBlock) { return item.height; } - getStyleForBlock(block: Block) { - const greenBackgroundHeight = 100 - (block.weight / 4000000) * 100; + updateStaticBlocks(animateSlide: boolean = false) { + // reset blocks + this.blocks = []; + this.blockStyles = []; + while (this.blocks.length < this.count) { + const height = this.height - this.blocks.length; + let block; + if (height >= 0) { + this.cacheService.loadBlock(height); + block = this.cacheService.getCachedBlock(height) || null; + if (block?.extras) { + block.extras.minFee = this.getMinBlockFee(block); + block.extras.maxFee = this.getMaxBlockFee(block); + } + } + this.blocks.push(block || { + placeholder: height < 0, + loading: height >= 0, + id: '', + height, + version: 0, + timestamp: 0, + bits: 0, + nonce: 0, + difficulty: 0, + merkle_root: '', + tx_count: 0, + size: 0, + weight: 0, + previousblockhash: '', + }); + } + this.blocks = this.blocks.slice(0, this.count); + this.blockStyles = []; + this.blocks.forEach((b, i) => this.blockStyles.push(this.getStyleForBlock(b, i, animateSlide ? -this.blockOffset : 0))); + this.cd.markForCheck(); + if (animateSlide) { + // animate blocks slide right + setTimeout(() => { + this.blockStyles = []; + this.blocks.forEach((b, i) => this.blockStyles.push(this.getStyleForBlock(b, i))); + this.cd.markForCheck(); + }, 50); + this.moveArrowToPosition(true, true); + } else { + this.moveArrowToPosition(false, false); + } + } + + onBlockLoaded(block: BlockExtended) { + const blockIndex = this.height - block.height; + if (blockIndex >= 0 && blockIndex < this.blocks.length) { + if (block?.extras) { + block.extras.minFee = this.getMinBlockFee(block); + block.extras.maxFee = this.getMaxBlockFee(block); + } + this.blocks[blockIndex] = block; + this.blockStyles[blockIndex] = this.getStyleForBlock(block, blockIndex); + } + this.cd.markForCheck(); + } + + isSpecial(height: number): boolean { + return this.specialBlocks[height]?.networks.includes(this.stateService.network || 'mainnet') ? true : false; + } + + getStyleForBlock(block: BlockchainBlock, index: number, animateEnterFrom: number = 0) { + if (!block || block.placeholder) { + return this.getStyleForPlaceholderBlock(index, animateEnterFrom); + } else if (block.loading) { + return this.getStyleForLoadingBlock(index, animateEnterFrom); + } + const greenBackgroundHeight = 100 - (block.weight / this.stateService.env.BLOCK_WEIGHT_UNITS) * 100; let addLeft = 0; - if (block.stage === 1) { - block.stage = 2; - addLeft = -205; + if (animateEnterFrom) { + addLeft = animateEnterFrom || 0; } return { - left: addLeft + 155 * this.blocks.indexOf(block) + 'px', + left: addLeft + this.blockOffset * index + 'px', background: `repeating-linear-gradient( - #2d3348, - #2d3348 ${greenBackgroundHeight}%, + var(--secondary), + var(--secondary) ${greenBackgroundHeight}%, ${this.gradientColors[this.network][0]} ${Math.max(greenBackgroundHeight, 0)}%, ${this.gradientColors[this.network][1]} 100% )`, + transition: animateEnterFrom ? 'background 2s, transform 1s' : null, + }; + } + + convertStyleForLoadingBlock(style) { + return { + ...style, + background: "var(--secondary)", + }; + } + + getStyleForLoadingBlock(index: number, animateEnterFrom: number = 0) { + const addLeft = animateEnterFrom || 0; + + return { + left: addLeft + (this.blockOffset * index) + 'px', + background: "var(--secondary)", }; } + getStyleForPlaceholderBlock(index: number, animateEnterFrom: number = 0) { + const addLeft = animateEnterFrom || 0; + return { + left: addLeft + (this.blockOffset * index) + 'px', + }; + } + + getStyleForEmptyBlock(block: BlockExtended, animateEnterFrom: number = 0) { + const addLeft = animateEnterFrom || 0; + + return { + left: addLeft + this.blockOffset * this.emptyBlocks.indexOf(block) + 'px', + background: "var(--secondary)", + }; + } + + mountEmptyBlocks() { + const emptyBlocks = []; + for (let i = 0; i < this.dynamicBlocksAmount; i++) { + emptyBlocks.push({ + id: '', + height: 0, + version: 0, + timestamp: 0, + bits: 0, + nonce: 0, + difficulty: 0, + merkle_root: '', + tx_count: 0, + size: 0, + weight: 0, + previousblockhash: '', + matchRate: 0, + }); + } + return emptyBlocks; + } + + getMinBlockFee(block: BlockExtended): number { + if (block?.extras?.feeRange) { + // heuristic to check if feeRange is adjusted for effective rates + if (block.extras.medianFee === block.extras.feeRange[3]) { + return block.extras.feeRange[1]; + } else { + return block.extras.feeRange[0]; + } + } + return 0; + } + + getMaxBlockFee(block: BlockExtended): number { + if (block?.extras?.feeRange) { + return block.extras.feeRange[block.extras.feeRange.length - 1]; + } + return 0; + } } diff --git a/frontend/src/app/components/blockchain/blockchain.component.html b/frontend/src/app/components/blockchain/blockchain.component.html index 1f630e49d2..af3bf52b19 100644 --- a/frontend/src/app/components/blockchain/blockchain.component.html +++ b/frontend/src/app/components/blockchain/blockchain.component.html @@ -1,19 +1,18 @@ -
-
- - - - -
-
- - -
-

Waiting for blocks...

-
-
+
+
+ +
+
+ + + + + +
+
+ +
- - +
-
\ No newline at end of file +
diff --git a/frontend/src/app/components/blockchain/blockchain.component.scss b/frontend/src/app/components/blockchain/blockchain.component.scss index d2b3d1e329..32225598ac 100644 --- a/frontend/src/app/components/blockchain/blockchain.component.scss +++ b/frontend/src/app/components/blockchain/blockchain.component.scss @@ -1,10 +1,8 @@ #divider { - width: 3px; + width: 2px; height: 200px; left: 0; top: -50px; - background-image: url('/resources/divider-new.png'); - background-repeat: repeat-y; position: absolute; margin-bottom: 120px; } @@ -16,30 +14,35 @@ } .blockchain-wrapper { - overflow: hidden; - height: 250px; + height: 260px; + -webkit-user-select: none; /* Safari */ + -moz-user-select: none; /* Firefox */ + -ms-user-select: none; /* IE10+/Edge */ + user-select: none; /* Standard */ } .position-container { position: absolute; - left: 50%; + left: 0; top: 75px; + transform: translateX(1280px); } -/* -@media (min-width: 1920px) { - .position-container { - transform: scale(1.3); - } -} -*/ - .black-background { - background-color: #11131f; + background-color: var(--active-bg); z-index: 100; position: relative; } +.scroll-spacer { + position: absolute; + top: 0; + left: 0; + width: 1px; + height: 1px; + pointer-events: none; +} + .loading-block { position: absolute; text-align: center; @@ -47,4 +50,67 @@ width: 300px; left: -150px; top: 0px; +} + +.time-toggle { + color: var(--fg); + font-size: 0.8rem; + position: absolute; + bottom: -2.2em; + left: 1px; + transform: translateX(-50%); + background: none; + border: none; + outline: none; + margin: 0; + padding: 0; +} + +.block-display-toggle { + color: var(--fg); + font-size: 0.8rem; + position: absolute; + bottom: 16.1em; + left: 1px; + transform: translateX(-50%) rotate(90deg); + background: none; + border: none; + outline: none; + margin: 0; + padding: 0; +} + +.blockchain-wrapper.ltr-transition .blocks-wrapper, +.blockchain-wrapper.ltr-transition .position-container, +.blockchain-wrapper.ltr-transition .time-toggle, +.blockchain-wrapper.ltr-transition .block-display-toggle { + transition: transform 1s; +} + +.blockchain-wrapper.time-ltr { + .blocks-wrapper { + transform: scaleX(-1); + } + + .time-toggle { + transform: translateX(-50%) scaleX(-1); + } + + .block-display-toggle { + transform: translateX(-50%) scaleX(-1) rotate(90deg); + } +} + +:host-context(.ltr-layout) { + .blockchain-wrapper.time-ltr .blocks-wrapper, + .blockchain-wrapper .blocks-wrapper { + direction: ltr; + } +} + +:host-context(.rtl-layout) { + .blockchain-wrapper.time-ltr .blocks-wrapper, + .blockchain-wrapper .blocks-wrapper { + direction: rtl; + } } \ No newline at end of file diff --git a/frontend/src/app/components/blockchain/blockchain.component.ts b/frontend/src/app/components/blockchain/blockchain.component.ts index fd6209e24e..d70e788a20 100644 --- a/frontend/src/app/components/blockchain/blockchain.component.ts +++ b/frontend/src/app/components/blockchain/blockchain.component.ts @@ -1,21 +1,146 @@ -import { Component, OnInit } from '@angular/core'; -import { StateService } from 'src/app/services/state.service'; +import { Component, OnInit, OnDestroy, ChangeDetectionStrategy, Input, Output, EventEmitter, ChangeDetectorRef, OnChanges, SimpleChanges } from '@angular/core'; +import { firstValueFrom, Subscription } from 'rxjs'; +import { StateService } from '../../services/state.service'; +import { StorageService } from '../../services/storage.service'; @Component({ selector: 'app-blockchain', templateUrl: './blockchain.component.html', - styleUrls: ['./blockchain.component.scss'] + styleUrls: ['./blockchain.component.scss'], + changeDetection: ChangeDetectionStrategy.OnPush, }) -export class BlockchainComponent implements OnInit { - txTrackingLoading = false; - txShowTxNotFound = false; - isLoading = true; +export class BlockchainComponent implements OnInit, OnDestroy, OnChanges { + @Input() pages: any[] = []; + @Input() pageIndex: number; + @Input() blocksPerPage: number = 8; + @Input() minScrollWidth: number = 0; + @Input() scrollableMempool: boolean = false; + @Input() containerWidth: number; + + @Output() mempoolOffsetChange: EventEmitter = new EventEmitter(); + + network: string; + timeLtrSubscription: Subscription; + timeLtr: boolean = this.stateService.timeLtr.value; + ltrTransitionEnabled = false; + flipping = false; + connectionStateSubscription: Subscription; + loadingTip: boolean = true; + connected: boolean = true; + blockDisplayMode: 'size' | 'fees'; + + dividerOffset: number | null = null; + mempoolOffset: number | null = null; + positionStyle = { + transform: "translateX(1280px)", + }; + blockDisplayToggleStyle = {}; constructor( - private stateService: StateService, + public stateService: StateService, + public StorageService: StorageService, + private cd: ChangeDetectorRef, ) {} - ngOnInit() { - this.stateService.blocks$.subscribe(() => this.isLoading = false); + ngOnInit(): void { + this.onResize(); + this.network = this.stateService.network; + this.timeLtrSubscription = this.stateService.timeLtr.subscribe((ltr) => { + this.timeLtr = !!ltr; + this.updateStyle(); + }); + this.connectionStateSubscription = this.stateService.connectionState$.subscribe(state => { + this.connected = (state === 2); + }); + firstValueFrom(this.stateService.chainTip$).then(() => { + this.loadingTip = false; + }); + this.blockDisplayMode = this.StorageService.getValue('block-display-mode-preference') as 'size' | 'fees' || 'fees'; + } + + ngOnDestroy(): void { + this.timeLtrSubscription.unsubscribe(); + this.connectionStateSubscription.unsubscribe(); + } + + trackByPageFn(index: number, item: { index: number }): number { + return item.index; + } + + toggleTimeDirection(): void { + this.ltrTransitionEnabled = false; + const prevOffset = this.mempoolOffset; + this.mempoolOffset = 0; + this.mempoolOffsetChange.emit(0); + this.updateStyle(); + setTimeout(() => { + this.ltrTransitionEnabled = true; + this.flipping = true; + this.stateService.timeLtr.next(!this.timeLtr); + this.cd.markForCheck(); + setTimeout(() => { + this.ltrTransitionEnabled = false; + this.flipping = false; + this.mempoolOffset = prevOffset; + this.mempoolOffsetChange.emit((this.mempoolOffset || 0)); + this.updateStyle(); + this.cd.markForCheck(); + }, 1000); + }, 0); + } + + toggleBlockDisplayMode(): void { + if (this.blockDisplayMode === 'size') this.blockDisplayMode = 'fees'; + else this.blockDisplayMode = 'size'; + this.StorageService.setValue('block-display-mode-preference', this.blockDisplayMode); + this.stateService.blockDisplayMode$.next(this.blockDisplayMode); + } + + onMempoolWidthChange(width): void { + if (this.flipping) { + return; + } + this.mempoolOffset = Math.max(0, width - (this.dividerOffset || 0)); + this.updateStyle(); + this.mempoolOffsetChange.emit(this.mempoolOffset); + } + + updateStyle(): void { + if (this.dividerOffset == null || this.mempoolOffset == null) { + return; + } + const oldTransform = this.positionStyle.transform; + this.positionStyle = this.timeLtr ? { + transform: `translateX(calc(100vw - ${this.dividerOffset + this.mempoolOffset}px)`, + } : { + transform: `translateX(${this.dividerOffset + this.mempoolOffset}px)`, + }; + if (oldTransform !== this.positionStyle.transform) { + this.cd.detectChanges(); + } + } + + ngOnChanges(changes: SimpleChanges): void { + if (changes.containerWidth) { + this.onResize(); + } + } + + onResize(): void { + const width = this.containerWidth || window.innerWidth; + if (width >= 768) { + if (this.stateService.isLiquid()) { + this.dividerOffset = 420; + } else { + this.dividerOffset = width * 0.5; + } + } else { + if (this.stateService.isLiquid()) { + this.dividerOffset = width * 0.5; + } else { + this.dividerOffset = width * 0.95; + } + } + this.updateStyle(); } } diff --git a/frontend/src/app/components/blocks-list/blocks-list.component.html b/frontend/src/app/components/blocks-list/blocks-list.component.html new file mode 100644 index 0000000000..d824724922 --- /dev/null +++ b/frontend/src/app/components/blocks-list/blocks-list.component.html @@ -0,0 +1,134 @@ + + +
+

Blocks

+
+ +
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
HeightPoolTimestampHealthRewardFeesTXsTransactionsSize
+ {{ block.height }} + +
+ + + {{ block.extras.pool.name }} + + {{ block.extras.coinbaseRaw | hex2ascii }} +
+
+ + {{ block.extras.pool.name }} + {{ block.extras.coinbaseRaw | hex2ascii }} +
+
+ ‎{{ block.timestamp * 1000 | date:'yyyy-MM-dd HH:mm:ss' }} + + {{ block.extras.matchRate }}% + + Unknown + + + + + + + + {{ block.extras.feeDelta > 0 ? '+' : '' }}{{ (block.extras.feeDelta * 100) | amountShortener: 2 }}% + + + {{ block.tx_count | number }} + +
+
+
+
+
+ + + + + + + + + + + + + + + + + +
+ + + + + +
+
+
+
+ +
diff --git a/frontend/src/app/components/blocks-list/blocks-list.component.scss b/frontend/src/app/components/blocks-list/blocks-list.component.scss new file mode 100644 index 0000000000..2315844aed --- /dev/null +++ b/frontend/src/app/components/blocks-list/blocks-list.component.scss @@ -0,0 +1,291 @@ +.spinner-border { + height: 25px; + width: 25px; + margin-top: 13px; +} + +.container-xl { + max-width: 1400px; +} +.container-xl.widget { + padding-left: 0px; + padding-bottom: 0px; +} +.container-xl.legacy { + max-width: 1140px; +} + +.container { + max-width: 100%; +} + +tr, td, th { + border: 0px; + padding-top: 0.65rem !important; + padding-bottom: 0.7rem !important; + + .difference { + margin-left: 0.5em; + + &.positive { + color: rgb(66, 183, 71); + } + &.negative { + color: rgb(183, 66, 66); + } + } +} + +.clear-link { + color: white; +} + +.disabled { + pointer-events: none; + opacity: 0.5; +} + +.progress { + background-color: var(--secondary); +} + +.pool { + width: 17%; + @media (max-width: 576px) { + width: 34%; + } + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + max-width: 160px; +} +.pool.widget { + width: 40%; + padding-left: 24px; + @media (min-width: 768px) AND (max-width: 926px) { + padding-left: 0px; + width: 60%; + } + @media (max-width: 430px) { + padding-left: 0px; + width: 60%; + } +} +.pool-name { + display: inline-block; + vertical-align: text-top; + padding-left: 10px; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + max-width: 160px; +} + +.height { + width: 8%; +} +.height.widget { + width: 15%; + @media (max-width: 576px) { + width: 10%; + } + @media (min-width: 768px) AND (max-width: 926px) { + width: 30%; + } + @media (max-width: 430px) { + width: 30%; + } +} +.height.legacy { + width: 15%; +} + +.timestamp { + width: 10%; + @media (max-width: 1100px) { + display: none; + } +} +.timestamp.legacy { + width: 20%; + @media (max-width: 1100px) { + display: table-cell; + } + @media (max-width: 850px) { + display: none; + } +} + +.mined { + width: 13%; + @media (max-width: 730px) { + display: none; + } +} +.mined.legacy { + width: 15%; + @media (max-width: 1000px) { + padding-right: 20px; + width: 20%; + } + @media (max-width: 576px) { + display: table-cell; + } +} + +.txs { + padding-right: 20px; + width: 6%; + @media (max-width: 1100px) { + padding-right: 10px; + } + @media (max-width: 875px) { + display: none; + } + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + max-width: 100px; +} +.txs.widget { + padding-right: 0; + display: none; + @media (max-width: 650px) { + display: none; + } +} +.txs.legacy { + width: 18%; + display: table-cell; + @media (max-width: 1000px) { + padding-right: 20px; + } +} + +.fees { + width: 8%; + @media (max-width: 820px) { + display: none; + } +} +.fees.widget { + width: 20%; +} +.fee-delta { + width: 6%; + padding-left: 0; + @media (max-width: 991px) { + display: none; + } +} +.fee-delta.widget { + display: none; +} + +.reward { + width: 8%; + @media (max-width: 576px) { + width: 7%; + padding-right: 30px; + } + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + max-width: 130px; +} +.reward.widget { + width: 20%; + @media (max-width: 576px) { + width: 30%; + padding-right: 0; + } + @media (min-width: 768px) AND (max-width: 926px) { + overflow: hidden; + text-overflow: ellipsis; + max-width: 90px; + } + @media (max-width: 430px) { + overflow: hidden; + text-overflow: ellipsis; + max-width: 90px; + } +} + +.size { + width: 10%; + @media (max-width: 1000px) { + width: 13%; + } + @media (max-width: 950px) { + width: 15%; + } + @media (max-width: 650px) { + width: 20%; + } + @media (max-width: 450px) { + display: none; + } +} +.size.legacy { + width: 30%; + @media (max-width: 576px) { + display: table-cell; + } +} + +.health { + width: 10%; + @media (max-width: 1100px) { + width: 13%; + } + @media (max-width: 560px) { + display: none; + } + + .progress-text .skeleton-loader { + top: -8.5px; + } +} +.health.widget { + width: 25%; + @media (max-width: 1105px) { + display: none; + } + @media (max-width: 767px) { + display: table-cell; + } + @media (max-width: 500px) { + display: none; + } +} + +/* Tooltip text */ +.tooltip-custom { + position: relative; +} + +.tooltip-custom .tooltiptext { + visibility: hidden; + color: var(--fg); + text-align: center; + padding: 5px 0; + border-radius: 6px; + position: absolute; + z-index: 1; + top: -40px; + left: 0; +} + +/* Show the tooltip text when you mouse over the tooltip container */ +.tooltip-custom:hover .tooltiptext { + visibility: visible; +} + +.scriptmessage { + overflow: hidden; + display: inline-block; + text-overflow: ellipsis; + vertical-align: middle; + max-width: 50vw; + text-align: left; +} diff --git a/frontend/src/app/components/blocks-list/blocks-list.component.ts b/frontend/src/app/components/blocks-list/blocks-list.component.ts new file mode 100644 index 0000000000..5270ee7be9 --- /dev/null +++ b/frontend/src/app/components/blocks-list/blocks-list.component.ts @@ -0,0 +1,200 @@ +import { Component, OnInit, ChangeDetectionStrategy, Input, ChangeDetectorRef, Inject, LOCALE_ID } from '@angular/core'; +import { ActivatedRoute, Router } from '@angular/router'; +import { BehaviorSubject, combineLatest, Observable, timer, of, Subscription } from 'rxjs'; +import { debounceTime, delayWhen, filter, map, retryWhen, scan, skip, switchMap, tap, throttleTime } from 'rxjs/operators'; +import { BlockExtended } from '../../interfaces/node-api.interface'; +import { ApiService } from '../../services/api.service'; +import { StateService } from '../../services/state.service'; +import { WebsocketService } from '../../services/websocket.service'; +import { SeoService } from '../../services/seo.service'; +import { OpenGraphService } from '../../services/opengraph.service'; +import { seoDescriptionNetwork } from '../../shared/common.utils'; + +@Component({ + selector: 'app-blocks-list', + templateUrl: './blocks-list.component.html', + styleUrls: ['./blocks-list.component.scss'], + changeDetection: ChangeDetectionStrategy.OnPush, +}) +export class BlocksList implements OnInit { + @Input() widget: boolean = false; + + blocks$: Observable = undefined; + + isMempoolModule = false; + indexingAvailable = false; + auditAvailable = false; + isLoading = true; + fromBlockHeight = undefined; + lastBlockHeightFetched = -1; + paginationMaxSize: number; + page = 1; + lastPage = 1; + maxSize = window.innerWidth <= 767.98 ? 3 : 5; + blocksCount: number; + fromHeightSubject: BehaviorSubject = new BehaviorSubject(this.fromBlockHeight); + skeletonLines: number[] = []; + lastBlockHeight = -1; + blocksCountInitialized$: BehaviorSubject = new BehaviorSubject(false); + blocksCountInitializedSubscription: Subscription; + keyNavigationSubscription: Subscription; + dir: 'rtl' | 'ltr' = 'ltr'; + + constructor( + private apiService: ApiService, + private websocketService: WebsocketService, + public stateService: StateService, + private cd: ChangeDetectorRef, + private seoService: SeoService, + private ogService: OpenGraphService, + private route: ActivatedRoute, + private router: Router, + @Inject(LOCALE_ID) private locale: string, + ) { + this.isMempoolModule = this.stateService.env.BASE_MODULE === 'mempool'; + if (this.locale.startsWith('ar') || this.locale.startsWith('fa') || this.locale.startsWith('he')) { + this.dir = 'rtl'; + } + } + + ngOnInit(): void { + this.indexingAvailable = (this.stateService.env.BASE_MODULE === 'mempool' && + this.stateService.env.MINING_DASHBOARD === true); + this.auditAvailable = this.indexingAvailable && this.stateService.env.AUDIT; + + if (!this.widget) { + this.websocketService.want(['blocks']); + + this.seoService.setTitle($localize`:@@8a7b4bd44c0ac71b2e72de0398b303257f7d2f54:Blocks`); + this.ogService.setManualOgImage('recent-blocks.jpg'); + if( this.stateService.network==='liquid'||this.stateService.network==='liquidtestnet' ) { + this.seoService.setDescription($localize`:@@meta.description.liquid.blocks:See the most recent Liquid${seoDescriptionNetwork(this.stateService.network)} blocks along with basic stats such as block height, block size, and more.`); + } else { + this.seoService.setDescription($localize`:@@meta.description.bitcoin.blocks:See the most recent Bitcoin${seoDescriptionNetwork(this.stateService.network)} blocks along with basic stats such as block height, block reward, block size, and more.`); + } + + this.blocksCountInitializedSubscription = combineLatest([this.blocksCountInitialized$, this.route.params]).pipe( + filter(([blocksCountInitialized, _]) => blocksCountInitialized), + tap(([_, params]) => { + this.page = +params['page'] || 1; + this.page === 1 ? this.fromHeightSubject.next(undefined) : this.fromHeightSubject.next((this.blocksCount - 1) - (this.page - 1) * 15); + }) + ).subscribe(); + + const prevKey = this.dir === 'ltr' ? 'ArrowLeft' : 'ArrowRight'; + const nextKey = this.dir === 'ltr' ? 'ArrowRight' : 'ArrowLeft'; + + this.keyNavigationSubscription = this.stateService.keyNavigation$ + .pipe( + filter((event) => event.key === prevKey || event.key === nextKey), + tap((event) => { + if (event.key === prevKey && this.page > 1) { + this.page--; + this.isLoading = true; + this.cd.markForCheck(); + } + if (event.key === nextKey && this.page * 15 < this.blocksCount) { + this.page++; + this.isLoading = true; + this.cd.markForCheck(); + } + }), + throttleTime(1000, undefined, { leading: true, trailing: true }), + ).subscribe(() => { + this.pageChange(this.page); + }); + } + + this.skeletonLines = this.widget === true ? [...Array(6).keys()] : [...Array(15).keys()]; + this.paginationMaxSize = window.matchMedia('(max-width: 670px)').matches ? 3 : 5; + + this.blocks$ = combineLatest([ + this.fromHeightSubject.pipe( + filter(fromBlockHeight => fromBlockHeight !== this.lastBlockHeightFetched), + switchMap((fromBlockHeight) => { + this.isLoading = true; + this.lastBlockHeightFetched = fromBlockHeight; + return this.apiService.getBlocks$(this.page === 1 ? undefined : fromBlockHeight) + .pipe( + tap(blocks => { + if (this.blocksCount === undefined) { + this.blocksCount = blocks[0].height + 1; + this.blocksCountInitialized$.next(true); + this.blocksCountInitialized$.complete(); + } + this.isLoading = false; + this.lastBlockHeight = Math.max(...blocks.map(o => o.height)); + }), + map(blocks => { + if (this.stateService.env.BASE_MODULE === 'mempool') { + for (const block of blocks) { + // @ts-ignore: Need to add an extra field for the template + block.extras.pool.logo = `/resources/mining-pools/` + block.extras.pool.slug + '.svg'; + } + } + if (this.widget) { + return blocks.slice(0, 6); + } + return blocks; + }), + retryWhen(errors => errors.pipe(delayWhen(() => timer(10000)))) + ); + }) + ), + this.stateService.blocks$ + .pipe( + switchMap((blocks) => { + if (blocks[0].height <= this.lastBlockHeight) { + return of([]); // Return an empty stream so the last pipe is not executed + } + this.lastBlockHeight = blocks[0].height; + return of(blocks); + }) + ) + ]) + .pipe( + scan((acc, blocks) => { + if (this.page > 1 || acc.length === 0 || (this.page === 1 && this.lastPage !== 1)) { + this.lastPage = this.page; + return blocks[0]; + } + if (blocks[1] && blocks[1].length) { + this.blocksCount = Math.max(this.blocksCount, blocks[1][0].height) + 1; + if (this.isMempoolModule) { + // @ts-ignore: Need to add an extra field for the template + blocks[1][0].extras.pool.logo = `/resources/mining-pools/` + + blocks[1][0].extras.pool.slug + '.svg'; + } + acc.unshift(blocks[1][0]); + acc = acc.slice(0, this.widget ? 6 : 15); + } + return acc; + }, []), + switchMap((blocks) => { + if (this.isMempoolModule && this.auditAvailable) { + blocks.forEach(block => { + block.extras.feeDelta = block.extras.expectedFees ? (block.extras.totalFees - block.extras.expectedFees) / block.extras.expectedFees : 0; + }); + } + return of(blocks); + }) + ); + } + + pageChange(page: number): void { + this.router.navigate(['blocks', page]); + } + + trackByBlock(index: number, block: BlockExtended): number { + return block.height; + } + + isEllipsisActive(e): boolean { + return (e.offsetWidth < e.scrollWidth); + } + + ngOnDestroy(): void { + this.blocksCountInitializedSubscription?.unsubscribe(); + this.keyNavigationSubscription?.unsubscribe(); + } +} diff --git a/frontend/src/app/components/calculator/calculator.component.html b/frontend/src/app/components/calculator/calculator.component.html new file mode 100644 index 0000000000..e4ade67d2f --- /dev/null +++ b/frontend/src/app/components/calculator/calculator.component.html @@ -0,0 +1,69 @@ +
+
+

Calculator

+
+ + + +
+ +
+
+
+ {{ currency$ | async }} +
+ + +
+ +
+
+ BTC +
+ + +
+ +
+
+ sats +
+ + +
+
+ +
+ +
+ +
+
+ ₿ + + sats +
+
+ +
+
+ +
+
+ +
+
+ Fiat price last updated +
+
+ + +
+ + +
+ Waiting for price feed... +
+
+ +
\ No newline at end of file diff --git a/frontend/src/app/components/calculator/calculator.component.scss b/frontend/src/app/components/calculator/calculator.component.scss new file mode 100644 index 0000000000..81f74f9ee0 --- /dev/null +++ b/frontend/src/app/components/calculator/calculator.component.scss @@ -0,0 +1,30 @@ +.input-group-text { + width: 75px; +} + +.bitcoin-satoshis-text { + font-size: 40px; +} + +.fiat-text { + font-size: 24px; +} + +.symbol { + font-style: italic; +} + +@media (max-width: 767.98px) { + .bitcoin-satoshis-text { + font-size: 30px; + } +} + +.sats { + font-size: 20px; + margin-left: 5px; +} + +.row { + margin: auto; +} diff --git a/frontend/src/app/components/calculator/calculator.component.ts b/frontend/src/app/components/calculator/calculator.component.ts new file mode 100644 index 0000000000..a6f10c0493 --- /dev/null +++ b/frontend/src/app/components/calculator/calculator.component.ts @@ -0,0 +1,137 @@ +import { ChangeDetectionStrategy, Component, OnInit } from '@angular/core'; +import { FormBuilder, FormGroup } from '@angular/forms'; +import { combineLatest, Observable } from 'rxjs'; +import { map, switchMap } from 'rxjs/operators'; +import { StateService } from '../../services/state.service'; +import { WebsocketService } from '../../services/websocket.service'; + +@Component({ + selector: 'app-calculator', + templateUrl: './calculator.component.html', + styleUrls: ['./calculator.component.scss'], + changeDetection: ChangeDetectionStrategy.OnPush +}) +export class CalculatorComponent implements OnInit { + satoshis = 10000; + form: FormGroup; + + currency$ = this.stateService.fiatCurrency$; + price$: Observable; + lastFiatPrice$: Observable; + + constructor( + private stateService: StateService, + private formBuilder: FormBuilder, + private websocketService: WebsocketService, + ) { } + + ngOnInit(): void { + this.form = this.formBuilder.group({ + fiat: [0], + bitcoin: [0], + satoshis: [0], + }); + + this.lastFiatPrice$ = this.stateService.conversions$.asObservable() + .pipe( + map((conversions) => conversions.time) + ); + + let currency; + this.price$ = this.currency$.pipe( + switchMap((result) => { + currency = result; + return this.stateService.conversions$.asObservable(); + }), + map((conversions) => { + return conversions[currency]; + }) + ); + + combineLatest([ + this.price$, + this.form.get('fiat').valueChanges + ]).subscribe(([price, value]) => { + const rate = (value / price).toFixed(8); + const satsRate = Math.round(value / price * 100_000_000); + if (isNaN(value)) { + return; + } + this.form.get('bitcoin').setValue(rate, { emitEvent: false }); + this.form.get('satoshis').setValue(satsRate, { emitEvent: false } ); + }); + + combineLatest([ + this.price$, + this.form.get('bitcoin').valueChanges + ]).subscribe(([price, value]) => { + const rate = parseFloat((value * price).toFixed(8)); + if (isNaN(value)) { + return; + } + this.form.get('fiat').setValue(rate, { emitEvent: false } ); + this.form.get('satoshis').setValue(Math.round(value * 100_000_000), { emitEvent: false } ); + }); + + combineLatest([ + this.price$, + this.form.get('satoshis').valueChanges + ]).subscribe(([price, value]) => { + const rate = parseFloat((value / 100_000_000 * price).toFixed(8)); + const bitcoinRate = (value / 100_000_000).toFixed(8); + if (isNaN(value)) { + return; + } + this.form.get('fiat').setValue(rate, { emitEvent: false } ); + this.form.get('bitcoin').setValue(bitcoinRate, { emitEvent: false }); + }); + + } + + transformInput(name: string): void { + const formControl = this.form.get(name); + if (!formControl.value) { + return formControl.setValue('', {emitEvent: false}); + } + let value = formControl.value.replace(',', '.').replace(/[^0-9.]/g, ''); + if (value === '.') { + value = '0'; + } + let sanitizedValue = this.removeExtraDots(value); + if (name === 'bitcoin' && this.countDecimals(sanitizedValue) > 8) { + sanitizedValue = this.toFixedWithoutRounding(sanitizedValue, 8); + } + if (sanitizedValue === '') { + sanitizedValue = '0'; + } + if (name === 'satoshis') { + sanitizedValue = parseFloat(sanitizedValue).toFixed(0); + } + formControl.setValue(sanitizedValue, {emitEvent: true}); + } + + removeExtraDots(str: string): string { + const [beforeDot, afterDot] = str.split('.', 2); + if (afterDot === undefined) { + return str; + } + const afterDotReplaced = afterDot.replace(/\./g, ''); + return `${beforeDot}.${afterDotReplaced}`; + } + + countDecimals(numberString: string): number { + const decimalPos = numberString.indexOf('.'); + if (decimalPos === -1) return 0; + return numberString.length - decimalPos - 1; + } + + toFixedWithoutRounding(numStr: string, fixed: number): string { + const re = new RegExp(`^-?\\d+(?:.\\d{0,${(fixed || -1)}})?`); + const result = numStr.match(re); + return result ? result[0] : numStr; + } + + selectAll(event): void { + event.target.select(); + } +} diff --git a/frontend/src/app/components/change/change.component.html b/frontend/src/app/components/change/change.component.html new file mode 100644 index 0000000000..ffc00bf5f0 --- /dev/null +++ b/frontend/src/app/components/change/change.component.html @@ -0,0 +1,3 @@ + + ‎{{ change >= 0 ? '+' : '' }}{{ change | amountShortener }}% + diff --git a/frontend/src/app/bisq/bisq-icon/bisq-icon.component.scss b/frontend/src/app/components/change/change.component.scss similarity index 100% rename from frontend/src/app/bisq/bisq-icon/bisq-icon.component.scss rename to frontend/src/app/components/change/change.component.scss diff --git a/frontend/src/app/components/change/change.component.ts b/frontend/src/app/components/change/change.component.ts new file mode 100644 index 0000000000..c4ae965cea --- /dev/null +++ b/frontend/src/app/components/change/change.component.ts @@ -0,0 +1,25 @@ +import { ChangeDetectionStrategy, Component, Input, OnChanges } from '@angular/core'; + +@Component({ + selector: 'app-change', + templateUrl: './change.component.html', + styleUrls: ['./change.component.scss'], + changeDetection: ChangeDetectionStrategy.OnPush, +}) +export class ChangeComponent implements OnChanges { + @Input() current: number; + @Input() previous: number; + + change: number; + + constructor() { } + + ngOnChanges(): void { + if (!this.previous) { + this.change = 0; + } else { + this.change = (this.current - this.previous) / this.previous * 100; + } + } + +} diff --git a/frontend/src/app/components/clipboard/clipboard.component.html b/frontend/src/app/components/clipboard/clipboard.component.html index 7e76856071..d23ccdf8c5 100644 --- a/frontend/src/app/components/clipboard/clipboard.component.html +++ b/frontend/src/app/components/clipboard/clipboard.component.html @@ -1,5 +1,15 @@ - - - \ No newline at end of file +
+ + + + + + diff --git a/frontend/src/app/components/clipboard/clipboard.component.scss b/frontend/src/app/components/clipboard/clipboard.component.scss index e69de29bb2..49294e5485 100644 --- a/frontend/src/app/components/clipboard/clipboard.component.scss +++ b/frontend/src/app/components/clipboard/clipboard.component.scss @@ -0,0 +1,13 @@ +.btn-link { + padding: 0.25rem 0 0.1rem 0rem; + line-height: 0; +} + +.padding { + padding-left: 0.4rem; +} + +img { + position: relative; + left: -3px; +} \ No newline at end of file diff --git a/frontend/src/app/components/clipboard/clipboard.component.spec.ts b/frontend/src/app/components/clipboard/clipboard.component.spec.ts deleted file mode 100644 index a9b89d62c6..0000000000 --- a/frontend/src/app/components/clipboard/clipboard.component.spec.ts +++ /dev/null @@ -1,25 +0,0 @@ -import { async, ComponentFixture, TestBed } from '@angular/core/testing'; - -import { ClipboardComponent } from './clipboard.component'; - -describe('ClipboardComponent', () => { - let component: ClipboardComponent; - let fixture: ComponentFixture; - - beforeEach(async(() => { - TestBed.configureTestingModule({ - declarations: [ ClipboardComponent ] - }) - .compileComponents(); - })); - - beforeEach(() => { - fixture = TestBed.createComponent(ClipboardComponent); - component = fixture.componentInstance; - fixture.detectChanges(); - }); - - it('should create', () => { - expect(component).toBeTruthy(); - }); -}); diff --git a/frontend/src/app/components/clipboard/clipboard.component.ts b/frontend/src/app/components/clipboard/clipboard.component.ts index af20dd7309..6e577d8b3b 100644 --- a/frontend/src/app/components/clipboard/clipboard.component.ts +++ b/frontend/src/app/components/clipboard/clipboard.component.ts @@ -1,16 +1,28 @@ -import { Component, OnInit, ViewChild, ElementRef, AfterViewInit, Input } from '@angular/core'; +import { Component, ViewChild, ElementRef, AfterViewInit, Input, ChangeDetectionStrategy } from '@angular/core'; import * as ClipboardJS from 'clipboard'; import * as tlite from 'tlite'; @Component({ selector: 'app-clipboard', templateUrl: './clipboard.component.html', - styleUrls: ['./clipboard.component.scss'] + styleUrls: ['./clipboard.component.scss'], + changeDetection: ChangeDetectionStrategy.OnPush, }) export class ClipboardComponent implements AfterViewInit { @ViewChild('btn') btn: ElementRef; @ViewChild('buttonWrapper') buttonWrapper: ElementRef; + @Input() button = false; + @Input() class = 'btn btn-secondary ml-1'; + @Input() size: 'small' | 'normal' | 'large' = 'normal'; @Input() text: string; + @Input() leftPadding = true; + copiedMessage: string = $localize`:@@clipboard.copied-message:Copied!`; + + widths = { + small: '10', + normal: '13', + large: '18', + }; clipboard: any; @@ -18,7 +30,7 @@ export class ClipboardComponent implements AfterViewInit { ngAfterViewInit() { this.clipboard = new ClipboardJS(this.btn.nativeElement); - this.clipboard.on('success', (e) => { + this.clipboard.on('success', () => { tlite.show(this.buttonWrapper.nativeElement); setTimeout(() => { tlite.hide(this.buttonWrapper.nativeElement); diff --git a/frontend/src/app/components/clock-face/clock-face.component.html b/frontend/src/app/components/clock-face/clock-face.component.html new file mode 100644 index 0000000000..b3d478ebbd --- /dev/null +++ b/frontend/src/app/components/clock-face/clock-face.component.html @@ -0,0 +1,42 @@ +
+ + + + + + + + + + + + + + + + + + + + + + + + + + +
\ No newline at end of file diff --git a/frontend/src/app/components/clock-face/clock-face.component.scss b/frontend/src/app/components/clock-face/clock-face.component.scss new file mode 100644 index 0000000000..e2bb215d48 --- /dev/null +++ b/frontend/src/app/components/clock-face/clock-face.component.scss @@ -0,0 +1,69 @@ +.clock-face { + position: relative; + height: 84.375%; + margin: auto; + overflow: hidden; + + .cut-out, .demo-dial { + position: absolute; + left: 0; + right: 0; + top: 0; + bottom: 0; + width: 100%; + height: 100%; + + .face { + fill: var(--active-bg); + } + } + + .gnomon { + transform-origin: center; + stroke-linejoin: round; + + &.minute { + fill:#80C2E1; + stroke:#80C2E1; + stroke-width: 2px; + } + + &.hour { + fill: var(--primary); + stroke: var(--primary); + stroke-width: 6px; + } + } + + .tick { + transform-origin: center; + fill: none; + stroke: white; + stroke-width: 2px; + stroke-linecap: butt; + + &.minor { + stroke-opacity: 0.5; + } + + &.very.major { + stroke-width: 4px; + } + } + + .block-segment { + fill: none; + stroke: url(#dial-gradient); + stroke-width: 18px; + } + + .dial-segment { + fill: none; + stroke: white; + stroke-width: 2px; + } + + .dial-gradient-img { + transform-origin: center; + } +} \ No newline at end of file diff --git a/frontend/src/app/components/clock-face/clock-face.component.ts b/frontend/src/app/components/clock-face/clock-face.component.ts new file mode 100644 index 0000000000..eec0fa98cb --- /dev/null +++ b/frontend/src/app/components/clock-face/clock-face.component.ts @@ -0,0 +1,148 @@ +import { ChangeDetectionStrategy, ChangeDetectorRef, Component, Input, OnChanges, OnDestroy, OnInit } from '@angular/core'; +import { Subscription, tap, timer } from 'rxjs'; +import { StateService } from '../../services/state.service'; + +@Component({ + selector: 'app-clock-face', + templateUrl: './clock-face.component.html', + styleUrls: ['./clock-face.component.scss'], + changeDetection: ChangeDetectionStrategy.OnPush, +}) +export class ClockFaceComponent implements OnInit, OnChanges, OnDestroy { + @Input() size: number = 300; + + blocksSubscription: Subscription; + timeSubscription: Subscription; + + faceStyle; + dialPath; + blockTimes = []; + segments = []; + hours: number = 0; + minutes: number = 0; + minorTicks: number[] = []; + majorTicks: number[] = []; + + constructor( + public stateService: StateService, + private cd: ChangeDetectorRef + ) { + this.updateTime(); + this.makeTicks(); + } + + ngOnInit(): void { + if (this.stateService.isBrowser) { + this.timeSubscription = timer(0, 250).pipe( + tap(() => { + console.log('face tick'); + this.updateTime(); + }) + ).subscribe(); + this.blocksSubscription = this.stateService.blocks$ + .subscribe((blocks) => { + this.blockTimes = blocks.map(block => [block.height, new Date(block.timestamp * 1000)]); + this.blockTimes = this.blockTimes.sort((a, b) => a[1].getTime() - b[1].getTime()); + this.updateSegments(); + }); + } + } + + ngOnChanges(): void { + this.faceStyle = { + width: `${this.size}px`, + height: `${this.size}px`, + }; + } + + ngOnDestroy(): void { + if (this.timeSubscription) { + this.timeSubscription.unsubscribe(); + } + } + + updateTime(): void { + const now = new Date(); + const seconds = now.getSeconds() + (now.getMilliseconds() / 1000); + this.minutes = (now.getMinutes() + (seconds / 60)) % 60; + this.hours = now.getHours() + (this.minutes / 60); + this.updateSegments(); + } + + updateSegments(): void { + const now = new Date(); + this.blockTimes = this.blockTimes.filter(time => (now.getTime() - time[1].getTime()) <= 3600000); + const tail = new Date(now.getTime() - 3600000); + const hourStart = new Date(now.getFullYear(), now.getMonth(), now.getDate(), now.getHours()); + + const times = [ + ['start', tail], + ...this.blockTimes, + ['end', now], + ]; + const minuteTimes = times.map(time => { + return [time[0], (time[1].getTime() - hourStart.getTime()) / 60000]; + }); + this.segments = []; + const r = 174; + const cx = 192; + const cy = cx; + for (let i = 1; i < minuteTimes.length; i++) { + const arc = this.getArc(minuteTimes[i-1][1], minuteTimes[i][1], r, cx, cy); + if (arc) { + arc.id = minuteTimes[i][0]; + this.segments.push(arc); + } + } + const arc = this.getArc(minuteTimes[0][1], minuteTimes[1][1], r, cx, cy); + if (arc) { + this.dialPath = arc.path; + } + + this.cd.markForCheck(); + } + + getArc(startTime, endTime, r, cx, cy): any { + const startDegrees = (startTime + 0.2) * 6; + const endDegrees = (endTime - 0.2) * 6; + const start = this.getPointOnCircle(startDegrees, r, cx, cy); + const end = this.getPointOnCircle(endDegrees, r, cx, cy); + const arcLength = endDegrees - startDegrees; + // merge gaps and omit lines shorter than 1 degree + if (arcLength >= 1) { + const path = `M ${start.x} ${start.y} A ${r} ${r} 0 ${arcLength > 180 ? 1 : 0} 1 ${end.x} ${end.y}`; + return { + path, + start, + end + }; + } else { + return null; + } + } + + getPointOnCircle(deg, r, cx, cy) { + const modDeg = ((deg % 360) + 360) % 360; + const rad = (modDeg * Math.PI) / 180; + return { + x: cx + (r * Math.sin(rad)), + y: cy - (r * Math.cos(rad)), + }; + } + + makeTicks() { + this.minorTicks = []; + this.majorTicks = []; + for (let i = 1; i < 60; i++) { + if (i % 5 === 0) { + this.majorTicks.push(i * 6); + } else { + this.minorTicks.push(i * 6); + } + } + } + + trackBySegment(index: number, segment) { + return segment.id; + } +} diff --git a/frontend/src/app/components/clock/clock.component.html b/frontend/src/app/components/clock/clock.component.html new file mode 100644 index 0000000000..376d72bfc3 --- /dev/null +++ b/frontend/src/app/components/clock/clock.component.html @@ -0,0 +1,73 @@ +
+
+
+ +
+
+
+ +
+ + +
+
+
+
+
+
+
+
+
+ +
+ +
+
+
+
+

{{ blocks[mode === 'mempool' ? 0 : blockIndex].height }}

+
+
+
+
+
+ +
+

Price

+

+ +

+
+
+

High Priority

+

+ +

+
+
+

+

Size

+
+
+

+ {{ blocks[blockIndex].tx_count | number }} + Transactions +

+
+ +
+

+

Memory Usage

+
+
+

{{ mempoolInfo.size | number }}

+

Unconfirmed

+
+
+
+
\ No newline at end of file diff --git a/frontend/src/app/components/clock/clock.component.scss b/frontend/src/app/components/clock/clock.component.scss new file mode 100644 index 0000000000..7423c1d8f1 --- /dev/null +++ b/frontend/src/app/components/clock/clock.component.scss @@ -0,0 +1,192 @@ +.clock-wrapper { + position: absolute; + left: 0; + right: 0; + top: 0; + bottom: 0; + width: 100%; + height: 100%; + display: flex; + flex-direction: column; + justify-content: flex-start; + overflow: hidden; + + --chain-height: 60px; + --clock-width: 300px; + + .clockchain-bar, .clock-face { + flex-shrink: 0; + flex-grow: 0; + } + + .clockchain-bar { + position: relative; + width: 100%; + height: 15.625%; + z-index: 2; + // overflow: hidden; + // background: #1d1f31; + // box-shadow: 0 0 15px #000; + } + + .clock-face { + position: relative; + height: 84.375%; + margin: auto; + overflow: hidden; + display: flex; + justify-content: center; + align-items: center; + z-index: 1; + } + + .stats { + position: absolute; + z-index: 3; + + p { + margin: 0; + font-size: calc(0.055 * var(--clock-width)); + line-height: calc(0.05 * var(--clock-width)); + opacity: 0.8; + + &.force-wrap { + word-spacing: 10000px; + } + + ::ng-deep .symbol { + font-size: inherit; + color: white; + } + } + + .label { + font-size: calc(0.04 * var(--clock-width)); + line-height: calc(0.05 * var(--clock-width)); + text-transform: lowercase; + } + + &.top { + top: calc(var(--chain-height) + 2%); + } + &.bottom { + bottom: 2%; + } + &.left { + left: 5%; + } + &.right { + right: 5%; + text-align: end; + text-align: right; + } + } +} + +.title-wrapper { + position: absolute; + left: 0; + right: 0; + top: 0; + bottom: 0; + width: 100%; + height: 100%; + display: flex; + flex-direction: row; + align-items: center; + justify-content: center; + + .block-height { + font-size: calc(0.2 * var(--clock-width)); + padding: 0; + margin: 0; + background: radial-gradient(rgba(0,0,0,0.5), transparent 67%); + padding: calc(0.05 * var(--clock-width)) calc(0.15 * var(--clock-width)); + } +} + +.block-wrapper { + position: absolute; + left: 0; + right: 0; + top: 0; + bottom: 0; + width: 100%; + height: 100%; + + .block-sizer { + position: absolute; + left: 0; + top: 0; + width: 100%; + height: 100%; + } + + .fader { + position: absolute; + left: 0; + right: 0; + top: 0; + bottom: 0; + background: radial-gradient(transparent 0%, transparent 44%, #11131f 58%, #11131f 100%); + } + + .block-cube { + --side-width: calc(0.4 * var(--clock-width)); + --half-side: calc(0.2 * var(--clock-width)); + --neg-half-side: calc(-0.2 * var(--clock-width)); + transform-style: preserve-3d; + animation: block-spin 60s infinite linear; + position: absolute; + z-index: -1; + top: 50%; + left: 50%; + transform: translate(-50%, -50%); + width: var(--side-width); + height: var(--side-width); + + .side { + width: var(--side-width); + height: var(--side-width); + line-height: 100px; + text-align: center; + background: #232838; + display: block; + position: absolute; + } + + .side.top { + transform: rotateX(90deg); + margin-top: var(--neg-half-side); + } + + .side.bottom { + background: var(--primary); + transform: rotateX(-90deg); + margin-top: var(--half-side); + } + + .side.right { + transform: rotateY(90deg); + margin-left: var(--half-side); + } + + .side.left { + transform: rotateY(-90deg); + margin-left: var(--neg-half-side); + } + + .side.front { + transform: translateZ(var(--half-side)); + } + + .side.back { + transform: translateZ(var(--neg-half-side)); + } + } +} + +@keyframes block-spin { + 0% {transform: translate(-50%, -50%) rotateX(-20deg) rotateY(0deg);} + 100% {transform: translate(-50%, -50%) rotateX(-20deg) rotateY(-360deg);} +} \ No newline at end of file diff --git a/frontend/src/app/components/clock/clock.component.ts b/frontend/src/app/components/clock/clock.component.ts new file mode 100644 index 0000000000..4a9b19e786 --- /dev/null +++ b/frontend/src/app/components/clock/clock.component.ts @@ -0,0 +1,133 @@ +import { ChangeDetectionStrategy, ChangeDetectorRef, Component, HostListener, Input, OnInit } from '@angular/core'; +import { Observable, Subscription, of, switchMap, tap } from 'rxjs'; +import { StateService } from '../../services/state.service'; +import { BlockExtended } from '../../interfaces/node-api.interface'; +import { WebsocketService } from '../../services/websocket.service'; +import { MempoolInfo, Recommendedfees } from '../../interfaces/websocket.interface'; +import { ActivatedRoute, ParamMap, Router } from '@angular/router'; +import { RelativeUrlPipe } from '../../shared/pipes/relative-url/relative-url.pipe'; + +@Component({ + selector: 'app-clock', + templateUrl: './clock.component.html', + styleUrls: ['./clock.component.scss'], + changeDetection: ChangeDetectionStrategy.OnPush, +}) +export class ClockComponent implements OnInit { + hideStats: boolean = false; + mode: 'mempool' | 'mined' = 'mined'; + blockIndex: number; + pageSubscription: Subscription; + blocksSubscription: Subscription; + recommendedFees$: Observable; + mempoolInfo$: Observable; + blocks: BlockExtended[] = []; + clockSize: number = 300; + chainWidth: number = 384; + chainHeight: number = 60; + blockStyle; + blockSizerStyle; + wrapperStyle; + limitWidth: number; + limitHeight: number; + + gradientColors = { + '': ['var(--mainnet-alt)', 'var(--primary)'], + liquid: ['var(--liquid)', 'var(--testnet-alt)'], + 'liquidtestnet': ['var(--liquidtestnet)', 'var(--liquidtestnet-alt)'], + testnet: ['var(--testnet)', 'var(--testnet-alt)'], + testnet4: ['var(--testnet)', 'var(--testnet-alt)'], + signet: ['var(--signet)', 'var(--signet-alt)'], + }; + + constructor( + public stateService: StateService, + private websocketService: WebsocketService, + private route: ActivatedRoute, + private router: Router, + private relativeUrlPipe: RelativeUrlPipe, + private cd: ChangeDetectorRef, + ) { + this.route.queryParams.subscribe((params) => { + this.hideStats = params && params.stats === 'false'; + this.limitWidth = Number.parseInt(params.width) || null; + this.limitHeight = Number.parseInt(params.height) || null; + }); + } + + ngOnInit(): void { + this.resizeCanvas(); + this.websocketService.want(['blocks', 'stats', 'mempool-blocks']); + + this.blocksSubscription = this.stateService.blocks$ + .subscribe((blocks) => { + this.blocks = blocks.slice(0, 16); + if (this.blocks[this.blockIndex]) { + this.blockStyle = this.getStyleForBlock(this.blocks[this.blockIndex]); + this.cd.markForCheck(); + } + }); + + this.recommendedFees$ = this.stateService.recommendedFees$; + this.mempoolInfo$ = this.stateService.mempoolInfo$; + + this.pageSubscription = this.route.paramMap.pipe( + switchMap((params: ParamMap) => { + const rawMode: string = params.get('mode'); + const mode = rawMode === 'mempool' ? 'mempool' : 'mined'; + const index: number = Number.parseInt(params.get('index')); + if (mode !== rawMode || index < 0 || isNaN(index)) { + this.router.navigate([this.relativeUrlPipe.transform('/clock'), mode, index || 0]); + } + return of({ + mode, + index, + }); + }), + tap((page: { mode: 'mempool' | 'mined', index: number }) => { + this.mode = page.mode; + this.blockIndex = page.index || 0; + if (this.blocks[this.blockIndex]) { + this.blockStyle = this.getStyleForBlock(this.blocks[this.blockIndex]); + this.cd.markForCheck(); + } + }) + ).subscribe(); + } + + getStyleForBlock(block: BlockExtended) { + const greenBackgroundHeight = 100 - (block.weight / this.stateService.env.BLOCK_WEIGHT_UNITS) * 100; + + return { + background: `repeating-linear-gradient( + var(--secondary), + var(--secondary) ${greenBackgroundHeight}%, + ${this.gradientColors[''][0]} ${Math.max(greenBackgroundHeight, 0)}%, + ${this.gradientColors[''][1]} 100% + )`, + }; + } + + @HostListener('window:resize', ['$event']) + resizeCanvas(): void { + const windowWidth = this.limitWidth || window.innerWidth || 800; + const windowHeight = this.limitHeight || window.innerHeight || 800; + this.chainWidth = windowWidth; + this.chainHeight = Math.max(60, windowHeight / 8); + this.clockSize = Math.min(800, windowWidth, windowHeight - (1.4 * this.chainHeight)); + const size = Math.ceil(this.clockSize / 75) * 75; + const margin = (this.clockSize - size) / 2; + this.blockSizerStyle = { + transform: `translate(${margin}px, ${margin}px)`, + width: `${size}px`, + height: `${size}px`, + }; + this.wrapperStyle = { + '--clock-width': `${this.clockSize}px`, + '--chain-height': `${this.chainHeight}px`, + 'width': this.limitWidth ? `${this.limitWidth}px` : undefined, + 'height': this.limitHeight ? `${this.limitHeight}px` : undefined, + }; + this.cd.markForCheck(); + } +} diff --git a/frontend/src/app/components/clockchain/clockchain.component.html b/frontend/src/app/components/clockchain/clockchain.component.html new file mode 100644 index 0000000000..b1f64cd74c --- /dev/null +++ b/frontend/src/app/components/clockchain/clockchain.component.html @@ -0,0 +1,41 @@ +
+
+ +
+ + +
+
+ + + +
+
+
+
diff --git a/frontend/src/app/components/clockchain/clockchain.component.scss b/frontend/src/app/components/clockchain/clockchain.component.scss new file mode 100644 index 0000000000..6ffc144e98 --- /dev/null +++ b/frontend/src/app/components/clockchain/clockchain.component.scss @@ -0,0 +1,94 @@ +.divider { + position: absolute; + left: -0.5px; + top: 0; + .divider-line { + stroke: white; + stroke-width: 4px; + stroke-linecap: butt; + stroke-dasharray: 25px 25px; + } +} + +.blockchain-wrapper { + height: 100%; + + -webkit-user-select: none; /* Safari */ + -moz-user-select: none; /* Firefox */ + -ms-user-select: none; /* IE10+/Edge */ + user-select: none; /* Standard */ +} + +.position-container { + position: absolute; + left: 50%; + top: 0; +} + +.black-background { + background-color: #11131f; + z-index: 100; + position: relative; +} + +.scroll-spacer { + position: absolute; + top: 0; + left: 0; + width: 1px; + height: 1px; + pointer-events: none; +} + +.loading-block { + position: absolute; + text-align: center; + margin: auto; + width: 300px; + left: -150px; + top: 0px; +} + +.time-toggle { + color: white; + font-size: 0.8rem; + position: absolute; + bottom: -1.8em; + left: 1px; + transform: translateX(-50%); + background: none; + border: none; + outline: none; + margin: 0; + padding: 0; +} + +.blockchain-wrapper.ltr-transition .blocks-wrapper, +.blockchain-wrapper.ltr-transition .position-container, +.blockchain-wrapper.ltr-transition .time-toggle { + transition: transform 1s; +} + +.blockchain-wrapper.time-ltr { + .blocks-wrapper { + transform: scaleX(-1); + } + + .time-toggle { + transform: translateX(-50%) scaleX(-1); + } +} + +:host-context(.ltr-layout) { + .blockchain-wrapper.time-ltr .blocks-wrapper, + .blockchain-wrapper .blocks-wrapper { + direction: ltr; + } +} + +:host-context(.rtl-layout) { + .blockchain-wrapper.time-ltr .blocks-wrapper, + .blockchain-wrapper .blocks-wrapper { + direction: rtl; + } +} \ No newline at end of file diff --git a/frontend/src/app/components/clockchain/clockchain.component.ts b/frontend/src/app/components/clockchain/clockchain.component.ts new file mode 100644 index 0000000000..c17b1e0aef --- /dev/null +++ b/frontend/src/app/components/clockchain/clockchain.component.ts @@ -0,0 +1,82 @@ +import { Component, OnInit, OnDestroy, ChangeDetectionStrategy, Input, OnChanges, ChangeDetectorRef } from '@angular/core'; +import { firstValueFrom, Subscription } from 'rxjs'; +import { StateService } from '../../services/state.service'; + +@Component({ + selector: 'app-clockchain', + templateUrl: './clockchain.component.html', + styleUrls: ['./clockchain.component.scss'], + changeDetection: ChangeDetectionStrategy.OnPush, +}) +export class ClockchainComponent implements OnInit, OnChanges, OnDestroy { + @Input() width: number = 300; + @Input() height: number = 60; + @Input() mode: 'mempool' | 'mined' | 'none'; + @Input() index: number = 0; + + mempoolBlocks: number = 3; + blockchainBlocks: number = 6; + blockWidth: number = 50; + dividerStyle; + + network: string; + timeLtrSubscription: Subscription; + timeLtr: boolean = this.stateService.timeLtr.value; + ltrTransitionEnabled = false; + connectionStateSubscription: Subscription; + loadingTip: boolean = true; + connected: boolean = true; + + constructor( + public stateService: StateService, + private cd: ChangeDetectorRef, + ) {} + + ngOnInit() { + this.ngOnChanges(); + + this.network = this.stateService.network; + this.timeLtrSubscription = this.stateService.timeLtr.subscribe((ltr) => { + this.timeLtr = !!ltr; + }); + this.connectionStateSubscription = this.stateService.connectionState$.subscribe(state => { + this.connected = (state === 2); + }); + firstValueFrom(this.stateService.chainTip$).then(() => { + this.loadingTip = false; + }); + } + + ngOnChanges() { + this.blockWidth = Math.floor(7 * this.height / 12); + this.mempoolBlocks = Math.floor(((this.width / 2) - (this.blockWidth * 0.32)) / (1.24 * this.blockWidth)); + this.blockchainBlocks = this.mempoolBlocks; + this.dividerStyle = { + width: '2px', + height: `${this.height}px`, + }; + this.cd.markForCheck(); + } + + ngOnDestroy() { + this.timeLtrSubscription.unsubscribe(); + this.connectionStateSubscription.unsubscribe(); + } + + trackByPageFn(index: number, item: { index: number }) { + return item.index; + } + + toggleTimeDirection() { + this.ltrTransitionEnabled = true; + this.stateService.timeLtr.next(!this.timeLtr); + } + + getMempoolUrl(index): string { + return `/clock/mempool/${index}`; + } + + getMinedUrl(index): string { + return `/clock/block/${index}`; + } +} diff --git a/frontend/src/app/components/custom-dashboard/custom-dashboard.component.html b/frontend/src/app/components/custom-dashboard/custom-dashboard.component.html new file mode 100644 index 0000000000..bf72aab691 --- /dev/null +++ b/frontend/src/app/components/custom-dashboard/custom-dashboard.component.html @@ -0,0 +1,286 @@ + +
+
+ @for (widget of widgets; track widget.component) { + @switch (widget.component) { + @case ('fees') { +
+
Transaction Fees
+
+
+ +
+
+
+ } + @case ('difficulty') { +
+ +
+ } + @case ('goggles') { +
+
+ +
+
+ } + @case ('incoming') { +
+
+
+ +
Incoming Transactions
+
+ +
+
+
+
+ +
+
+
Minimum fee
+
Purging
+

+ < +

+
+
+
Unconfirmed
+

+ {{ mempoolInfoData.value.memPoolInfo.size | number }} TXs +

+
+
+
Memory Usage
+
+
+
 
+
/
+
+
+
+
+
+ } + @case ('replacements') { +
+
+
+ +
Recent Replacements
+   + +
+ + + + + + + + + + + + + + + +
TXIDPrevious feeNew feeStatus
+ + + + + Mined + Full RBF + RBF +
+
+
+
+ + + +
+
+
+
+ + +
+ } + @case ('blocks') { +
+
+
+ +
Recent Blocks
+   + +
+ + + + + + + + + + + + + + + +
HeightMinedTXsSize
{{ block.height }}{{ block.tx_count | number }} +
+
 
+
+
+
+
+
+
+ + + +
+
+
+
+ + +
+ } + @case ('transactions') { +
+
+
+
Recent Transactions
+ + + + + + + + + + + + + + + +
TXIDAmount{{ currency }}Fee
+ + + + Confidential
+
 
+
+
+
+ + + +
+
+
+
+ + +
+ } + @case ('balance') { +
+
Treasury
+ +
+ } + @case ('address') { + + } + @case ('addressTransactions') { + + } + @case ('twitter') { +
+
+
+ +
X Timeline
+   + +
+ @defer { + + } +
+
+
+ } + } + } +
+
+ + +
+
+ + + \ No newline at end of file diff --git a/frontend/src/app/components/custom-dashboard/custom-dashboard.component.scss b/frontend/src/app/components/custom-dashboard/custom-dashboard.component.scss new file mode 100644 index 0000000000..4a9ffe94aa --- /dev/null +++ b/frontend/src/app/components/custom-dashboard/custom-dashboard.component.scss @@ -0,0 +1,490 @@ +.dashboard-container { + text-align: center; + margin-top: 0.5rem; + .col { + margin-bottom: 1.5rem; + } +} + +.card { + background-color: var(--bg); + height: 100%; +} + +.card-title { + color: var(--title-fg); + font-size: 1rem; +} + +.info-block { + float: left; + width: 350px; + line-height: 25px; +} + +.progress { + display: inline-flex; + width: 100%; + background-color: var(--secondary); + height: 1.1rem; + max-width: 180px; +} + +.bg-warning { + background-color: #b58800 !important; +} + +.skeleton-loader { + max-width: 100%; +} + +.more-padding { + padding: 18px; +} + +.graph-card { + height: 100%; + @media (min-width: 768px) { + height: 415px; + } + @media (min-width: 992px) { + height: 510px; + } +} + +.mempool-info-data { + min-height: 56px; + display: block; + @media (min-width: 485px) { + display: flex; + flex-direction: row; + } + &.lbtc-pegs-stats { + display: flex; + flex-direction: row; + } + h5 { + margin-bottom: 10px; + } + .item { + width: 50%; + margin: 0px auto 20px; + display: inline-block; + @media (min-width: 485px) { + margin: 0px auto 10px; + } + @media (min-width: 768px) { + margin: 0px auto 0px; + } + &:last-child { + margin: 0px auto 0px; + } + &:nth-child(2) { + order: 2; + @media (min-width: 485px) { + order: 3; + } + } + &:nth-child(3) { + order: 3; + @media (min-width: 485px) { + order: 2; + display: block; + } + @media (min-width: 768px) { + display: none; + } + @media (min-width: 992px) { + display: block; + } + } + .card-text { + font-size: 18px; + span { + color: var(--transparent-fg); + font-size: 12px; + } + .bitcoin-color { + color: var(--orange); + } + } + .progress { + width: 90%; + @media (min-width: 768px) { + width: 100%; + } + } + } + .bar { + width: 93%; + margin: 0px 5px 20px; + @media (min-width: 485px) { + max-width: 200px; + margin: 0px auto 0px; + } + } + .skeleton-loader { + width: 100%; + max-width: 100px; + display: block; + margin: 18px auto 0; + } + .skeleton-loader-big { + max-width: 180px; + } +} + +.latest-transactions { + width: 100%; + text-align: left; + table-layout:fixed; + tr, td, th { + border: 0px; + padding-top: 0.71rem !important; + padding-bottom: 0.75rem !important; + } + td { + overflow:hidden; + width: 25%; + } + .table-cell-satoshis { + display: none; + text-align: right; + @media (min-width: 576px) { + display: table-cell; + } + @media (min-width: 768px) { + display: none; + } + @media (min-width: 1100px) { + display: table-cell; + } + } + .table-cell-fiat { + display: none; + text-align: right; + @media (min-width: 485px) { + display: table-cell; + } + @media (min-width: 768px) { + display: none; + } + @media (min-width: 992px) { + display: table-cell; + } + } + .table-cell-fees { + text-align: right; + } +} +.skeleton-loader-transactions { + max-width: 250px; + position: relative; + top: 2px; + margin-bottom: -3px; + height: 18px; +} + +.lastest-blocks-table { + width: 100%; + text-align: left; + tr, td, th { + border: 0px; + padding-top: 0.65rem !important; + padding-bottom: 0.7rem !important; + } + .table-cell-height { + width: 15%; + } + .table-cell-mined { + width: 35%; + text-align: left; + } + .table-cell-transaction-count { + display: none; + text-align: right; + width: 20%; + display: table-cell; + } + .table-cell-size { + display: none; + text-align: center; + width: 30%; + @media (min-width: 485px) { + display: table-cell; + } + @media (min-width: 768px) { + display: none; + } + @media (min-width: 992px) { + display: table-cell; + } + } +} + +.lastest-replacements-table { + width: 100%; + text-align: left; + table-layout:fixed; + tr, td, th { + border: 0px; + padding-top: 0.71rem !important; + padding-bottom: 0.75rem !important; + } + td { + overflow:hidden; + width: 25%; + } + .table-cell-txid { + width: 25%; + text-align: start; + } + .table-cell-old-fee { + width: 25%; + text-align: end; + + @media(max-width: 1080px) { + display: none; + } + } + .table-cell-new-fee { + width: 20%; + text-align: end; + } + .table-cell-badges { + width: 23%; + padding-right: 0; + padding-left: 5px; + text-align: end; + + .badge { + margin-left: 5px; + } + } +} + +.mempool-graph { + height: 255px; + @media (min-width: 768px) { + height: 285px; + } + @media (min-width: 992px) { + height: 370px; + } +} +.loadingGraphs{ + height: 250px; + display: grid; + place-items: center; +} + +.inc-tx-progress-bar { + max-width: 250px; + .progress-bar { + padding: 4px; + } +} + +.terms-of-service { + margin-top: 1rem; +} + +.small-bar { + height: 8px; + top: -4px; + max-width: 120px; +} + +.loading-container { + min-height: 76px; +} + +.main-title { + position: relative; + color: #ffffff91; + margin-top: -13px; + font-size: 10px; + text-transform: uppercase; + font-weight: 500; + text-align: center; + padding-bottom: 3px; +} + +.card-wrapper { + .card { + height: auto !important; + } + .card-body { + display: flex; + flex: inherit; + text-align: center; + flex-direction: column; + justify-content: space-around; + padding: 22px 20px; + &.liquid { + height: 124.5px; + } + } + .less-padding { + padding: 20px 20px; + } +} + +.retarget-sign { + margin-right: -3px; + font-size: 14px; + top: -2px; + position: relative; +} + +.previous-retarget-sign { + margin-right: -2px; + font-size: 10px; +} + +.assetIcon { + width: 40px; + height: 40px; +} + +.asset-title { + text-align: left; + vertical-align: middle; +} + +.asset-icon { + width: 65px; + height: 65px; + vertical-align: middle; +} + +.circulating-amount { + text-align: right; + width: 100%; + vertical-align: middle; +} + +.clear-link { + color: white; +} + +.pool-name { + display: inline-block; + vertical-align: text-top; + padding-left: 10px; +} + +.title-link, .title-link:hover, .title-link:focus, .title-link:active { + display: block; + margin-bottom: 10px; + text-decoration: none; + color: inherit; +} + +.mempool-block-wrapper { + max-height: 410px; + max-width: 410px; + margin: auto; + + @media (min-width: 768px) { + max-height: 344px; + max-width: 344px; + } + @media (min-width: 992px) { + max-height: 410px; + max-width: 410px; + } +} + +.goggle-badge { + margin: 6px 5px 8px; + background: none; + border: solid 2px var(--primary); + cursor: pointer; + + &.active { + background: var(--primary); + } +} + +.btn-xs { + padding: 0.35rem 0.5rem; + font-size: 12px; +} + +.quick-filter { + margin-top: 5px; + margin-bottom: 6px; +} + +.card-liquid { + background-color: var(--bg); + height: 418px; + @media (min-width: 992px) { + height: 512px; + } + &.smaller { + height: 408px; + } +} + +.card-title-liquid { + padding-top: 20px; + margin-left: 10px; +} + +.in-progress-message { + position: relative; + color: #ffffff91; + margin-top: 20px; + text-align: center; + padding-bottom: 3px; + font-weight: 500; +} + +.stats-card { + min-height: 56px; + display: block; + @media (min-width: 485px) { + display: flex; + flex-direction: row; + } + h5 { + margin-bottom: 10px; + } + .item { + width: 50%; + display: inline-block; + margin: 0px auto 20px; + &:nth-child(2) { + order: 2; + @media (min-width: 485px) { + order: 3; + } + } + &:nth-child(3) { + order: 3; + @media (min-width: 485px) { + order: 2; + display: block; + } + @media (min-width: 768px) { + display: none; + } + @media (min-width: 992px) { + display: block; + } + } + .card-title { + font-size: 1rem; + color: var(--title-fg); + } + .card-text { + font-size: 18px; + span { + color: var(--transparent-fg); + font-size: 12px; + } + } + } +} \ No newline at end of file diff --git a/frontend/src/app/components/custom-dashboard/custom-dashboard.component.ts b/frontend/src/app/components/custom-dashboard/custom-dashboard.component.ts new file mode 100644 index 0000000000..fbaf7be748 --- /dev/null +++ b/frontend/src/app/components/custom-dashboard/custom-dashboard.component.ts @@ -0,0 +1,378 @@ +import { AfterViewInit, ChangeDetectionStrategy, ChangeDetectorRef, Component, HostListener, Inject, OnDestroy, OnInit, PLATFORM_ID } from '@angular/core'; +import { combineLatest, merge, Observable, of, Subject, Subscription } from 'rxjs'; +import { catchError, filter, map, scan, share, shareReplay, startWith, switchMap, tap } from 'rxjs/operators'; +import { BlockExtended, OptimizedMempoolStats, TransactionStripped } from '../../interfaces/node-api.interface'; +import { MempoolInfo, ReplacementInfo } from '../../interfaces/websocket.interface'; +import { ApiService } from '../../services/api.service'; +import { StateService } from '../../services/state.service'; +import { WebsocketService } from '../../services/websocket.service'; +import { SeoService } from '../../services/seo.service'; +import { ActiveFilter, FilterMode, GradientMode, toFlags } from '../../shared/filters.utils'; +import { detectWebGL } from '../../shared/graphs.utils'; +import { Address, AddressTxSummary } from '../../interfaces/electrs.interface'; +import { ElectrsApiService } from '../../services/electrs-api.service'; + +interface MempoolBlocksData { + blocks: number; + size: number; +} + +interface MempoolInfoData { + memPoolInfo: MempoolInfo; + vBytesPerSecond: number; + progressWidth: string; + progressColor: string; +} + +interface MempoolStatsData { + mempool: OptimizedMempoolStats[]; + weightPerSecond: any; +} + +@Component({ + selector: 'app-custom-dashboard', + templateUrl: './custom-dashboard.component.html', + styleUrls: ['./custom-dashboard.component.scss'], + changeDetection: ChangeDetectionStrategy.OnPush +}) +export class CustomDashboardComponent implements OnInit, OnDestroy, AfterViewInit { + network$: Observable; + mempoolBlocksData$: Observable; + mempoolInfoData$: Observable; + mempoolLoadingStatus$: Observable; + vBytesPerSecondLimit = 1667; + transactions$: Observable; + blocks$: Observable; + replacements$: Observable; + latestBlockHeight: number; + mempoolTransactionsWeightPerSecondData: any; + mempoolStats$: Observable; + transactionsWeightPerSecondOptions: any; + isLoadingWebSocket$: Observable; + isLoad: boolean = true; + filterSubscription: Subscription; + mempoolInfoSubscription: Subscription; + currencySubscription: Subscription; + currency: string; + incomingGraphHeight: number = 300; + graphHeight: number = 300; + webGlEnabled = true; + isMobile: boolean = window.innerWidth <= 767.98; + + widgets; + + addressSubscription: Subscription; + blockTxSubscription: Subscription; + addressSummary$: Observable; + address: Address; + + goggleResolution = 82; + goggleCycle: { index: number, name: string, mode: FilterMode, filters: string[], gradient: GradientMode }[] = [ + { index: 0, name: $localize`:@@dfc3c34e182ea73c5d784ff7c8135f087992dac1:All`, mode: 'and', filters: [], gradient: 'age' }, + { index: 1, name: $localize`Consolidation`, mode: 'and', filters: ['consolidation'], gradient: 'fee' }, + { index: 2, name: $localize`Coinjoin`, mode: 'and', filters: ['coinjoin'], gradient: 'fee' }, + { index: 3, name: $localize`Data`, mode: 'or', filters: ['inscription', 'fake_pubkey', 'op_return'], gradient: 'fee' }, + ]; + goggleFlags = 0n; + goggleMode: FilterMode = 'and'; + gradientMode: GradientMode = 'age'; + goggleIndex = 0; + + private destroy$ = new Subject(); + + constructor( + public stateService: StateService, + private apiService: ApiService, + private electrsApiService: ElectrsApiService, + private websocketService: WebsocketService, + private seoService: SeoService, + private cd: ChangeDetectorRef, + @Inject(PLATFORM_ID) private platformId: Object, + ) { + this.webGlEnabled = this.stateService.isBrowser && detectWebGL(); + this.widgets = this.stateService.env.customize?.dashboard.widgets || []; + } + + ngAfterViewInit(): void { + this.stateService.focusSearchInputDesktop(); + } + + ngOnDestroy(): void { + this.filterSubscription.unsubscribe(); + this.mempoolInfoSubscription.unsubscribe(); + this.currencySubscription.unsubscribe(); + this.websocketService.stopTrackRbfSummary(); + if (this.addressSubscription) { + this.addressSubscription.unsubscribe(); + this.websocketService.stopTrackingAddress(); + this.address = null; + } + this.destroy$.next(1); + this.destroy$.complete(); + } + + ngOnInit(): void { + this.onResize(); + this.isLoadingWebSocket$ = this.stateService.isLoadingWebSocket$; + this.seoService.resetTitle(); + this.seoService.resetDescription(); + this.websocketService.want(['blocks', 'stats', 'mempool-blocks', 'live-2h-chart']); + this.websocketService.startTrackRbfSummary(); + this.network$ = merge(of(''), this.stateService.networkChanged$); + this.mempoolLoadingStatus$ = this.stateService.loadingIndicators$ + .pipe( + map((indicators) => indicators.mempool !== undefined ? indicators.mempool : 100) + ); + + this.filterSubscription = this.stateService.activeGoggles$.subscribe((active: ActiveFilter) => { + const activeFilters = active.filters.sort().join(','); + for (const goggle of this.goggleCycle) { + if (goggle.mode === active.mode) { + const goggleFilters = goggle.filters.sort().join(','); + if (goggleFilters === activeFilters) { + this.goggleIndex = goggle.index; + this.goggleFlags = toFlags(goggle.filters); + this.goggleMode = goggle.mode; + this.gradientMode = active.gradient; + return; + } + } + } + this.goggleCycle.push({ + index: this.goggleCycle.length, + name: 'Custom', + mode: active.mode, + filters: active.filters, + gradient: active.gradient, + }); + this.goggleIndex = this.goggleCycle.length - 1; + this.goggleFlags = toFlags(active.filters); + this.goggleMode = active.mode; + }); + + this.mempoolInfoData$ = combineLatest([ + this.stateService.mempoolInfo$, + this.stateService.vbytesPerSecond$ + ]).pipe( + map(([mempoolInfo, vbytesPerSecond]) => { + const percent = Math.round((Math.min(vbytesPerSecond, this.vBytesPerSecondLimit) / this.vBytesPerSecondLimit) * 100); + + let progressColor = 'bg-success'; + if (vbytesPerSecond > 1667) { + progressColor = 'bg-warning'; + } + if (vbytesPerSecond > 3000) { + progressColor = 'bg-danger'; + } + + const mempoolSizePercentage = (mempoolInfo.usage / mempoolInfo.maxmempool * 100); + let mempoolSizeProgress = 'bg-danger'; + if (mempoolSizePercentage <= 50) { + mempoolSizeProgress = 'bg-success'; + } else if (mempoolSizePercentage <= 75) { + mempoolSizeProgress = 'bg-warning'; + } + + return { + memPoolInfo: mempoolInfo, + vBytesPerSecond: vbytesPerSecond, + progressWidth: percent + '%', + progressColor: progressColor, + mempoolSizeProgress: mempoolSizeProgress, + }; + }) + ); + + this.mempoolInfoSubscription = this.mempoolInfoData$.subscribe(); + + this.mempoolBlocksData$ = this.stateService.mempoolBlocks$ + .pipe( + map((mempoolBlocks) => { + const size = mempoolBlocks.map((m) => m.blockSize).reduce((a, b) => a + b, 0); + const vsize = mempoolBlocks.map((m) => m.blockVSize).reduce((a, b) => a + b, 0); + + return { + size: size, + blocks: Math.ceil(vsize / this.stateService.blockVSize) + }; + }) + ); + + this.transactions$ = this.stateService.transactions$; + + this.blocks$ = this.stateService.blocks$ + .pipe( + tap((blocks) => { + this.latestBlockHeight = blocks[0].height; + }), + switchMap((blocks) => { + if (this.stateService.env.MINING_DASHBOARD === true) { + for (const block of blocks) { + // @ts-ignore: Need to add an extra field for the template + block.extras.pool.logo = `/resources/mining-pools/` + + block.extras.pool.slug + '.svg'; + } + } + return of(blocks.slice(0, 6)); + }) + ); + + this.replacements$ = this.stateService.rbfLatestSummary$; + + this.mempoolStats$ = this.stateService.connectionState$ + .pipe( + filter((state) => state === 2), + switchMap(() => this.apiService.list2HStatistics$().pipe( + catchError((e) => { + return of(null); + }) + )), + switchMap((mempoolStats) => { + return merge( + this.stateService.live2Chart$ + .pipe( + scan((acc, stats) => { + const now = Date.now() / 1000; + const start = now - (2 * 60 * 60); + acc.unshift(stats); + acc = acc.filter(p => p.added >= start); + return acc; + }, (mempoolStats || [])) + ), + of(mempoolStats) + ); + }), + map((mempoolStats) => { + if (mempoolStats) { + return { + mempool: mempoolStats, + weightPerSecond: this.handleNewMempoolData(mempoolStats.concat([])), + }; + } else { + return null; + } + }), + shareReplay(1), + ); + + this.currencySubscription = this.stateService.fiatCurrency$.subscribe((fiat) => { + this.currency = fiat; + }); + + this.startAddressSubscription(); + } + + handleNewMempoolData(mempoolStats: OptimizedMempoolStats[]) { + mempoolStats.reverse(); + const labels = mempoolStats.map(stats => stats.added); + + return { + labels: labels, + series: [mempoolStats.map((stats) => [stats.added * 1000, stats.vbytes_per_second])], + }; + } + + trackByBlock(index: number, block: BlockExtended) { + return block.height; + } + + getArrayFromNumber(num: number): number[] { + return Array.from({ length: num }, (_, i) => i + 1); + } + + setFilter(index): void { + const selected = this.goggleCycle[index]; + this.stateService.activeGoggles$.next(selected); + } + + startAddressSubscription(): void { + if (this.stateService.env.customize && this.stateService.env.customize.dashboard.widgets.some(w => w.props?.address)) { + let addressString = this.stateService.env.customize.dashboard.widgets.find(w => w.props?.address).props.address; + addressString = (/^[A-Z]{2,5}1[AC-HJ-NP-Z02-9]{8,100}|04[a-fA-F0-9]{128}|(02|03)[a-fA-F0-9]{64}$/.test(addressString)) ? addressString.toLowerCase() : addressString; + + this.addressSubscription = ( + addressString.match(/04[a-fA-F0-9]{128}|(02|03)[a-fA-F0-9]{64}/) + ? this.electrsApiService.getPubKeyAddress$(addressString) + : this.electrsApiService.getAddress$(addressString) + ).pipe( + catchError((err) => { + console.log(err); + return of(null); + }), + filter((address) => !!address), + ).subscribe((address: Address) => { + this.websocketService.startTrackAddress(address.address); + this.address = address; + this.cd.markForCheck(); + }); + + this.addressSummary$ = ( + addressString.match(/04[a-fA-F0-9]{128}|(02|03)[a-fA-F0-9]{64}/) + ? this.electrsApiService.getScriptHashSummary$((addressString.length === 66 ? '21' : '41') + addressString + 'ac') + : this.electrsApiService.getAddressSummary$(addressString)).pipe( + catchError(e => { + return of(null); + }), + switchMap(initial => this.stateService.blockTransactions$.pipe( + startWith(null), + scan((summary, tx) => { + if (tx && !summary.some(t => t.txid === tx.txid)) { + let value = 0; + let funded = 0; + let fundedCount = 0; + let spent = 0; + let spentCount = 0; + for (const vout of tx.vout) { + if (vout.scriptpubkey_address === addressString) { + value += vout.value; + funded += vout.value; + fundedCount++; + } + } + for (const vin of tx.vin) { + if (vin.prevout?.scriptpubkey_address === addressString) { + value -= vin.prevout?.value; + spent += vin.prevout?.value; + spentCount++; + } + } + if (this.address && this.address.address === addressString) { + this.address.chain_stats.tx_count++; + this.address.chain_stats.funded_txo_sum += funded; + this.address.chain_stats.funded_txo_count += fundedCount; + this.address.chain_stats.spent_txo_sum += spent; + this.address.chain_stats.spent_txo_count += spentCount; + } + summary.unshift({ + txid: tx.txid, + time: tx.status?.block_time, + height: tx.status?.block_height, + value + }); + } + return summary; + }, initial) + )), + share(), + ); + } + } + + @HostListener('window:resize', ['$event']) + onResize(): void { + if (window.innerWidth >= 992) { + this.incomingGraphHeight = 300; + this.goggleResolution = 82; + this.graphHeight = 400; + } else if (window.innerWidth >= 768) { + this.incomingGraphHeight = 215; + this.goggleResolution = 80; + this.graphHeight = 310; + } else { + this.incomingGraphHeight = 180; + this.goggleResolution = 86; + this.graphHeight = 310; + } + this.isMobile = window.innerWidth <= 767.98; + } +} diff --git a/frontend/src/app/components/difficulty-adjustments-table/difficulty-adjustments-table.component.html b/frontend/src/app/components/difficulty-adjustments-table/difficulty-adjustments-table.component.html new file mode 100644 index 0000000000..bf480289be --- /dev/null +++ b/frontend/src/app/components/difficulty-adjustments-table/difficulty-adjustments-table.component.html @@ -0,0 +1,34 @@ +
+ + + + + + + + + + + + + + + + + + + + + + + + + +
HeightAdjustedDifficultyChange
+ {{ diffChange.height }} + + + {{ diffChange.difficultyShorten }} + {{ diffChange.change >= 0 ? '+' : '' }}{{ diffChange.change | amountShortener: 2 }}% +
+
\ No newline at end of file diff --git a/frontend/src/app/components/difficulty-adjustments-table/difficulty-adjustments-table.component.scss b/frontend/src/app/components/difficulty-adjustments-table/difficulty-adjustments-table.component.scss new file mode 100644 index 0000000000..f53c052dbb --- /dev/null +++ b/frontend/src/app/components/difficulty-adjustments-table/difficulty-adjustments-table.component.scss @@ -0,0 +1,28 @@ +.latest-adjustments { + width: 100%; + text-align: left; + table-layout:fixed; + tr, th { + border: 0px; + padding-top: 0.65rem !important; + padding-bottom: 0.7rem !important; + } + td { + border: 0px; + padding-top: 0.71rem !important; + padding-bottom: 0.75rem !important; + width: 25%; + @media (max-width: 376px) { + padding: 0.85rem; + } + } +} + +.date { + @media (min-width: 767px) AND (max-width: 991px) { + display: none; + } + @media (max-width: 500px) { + display: none; + } +} \ No newline at end of file diff --git a/frontend/src/app/components/difficulty-adjustments-table/difficulty-adjustments-table.components.ts b/frontend/src/app/components/difficulty-adjustments-table/difficulty-adjustments-table.components.ts new file mode 100644 index 0000000000..7db1367ea8 --- /dev/null +++ b/frontend/src/app/components/difficulty-adjustments-table/difficulty-adjustments-table.components.ts @@ -0,0 +1,65 @@ +import { Component, Inject, LOCALE_ID, OnInit } from '@angular/core'; +import { Observable } from 'rxjs'; +import { map } from 'rxjs/operators'; +import { ApiService } from '../../services/api.service'; +import { formatNumber } from '@angular/common'; +import { selectPowerOfTen } from '../../bitcoin.utils'; +import { StateService } from '../../services/state.service'; + +@Component({ + selector: 'app-difficulty-adjustments-table', + templateUrl: './difficulty-adjustments-table.component.html', + styleUrls: ['./difficulty-adjustments-table.component.scss'], + styles: [` + .loadingGraphs { + position: absolute; + top: 50%; + left: calc(50% - 15px); + z-index: 100; + } + `], +}) +export class DifficultyAdjustmentsTable implements OnInit { + hashrateObservable$: Observable; + isLoading = true; + formatNumber = formatNumber; + + constructor( + @Inject(LOCALE_ID) public locale: string, + private apiService: ApiService, + public stateService: StateService + ) { + } + + ngOnInit(): void { + let decimals = 2; + if (this.stateService.network === 'signet') { + decimals = 5; + } + + this.hashrateObservable$ = this.apiService.getDifficultyAdjustments$('3m') + .pipe( + map((response) => { + const data = response.body; + const tableData = []; + for (const adjustment of data) { + const selectedPowerOfTen: any = selectPowerOfTen(adjustment[2]); + tableData.push({ + height: adjustment[1], + timestamp: adjustment[0], + change: (adjustment[3] - 1) * 100, + difficultyShorten: formatNumber( + adjustment[2] / selectedPowerOfTen.divider, + this.locale, `1.${decimals}-${decimals}`) + selectedPowerOfTen.unit + }); + } + this.isLoading = false; + return tableData.slice(0, 6); + }), + ); + } + + isMobile() { + return (window.innerWidth <= 767.98); + } +} diff --git a/frontend/src/app/components/difficulty-mining/difficulty-mining.component.html b/frontend/src/app/components/difficulty-mining/difficulty-mining.component.html new file mode 100644 index 0000000000..4d135dfbe3 --- /dev/null +++ b/frontend/src/app/components/difficulty-mining/difficulty-mining.component.html @@ -0,0 +1,95 @@ +
Difficulty Adjustment
+
+
+
+
+
+
Remaining
+
+ + {{ i }} blocks + {{ i }} block +
+
+
+
+
Estimate
+
+ + + + + + + {{ epochData.change | absolute | number: '1.2-2' }} + % +
+
+ Previous: + + + + + + + + {{ epochData.previousRetarget | absolute | number: '1.2-2' }} % +
+
+
+
Current Period
+
{{ epochData.progress | number: '1.2-2' }} %
+
+
 
+
+
+
+
Next Halving
+
+ {{ timeUntilHalving | date }} +
+ +
+ +
+ +
+
+
+
+
+
+
+
+ + + + {{ i }} blocks + {{ i }} block + + + +
+
+
Remaining
+
+
+
+
+
+
+
Estimate
+
+
+
+
+
+
+
Next Halving
+
+
+
+
+
+
+
diff --git a/frontend/src/app/components/difficulty-mining/difficulty-mining.component.scss b/frontend/src/app/components/difficulty-mining/difficulty-mining.component.scss new file mode 100644 index 0000000000..bd396928fc --- /dev/null +++ b/frontend/src/app/components/difficulty-mining/difficulty-mining.component.scss @@ -0,0 +1,161 @@ +.difficulty-adjustment-container { + display: flex; + flex-direction: row; + justify-content: space-around; + height: 76px; + .shared-block { + color: var(--transparent-fg); + font-size: 12px; + } + .item { + padding: 0 5px; + width: 100%; + max-width: 150px; + &:nth-child(1) { + display: none; + @media (min-width: 485px) { + display: table-cell; + } + @media (min-width: 768px) { + display: none; + } + @media (min-width: 992px) { + display: table-cell; + } + } + } + .card-text { + font-size: 22px; + margin-top: -9px; + position: relative; + } +} + + +.difficulty-skeleton { + display: flex; + justify-content: space-between; + @media (min-width: 376px) { + flex-direction: row; + } + .item { + min-width: 120px; + max-width: 150px; + margin: 0; + width: -webkit-fill-available; + @media (min-width: 376px) { + margin: 0 auto 0px; + } + &:first-child{ + display: none; + @media (min-width: 485px) { + display: block; + } + @media (min-width: 768px) { + display: none; + } + @media (min-width: 992px) { + display: block; + } + } + &:last-child { + margin-bottom: 0; + } + } + .card-text { + .skeleton-loader { + width: 100%; + display: block; + &:first-child { + margin: 14px auto 0; + max-width: 80px; + } + &:last-child { + margin: 10px auto 0; + max-width: 120px; + } + } + } +} + +.card { + background-color: var(--bg); + height: 100%; +} + +.card-title { + color: var(--title-fg); + font-size: 1rem; + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; +} + +.progress { + display: inline-flex; + width: 100%; + background-color: var(--secondary); + height: 1.1rem; + max-width: 180px; +} + +.skeleton-loader { + max-width: 100%; +} + +.more-padding { + padding: 18px; +} + +.small-bar { + height: 8px; + top: -4px; + max-width: 120px; +} + +.loading-container { + min-height: 76px; +} + +.main-title { + position: relative; + color: var(--fg); + opacity: var(--opacity); + margin-top: -13px; + font-size: 10px; + text-transform: uppercase; + font-weight: 500; + text-align: center; + padding-bottom: 3px; +} + +.card-wrapper { + .card { + height: auto !important; + } + .card-body { + display: flex; + flex: inherit; + text-align: center; + flex-direction: column; + justify-content: space-around; + padding: 24px 20px; + } +} + +.retarget-sign { + margin-right: -3px; + font-size: 14px; + top: -2px; + position: relative; +} + +.previous-retarget-sign { + margin-right: -2px; + font-size: 10px; +} + +.symbol { + font-size: 13px; + white-space: nowrap; +} \ No newline at end of file diff --git a/frontend/src/app/components/difficulty-mining/difficulty-mining.component.ts b/frontend/src/app/components/difficulty-mining/difficulty-mining.component.ts new file mode 100644 index 0000000000..90b41d7492 --- /dev/null +++ b/frontend/src/app/components/difficulty-mining/difficulty-mining.component.ts @@ -0,0 +1,99 @@ +import { ChangeDetectionStrategy, Component, Input, OnInit } from '@angular/core'; +import { combineLatest, Observable } from 'rxjs'; +import { map } from 'rxjs/operators'; +import { StateService } from '../../services/state.service'; + +interface EpochProgress { + base: string; + change: number; + progress: number; + remainingBlocks: number; + newDifficultyHeight: number; + colorAdjustments: string; + colorPreviousAdjustments: string; + estimatedRetargetDate: number; + previousRetarget: number; + blocksUntilHalving: number; + timeUntilHalving: number; + timeAvg: number; + adjustedTimeAvg: number; +} + +@Component({ + selector: 'app-difficulty-mining', + templateUrl: './difficulty-mining.component.html', + styleUrls: ['./difficulty-mining.component.scss'], + changeDetection: ChangeDetectionStrategy.OnPush, +}) +export class DifficultyMiningComponent implements OnInit { + isLoadingWebSocket$: Observable; + difficultyEpoch$: Observable; + blocksUntilHalving: number | null = null; + timeUntilHalving = 0; + now = new Date().getTime(); + + @Input() showProgress = true; + @Input() showHalving = false; + @Input() showTitle = true; + + constructor( + public stateService: StateService, + ) { } + + ngOnInit(): void { + this.isLoadingWebSocket$ = this.stateService.isLoadingWebSocket$; + this.difficultyEpoch$ = combineLatest([ + this.stateService.blocks$, + this.stateService.difficultyAdjustment$, + ]) + .pipe( + map(([blocks, da]) => { + const maxHeight = blocks.reduce((max, block) => Math.max(max, block.height), 0); + let colorAdjustments = 'var(--transparent-fg)'; + if (da.difficultyChange > 0) { + colorAdjustments = 'var(--green)'; + } + if (da.difficultyChange < 0) { + colorAdjustments = 'var(--red)'; + } + + let colorPreviousAdjustments = 'var(--red)'; + if (da.previousRetarget) { + if (da.previousRetarget >= 0) { + colorPreviousAdjustments = 'var(--green)'; + } + if (da.previousRetarget === 0) { + colorPreviousAdjustments = 'var(--transparent-fg)'; + } + } else { + colorPreviousAdjustments = 'var(--transparent-fg)'; + } + + this.blocksUntilHalving = 210000 - (maxHeight % 210000); + this.timeUntilHalving = new Date().getTime() + (this.blocksUntilHalving * 600000); + this.now = new Date().getTime(); + + const data = { + base: `${da.progressPercent.toFixed(2)}%`, + change: da.difficultyChange, + progress: da.progressPercent, + remainingBlocks: da.remainingBlocks - 1, + colorAdjustments, + colorPreviousAdjustments, + newDifficultyHeight: da.nextRetargetHeight, + estimatedRetargetDate: da.estimatedRetargetDate, + previousRetarget: da.previousRetarget, + blocksUntilHalving: this.blocksUntilHalving, + timeUntilHalving: this.timeUntilHalving, + timeAvg: da.timeAvg, + adjustedTimeAvg: da.adjustedTimeAvg, + }; + return data; + }) + ); + } + + isEllipsisActive(e): boolean { + return (e.offsetWidth < e.scrollWidth); + } +} diff --git a/frontend/src/app/components/difficulty/difficulty-tooltip.component.html b/frontend/src/app/components/difficulty/difficulty-tooltip.component.html new file mode 100644 index 0000000000..7e4b421e10 --- /dev/null +++ b/frontend/src/app/components/difficulty/difficulty-tooltip.component.html @@ -0,0 +1,59 @@ +
+ + + + + + + + + + + + + + + + + + + + Next Block + + + + + + + + + +
+ +
+ + + + + + +
+
+ +{{ i }} blocks expected +{{ i }} block expected +{{ i }} blocks mined +{{ i }} block mined +{{ i }} blocks remaining +{{ i }} block remaining +{{ i }} blocks ahead +{{ i }} block ahead +{{ i }} blocks behind +{{ i }} block behind \ No newline at end of file diff --git a/frontend/src/app/components/difficulty/difficulty-tooltip.component.scss b/frontend/src/app/components/difficulty/difficulty-tooltip.component.scss new file mode 100644 index 0000000000..e4fd989af9 --- /dev/null +++ b/frontend/src/app/components/difficulty/difficulty-tooltip.component.scss @@ -0,0 +1,22 @@ +.difficulty-tooltip { + position: fixed; + background: color-mix(in srgb, var(--active-bg) 95%, transparent); + border-radius: 4px; + box-shadow: 1px 1px 10px rgba(0,0,0,0.5); + color: var(--tooltip-grey); + padding: 10px 15px; + text-align: left; + pointer-events: none; + max-width: 300px; + min-width: 200px; + text-align: center; + + p { + margin: 0; + white-space: nowrap; + } +} + +.next-block { + text-transform: lowercase; +} diff --git a/frontend/src/app/components/difficulty/difficulty-tooltip.component.ts b/frontend/src/app/components/difficulty/difficulty-tooltip.component.ts new file mode 100644 index 0000000000..42d2a61b46 --- /dev/null +++ b/frontend/src/app/components/difficulty/difficulty-tooltip.component.ts @@ -0,0 +1,74 @@ +import { Component, ElementRef, ViewChild, Input, OnChanges, HostListener } from '@angular/core'; + +interface EpochProgress { + base: string; + change: number; + progress: number; + minedBlocks: number; + remainingBlocks: number; + expectedBlocks: number; + newDifficultyHeight: number; + colorAdjustments: string; + colorPreviousAdjustments: string; + estimatedRetargetDate: number; + previousRetarget: number; + blocksUntilHalving: number; + timeUntilHalving: number; +} + +const EPOCH_BLOCK_LENGTH = 2016; // Bitcoin mainnet + +@Component({ + selector: 'app-difficulty-tooltip', + templateUrl: './difficulty-tooltip.component.html', + styleUrls: ['./difficulty-tooltip.component.scss'], +}) +export class DifficultyTooltipComponent implements OnChanges { + @Input() status: string | void; + @Input() progress: EpochProgress | void = null; + @Input() cursorPosition: { x: number, y: number }; + + mined: number; + ahead: number; + behind: number; + expected: number; + remaining: number; + isAhead: boolean; + isBehind: boolean; + isMobile: boolean; + + tooltipPosition = { x: 0, y: 0 }; + + @ViewChild('tooltip') tooltipElement: ElementRef; + + constructor() { + this.onResize(); + } + + ngOnChanges(changes): void { + if (changes.cursorPosition && changes.cursorPosition.currentValue) { + let x = changes.cursorPosition.currentValue.x; + let y = changes.cursorPosition.currentValue.y - 50; + if (this.tooltipElement) { + const elementBounds = this.tooltipElement.nativeElement.getBoundingClientRect(); + x -= elementBounds.width / 2; + x = Math.min(Math.max(x, 20), (window.innerWidth - 20 - elementBounds.width)); + } + this.tooltipPosition = { x, y }; + } + if ((changes.progress || changes.status) && this.progress && this.status) { + this.remaining = this.progress.remainingBlocks; + this.expected = this.progress.expectedBlocks; + this.mined = this.progress.minedBlocks; + this.ahead = Math.max(0, this.mined - this.expected); + this.behind = Math.max(0, this.expected - this.mined); + this.isAhead = this.ahead > 0; + this.isBehind = this.behind > 0; + } + } + + @HostListener('window:resize', ['$event']) + onResize(): void { + this.isMobile = window.innerWidth <= 767.98; + } +} diff --git a/frontend/src/app/components/difficulty/difficulty.component.html b/frontend/src/app/components/difficulty/difficulty.component.html new file mode 100644 index 0000000000..e9bf36515a --- /dev/null +++ b/frontend/src/app/components/difficulty/difficulty.component.html @@ -0,0 +1,164 @@ +
Difficulty Adjustment
+
Halving Countdown
+
+
+
+ difficulty + | + halving +
+
+
+
+ + + + + + + + + + + + + + + +
+
+
+
+ ~ +
+
Average block time
+
+
+
+ + + + + + + {{ epochData.change | absolute | number: '1.2-2' }} + % +
+
+ Previous: + + + + + + + + {{ epochData.previousRetarget | absolute | number: '1.2-2' }} % +
+
+
+
+
+ {{ epochData.retargetDateString }} +
+
+
+
+
+
+
+ + +
+
+
+
+
+
+ {{ ((210000 - epochData.blocksUntilHalving) / 2100).toFixed(2) }}% +
+
+
+
+
+ +
+
+ New subsidy +
+
+
+
+ {{ epochData.blocksUntilHalving | number }} +
+
+ Blocks remaining + Block remaining +
+
+
+
+ {{ epochData.timeUntilHalving | date }} +
+
+ +
+ +
+ +
+
+
+
+
+
+
+ + +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ + \ No newline at end of file diff --git a/frontend/src/app/components/difficulty/difficulty.component.scss b/frontend/src/app/components/difficulty/difficulty.component.scss new file mode 100644 index 0000000000..8de7fae2c7 --- /dev/null +++ b/frontend/src/app/components/difficulty/difficulty.component.scss @@ -0,0 +1,255 @@ +.difficulty-adjustment-container { + display: flex; + flex-direction: column; + justify-content: space-between; +} + +.difficulty-stats { + display: flex; + flex-direction: row; + justify-content: space-around; + height: 50.5px; + .shared-block { + color: var(--transparent-fg); + font-size: 12px; + } + .item { + padding: 0 5px; + width: 100%; + &:nth-child(1) { + display: none; + @media (min-width: 485px) { + display: table-cell; + } + @media (min-width: 768px) { + display: none; + } + @media (min-width: 992px) { + display: table-cell; + } + } + } + .card-text { + font-size: 18px; + margin: auto; + position: relative; + margin-bottom: 0.2rem; + &.bigger { + font-size: 20px; + margin-bottom: 0; + } + } +} + + +.difficulty-skeleton { + display: flex; + flex-direction: row; + justify-content: space-around; + height: 50.5px; + @media (min-width: 376px) { + flex-direction: row; + } + .item { + min-width: 120px; + max-width: 150px; + margin: 0; + width: -webkit-fill-available; + @media (min-width: 376px) { + margin: 0 auto 0px; + } + &:first-child{ + display: none; + @media (min-width: 485px) { + display: block; + } + @media (min-width: 768px) { + display: none; + } + @media (min-width: 992px) { + display: block; + } + } + &:last-child { + margin-bottom: 0; + } + } + .card-text { + .skeleton-loader { + width: 100%; + display: block; + &:first-child { + margin: 10px auto 4px; + max-width: 80px; + } + &:last-child { + margin: 10px auto 0; + max-width: 120px; + } + } + } +} + +.card { + background-color: var(--bg); + height: 100%; +} + +.card-title { + color: var(--title-fg); + font-size: 1rem; +} + +.progress { + display: inline-flex; + width: 100%; + background-color: var(--secondary); + height: 1.1rem; + max-width: 180px; +} + +.skeleton-loader { + max-width: 100%; +} + +.more-padding { + padding: 18px; +} + +.small-bar { + height: 8px; + top: -4px; + max-width: 120px; +} + +.loading-container { + min-height: 50.5px; +} + +.main-title { + position: relative; + color: var(--fg); + opacity: var(--opacity); + margin-top: -13px; + font-size: 10px; + text-transform: uppercase; + font-weight: 500; + text-align: center; + padding-bottom: 3px; +} + +.card-wrapper { + .card { + height: auto !important; + } + .card-body { + display: flex; + flex: inherit; + text-align: center; + flex-direction: column; + justify-content: space-around; + padding: 20px; + } +} + +.retarget-sign { + margin-right: -3px; + font-size: 14px; + top: -2px; + position: relative; +} + +.previous-retarget-sign { + margin-right: -2px; + font-size: 10px; +} + +.symbol { + font-size: 13px; + white-space: nowrap; +} + +.epoch-progress, .halving-progress { + width: 100%; + height: 22px; + margin-bottom: 12px; +} + +.epoch-blocks { + display: block; + width: 100%; + background: var(--secondary); + + .rect { + fill: var(--secondary); + + &.behind { + fill: var(--red); + } + &.mined { + fill: url(#diff-gradient); + } + &.ahead { + fill: var(--success); + } + + &.hover { + fill: #535e84; + &.behind { + fill: #e94d86; + } + &.mined { + fill: url(#diff-hover-gradient); + } + &.ahead { + fill: #29d951; + } + } + } +} + +.blocks-ahead { + color: var(--green); +} +.blocks-behind { + color: var(--red); +} + +.halving-progress { + position: relative; + .background, .remaining { + position: absolute; + top: 0; + bottom: 0; + height: 100%; + } + .background { + background: linear-gradient(to right, var(--primary), var(--mainnet-alt)); + left: 0; + right: 0; + } + .remaining { + background: var(--secondary); + right: 0; + } + .label { + position: relative; + margin: auto; + } +} + +.widget-toggler { + font-size: 12px; + position: absolute; + top: -20px; + right: 3px; + text-align: right; +} + +.toggler-option { + text-decoration: none; +} + +.inactive { + color: var(--transparent-fg); +} \ No newline at end of file diff --git a/frontend/src/app/components/difficulty/difficulty.component.ts b/frontend/src/app/components/difficulty/difficulty.component.ts new file mode 100644 index 0000000000..579b49fc30 --- /dev/null +++ b/frontend/src/app/components/difficulty/difficulty.component.ts @@ -0,0 +1,250 @@ +import { ChangeDetectionStrategy, ChangeDetectorRef, Component, HostListener, ElementRef, ViewChild, Inject, Input, LOCALE_ID, OnInit } from '@angular/core'; +import { combineLatest, Observable } from 'rxjs'; +import { map } from 'rxjs/operators'; +import { StateService } from '../..//services/state.service'; + +interface EpochProgress { + base: string; + change: number; + progress: number; + minedBlocks: number; + remainingBlocks: number; + expectedBlocks: number; + newDifficultyHeight: number; + colorAdjustments: string; + colorPreviousAdjustments: string; + estimatedRetargetDate: number; + retargetDateString: string; + previousRetarget: number; + blocksUntilHalving: number; + timeUntilHalving: number; + timeAvg: number; + adjustedTimeAvg: number; +} + +type BlockStatus = 'mined' | 'behind' | 'ahead' | 'next' | 'remaining'; + +interface DiffShape { + x: number; + y: number; + w: number; + h: number; + status: BlockStatus; + expected: boolean; +} + +const EPOCH_BLOCK_LENGTH = 2016; // Bitcoin mainnet + +@Component({ + selector: 'app-difficulty', + templateUrl: './difficulty.component.html', + styleUrls: ['./difficulty.component.scss'], + changeDetection: ChangeDetectionStrategy.OnPush, +}) +export class DifficultyComponent implements OnInit { + @Input() showProgress = true; + @Input() showHalving = false; + @Input() showTitle = true; + + @ViewChild('epochSvg') epochSvgElement: ElementRef; + + isLoadingWebSocket$: Observable; + difficultyEpoch$: Observable; + + mode: 'difficulty' | 'halving' = 'difficulty'; + userSelectedMode: boolean = false; + + now: number = Date.now(); + epochStart: number; + currentHeight: number; + currentIndex: number; + expectedHeight: number; + expectedIndex: number; + difference: number; + shapes: DiffShape[]; + nextSubsidy: number; + + tooltipPosition = { x: 0, y: 0 }; + hoverSection: DiffShape | void; + + constructor( + public stateService: StateService, + private cd: ChangeDetectorRef, + @Inject(LOCALE_ID) private locale: string, + ) { } + + ngOnInit(): void { + this.isLoadingWebSocket$ = this.stateService.isLoadingWebSocket$; + this.difficultyEpoch$ = combineLatest([ + this.stateService.blocks$, + this.stateService.difficultyAdjustment$, + ]) + .pipe( + map(([blocks, da]) => { + const maxHeight = blocks.reduce((max, block) => Math.max(max, block.height), 0); + let colorAdjustments = 'var(--transparent-fg)'; + if (da.difficultyChange > 0) { + colorAdjustments = 'var(--green)'; + } + if (da.difficultyChange < 0) { + colorAdjustments = 'var(--red)'; + } + + let colorPreviousAdjustments = 'var(--red)'; + if (da.previousRetarget) { + if (da.previousRetarget >= 0) { + colorPreviousAdjustments = 'var(--green)'; + } + if (da.previousRetarget === 0) { + colorPreviousAdjustments = 'var(--transparent-fg)'; + } + } else { + colorPreviousAdjustments = 'var(--transparent-fg)'; + } + + const blocksUntilHalving = 210000 - (maxHeight % 210000); + const timeUntilHalving = new Date().getTime() + (blocksUntilHalving * 600000); + const newEpochStart = Math.floor(this.stateService.latestBlockHeight / EPOCH_BLOCK_LENGTH) * EPOCH_BLOCK_LENGTH; + const newExpectedHeight = Math.floor(newEpochStart + da.expectedBlocks); + this.now = new Date().getTime(); + this.nextSubsidy = getNextBlockSubsidy(maxHeight); + + if (blocksUntilHalving < da.remainingBlocks && !this.userSelectedMode) { + this.mode = 'halving'; + } + + if (newEpochStart !== this.epochStart || newExpectedHeight !== this.expectedHeight || this.currentHeight !== this.stateService.latestBlockHeight) { + this.epochStart = newEpochStart; + this.expectedHeight = newExpectedHeight; + this.currentHeight = this.stateService.latestBlockHeight; + this.currentIndex = this.currentHeight - this.epochStart; + this.expectedIndex = Math.min(this.expectedHeight - this.epochStart, 2016) - 1; + this.difference = this.currentIndex - this.expectedIndex; + + this.shapes = []; + this.shapes = this.shapes.concat(this.blocksToShapes( + 0, Math.min(this.currentIndex, this.expectedIndex), 'mined', true + )); + this.shapes = this.shapes.concat(this.blocksToShapes( + this.currentIndex + 1, this.expectedIndex, 'behind', true + )); + this.shapes = this.shapes.concat(this.blocksToShapes( + this.expectedIndex + 1, this.currentIndex, 'ahead', false + )); + if (this.currentIndex < 2015) { + this.shapes = this.shapes.concat(this.blocksToShapes( + this.currentIndex + 1, this.currentIndex + 1, 'next', (this.expectedIndex > this.currentIndex) + )); + } + this.shapes = this.shapes.concat(this.blocksToShapes( + Math.max(this.currentIndex + 2, this.expectedIndex + 1), 2105, 'remaining', false + )); + } + + + let retargetDateString; + if (da.remainingBlocks > 1870) { + retargetDateString = (new Date(da.estimatedRetargetDate)).toLocaleDateString(this.locale, { month: 'long', day: 'numeric' }); + } else { + retargetDateString = (new Date(da.estimatedRetargetDate)).toLocaleTimeString(this.locale, { month: 'long', day: 'numeric', hour: 'numeric', minute: 'numeric' }); + } + + const data = { + base: `${da.progressPercent.toFixed(2)}%`, + change: da.difficultyChange, + progress: da.progressPercent, + minedBlocks: this.currentIndex + 1, + remainingBlocks: da.remainingBlocks - 1, + expectedBlocks: Math.floor(da.expectedBlocks), + colorAdjustments, + colorPreviousAdjustments, + newDifficultyHeight: da.nextRetargetHeight, + estimatedRetargetDate: da.estimatedRetargetDate, + retargetDateString, + previousRetarget: da.previousRetarget, + blocksUntilHalving, + timeUntilHalving, + timeAvg: da.timeAvg, + adjustedTimeAvg: da.adjustedTimeAvg, + }; + return data; + }) + ); + } + + blocksToShapes(start: number, end: number, status: BlockStatus, expected: boolean = false): DiffShape[] { + const startY = start % 9; + const startX = Math.floor(start / 9); + const endY = (end % 9); + const endX = Math.floor(end / 9); + + if (startX > endX) { + return []; + } + + if (startX === endX) { + return [{ + x: startX, y: startY, w: 1, h: 1 + endY - startY, status, expected + }]; + } + + const shapes = []; + shapes.push({ + x: startX, y: startY, w: 1, h: 9 - startY, status, expected + }); + shapes.push({ + x: endX, y: 0, w: 1, h: endY + 1, status, expected + }); + + if (startX < endX - 1) { + shapes.push({ + x: startX + 1, y: 0, w: endX - startX - 1, h: 9, status, expected + }); + } + + return shapes; + } + + setMode(mode: 'difficulty' | 'halving'): boolean { + this.mode = mode; + this.userSelectedMode = true; + return false; + } + + @HostListener('pointerdown', ['$event']) + onPointerDown(event): void { + if (this.epochSvgElement?.nativeElement?.contains(event.target)) { + this.onPointerMove(event); + event.preventDefault(); + } + } + + @HostListener('pointermove', ['$event']) + onPointerMove(event): void { + if (this.epochSvgElement?.nativeElement?.contains(event.target)) { + this.tooltipPosition = { x: event.clientX, y: event.clientY }; + this.cd.markForCheck(); + } + } + + onHover(_, rect): void { + this.hoverSection = rect; + } + + onBlur(): void { + this.hoverSection = null; + } +} + +function getNextBlockSubsidy(height: number): number { + const halvings = Math.floor(height / 210_000) + 1; + // Force block reward to zero when right shift is undefined. + if (halvings >= 64) { + return 0; + } + + let subsidy = BigInt(50 * 100_000_000); + // Subsidy is cut in half every 210,000 blocks which will occur approximately every 4 years. + subsidy >>= BigInt(halvings); + return Number(subsidy); +} \ No newline at end of file diff --git a/frontend/src/app/components/eight-blocks/eight-blocks.component.html b/frontend/src/app/components/eight-blocks/eight-blocks.component.html new file mode 100644 index 0000000000..414a693d36 --- /dev/null +++ b/frontend/src/app/components/eight-blocks/eight-blocks.component.html @@ -0,0 +1,25 @@ +
+ +
+
+ +
+

{{ blockInfo[i].height }}

+

by {{ blockInfo[i].extras.pool.name || 'Unknown' }}

+
+
+
+
+
\ No newline at end of file diff --git a/frontend/src/app/components/eight-blocks/eight-blocks.component.scss b/frontend/src/app/components/eight-blocks/eight-blocks.component.scss new file mode 100644 index 0000000000..6d2c9931cf --- /dev/null +++ b/frontend/src/app/components/eight-blocks/eight-blocks.component.scss @@ -0,0 +1,69 @@ +.blocks { + width: 100%; + height: 100%; + min-width: 100vw; + display: flex; + flex-direction: row; + flex-wrap: nowrap; + justify-content: flex-start; + align-items: flex-start; + align-content: flex-start; + + &.wrap { + flex-wrap: wrap; + } + + .block-wrapper { + flex-grow: 0; + flex-shrink: 0; + position: relative; + --block-width: 1080px; + + .info { + position: absolute; + left: 8%; + top: 8%; + right: 8%; + bottom: 8%; + height: 84%; + width: 84%; + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + font-weight: 700; + font-size: calc(var(--block-width) * 0.03); + text-shadow: 0 0 calc(var(--block-width) * 0.05) black; + + h1 { + font-size: 6em; + line-height: 1; + margin-bottom: calc(var(--block-width) * 0.03); + } + h2 { + font-size: 1.8em; + line-height: 1; + margin-bottom: calc(var(--block-width) * 0.03); + } + + .hash { + font-family: monospace; + word-wrap: break-word; + font-size: 1.4em; + line-height: 1; + margin-bottom: calc(var(--block-width) * 0.03); + } + + .mined-by { + position: absolute; + bottom: 0; + margin: auto; + text-align: center; + } + } + } + + .block-container { + overflow: hidden; + } +} \ No newline at end of file diff --git a/frontend/src/app/components/eight-blocks/eight-blocks.component.ts b/frontend/src/app/components/eight-blocks/eight-blocks.component.ts new file mode 100644 index 0000000000..81dcc4c5bf --- /dev/null +++ b/frontend/src/app/components/eight-blocks/eight-blocks.component.ts @@ -0,0 +1,253 @@ +import { Component, OnInit, OnDestroy, ViewChildren, QueryList } from '@angular/core'; +import { ActivatedRoute, Router } from '@angular/router'; +import { catchError, startWith } from 'rxjs/operators'; +import { Subject, Subscription, of } from 'rxjs'; +import { StateService } from '../../services/state.service'; +import { WebsocketService } from '../../services/websocket.service'; +import { RelativeUrlPipe } from '../../shared/pipes/relative-url/relative-url.pipe'; +import { BlockExtended, TransactionStripped } from '../../interfaces/node-api.interface'; +import { ApiService } from '../../services/api.service'; +import { BlockOverviewGraphComponent } from '../block-overview-graph/block-overview-graph.component'; +import { detectWebGL } from '../../shared/graphs.utils'; +import { animate, style, transition, trigger } from '@angular/animations'; +import { BytesPipe } from '../../shared/pipes/bytes-pipe/bytes.pipe'; + +function bestFitResolution(min, max, n): number { + const target = (min + max) / 2; + let bestScore = Infinity; + let best = null; + for (let i = min; i <= max; i++) { + const remainder = (n % i); + if (remainder < bestScore || (remainder === bestScore && (Math.abs(i - target) < Math.abs(best - target)))) { + bestScore = remainder; + best = i; + } + } + return best; +} + +interface BlockInfo extends BlockExtended { + timeString: string; +} + +@Component({ + selector: 'app-eight-blocks', + templateUrl: './eight-blocks.component.html', + styleUrls: ['./eight-blocks.component.scss'], + animations: [ + trigger('infoChange', [ + transition(':enter', [ + style({ opacity: 0 }), + animate('1000ms', style({ opacity: 1 })), + ]), + transition(':leave', [ + animate('1000ms 500ms', style({ opacity: 0 })) + ]) + ]), + ], +}) +export class EightBlocksComponent implements OnInit, OnDestroy { + network = ''; + latestBlocks: BlockExtended[] = []; + isLoadingTransactions = true; + strippedTransactions: { [height: number]: TransactionStripped[] } = {}; + webGlEnabled = true; + hoverTx: string | null = null; + + blocksSubscription: Subscription; + cacheBlocksSubscription: Subscription; + networkChangedSubscription: Subscription; + queryParamsSubscription: Subscription; + graphChangeSubscription: Subscription; + + numBlocks: number = 8; + blockIndices: number[] = [...Array(8).keys()]; + autofit: boolean = false; + padding: number = 0; + wrapBlocks: boolean = false; + blockWidth: number = 1080; + animationDuration: number = 2000; + animationOffset: number = 0; + stagger: number = 0; + testing: boolean = true; + testHeight: number = 800000; + testShiftTimeout: number; + + showInfo: boolean = true; + blockInfo: BlockInfo[] = []; + + wrapperStyle = { + '--block-width': '1080px', + width: '1080px', + maxWidth: '1080px', + padding: '', + }; + containerStyle = {}; + resolution: number = 86; + + @ViewChildren('blockGraph') blockGraphs: QueryList; + + constructor( + private route: ActivatedRoute, + private router: Router, + public stateService: StateService, + private websocketService: WebsocketService, + private apiService: ApiService, + private bytesPipe: BytesPipe, + ) { + this.webGlEnabled = this.stateService.isBrowser && detectWebGL(); + } + + ngOnInit(): void { + this.websocketService.want(['blocks']); + this.network = this.stateService.network; + + this.queryParamsSubscription = this.route.queryParams.subscribe((params) => { + this.numBlocks = Number.isInteger(Number(params.numBlocks)) ? Number(params.numBlocks) : 8; + this.blockIndices = [...Array(this.numBlocks).keys()]; + this.autofit = params.autofit !== 'false'; + this.padding = Number.isInteger(Number(params.padding)) ? Number(params.padding) : 10; + this.blockWidth = Number.isInteger(Number(params.blockWidth)) ? Number(params.blockWidth) : 540; + this.wrapBlocks = params.wrap !== 'false'; + this.stagger = Number.isInteger(Number(params.stagger)) ? Number(params.stagger) : 0; + this.animationDuration = Number.isInteger(Number(params.animationDuration)) ? Number(params.animationDuration) : 2000; + this.animationOffset = this.padding * 2; + + if (this.autofit) { + this.resolution = bestFitResolution(76, 96, this.blockWidth - this.padding * 2); + } else { + this.resolution = 86; + } + + this.wrapperStyle = { + '--block-width': this.blockWidth + 'px', + width: this.blockWidth + 'px', + maxWidth: this.blockWidth + 'px', + padding: (this.padding || 0) +'px 0px', + }; + + if (params.test === 'true') { + if (this.blocksSubscription) { + this.blocksSubscription.unsubscribe(); + } + this.blocksSubscription = (new Subject()).subscribe((blocks) => { + this.handleNewBlock(blocks.slice(0, this.numBlocks)); + }); + this.shiftTestBlocks(); + } else if (!this.blocksSubscription) { + this.blocksSubscription = this.stateService.blocks$ + .subscribe((blocks) => { + this.handleNewBlock(blocks.slice(0, this.numBlocks)); + }); + } + }); + + this.setupBlockGraphs(); + + this.networkChangedSubscription = this.stateService.networkChanged$ + .subscribe((network) => this.network = network); + } + + ngAfterViewInit(): void { + this.graphChangeSubscription = this.blockGraphs.changes.pipe(startWith(null)).subscribe(() => { + this.setupBlockGraphs(); + }); + } + + ngOnDestroy(): void { + this.stateService.markBlock$.next({}); + if (this.blocksSubscription) { + this.blocksSubscription?.unsubscribe(); + } + this.cacheBlocksSubscription?.unsubscribe(); + this.networkChangedSubscription?.unsubscribe(); + this.queryParamsSubscription?.unsubscribe(); + } + + shiftTestBlocks(): void { + const sub = this.apiService.getBlocks$(this.testHeight).subscribe(result => { + sub.unsubscribe(); + this.handleNewBlock(result.slice(0, this.numBlocks)); + this.testHeight++; + clearTimeout(this.testShiftTimeout); + this.testShiftTimeout = window.setTimeout(() => { this.shiftTestBlocks(); }, 10000); + }); + } + + async handleNewBlock(blocks: BlockExtended[]): Promise { + const readyPromises: Promise[] = []; + const previousBlocks = this.latestBlocks; + const newHeights = {}; + this.latestBlocks = blocks; + for (const block of blocks) { + newHeights[block.height] = true; + if (!this.strippedTransactions[block.height]) { + readyPromises.push(new Promise((resolve) => { + const subscription = this.apiService.getStrippedBlockTransactions$(block.id).pipe( + catchError(() => { + return of([]); + }), + ).subscribe((transactions) => { + this.strippedTransactions[block.height] = transactions; + subscription.unsubscribe(); + resolve(transactions); + }); + })); + } + } + await Promise.allSettled(readyPromises); + this.updateBlockGraphs(blocks); + + // free up old transactions + previousBlocks.forEach(block => { + if (!newHeights[block.height]) { + delete this.strippedTransactions[block.height]; + } + }); + } + + updateBlockGraphs(blocks): void { + const startTime = performance.now() + 1000 - (this.stagger < 0 ? this.stagger * 8 : 0); + if (this.blockGraphs) { + this.blockGraphs.forEach((graph, index) => { + graph.replace(this.strippedTransactions[blocks?.[index]?.height] || [], 'right', false, startTime + (this.stagger * index)); + }); + } + this.showInfo = false; + setTimeout(() => { + this.blockInfo = blocks.map(block => { + return { + ...block, + timeString: (new Date(block.timestamp * 1000)).toLocaleTimeString(), + }; + }); + this.showInfo = true; + }, 1600); // Should match the animation time. + } + + setupBlockGraphs(): void { + if (this.blockGraphs) { + this.blockGraphs.forEach((graph, index) => { + graph.destroy(); + graph.setup(this.strippedTransactions[this.latestBlocks?.[index]?.height] || []); + }); + } + } + + onTxClick(event: { tx: TransactionStripped, keyModifier: boolean }): void { + const url = new RelativeUrlPipe(this.stateService).transform(`/tx/${event.tx.txid}`); + if (!event.keyModifier) { + this.router.navigate([url]); + } else { + window.open(url, '_blank'); + } + } + + onTxHover(txid: string): void { + if (txid && txid.length) { + this.hoverTx = txid; + } else { + this.hoverTx = null; + } + } +} diff --git a/frontend/src/app/components/faucet/faucet.component.html b/frontend/src/app/components/faucet/faucet.component.html new file mode 100644 index 0000000000..89e6bb8a8a --- /dev/null +++ b/frontend/src/app/components/faucet/faucet.component.html @@ -0,0 +1,90 @@ +
+ +
+

Testnet4 Faucet

+
+ +
+ + @if (txid) { +
+ + Sent! + {{ txid }} +
+ } + @if (loading) { +

Loading faucet...

+
+ } @else if (!user) { + +
+
+ To use the faucet, please  + login +  or +
+ +
+ } + @else if (error === 'not_available') { + +
+
+ To use the faucet, please +
+ +
+ } + @else if (error) { + + + } + + @if (!loading) { +
+
+
+
+
+
+ Amount (sats) +
+ +
+ + + +
+
+
+
Amount is required
+
Minimum is {{ amount?.errors?.['min'].min | number }} tSats
+
Maximum is {{ amount?.errors?.['max'].max | number }} tSats
+
+
+
+ Address +
+ + +
+
+
Address is required
+
Must be a valid testnet4 address
+
You cannot use this address
+
+
+
+
+
+ } + + + @if (status?.address) { +
If you no longer need your testnet4 coins, please consider sending them back to replenish the faucet.
+ } + +
+ +
\ No newline at end of file diff --git a/frontend/src/app/components/faucet/faucet.component.scss b/frontend/src/app/components/faucet/faucet.component.scss new file mode 100644 index 0000000000..c3d3a5b339 --- /dev/null +++ b/frontend/src/app/components/faucet/faucet.component.scss @@ -0,0 +1,52 @@ +.formGroup { + width: 100%; +} + +.input-group { + display: flex; + flex-wrap: wrap; + align-items: stretch; + justify-content: flex-end; + row-gap: 0.5rem; + gap: 0.5rem; + + .form-control { + min-width: 160px; + flex-grow: 100; + } + + .button-group { + display: flex; + align-items: stretch; + } + + .submit-button, .button-group, .button-group .btn { + flex-grow: 1; + } + .submit-button:disabled { + cursor: not-allowed; + } + + #satoshis::after { + content: 'sats'; + position: absolute; + right: 0.5em; + top: 0; + bottom: 0; + } +} + +.faucet-container { + display: flex; + flex-direction: column; + align-items: center; + justify-content: flex-start; + width: 100%; + max-width: 800px; + margin: auto; +} + +.invalid { + border-width: 1px; + border-color: var(--red); +} diff --git a/frontend/src/app/components/faucet/faucet.component.ts b/frontend/src/app/components/faucet/faucet.component.ts new file mode 100644 index 0000000000..891b6310dd --- /dev/null +++ b/frontend/src/app/components/faucet/faucet.component.ts @@ -0,0 +1,184 @@ +import { Component, OnDestroy, OnInit, ChangeDetectorRef } from "@angular/core"; +import { FormBuilder, FormGroup, Validators, ValidatorFn, AbstractControl, ValidationErrors } from "@angular/forms"; +import { Subscription } from "rxjs"; +import { StorageService } from "../../services/storage.service"; +import { ServicesApiServices } from "../../services/services-api.service"; +import { getRegex } from "../../shared/regex.utils"; +import { StateService } from "../../services/state.service"; +import { WebsocketService } from "../../services/websocket.service"; +import { AudioService } from "../../services/audio.service"; +import { HttpErrorResponse } from "@angular/common/http"; + +@Component({ + selector: 'app-faucet', + templateUrl: './faucet.component.html', + styleUrls: ['./faucet.component.scss'] +}) +export class FaucetComponent implements OnInit, OnDestroy { + loading = true; + error: string = ''; + user: any = undefined; + txid: string = ''; + + faucetStatusSubscription: Subscription; + status: { + min: number; // minimum amount to request at once (in sats) + max: number; // maximum amount to request at once + address?: string; // faucet address + code: 'ok' | 'faucet_not_available' | 'faucet_maximum_reached' | 'faucet_too_soon'; + } | null = null; + faucetForm: FormGroup; + + mempoolPositionSubscription: Subscription; + confirmationSubscription: Subscription; + + constructor( + private cd: ChangeDetectorRef, + private storageService: StorageService, + private servicesApiService: ServicesApiServices, + private formBuilder: FormBuilder, + private stateService: StateService, + private websocketService: WebsocketService, + private audioService: AudioService + ) { + this.initForm(5000, 500_000, null); + } + + ngOnDestroy() { + this.stateService.markBlock$.next({}); + this.websocketService.stopTrackingTransaction(); + if (this.mempoolPositionSubscription) { + this.mempoolPositionSubscription.unsubscribe(); + } + if (this.confirmationSubscription) { + this.confirmationSubscription.unsubscribe(); + } + } + + ngOnInit() { + this.user = this.storageService.getAuth()?.user ?? null; + if (!this.user) { + this.loading = false; + return; + } + + // Setup form + this.updateFaucetStatus(); + + // Track transaction + this.websocketService.want(['blocks', 'mempool-blocks']); + this.mempoolPositionSubscription = this.stateService.mempoolTxPosition$.subscribe(txPosition => { + if (txPosition && txPosition.txid === this.txid) { + this.stateService.markBlock$.next({ + txid: txPosition.txid, + mempoolPosition: txPosition.position, + }); + } + }); + + this.confirmationSubscription = this.stateService.txConfirmed$.subscribe(([txConfirmed, block]) => { + if (txConfirmed && txConfirmed === this.txid) { + this.stateService.markBlock$.next({ blockHeight: block.height }); + } + }); + } + + updateFaucetStatus(): void { + this.servicesApiService.getFaucetStatus$().subscribe({ + next: (status) => { + if (!status) { + this.error = 'internal_server_error'; + return; + } + this.status = status; + if (this.status.code !== 'ok') { + this.error = this.status.code; + this.updateForm(this.status.min ?? 5000, this.status.max ?? 500_000, this.status.address); + return; + } + // update the form with the proper validation parameters + this.updateForm(this.status.min, this.status.max, this.status.address); + }, + error: (response) => { + this.loading = false; + this.error = response.error; + this.cd.markForCheck(); + } + }); + } + + requestCoins(): void { + if (this.isDisabled()) { + return; + } + this.error = null; + this.txid = ''; + this.stateService.markBlock$.next({}); + this.servicesApiService.requestTestnet4Coins$(this.faucetForm.get('address')?.value, parseInt(this.faucetForm.get('satoshis')?.value)) + .subscribe({ + next: ((response) => { + this.txid = response.txid; + this.websocketService.startTrackTransaction(this.txid); + this.audioService.playSound('cha-ching'); + this.updateFaucetStatus(); + this.cd.markForCheck(); + }), + error: (response: HttpErrorResponse) => { + this.error = response.error; + }, + }); + } + + isDisabled(): boolean { + return !(this.user && this.status?.code === 'ok' && !this.error); + } + + getNotFaucetAddressValidator(faucetAddress: string): ValidatorFn { + return faucetAddress ? (control: AbstractControl): ValidationErrors | null => { + const forbidden = control.value === faucetAddress; + return forbidden ? { forbiddenAddress: { value: control.value } } : null; + }: () => null; + } + + initForm(min: number, max: number, faucetAddress: string): void { + this.faucetForm = this.formBuilder.group({ + 'address': ['', [Validators.required, Validators.pattern(getRegex('address', 'testnet4')), this.getNotFaucetAddressValidator(faucetAddress)]], + 'satoshis': [min, [Validators.required, Validators.min(min), Validators.max(max)]] + }); + + this.loading = false; + this.cd.markForCheck(); + } + + updateForm(min, max, faucetAddress: string): void { + if (!this.faucetForm) { + this.initForm(min, max, faucetAddress); + } else { + this.faucetForm.get('address').setValidators([Validators.required, Validators.pattern(getRegex('address', 'testnet4')), this.getNotFaucetAddressValidator(faucetAddress)]); + this.faucetForm.get('satoshis').setValidators([Validators.required, Validators.min(min), Validators.max(max)]); + this.faucetForm.get('satoshis').setValue(Math.max(min, this.faucetForm.get('satoshis').value)); + this.faucetForm.get('satoshis').updateValueAndValidity(); + this.faucetForm.get('satoshis').markAsDirty(); + } + } + + setAmount(value: number): void { + if (this.faucetForm) { + this.faucetForm.get('satoshis').setValue(value); + this.faucetForm.get('satoshis').updateValueAndValidity(); + this.faucetForm.get('satoshis').markAsDirty(); + } + } + + get amount() { return this.faucetForm.get('satoshis')!; } + get invalidAmount() { + const amount = this.faucetForm.get('satoshis')!; + return amount?.invalid && (amount.dirty || amount.touched) + } + + get address() { return this.faucetForm.get('address')!; } + get invalidAddress() { + const address = this.faucetForm.get('address')!; + return address?.invalid && (address.dirty || address.touched) + } +} diff --git a/frontend/src/app/components/fee-distribution-graph/fee-distribution-graph.component.html b/frontend/src/app/components/fee-distribution-graph/fee-distribution-graph.component.html index 2fba6ec903..9451133561 100644 --- a/frontend/src/app/components/fee-distribution-graph/fee-distribution-graph.component.html +++ b/frontend/src/app/components/fee-distribution-graph/fee-distribution-graph.component.html @@ -1,9 +1,5 @@ -
- - +
+
diff --git a/frontend/src/app/components/fee-distribution-graph/fee-distribution-graph.component.scss b/frontend/src/app/components/fee-distribution-graph/fee-distribution-graph.component.scss index e69de29bb2..e7150a720f 100644 --- a/frontend/src/app/components/fee-distribution-graph/fee-distribution-graph.component.scss +++ b/frontend/src/app/components/fee-distribution-graph/fee-distribution-graph.component.scss @@ -0,0 +1,3 @@ +.fee-distribution-chart { + margin-top: 0.75rem; +} \ No newline at end of file diff --git a/frontend/src/app/components/fee-distribution-graph/fee-distribution-graph.component.ts b/frontend/src/app/components/fee-distribution-graph/fee-distribution-graph.component.ts index db3dbb7340..c26aae31a7 100644 --- a/frontend/src/app/components/fee-distribution-graph/fee-distribution-graph.component.ts +++ b/frontend/src/app/components/fee-distribution-graph/fee-distribution-graph.component.ts @@ -1,69 +1,200 @@ -import { Component, Input, OnChanges } from '@angular/core'; -import * as Chartist from 'chartist'; +import { HostListener, OnChanges, OnDestroy } from '@angular/core'; +import { Component, Input, OnInit, ChangeDetectionStrategy } from '@angular/core'; +import { TransactionStripped } from '../../interfaces/node-api.interface'; +import { StateService } from '../../services/state.service'; +import { VbytesPipe } from '../../shared/pipes/bytes-pipe/vbytes.pipe'; +import { selectPowerOfTen } from '../../bitcoin.utils'; +import { Subscription } from 'rxjs'; @Component({ selector: 'app-fee-distribution-graph', templateUrl: './fee-distribution-graph.component.html', - styleUrls: ['./fee-distribution-graph.component.scss'] + styleUrls: ['./fee-distribution-graph.component.scss'], + changeDetection: ChangeDetectionStrategy.OnPush, }) -export class FeeDistributionGraphComponent implements OnChanges { - @Input() feeRange; +export class FeeDistributionGraphComponent implements OnInit, OnChanges, OnDestroy { + @Input() feeRange: number[]; + @Input() vsize: number; + @Input() transactions: TransactionStripped[]; + @Input() height: number | string = 210; + @Input() top: number | string = 20; + @Input() right: number | string = 22; + @Input() left: number | string = 30; + @Input() numSamples: number = 200; + @Input() numLabels: number = 10; - mempoolVsizeFeesData: any; - mempoolVsizeFeesOptions: any; + simple: boolean = false; + data: number[][]; + labelInterval: number = 50; + smallScreen: boolean = window.innerWidth < 450; - feeLevels = [1, 2, 3, 4, 5, 6, 8, 10, 12, 15, 20, 30, 40, 50, 60, 70, 80, 90, 100, 125, 150, 175, 200, - 250, 300, 350, 400, 500]; + rateUnitSub: Subscription; + weightMode: boolean = false; + mempoolVsizeFeesOptions: any; + mempoolVsizeFeesInitOptions = { + renderer: 'svg' + }; constructor( + public stateService: StateService, + private vbytesPipe: VbytesPipe, ) { } - ngOnChanges() { - this.mempoolVsizeFeesOptions = { - showArea: true, - showLine: true, - fullWidth: true, - showPoint: true, - low: 0, - axisY: { - showLabel: false, - offset: 0 - }, - axisX: { - showGrid: true, - showLabel: false, - offset: 0 - }, - plugins: [ - Chartist.plugins.ctPointLabels({ - textAnchor: 'middle', - labelInterpolationFnc: (value) => Math.round(value) - }) - ] - }; + ngOnInit() { + this.rateUnitSub = this.stateService.rateUnits$.subscribe(rateUnits => { + this.weightMode = rateUnits === 'wu'; + if (this.data) { + this.mountChart(); + } + }); + } - const fees = this.feeRange; - const series = []; + ngOnChanges(): void { + this.simple = !!this.feeRange?.length; + this.prepareChart(); + this.mountChart(); + } - for (let i = 0; i < this.feeLevels.length; i++) { - let total = 0; - // for (let j = 0; j < fees.length; j++) { - for (const fee of fees) { - if (i === this.feeLevels.length - 1) { - if (fee >= this.feeLevels[i]) { - total += 1; - } - } else if (fee >= this.feeLevels[i] && fee < this.feeLevels[i + 1]) { - total += 1; - } + prepareChart(): void { + if (this.simple) { + this.data = this.feeRange.map((rate, index) => [index * 10, rate]); + this.labelInterval = 1; + return; + } + this.data = []; + if (!this.transactions?.length) { + return; + } + const samples = []; + const txs = this.transactions.map(tx => { return { vsize: tx.vsize, rate: tx.rate || (tx.fee / tx.vsize) }; }).sort((a, b) => { return b.rate - a.rate; }); + const maxBlockVSize = this.stateService.env.BLOCK_WEIGHT_UNITS / 4; + const sampleInterval = maxBlockVSize / this.numSamples; + let cumVSize = 0; + let sampleIndex = 0; + let nextSample = 0; + let txIndex = 0; + this.labelInterval = this.numSamples / this.numLabels; + while (nextSample <= maxBlockVSize) { + if (txIndex >= txs.length) { + samples.push([(1 - (sampleIndex / this.numSamples)) * 100, 0.000001]); + nextSample += sampleInterval; + sampleIndex++; + continue; + } + + while (txs[txIndex] && nextSample < cumVSize + txs[txIndex].vsize) { + samples.push([(1 - (sampleIndex / this.numSamples)) * 100, txs[txIndex].rate || 0.000001]); + nextSample += sampleInterval; + sampleIndex++; } - series.push(total); + cumVSize += txs[txIndex].vsize; + txIndex++; } + this.data = samples.reverse(); + } - this.mempoolVsizeFeesData = { - series: [fees], - labels: fees.map((d, i) => i) + mountChart(): void { + this.mempoolVsizeFeesOptions = { + grid: { + height: '210', + right: this.smallScreen ? '10' : '20', + top: '22', + left: this.smallScreen ? '10' : '40', + }, + xAxis: { + type: 'category', + boundaryGap: false, + name: '% Weight', + nameLocation: 'middle', + nameGap: 0, + nameTextStyle: { + verticalAlign: 'top', + padding: [30, 0, 0, 0], + }, + axisLabel: { + interval: (index: number): boolean => { return index && (index % this.labelInterval === 0); }, + formatter: (value: number): string => { return Number(value).toFixed(0); }, + }, + axisTick: { + interval: (index:number): boolean => { return (index % this.labelInterval === 0); }, + }, + }, + yAxis: { + type: 'log', + min: 1, + max: this.data.reduce((min, val) => Math.max(min, val[1]), 1), + // name: 'Effective Fee Rate s/vb', + // nameLocation: 'middle', + splitLine: { + lineStyle: { + type: 'dotted', + color: 'var(--transparent-fg)', + opacity: 0.25, + } + }, + axisLabel: { + show: !this.smallScreen, + formatter: (value: number): string => { + const unitValue = this.weightMode ? value / 4 : value; + const selectedPowerOfTen = selectPowerOfTen(unitValue); + const scaledValue = unitValue / selectedPowerOfTen.divider; + const newVal = scaledValue >= 100 ? Math.round(scaledValue) : scaledValue.toPrecision(3); + return `${newVal}${selectedPowerOfTen.unit}`; + }, + }, + axisTick: { + show: !this.smallScreen, + } + }, + series: [{ + data: this.data, + type: 'line', + label: { + show: true, + position: 'top', + color: '#ffffff', + textShadowBlur: 0, + fontSize: this.smallScreen ? 10 : 12, + formatter: (label: { data: number[] }): string => { + const value = label.data[1]; + const unitValue = this.weightMode ? value / 4 : value; + const selectedPowerOfTen = selectPowerOfTen(unitValue); + const scaledValue = unitValue / selectedPowerOfTen.divider; + const newVal = scaledValue >= 100 ? Math.round(scaledValue) : scaledValue.toPrecision(3); + return `${newVal}${selectedPowerOfTen.unit}`; + } + }, + showAllSymbol: false, + smooth: true, + lineStyle: { + color: '#D81B60', + width: 1, + }, + itemStyle: { + color: '#b71c1c', + borderWidth: 10, + borderMiterLimit: 10, + opacity: 1, + }, + areaStyle: { + color: '#D81B60', + opacity: 1, + } + }] }; } + @HostListener('window:resize', ['$event']) + onResize(): void { + const isSmallScreen = window.innerWidth < 450; + if (this.smallScreen !== isSmallScreen) { + this.smallScreen = isSmallScreen; + this.prepareChart(); + this.mountChart(); + } + } + + ngOnDestroy(): void { + this.rateUnitSub.unsubscribe(); + } } diff --git a/frontend/src/app/components/fees-box/fees-box.component.html b/frontend/src/app/components/fees-box/fees-box.component.html new file mode 100644 index 0000000000..580307df5d --- /dev/null +++ b/frontend/src/app/components/fees-box/fees-box.component.html @@ -0,0 +1,77 @@ +
+
+
+ No Priority +
+
+
+ Low Priority + Medium Priority + High Priority +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ + +
+
+ No Priority +
+
+
+ Low Priority + Medium Priority + High Priority +
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/frontend/src/app/components/fees-box/fees-box.component.scss b/frontend/src/app/components/fees-box/fees-box.component.scss new file mode 100644 index 0000000000..c5843f58b2 --- /dev/null +++ b/frontend/src/app/components/fees-box/fees-box.component.scss @@ -0,0 +1,129 @@ +.card-title { + color: var(--title-fg); + font-size: 10px; + margin-bottom: 4px; + font-size: 1rem; +} + +.card-text { + font-size: 22px; + span { + font-size: 11px; + position: relative; + top: -2px; + display: inline-flex; + } + .green-color { + display: block; + } +} + +.fee-estimation-container { + display: flex; + justify-content: space-between; + flex-direction: row; + .item { + width: 100px; + margin: 0; + width: -webkit-fill-available; + &:first-child { + @media (767px < width < 992px), (width < 576px) { + display: none + } + } + margin: 0 auto 0px; + &:last-child { + margin-bottom: 0; + } + .card-text span { + color: var(--transparent-fg); + font-size: 12px; + top: 0px; + } + .fee-text{ + border-bottom: 1px solid #ffffff1c; + width: fit-content; + margin: auto; + font-size: 20px; + } + .fiat { + display: block; + font-size: 13px !important; + } + } +} + +.loading-container{ + height: 50px; +} + +.card-text { + .skeleton-loader { + width: 100%; + display: block; + &:first-child { + max-width: 70px; + margin: 10px auto 3px; + } + &:last-child { + margin: 10px auto 3px; + max-width: 55px; + } + } +} + +.fee-progress-bar { + width: 25%; + height: 22px; + margin-bottom: 12px; + display: flex; + flex-direction: row; + transition: background-color 1s; + color: #fff; + &.priority { + @media (767px < width < 992px), (width < 576px) { + width: 100%; + } + width: 75%; + border-radius: 0px 10px 10px 0px; + } + &:first-child { + @media (767px < width < 992px), (width < 576px) { + display: none + } + } +} + +.band-separator { + width: 5%; + @media (767px < width < 992px), (width < 576px) { + display: none + } + &.fill { + height: 22px; + background: repeating-linear-gradient( + 90deg, + rgb(45, 51, 72), + rgb(45, 51, 72) 2px, + rgb(29, 31, 49) 2px, + rgb(29, 31, 49) 4px + ); + } +} + +.fee-label { + padding-top: 2px; + font-size: 12px; + width: 100%; + @media (767px < width < 992px), (width < 576px) { + width: 33%; + } + &.prority { + width: 33%; + } + overflow: hidden; + text-overflow: ellipsis; + white-space: nowrap; + padding-left: 5px; + padding-right: 5px; +} \ No newline at end of file diff --git a/frontend/src/app/components/fees-box/fees-box.component.ts b/frontend/src/app/components/fees-box/fees-box.component.ts new file mode 100644 index 0000000000..78fd102ca3 --- /dev/null +++ b/frontend/src/app/components/fees-box/fees-box.component.ts @@ -0,0 +1,67 @@ +import { Component, OnInit, ChangeDetectionStrategy, OnDestroy, ChangeDetectorRef } from '@angular/core'; +import { StateService } from '../../services/state.service'; +import { Observable, combineLatest, Subscription } from 'rxjs'; +import { Recommendedfees } from '../../interfaces/websocket.interface'; +import { feeLevels } from '../../app.constants'; +import { map, startWith, tap } from 'rxjs/operators'; +import { ThemeService } from '../../services/theme.service'; + +@Component({ + selector: 'app-fees-box', + templateUrl: './fees-box.component.html', + styleUrls: ['./fees-box.component.scss'], + changeDetection: ChangeDetectionStrategy.OnPush, +}) +export class FeesBoxComponent implements OnInit, OnDestroy { + isLoading$: Observable; + recommendedFees$: Observable; + themeSubscription: Subscription; + gradient = 'linear-gradient(to right, var(--skeleton-bg), var(--skeleton-bg))'; + noPriority = 'var(--skeleton-bg)'; + fees: Recommendedfees; + + constructor( + private stateService: StateService, + private themeService: ThemeService, + private cd: ChangeDetectorRef, + ) { } + + ngOnInit(): void { + this.isLoading$ = combineLatest( + this.stateService.isLoadingWebSocket$.pipe(startWith(false)), + this.stateService.loadingIndicators$.pipe(startWith({ mempool: 0 })), + ).pipe(map(([socket, indicators]) => { + return socket || (indicators.mempool != null && indicators.mempool !== 100); + })); + this.recommendedFees$ = this.stateService.recommendedFees$ + .pipe( + tap((fees) => { + this.fees = fees; + this.setFeeGradient(); + } + ) + ); + this.themeSubscription = this.themeService.themeChanged$.subscribe(() => { + this.setFeeGradient(); + }) + } + + setFeeGradient() { + let feeLevelIndex = feeLevels.slice().reverse().findIndex((feeLvl) => this.fees.minimumFee >= feeLvl); + feeLevelIndex = feeLevelIndex >= 0 ? feeLevels.length - feeLevelIndex : feeLevelIndex; + const startColor = '#' + (this.themeService.mempoolFeeColors[feeLevelIndex - 1] || this.themeService.mempoolFeeColors[this.themeService.mempoolFeeColors.length - 1]); + + feeLevelIndex = feeLevels.slice().reverse().findIndex((feeLvl) => this.fees.fastestFee >= feeLvl); + feeLevelIndex = feeLevelIndex >= 0 ? feeLevels.length - feeLevelIndex : feeLevelIndex; + const endColor = '#' + (this.themeService.mempoolFeeColors[feeLevelIndex - 1] || this.themeService.mempoolFeeColors[this.themeService.mempoolFeeColors.length - 1]); + + this.gradient = `linear-gradient(to right, ${startColor}, ${endColor})`; + this.noPriority = startColor; + + this.cd.markForCheck(); + } + + ngOnDestroy(): void { + this.themeSubscription.unsubscribe(); + } +} diff --git a/frontend/src/app/components/fiat-selector/fiat-selector.component.html b/frontend/src/app/components/fiat-selector/fiat-selector.component.html new file mode 100644 index 0000000000..4fa55deb9e --- /dev/null +++ b/frontend/src/app/components/fiat-selector/fiat-selector.component.html @@ -0,0 +1,5 @@ +
+ +
diff --git a/frontend/src/app/bisq/bisq-transactions/bisq-transactions.component.scss b/frontend/src/app/components/fiat-selector/fiat-selector.component.scss similarity index 100% rename from frontend/src/app/bisq/bisq-transactions/bisq-transactions.component.scss rename to frontend/src/app/components/fiat-selector/fiat-selector.component.scss diff --git a/frontend/src/app/components/fiat-selector/fiat-selector.component.ts b/frontend/src/app/components/fiat-selector/fiat-selector.component.ts new file mode 100644 index 0000000000..732c6e8628 --- /dev/null +++ b/frontend/src/app/components/fiat-selector/fiat-selector.component.ts @@ -0,0 +1,50 @@ +import { ChangeDetectionStrategy, Component, OnInit } from '@angular/core'; +import { UntypedFormBuilder, UntypedFormGroup } from '@angular/forms'; +import { StorageService } from '../../services/storage.service'; +import { fiatCurrencies } from '../../app.constants'; +import { StateService } from '../../services/state.service'; + +@Component({ + selector: 'app-fiat-selector', + templateUrl: './fiat-selector.component.html', + styleUrls: ['./fiat-selector.component.scss'], + changeDetection: ChangeDetectionStrategy.OnPush +}) +export class FiatSelectorComponent implements OnInit { + fiatForm: UntypedFormGroup; + currencies = Object.entries(fiatCurrencies).sort((a: any, b: any) => { + if (a[1].code < b[1].code) { + return -1; + } + if (a[1].code > b[1].code) { + return 1; + } + return 0; + }); + + constructor( + private formBuilder: UntypedFormBuilder, + private stateService: StateService, + private storageService: StorageService, + ) { } + + ngOnInit() { + this.fiatForm = this.formBuilder.group({ + fiat: ['USD'] + }); + this.stateService.fiatCurrency$.subscribe((fiat) => { + this.fiatForm.get('fiat')?.setValue(fiat); + }); + if (!this.stateService.env.ADDITIONAL_CURRENCIES) { + this.currencies = this.currencies.filter((currency: any) => { + return ['AUD', 'CAD', 'EUR', 'JPY', 'GBP', 'CHF', 'USD'].includes(currency[0]); + }); + } + } + + changeFiat() { + const newFiat = this.fiatForm.get('fiat')?.value; + this.storageService.setValue('fiat-preference', newFiat); + this.stateService.fiatCurrency$.next(newFiat); + } +} diff --git a/frontend/src/app/components/footer/footer.component.html b/frontend/src/app/components/footer/footer.component.html index 4e52aecb7d..a0967b7cbc 100644 --- a/frontend/src/app/components/footer/footer.component.html +++ b/frontend/src/app/components/footer/footer.component.html @@ -1,25 +1,35 @@ -